探してもあまり出てこなかったので、構築の記録を記します。
今回紹介するのは docker 本来の使い方である immutable な使い方ではありませんので、ご注意を。
参考
こちらの記事を参考にしました。
環境
- Ubuntu 18.04.4 LTS
- Docker CE
- docker-compose
nano
や cp
を使いますが、特に記述がない場合は docker-compose が置いてあるフォルダからの相対パスだとお考え下さい。
docker-compose
適当なフォルダを作成し、以下の2つのファイルを配置します。
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_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=#