テスト環境におけるDockerコンテナ間のHTTPS通信


この記事はZOZOテクノロジーズ #1 Advent Calendar 2019 17日目の記事になります。
昨日の記事は @pakio さんによる「非ElasticsearchユーザーにもおススメなKibanaで地味に便利な機能を紹介したい」でした。

本記事では、Dockerのコンテナ間でHTTPS通信をするテストを実装した際に困ったことの解決方法を紹介します。

概要

テスト環境に対してHTTPS通信を行うために自己証明書(いわゆるオレオレ証明書)を使う場合、基本的に警告が出るので明示的に通信を許可する必要があります。
SeleniumやPuppeteerなどを使っている場合は、証明書に関するエラーを無視するようなオプションを設定することで、この状況を回避できますが、内部でHTTPS通信を行うライブラリによっては、そのようなオプションが用意されていない場合もあります。
Dockerのコンテナ間でHTTPS通信する際にそういった状況に遭遇した場合の解決方法を紹介していきます。

環境

  • macOS High Sierra (v10.13.6)
  • mkcert (v1.4.0)
  • docker desktop (v2.1.0.4)

解決方法の概要

オレオレ証明書の代わりにオレオレ認証局を作り、その認証局をアクセス元のコンテナで信用するようにします。

  1. ホストマシン上に認証局を作成
  2. 認証局からコンテナB用のSSLサーバー証明書を発行
  3. 認証局のルート証明書をコンテナAが持つルート証明書一覧に追加
  4. 発行されたサーバー証明書をコンテナBで利用
  5. コンテナAからコンテナBにHTTPSアクセス

サンプルコード

本記事で紹介する例とは多少異なりますが、SSLサーバー証明書を利用したNginxにPuppeteerでアクセスする場合のサンプルコードを上げているので、こちらも必要に応じてご参照ください。

詳細手順

認証局の作成

mkcertを使うと簡単に認証局を作成できます。

mkcert -install

SSLサーバー証明書の発行

続いて、mkcertを使って認証局からSSLサーバー証明書を発行します。

mkcert container-b

このコマンドでは、証明するホスト名を指定する必要があるので、コンテナAから見たコンテナBのホスト名を指定します。

ルート証明書のエクスポート

キーチェーンアクセスからmkcertによって作られた認証局のルート証明書を探し、メニューバーの「ファイル」→「書き出す」で保存します。
この記事では local-root-ca.pem というファイル名で保存しています。

ルート証明書の追加

Dockerfile
...
COPY local-root-ca.pem /usr/local/share/ca-certificates/local-root-ca.crt
RUN update-ca-certificates
...

エクスポートしたルート証明書をコンテナAのルート証明書一覧が管理されているディレクトリ下に配置し、一覧情報を更新します。

* 証明書一覧が管理されているディレクトリや、更新のコマンドはOSによって異なります。上のはDebianの場合です。

SSLサーバー証明書の利用

構成によって変わるので、割愛します。

コンテナAからコンテナBへのHTTPSアクセス

Dockerfile
CMD curl https://container-b/

-k--insecureのオプションを付けなくてもエラーが出ないことを確認します。

最後に

オレオレ認証局を作成して発行したSSLサーバー証明書を利用することで、コンテナ間のHTTPS通信を警告なしに行うことができるようになりました。開発環境やテスト環境でお困りの際にはぜひご活用ください。

明日の記事は、 @katsuyan さんによる「Googleスプレッドシートの縦横変換をSQLでおこなう」です。そちらもぜひご覧下さい。

余談

JRE (Java Runtime Environment)といった環境やライブラリによってはルート証明書一覧が同梱されており、OS側のルート証明書一覧を参照しないという場合もあります。
こういった場合には、ルート証明書追加の手順で行ったような操作では意味がないため、ライブラリ等に同梱されたルート証明書一覧に追加する方法や、OS側のルート証明書一覧を見るように処理を上書きする方法を考える必要があります。