概要
Docker はネットワークを使わない方法も平文でのネットワーク通信も可能です。ここでは Docker を安全に使うため TLS を使用して信頼できるクライアントから信頼できるサーバへのみ接続できるようにします。 Docker Engine の起動引数に認証局の証明書およびサーバの証明書と鍵を設定します。クライアントは認証局の証明書およびクライアントの証明書と鍵を設定して接続します。
環境
- Docker クライアント
- Windows 8.1
- Docker Toolbox 1.12.2
- Docker Engine
- Oracle Linux 7 update 2
- docker-engine 1.12.3
- OpenSSL 1.0.1e
- Virtualbox 5.1.8
- IPアドレス 192.168.56.100
鍵の作成
証明書や鍵があれば別途作る必要はありません。証明書や鍵が無い場合にはこれらを作成します。認証局、Docker Engine(サーバ)、Docker クライアントの分をそれぞれ作成します。
作成されるファイル名は Docker Machine のデフォルト値で作成します。
作成中に様々な入力を求められますが、以下の 2 つ以外は何も入力しないでも大丈夫です。
Enter pass phrase for ca-key.pem: Verifying - Enter pass phrase for ca-key.pem:
各コマンドの出力は参考のページなどでご確認下さい。
認証局用の作業
俗に言うオレオレ認証局(CA)の秘密鍵と公開鍵を作成します
$ openssl genrsa -aes256 -out ca-key.pem 4096
$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Docker Engine用の作業
サーバの鍵(server-key.pem)と証明書署名要求(server.csr)を作成します
$ openssl genrsa -out server-key.pem 4096
$ openssl req -sha256 -new -key server-key.pem -out server.csr
サーバの証明書(server.pem)を作成します
$ echo subjectAltName = IP:192.168.56.100,IP:127.0.0.1 > extfile.cnf
$ openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server.pem -extfile extfile.cnf
Docker クライアント用の作業
クライアントの鍵(key.pem)と証明書署名要求(client.csr)を作成
$ openssl genrsa -out key.pem 4096
$ openssl req -new -key key.pem -out client.csr
クライアントの証明書(cert.pem)を作成
$ echo extendedKeyUsage = clientAuth > extfile.cnf
$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
署名と鍵の整理
証明書署名要求は不要なため削除
$ rm -v client.csr server.csr
秘密鍵は所持者のみが読めるようにします
$ chmod -v 0400 ca-key.pem server-key.pem key.pem
証明書は全てのユーザが読めるようにします
$ chmod -v 0444 ca.pem server.pem cert.pem
Docker Engine の設定
CAの証明書と、Docker Engine の証明書と鍵を使用するように--tlsverify --tlscacert=ca.pem --tlscert=server.pem --tlskey=server-key.pem
を追加。
所持する全ての IP で tcp の 2376 番ポートでリッスンするように ExecStart に-H tcp://0.0.0.0:2376
を追加
これらの設定を起動引数に設定します。
$ vim /usr/lib/systemd/system/docker.service
[Service] # ExecStart=/usr/bin/dockerd ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=ca.pem --tlscert=server.pem --tlskey=server-key.pem -H tcp://0.0.0.0:2376
設定を反映し docker を再起動します
$ systemctl daemon-reload
$ systemctl restart docker
TCP の 2376 で動いていることを確認
$ netstat -tln | grep 2376
tcp6 0 0 :::2376 :::* LISTEN
Docker クライアント
作成した証明書と鍵を配置して、TLS を使用する設定をして Docker Engine へ接続します。
証明書と鍵の配置
ホームディレクトリに .docker ディレクトリを作成し、このディレクトリに認証局の公開鍵(ca.pem)とクライアントの証明書(cert.pem)と鍵(key.pem)をコピーします。
$ dir /b
ca.pem cert.pem key.pem
このディレクトリは DOCKER_CERT_PATH 環境変数でも変更できます。
$ export DOCKER_CERT_PATH=~/.docker/dev/
実行時に TLS を使うことを指定する
実行時に --tlsverify を指定します。
$ docker -H tcp://192.168.56.100:2376 --tlsverify run hello-world
Hello from Docker! (略)
環境変数で TLS を使うことを指定する方法
TLS の使用は DOCKER_HOST 環境変数で指定します。
set DOCKER_TLS_VERIFY=1
環境変数で指定した場合には実行時に --tlsverify 指定する必要はありません。
$ docker -H tcp://192.168.56.100:2376 run hello-world
Hello from Docker! (略)
ダメな例
証明書や鍵をディレクトリに置いていない(読めない)と以下のエラーが発生します。
Could not read CA certificate "C:\\Users\\user\\.docker\\ca.pem": open C:\Users\user\.docker\ca.pem: The system cannot find the file specified.
環境変数でも実行時にも指定してない場合は以下のエラーが発生します。
Get http://192.168.56.100:2376/v1.24/containers/json: malformed HTTP response "\x15\x03\x01\x00\x02\x02". * Are you trying to connect to a TLS-enabled daemon without TLS?
参考: docs.docker.com