SSL/TLS設定によるPostgreSQL接続のセキュリティ保護:完全ガイド

SSL/TLS暗号化を使用してPostgreSQL接続を保護する方法を学びます。この包括的なガイドでは、証明書の生成、`postgresql.conf`と`pg_hba.conf`の変更、安全な暗号化通信のためのクライアント設定など、サーバー側とクライアント側の設定をカバーします。転送中の機密データを保護し、最新のセキュリティ基準への準拠を確保します。

SSL/TLS設定によるPostgreSQL接続のセキュリティ保護:完全ガイド

PostgreSQLのSSL/TLS設定には、2つの別々の作業があります。1つ目は暗号化で、ネットワーク上の誰かが転送中の認証情報やクエリ結果を読み取れないようにします。2つ目はID確認で、クライアントが本物のデータベースサーバーと通信していることを確認し、偽装したマシンと通信しないようにします。多くの設定では、最初の部分を行い、2番目を誤ってスキップします。

この区別は実際のデプロイメントで重要です。sslmode=requireは接続を暗号化しますが、それだけではサーバーのホスト名を完全に検証しません。sslmode=verify-fullはそれを実行します。アプリケーションがパブリックネットワーク、共有の企業ネットワーク、完全に制御できないKubernetesオーバーレイ、またはトラフィックが傍受される可能性のある環境を介して接続する場合、verify-fullを目標にする必要があります。

PostgreSQLにおけるSSL/TLSの理解

SSL/TLS(Secure Sockets Layer/Transport Layer Security)は、コンピュータネットワーク上で通信セキュリティを提供するために設計された暗号化プロトコルです。PostgreSQLに適用すると、データベースサーバーとクライアント間で交換されるデータを暗号化します。これにより、不正な第三者が認証情報、財務データ、個人情報などの機密情報を傍受して読み取ることを防ぎます。

PostgreSQLクライアントは、いくつかのSSLモードをサポートしています:

  • sslmode=disable:平文の暗号化されていない接続のみを使用します。
  • sslmode=prefer:最初にTLSを試し、TLSが利用できない場合はプレーンTCPにフォールバックします。これは便利ですが、設定ミスを隠す可能性があります。
  • sslmode=require:TLS暗号化を要求しますが、サーバーのホスト名を必ずしも検証しません。
  • sslmode=verify-ca:TLSを要求し、証明書が信頼できるCAにチェーンされていることを検証します。
  • sslmode=verify-full:TLSを要求し、CAを検証し、ホスト名が証明書と一致することを検証します。

サーバー側では、ssl = onはPostgreSQLがTLS接続を受け入れ可能であることを意味するだけです。すべてのクライアントにTLSの使用を強制するわけではありません。強制はpg_hba.confhostsslルールを使用し、同じユーザーとネットワークがTLSなしで接続できるより広範なhostルールを避けることで行われます。

SSL/TLS設定の前提条件

PostgreSQLのSSL/TLS設定を開始する前に、以下が揃っていることを確認してください:

  1. OpenSSLがインストールされていること:OpenSSLツールキットは、SSL証明書の生成と管理に不可欠です。通常、LinuxおよびmacOSシステムにはプリインストールされています。Windowsの場合は、別途ダウンロードしてインストールする必要があるかもしれません。
  2. PostgreSQL設定ファイルへのアクセスpostgresql.confおよびpg_hba.confファイルを変更するための管理者権限が必要です。
  3. 認証局(CA)の理解:テスト用に自己署名証明書を作成できますが、本番環境では理想的には信頼できる認証局(CA)または内部エンタープライズCAによって署名された証明書を使用する必要があります。

サーバー側のSSL/TLS設定

サーバー側の設定には、SSLの有効化、SSL証明書とキーの場所の指定、クライアント認証の設定が含まれます。

1. SSL証明書とキーの生成または取得

PostgreSQLサーバー用のSSL証明書を取得するには、主に2つの方法があります:

  • 自己署名証明書(テスト/開発用):OpenSSLを使用して作成され、デフォルトでは外部クライアントから信頼されません。初期設定や内部テストに役立ちます。
  • 認証局(CA)からの証明書(本番用):信頼できる公開CA(例:Let's Encrypt、DigiCert)または内部エンタープライズCAから証明書を取得します。これにより、クライアントがサーバーのIDを検証できるようになります。

OpenSSLを使用した自己署名証明書の作成:

これは開発環境や内部環境で一般的なアプローチです。PostgreSQLサーバーまたはOpenSSLがインストールされたマシンで以下のコマンドを実行します:

  1. 証明書用のディレクトリを作成:証明書を整理しておくことをお勧めします。

    sudo mkdir -p /etc/postgresql/ssl
    sudo chown postgres:postgres /etc/postgresql/ssl
    cd /etc/postgresql/ssl
    
  2. サーバーの秘密鍵を生成:この鍵は秘密にしておく必要があります。

    sudo openssl genrsa -out server.key 2048
    
  3. サーバー証明書署名要求(CSR)を作成:サーバーに関する情報が含まれます。

    sudo openssl req -new -key server.key -out server.csr
    

    クライアントが接続するホスト名(例:db01.internal.example.com)を使用します。最近のクライアントは通常、Subject Alternative Name(SAN)をチェックするため、CAプロセスがサポートしている場合は証明書要求にDNS名を含めてください。

  4. 独自のCAで証明書に署名(内部使用の場合)

    • ルートCAの秘密鍵と証明書を作成(まだない場合)
      # CA秘密鍵を生成
      sudo openssl genrsa -des3 -out root.key 2048
      # CA証明書を作成(3650日間有効)
      sudo openssl req -new -x509 -days 3650 -key root.key -out root.crt
      
    • CAでサーバーCSRに署名:これにより、信頼されるサーバー証明書が作成されます。
      sudo openssl x509 -req -days 365 -in server.csr -CA root.crt -CAkey root.key -set_serial 01 -out server.crt
      
  5. パーミッションを設定:PostgreSQLユーザーがこれらのファイルを読み取れるようにします。

    sudo chown postgres:postgres server.key server.crt root.crt
    sudo chmod 600 server.key
    sudo chmod 644 server.crt root.crt
    

公開/エンタープライズCAからの証明書の使用:

CAから証明書を取得する場合、通常は以下を受け取ります:

  • server.crt:サーバーの公開証明書。
  • server.key:サーバーの秘密鍵。
  • root.crt(または類似):CAのルート証明書(および場合によっては中間証明書)。

これらのファイルを安全なディレクトリ(例:/etc/postgresql/ssl/)に配置し、PostgreSQLユーザーが読み取り権限を持つようにします。

2. postgresql.confの設定

postgresql.confファイル(通常はPostgreSQLデータディレクトリにあります)を編集して、SSLを有効にし、証明書ファイルを指定します。

#------------------------------------------------------------------------------
# SSL
#------------------------------------------------------------------------------

ssl = on

# これらはすべてPEM形式であり、サーバーキー/証明書が設定されていない場合は無視されます。
# デフォルトでは、ファイルはサーバーのデータディレクトリにあることが期待されます。
# または、フルパスとして指定することもできます。
ssl_cert_file = '/etc/postgresql/ssl/server.crt'     # (必要に応じてファイル名を変更)
ssl_key_file = '/etc/postgresql/ssl/server.key'      # (必要に応じてファイル名を変更)
ssl_ca_file = '/etc/postgresql/ssl/root.crt'         # (オプション、クライアント証明書検証用)

# オプション:必要に応じて暗号スイートを指定
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'

# オプション:クライアント証明書検証を有効化
#ssl_ca_fileは、信頼するCA証明書を含むファイルに設定する必要があります
#ssl_crl_file = ''
#ssl_crl_dir = ''
  • ssl = on:サーバーでSSLサポートを有効にします。
  • ssl_cert_file:サーバーの公開証明書へのパス。
  • ssl_key_file:サーバーの秘密鍵へのパス。
  • ssl_ca_file:クライアント証明書を検証する際にPostgreSQLが信頼するCA証明書へのパス。クライアントは、サーバーを検証するためにsslrootcertなどの独自のCAファイルを使用します。

3. SSL強制のためのpg_hba.confの設定

pg_hba.confファイルはクライアント認証を制御します。SSL接続を強制するためにエントリを変更する必要があります。

デフォルトでは、pg_hba.confのエントリは次のようになります:

# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            scram-sha-256
# IPv6 local connections:
host    all             all             ::1/128                 scram-sha-256

SSLを強制するには、hostエントリをhostsslに変更します:

# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             all                                     peer
# IPv4 local connections:
hostssl all             all             127.0.0.1/32            scram-sha-256
# IPv6 local connections:
hostssl all             all             ::1/128                 scram-sha-256

# 外部ネットワークアクセスの例 - SSLが必要
hostssl all             app_user        10.20.0.0/16            scram-sha-256
hostssl all             app_user        2001:db8:20::/48        scram-sha-256
  • hostssl:このレコードタイプはSSL接続を要求します。SSLなしの接続試行は拒否されます。
  • hostnossl:このレコードタイプはSSL接続を明示的に禁止します。
  • host:SSL接続と非SSL接続の両方を許可します。hostsslルールの前または代わりに一致するhostルールが存在する場合、クライアントはTLSなしで接続できる可能性があります。

強い理由があり、他の制御が整っていない限り、0.0.0.0/0アクセスを公開しないでください。ほとんどの本番データベースは、アプリケーションサブネット、踏み台ホスト、コネクションプーラー、またはプライベートネットワーク範囲からの接続のみを受け入れるべきです。

4. PostgreSQLサーバーの再起動

postgresql.confpg_hba.confを変更した後、変更を有効にするためにPostgreSQLサービスを再起動する必要があります。

# systemdを使用するシステム(最新のLinuxディストリビューションのほとんど)
sudo systemctl restart postgresql

# init.dを使用するシステム
sudo service postgresql restart

クライアント側のSSL/TLS設定

クライアントも安全に接続するように設定する必要があります。これには、接続パラメータの指定、クライアント証明書の提供、サーバー証明書の検証が含まれます。

1. 接続文字列パラメータ

psqlまたは任意のPostgreSQLクライアントライブラリを介して接続する場合、接続文字列または個別のオプションとしてSSLパラメータを指定できます。

基本的なSSL接続(サーバー認証のみ)

psql "sslmode=require host=your_server_hostname dbname=your_db user=your_user"
  • sslmode:クライアントのSSL動作を制御します。
    • disable:非SSL接続のみ許可。
    • allow:非SSLを許可するが、サーバーがサポートしていればSSLを優先。
    • prefer(デフォルト):SSLを優先するが、SSLが失敗した場合は非SSLを許可。
    • require:SSL接続のみ許可。サーバーがSSLをサポートしていない場合、接続は失敗。
    • verify-ca:SSL接続のみ許可し、サーバー証明書が信頼できるCAによって署名されていることを検証。sslrootcertパラメータを設定する必要があります。
    • verify-full:SSL接続のみ許可し、サーバー証明書を信頼できるCAに対して検証し、サーバーのホスト名が証明書のコモンネーム(CN)またはサブジェクト代替名(SAN)と一致することを検証。

サーバー証明書の検証(verify-caまたはverify-full

セキュリティを強化するには、クライアントがサーバーのIDを検証する必要があります。これには、クライアントがサーバーの証明書に署名したCAを信頼する必要があります。

  1. CA証明書を取得:サーバーの証明書の署名に使用されたroot.crtファイル(または適切なCA証明書)を入手します。
  2. sslrootcertを指定:このCA証明書の場所をクライアントに伝えます。
psql "sslmode=verify-full host=your_server_hostname dbname=your_db user=your_user sslrootcert=/path/to/your/root.crt"

これは、アプリケーションを実行する同じホストまたはコンテナからテストする必要がある接続文字列です。管理者のラップトップではCAファイルが存在するためにpsqlが動作するが、アプリケーションコンテナではCAバンドルがマウントされていないために失敗するというのはよくある失敗です。

2. クライアント証明書(相互認証)

さらに高いレベルのセキュリティのために、サーバーがクライアント証明書を使用してクライアントのIDも検証する相互認証を実装できます。

クライアント証明書の生成:

サーバー証明書と同様に、クライアントの秘密鍵と、サーバーが信頼するCA(多くの場合、サーバー証明書と同じCA)によって署名されたクライアント証明書が必要です。

  1. クライアント秘密鍵を生成

    openssl genrsa -des3 -out client.key 2048
    
  2. クライアントCSRを作成

    openssl req -new -key client.key -out client.csr
    

    詳細を入力し、コモンネームがクライアントに対して一意であることを確認します。

  3. CAでクライアントCSRに署名

    sudo openssl x509 -req -days 365 -in client.csr -CA root.crt -CAkey root.key -set_serial <unique_serial> -out client.crt
    
  4. パーミッションを設定

    chmod 600 client.key
    chmod 644 client.crt
    

クライアント証明書認証のためのpg_hba.confの設定:

サーバー側で、クライアント証明書認証を受け入れるようにpg_hba.confを設定する必要があります。これは多くの場合、cert認証方式を使用します。

# TYPE  DATABASE        USER            ADDRESS                 METHOD
# 特定のユーザー/DBに対してSSLとクライアント証明書認証を要求
hostssl all             your_user       your_client_ip/32       cert map=your_cert_map

特定のクライアント証明書の詳細(SubjectSubjectAltNameなど)をPostgreSQLユーザーにマッピングする場合は、証明書マップファイル(cert_mapオプション)を定義する必要があるかもしれません。詳細なcert認証と証明書マッピングの設定については、PostgreSQLのドキュメントを参照してください。

証明書を使用するクライアントの設定:

クライアントの接続文字列を更新して、証明書とキーへのパスを含めます:

psql "sslmode=verify-full host=your_server_hostname dbname=your_db user=your_user \
sslrootcert=/path/to/your/root.crt sslcert=/path/to/your/client.crt sslkey=/path/to/your/client.key"

ベストプラクティスとヒント

  • sslmode=verify-fullを使用:クライアント側でverify-fullを使用して、中間者攻撃のリスクを低減します。
  • 秘密鍵を保護:秘密鍵(.keyファイル)には厳格なファイルパーミッション(例:chmod 600)を設定し、サーバー上ではPostgreSQLユーザーのみ、クライアント上では接続ユーザーのみが読み取れるようにします。
  • 定期的に証明書を更新:証明書には有効期限があります。接続の中断を避けるために、期限切れ前に更新するプロセスを実装します。
  • 集中型証明書管理:大規模なデプロイメントでは、証明書管理システムの使用や、証明書の発行と更新の自動化を検討します。
  • ログを監視:起動時や接続試行時にSSL関連のエラーがないか、PostgreSQLログを確認します。
  • ドキュメントを参照:最新のパラメータや、PostgreSQLのバージョンに固有の高度な設定オプションについては、公式のPostgreSQLドキュメントを参照してください。

クイック検証チェックリスト

PostgreSQLを再起動した後、サーバーがTLSを有効にしてリッスンしていることを確認します:

SHOW ssl;
SHOW ssl_cert_file;
SHOW ssl_key_file;

次に、クライアントホストからテストします:

psql "host=your_server_hostname dbname=your_db user=your_user sslmode=verify-full sslrootcert=/path/to/root.crt"

セッション内で、接続が暗号化されていることを確認します:

SELECT ssl, version, cipher
FROM pg_stat_ssl
WHERE pid = pg_backend_pid();

sslがfalseの場合、pg_hba.confルールが意図したとおりに強制されていません。verify-fullが失敗するがrequireが機能する場合、証明書に正しいホスト名が欠けているか、クライアントがCAを信頼していないか、アプリケーションがIPアドレスで接続している一方で証明書がDNS名に対して発行されている可能性があります。

優れたPostgreSQL TLS設定は、単にssl = onだけではありません。それはチェーンです:適切な名前を持つ証明書、厳格なパーミッションの秘密鍵、実際にTLSを強制するhostsslルール、そしてソケットを暗号化するだけでなくサーバーを検証するクライアント。