証明書を使ったリポジトリクライアントの確認
HTTPS による Docker 起動 において学んだことは、デフォルトにおいて Docker はインターネット通信ではない Unix ソケットを通じて動作しているということでした。 また Docker クライアントとデーモンとの間で HTTPS を介して安全なやり取りとするためには TLS を有効にしなければならないということでした。 TLS はレジストリエンドポイントが信頼できるものであることを確実にし、レジストリとの間のトラフィックは暗号化してくれます。
本文においては、Docker レジストリサーバーと Docker デーモン(レジストリサーバーに対するクライアント)の間において、通信トラフィックが暗号化され、証明書ベースのクライアントサーバー認証 を用いて適切に認証されることを示します。
ここではレジストリにおいて、認証局(Certificate Authority; CA)のルート証明書のインストール方法と、クライアント TLS 証明書の設定方法を示します。
設定内容の理解
カスタム証明書は/etc/docker/certs.d
ディレクトリ配下に新たなディレクトリを生成して、そこに設定ファイルを置きます。
ディレクトリ名はレジストリのホスト名と同一に、たとえばlocalhost
のようにします。
*.crt
ファイルはすべて、CA ルートとしてこのディレクトリに追加していきます。
メモ
Linux 上のルート認証局は、システムが持つデフォルトのものにマージされます。 したがってそこにはホストのルート認証局のセットも含まれます。 Windows Server 上の Docker や Docker Desktop for Windows において Windows コンテナーを利用する場合は、カスタムルート証明書が設定されていない場合に限って、システムのデフォルト証明書が利用されます。
1 つでも<filename>.key/cert
のペアがあるということは、そのリポジトリに対するアクセスにはカスタム証明書が必要であることを Docker に伝えるものです。
メモ: 複数の証明書が存在していた場合、その処理はアルファベット順に行われます。 4xx や 5xx のレベルの認証エラーがあると、Docker はその次の証明書を使った処理を試します。
以下は、複数のカスタム証明書がある場合の設定例です。
/etc/docker/certs.d/ <-- 証明書のディレクトリ
└── localhost:5000 <-- ホスト名:ポート
├── client.cert <-- クライアント証明書
├── client.key <-- クライアント鍵
└── ca.crt <-- レジストリ証明書に署名した認証局
上記は、オペレーティングシステムに特有のものであって、単に一例を示しただけにすぎません。 OS が提供する証明書チェーンを生成するためには、各オペレーティングシステムのドキュメントを参照してください。
クライアント証明書の生成
OpenSSL のgenrsa
コマンドとreq
コマンドを使って、まずは RSA 鍵を生成します。
そしてこの鍵を使って証明書を生成します。
$ openssl genrsa -out client.key 4096
$ openssl req -new -x509 -text -key client.key -out client.cert
メモ: この TLS コマンドが生成するのは Linux 上において動作する証明書です。 macOS における OpenSSL バージョンは、Docker が必要とする種類の証明書のタイプとは互換性がありません。
トラブルシューティングのためのヒント
Docker デーモンは.crt
ファイルを CA 証明書として、.cert
ファイルをクライアント証明書として、それぞれ解釈します。
仮に CA 証明書の拡張子が、本来の正しい.crt
でなく間違って .cert
になってしまっていたら、Docker デーモンは以下のようなエラーメッセージをログ出力します。
Missing key KEY_NAME for client certificate CERT_NAME. CA certificates should use the extension .crt.
Docker レジストリをポート番号なしにアクセスするなら、ディレクトリ名にポート番号をつけないでください。
以下に示す設定は、デフォルトのポート 443 を使ってレジストリにアクセスできるようにするものです。
実際のアクセスはdocker login my-https.registry.example.com
のように行います。
/etc/docker/certs.d/
└── my-https.registry.example.com <-- ポートなしのホスト名
├── client.cert
├── client.key
└── ca.crt