Dockerソフトウェアでも（お手軽に）SSL化対応したい

この記事は、[NTTテクノクロス Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ntt-tx) の18日目です。
[NTTテクノクロス](https://www.ntt-tx.co.jp/)の竹内 光治です。普段は AWS関連案件のマネージャーをしています。最近は GCPと Salesforceを中心に触っています。

# はじめに
今回は、DockerソフトウェアでのSSL化対応方法についてのお話です。色々探したんですがしっくりくる記事が見つけられなかったので、ならば備忘録として書き残しておきます。

# 記事の要約
DockerのVolumeマウント設定を活用してSSL証明書（TLS証明書）を割り当てます。

- 今回の環境条件
 - HOST OSはCentOS
 - コンテナにイメージとして（たまたま）mediawikiを使用
 - コンテナのOSはDebian
 - コンテナのWebサーバーはAapche2

# 記事の背景
WebサイトのSSL化について私がよく実施するのは次の方法です。

- フロントにLBを配置しSSLを終端させる。LBからインスタンスへの通信は非SSLのプレーン通信。

しかし「そんなにアクセストラヒックが無いから冗長構成もLoad BalancerもKubernetesクラスタもいらないよ。ランニングコスト抑えたいし。」とのお題が。そうです、いつもの（？）節約プロジェクトからの打診です。であれば、Dockerコンテナ単品を立てて、直接 コンテナ内のWebサーバーをSSL化することで十分でしょう。

# 設定の手順
じゃ具体的にどうやるの？ということで、DebianにおけるApacheのSSL化の手順は次の通りです。
![Figure1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276405/03ceaa16-a270-72be-9050-7b547ccf1cbb.png)

### (1) a2enmod にて SSLモジュールを有効にする
モジュールの有効化には`a2enmod`コマンドを使用します。これにより、mods-availableに登録されているApacheモジュールに対し、mods-enabledにリンクが張られます。mods-availableに登録が無ければ、moduleをインストールする必要があります。今回のイメージには既にSSLモジュールが登録されてるので、そのまま利用しました。
このコマンドはDockerイメージをビルドするDockerfileに記述します。

```Docker
RUN a2enmod ssl
```

### (2) サイト設定と SSL証明書を配置する
この記事では証明書の準備には触れませんが、用意した証明書は以下の構成で配置しました。

```None
（ホスト側）
　mediawiki/
　 ├ mediawiki_ssl.conf　----- サイト設定config（SSL証明書へのPATHを記述）
　 └ certs/
　　　├ server.crt ----------- 設定するSSL証明書（サーバー証明書）
　　　└ server.key ----------- 設定するSSL証明書（SSL秘密鍵）
```

### (3) a2ensite にて SSLサイトを有効にする
サイトの有効化には`a2ensite`コマンドを使用します。これにより、sites-availableに登録されている設定ファイルに対し、sites-enabledにリンクが張られます。sites-availableに登録が無ければ、設定を準備する必要があります。
素直に考えると、ホスト側で用意した証明書類をコンテナ内にコピーして、`a2ensite`コマンドを発行する、と思うじゃないですか。いえいえ、もう少し簡単になります。ここがこの記事の主題でして、用意したサイト設定はHOST側には既に存在しているので、`a2ensite`の代わりにDockerのボリュームマウントを使用してしまえば良いのです。

```YAML
    volumes:
      - ./mediawiki/mediawiki_ssl.conf:/etc/apache2/site-enabled/mediawiki_ssl.conf
      - ./mediawiki/certs:/etc/ssl/mediawiki
```

### (4) コンテナを起動し設定を確認する
さて、まずは`curl`で接続確認をしてみます。「SSL certificate verify ok.」が返りました。 大丈夫ですね。

```shell-session
curl -s -v https://***.***.***.*** --proxy http://***.***.***.***:****
   :
（中略）
   :
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=***.***.***.***
*  start date: Jul 29 07:39:03 2021 GMT
*  expire date: Aug 30 07:39:03 2022 GMT
*  subjectAltName: host "***.***.***.***" matched cert's "***.***.***.***"
*  issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign GCC R3 DV TLS CA 2020
*  SSL certificate verify ok.
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
```
ブラウザからも確認してみます。「この証明書は問題ありません」と表示されました。大丈夫ですね。
![figure2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276405/049483dc-d29e-2573-41f7-4b172f157faf.png)

# まとめ
Dockerfile、docker-compose.yaml 全体像は以下のようになりました。これで無事にコンテナ内のApacheがSSL化されました。

```Dockerfile:Dockerfile
FROM mediawiki
ENV LANG C.UTF-8

RUN a2enmod ssl
```

```yaml:docker-compose.yaml
# 関連個所を抜粋しています
service:
  mediawiki:
    container_name: myWiki
    build: .
    restart: always
    ports:
      - '8443:443'
    networks:
      - wiki-net
    volumes:
      - ./mediawiki/mediawiki_ssl.conf:/etc/apache2/site-enabled/mediawiki_ssl.conf
      - ./mediawiki/certs:/etc/ssl/mediawiki
```
# おわりに
a2ensiteのコマンドを使用しても実態はsites-availableからsites-enabledへのリンク設定です。であればDockerのVolumeマウントを使用してHOST側のディレクトリを、コンテナのsites-enabledディレクトリにマウントすればa2ensiteと同様の効果が得られます。定期的に更新されるSSL証明書はHOST側に置くのが便利ですしね。今後は、SSL証明書の自動更新として ACMEプロトコルを組み込みたいと思います（できればお手軽に）。

[NTTテクノクロス Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ntt-tx)、明日は [@subutakahiro](https://qiita.com/subutakahiro)さんです。お楽しみに！

# 参考
- [Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc. in the United States and/or other countries. Docker, Inc. and other parties may also have trademark rights in other terms used herein.](https://www.docker.com/legal/trademark-guidelines)
- [Kubernetes® は The Linux Foundation の登録商標です。](https://www.linuxfoundation.jp/trademark-usage/)
- https://manpages.debian.org/buster/apache2/index.html
- https://www.mediawiki.org/wiki/MediaWiki/ja