nginxコンテナを自己署名認証局でHTTPS化する
前回の記事では自己署名証明書を使ってリバースプロキシとして動作するnginxコンテナをHTTPS化しました。
しかしブラウザがエラーや警告を色々出すのでHTTPS化した実感がありませんでした。
今回は自己署名認証局が署名した証明書を使ってHTTPS化してエラーや警告をなくしたいと思います。
自己署名証明書との違い
認証局(CA)を自分で立ててその認証局にサーバ証明書に署名してもらいます。
オレオレCAですが一応、CAが署名しているのでオレオレ証明書ではなくなります。
これでnginxにアクセスしたときのエラーや警告がなくなるはずです。
CA証明書とサーバ証明書作成
構築していきましょう。
CA証明書とサーバ証明書はopensslコマンド連打で作成することができます。以下のページが参考になります。
https://qiita.com/makoto1899/items/ef15372d4cf4621a674e
もっと簡単かつ環境を汚さない方法はないかな、、、Dockerみたいな、、、と探したらopensslコマンドを連打してCA証明書とサーバ証明書を作成するDockerイメージがありました。
https://hub.docker.com/r/paulczar/omgwtfssl
怪しい名前ですがPull回数は100万回を超えています。GitHubにソースが公開されています。
https://github.com/paulczar/omgwtfssl
今回はこれを使うことにします。
omgwtfsslを使い、Dockerコマンド一発でCA証明書とサーバ証明書作成を作成します。
docker run --rm -e SSL_SUBJECT="localhost" -e SSL_DNS="localhost" -v /Users/john/certs:/certs paulczar/omgwtfssl
-e SSL_SUBJECTはSubjectのCommon Name(CN)を指定します。
-e SSL_DNSはSubject Alternative Name(SAN)を指定します。Chromeの場合、これがないと以下のようにERR_CERT_COMMON_NAME_INVALIDエラーを出します。
ChromeはSubjectのCNではなくSANをチェックします。CNはあってSANがないのにERR_CERT_COMMON_NAME_INVALIDエラーってエラー名がおかしくないか?と思うのですがSANを忘れるとこのエラーが出ます。fetch APIはCNを見てるっぽいし、ややこしいですね。
-vで指定した/Users/john/certsに色々作成されます。
$ ls /Users/john/certs ca-key.pem ca.pem ca.srl cert.pem key.csr key.pem openssl.cnf secret.yaml
この先の作業で使うのは以下の3つです。
証明書をチェック
サーバ証明書の内容をチェックします。署名がtest-caになっています。自己署名証明書ではないことがわかります。
60日でExpireします。-e SSL_EXPIREオプションで変更できるそうです。
SANもlocalhostになっています。DNSが2つある理由はわかりません。
# openssl x509 -text -noout -in cert.pem Issuer: CN = test-ca Validity Not Before: Jan 15 15:47:42 2021 GMT Not After : Mar 16 15:47:42 2021 GMT Subject: CN = localhost <略> X509v3 Subject Alternative Name: DNS:localhost, DNS:localhost
nginx設定変更
前回、下記Dockerコマンドで作成したnginxコンテナを引き続き使用します。nginxコンテナがまだない場合は下記Dockerコマンドで作成して下さい。
docker run -it --name nginx -p 443:443 nginx /bin/bash
作成されたサーバ証明書とサーバ秘密鍵をnginxコンテナにコピーします。
docker cp /Users/john/certs/cert.pem <コンテナID>:/etc/nginx/conf.d/ssl/ docker cp /Users/john/certs/key.pem <コンテナID>:/etc/nginx/conf.d/ssl/
/etc/nginx/conf.d/default.confを下記の通り変更します。
vimが入っていない場合はapt-getでインストールして下さい。
前回からの変更はサーバ証明書と秘密鍵を新しく作成したものに変えただけです。
server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/conf.d/ssl/cert.pem; <<< 変更1 ssl_certificate_key /etc/nginx/conf.d/ssl/key.pem; <<< 変更2 access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } location /api { proxy_pass http://todoapi-app:5000; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
nginxを再起動します。今回はpass phraseは要求されません。
CA証明書のインポート
ブラウザがnginxのサーバ証明書を検証するにはCA証明書(ca.pem)をブラウザにインポートする必要があります。
インポートの方法はOSやブラウザによって異なります。
Firefoxだと「オプション」 / 「プライバシーとセキュリティー」→「証明書」→「証明書を表示」からインポートするそうです。
WindowsのChromeは「インターネットオプション」→「コンテンツ」→「証明書」→「信頼されたルート機関タブ」からインポートするそうです。
ここではMacのChromeを使います。MacのChromeはキーチェーンアクセスからインポートします。
- Macのキーチェーンアクセスを起動します。
- 画面左側「キーチェーン」で「ログイン」が選択されていることを確認します。
- 画面右側の証明書や鍵の一覧が表示されているところに生成したca.pemをドラッグ&ドロップします。
- 下記のようにtest-caという名前で登録されるので一覧からtest-caを見つけてダブルクリックします。
- 「信頼」→「この証明書を使用するとき」で「常に信頼」を選びます。
- 閉じます。
動作確認
ブラウザでhttps://localhostへアクセスします。
エラーはありません。
アドレスバーはこの接続が安全であることを示しています。
安全なHTTPS接続を確立することができました。
結論
ようやく安全なHTTPセッションができました。
しかもomgwtfsslを使ったお陰で証明書はコマンド1発で出来てしまいました。すごい便利です。
あえてpaulczar/omgwtfsslの難点を上げるとすれば、このコンテナが作ったCA証明書をキーチェーンアクセスに登録して本当に安全なのかという点です。
安心が欲しい人は自分でopenssl連打で証明書を作成した方が安心かもしれません。
omgwtfsslを利用する場合でも利用前にGitHubでソースを確認して納得した上で使った方がよいでしょう。