What's?
DockerHubにあるPostgreSQLのオフィシャルのDockerイメージですが、こちらはSSLが有効になっていません。
これをなんとかしたいな、ということで。
環境
今回の環境は、こちら。
$ docker version
Client: Docker Engine - Community
Version: 23.0.3
API version: 1.42
Go version: go1.19.7
Git commit: 3e7cbfd
Built: Tue Apr 4 22:05:48 2023
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 23.0.3
API version: 1.42 (minimum version 1.12)
Go version: go1.19.7
Git commit: 59118bf
Built: Tue Apr 4 22:05:48 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.20
GitCommit: 2806fc1057397dbaeefbea0e4e17bddfbd388f38
runc:
Version: 1.1.5
GitCommit: v1.1.5-0-gf19387a
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Docker Composeも。
$ docker compose version
Docker Compose version v2.17.2
PostgreSQLのイメージは、15.2のものを使うことにします。
SSL証明書を作成する
SSL接続に関するPostgreSQLのドキュメントはこちら。
PostgreSQLのイメージをSSL化するにあたり、SSL証明書を作成することになるわけですが、コマンドは先に載せておきましょう。
$ openssl req -new -x509 -days 365 -nodes -text -out /path/to/server.crt -keyout /path/to/server.key -subj '/CN=example.com'
/path/to
の部分は、利用する箇所に応じて変更して使うことにします。
SubjectはCommmon Nameだけ指定することにしました。
Dockerfileを書く
身も蓋もないですが、この方法が1番まとまりがいい気がします…。
FROM postgres:15.2-bullseye
RUN openssl req -new -x509 -days 365 -nodes -text -out /etc/postgresql/server.crt -keyout /etc/postgresql/server.key -subj '/CN=example.com' \
&& chown postgres:postgres /etc/postgresql/server.key \
&& chmod 600 /etc/postgresql/server.key
RUN chown postgres:postgres /etc/postgresql/server.key \
&& chmod 600 /etc/postgresql/server.key
CMD ["-c", "ssl=on", "-c", "ssl_cert_file=/etc/postgresql/server.crt", "-c", "ssl_key_file=/etc/postgresql/server.key"]
ビルド。
$ docker image build -t charon/postgres:15.2-bullseye .
確認。
$ docker container run -it --rm --name postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_USER=myuser \
-e POSTGRES_DB=example \
charon/postgres:15.2-bullseye
$ docker container exec -it postgres psql -U myuser -h localhost example
psql (15.2 (Debian 15.2-1.pgdg110+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
example=#
OKですね。
あらかじめSSL証明書を作成しておいて
$ openssl req -new -x509 -days 365 -nodes -text -out server.crt -keyout server.key -subj '/CN=example.com'
コンテナに取り込むという方法でもいいと思います。
FROM postgres:15.2-bullseye
COPY server.key /etc/postgresql/server.key
COPY server.crt /etc/postgresql/server.crt
RUN chown postgres:postgres /etc/postgresql/server.key \
&& chmod 600 /etc/postgresql/server.key
CMD ["-c", "ssl=on", "-c", "ssl_cert_file=/etc/postgresql/server.crt", "-c", "ssl_key_file=/etc/postgresql/server.key"]
オフィシャルイメージのままでなんとかしたい
とはいえ、オフィシャルイメージのままでもなんとかしたいという話はあると思うので…。
SSL証明書の所有者を変更する
こんな感じで、SSL証明書を作成してuidを999
にします。
$ openssl req -new -x509 -days 365 -nodes -text -out server.crt -keyout server.key -subj '/CN=example.com'
$ chmod 600 server.key
$ sudo chown 999 server.key
999
は、オフィシャルイメージ内でのpostgres
ユーザーのuidですね。
前は70
だったようなので、あまりこの方法は取りたくないものですが…。
確認。
$ docker container run -it --rm --name postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_USER=myuser \
-e POSTGRES_DB=example \
-v $(pwd)/server.crt:/etc/postgresql/server.crt \
-v $(pwd)/server.key:/etc/postgresql/server.key \
postgres:15.2-bullseye \
-c ssl=on \
-c ssl_cert_file=/etc/postgresql/server.crt \
-c ssl_key_file=/etc/postgresql/server.key
OKですね。
$ docker container exec -it postgres psql -U myuser -h localhost example
psql (15.2 (Debian 15.2-1.pgdg110+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
example=#
当然ながら、uidが決め打ちになるのが難点です。
ENTRYPOINTを調整する
あまりやりたくないですが、ENTRYPOINT
を調整する方法もあるでしょう。
$ docker container run -it --rm --name postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_USER=myuser \
-e POSTGRES_DB=example \
--entrypoint bash \
postgres:15.2-bullseye \
-c 'openssl req -new -x509 -days 365 -nodes -text -out /etc/postgresql/server.crt -keyout /etc/postgresql/server.key -subj "/CN=example.com" && chown postgres:postgres /etc/postgresql/server.{crt,key} && chmod 600 /etc/postgresql/server.key && docker-entrypoint.sh postgres -c ssl=on -c ssl_cert_file=/etc/postgresql/server.crt -c ssl_key_file=/etc/postgresql/server.key'
これでできなくもないですが、ここまでするならもうDockerfile
を書いた方がいい気がしますね…。
Docker Composeで定義すると、多少は見やすくなるかもしれません。
services:
postgres:
image: postgres:15.2-bullseye
environment:
POSTGRES_PASSWORD: password
POSTGRES_USER: myuser
POSTGRES_DB: example
entrypoint: >-
bash -c '
openssl req -new -x509 -days 365 -nodes -text -out /etc/postgresql/server.crt -keyout /etc/postgresql/server.key -subj '/CN=example.com' \
&& chown postgres:postgres /etc/postgresql/server.{crt,key} \
&& chmod 600 /etc/postgresql/server.key \
&& docker-entrypoint.sh postgres \
-c ssl=on -c ssl_cert_file=/etc/postgresql/server.crt -c ssl_key_file=/etc/postgresql/server.key
'