2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SSL証明書接続が必要な PostgresQL サーバーを docker-compose で立ち上げる

Last updated at Posted at 2020-04-14

探してもあまり出てこなかったので、構築の記録を記します。
今回紹介するのは docker 本来の使い方である immutable な使い方ではありませんので、ご注意を。

参考

こちらの記事を参考にしました。

環境

  • Ubuntu 18.04.4 LTS
  • Docker CE
  • docker-compose

nanocp を使いますが、特に記述がない場合は docker-compose が置いてあるフォルダからの相対パスだとお考え下さい。

docker-compose

適当なフォルダを作成し、以下の2つのファイルを配置します。

docker-compose.yaml
version: "3.5"
services:
  db:
    image: postgres:12.2
    container_name: db
    ports:
      - 5432:5432
    env_file:
      - postgres.env
    tty: true
    restart: always
    volumes:
      - ./pgdata:/var/lib/postgresql/data

起動すると、同じフォルダの中に pgdata というフォルダができ、その中に postgres のデータが入って来ます。

postgres.env
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password

postgres.env は、docker-compose.yaml の中にシークレットを保存しておきたくなかったので外持ちにしています。一度立ち上げて、 pgdata にデータが出来た後は消して問題ありません。

ファイルを用意したら、立ち上げます。

docker-compose up -d

証明書作成

まずはコンテナの中に入ります。

docker-compose exec db bash

/var/lib/postgresql/data/ にpostgresのデータが入っています。

cd /var/lib/postgresql/data/

あとは、基本的に愚直に参考記事の通りにコマンドを叩いていきます。

まずはサーバー関連の証明書。

mkdir cert && cd cert
openssl req -new -nodes -text -out ca.csr -keyout ca-key.pem -subj "/CN=certificate-authority"
openssl x509 -req -in ca.csr -text -extfile /etc/ssl/openssl.cnf -extensions v3_ca -signkey ca-key.pem -out ca-cert.pem
openssl req -new -nodes -text -out server.csr -keyout server-key.pem -subj "/CN=pg-server"
openssl x509 -req -in server.csr -text -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem

追記

100年有効にしたい場合はこちら

mkdir cert && cd cert
openssl req -new -nodes -text -out ca.csr -keyout ca-key.pem -subj "/CN=certificate-authority"
openssl x509 -req -days 36500 -in ca.csr -text -extfile /etc/ssl/openssl.cnf -extensions v3_ca -signkey ca-key.pem -out ca-cert.pem
openssl req -new -nodes -text -out server.csr -keyout server-key.pem -subj "/CN=pg-server"
openssl x509 -req -days 36500 -in server.csr -text -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem

次にクライアント用も作ります。
DBに接続するユーザー名を変える場合は /CN=postgres の個所を変更してください。

openssl req -new -nodes -text -out client.csr -keyout client-key.pem -subj "/CN=postgres"
openssl x509 -req -in client.csr -text -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem

100年有効にしたい場合はこちら

openssl req -new -nodes -text -out client.csr -keyout client-key.pem -subj "/CN=postgres"
openssl x509 -req -days 36500 -in client.csr -text -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem

ls で確認すると、以下のファイルが出来ています。

ca-cert.pem  ca.csr      client-cert.pem  client-key.pem   server.csr
ca-cert.srl  ca-key.pem  client.csr       server-cert.pem  server-key.pem

所有者が root になっているので、postgres に変更します。

chown -R postgres:postgres ./

参考記事ではここから別の場所に移動していますが、この場所のまま設定していこうと思います。

通信の SSL 化

nano を使いたいのですが、そんな高等なものはこのイメージにはインストールされていないので、一旦コンテナを抜けます。vi は入っているので、使える方は vi で直接編集した方が楽です。

exit

pgdata フォルダに入っているデータは root じゃないと編集できないので、root になります。

sudo su

まずは postgres.conf から。

nano pgdata/postgresql.conf

# - SSL - から始まるセクションを、以下のように変更します。

# - SSL -
ssl = on
ssl_ca_file = '/var/lib/postgresql/data/cert/ca-cert.pem'
ssl_cert_file = '/var/lib/postgresql/data/cert/server-cert.pem'
#ssl_crl_file = ''
ssl_key_file = '/var/lib/postgresql/data/cert/server-key.pem'
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off

次に、pg_hba.conf を編集します。

nano pgdata/pg_hba.conf

最後の行をコメントアウトし、新たに一行追加します。

# host all all all md5 
hostssl all             all             0.0.0.0/0               md5

元のユーザーに戻り、コンテナを再起動します。

exit
docker-compose down
docker-compose up -d

psql がインストールされている適当な別マシンから、接続を試みます。

psql "host=<host address> user=postgres dbname=postgres"

次のように、SSL connection ~~~ と出てくれば成功です。

psql (12.2 (Ubuntu 12.2-2.pgdg18.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=#

証明書接続の強制

ここから、クライアント側に証明書による接続を強制していきます。

まず、 pg_hba.conf を編集し、最後の行のmd5をcertに変更します。

# host all all all md5 
hostssl all             all             0.0.0.0/0               cert

試しにこの状態で、別クライアントから先程と同じコマンドで接続すると…

psql: error: could not connect to server: FATAL:  connection requires a valid client certificate
FATAL:  no pg_hba.conf entry for host "<host address>", user "postgres", database "postgres", SSL off

このようにエラーが出ます。
サーバーの方に戻って、クライアント用の証明書を用意します。

…と言っても、証明書自体は先程一緒に作ったので、分かりやすい位置にコピーしてきます。
相変わらず root 権限が必要です。

sudo su
mkdir client
cp pgdata/cert/ca-cert.pem client/root.crt
cp pgdata/cert/client-cert.pem client/postgresql.crt
cp pgdata/cert/client-key.pem client/postgresql.key
exit

コピーしたものは root 権限にになっているので、現在のユーザーとグループに権限を与えます。

sudo chown -R $(id -u -n):$(id -g -n)  client

この client フォルダを、クライアントに配布します。
方法はUSBメモリでも scp でも問題ありませんが、コピー先はクライアントの~/.postgresql である必要があります。

scp -r <user>@<server>:/home/<user>/<docker-compose dir>/client ~/.postgresql

証明書を配置したら接続します。
sslmode=require あるいは sslmode=verify-ca で接続するのですが、 ~/.postgresql が存在していれば自動的に見に行ってくれるようで、指定なしでも接続出来ました。

psql "host=<host address> user=postgres dbname=postgres"
psql "sslmode=require host=<host address> user=postgres dbname=postgres"
psql "sslmode=verify-ca host=<host address> user=postgres dbname=postgres"

先程と同じようにログインできれば、成功です。

psql (12.2 (Ubuntu 12.2-2.pgdg18.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=#
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?