NGINX PlusでmTLS認証を試してみた!

NGINXでは様々な認証方式が利用できます、今回はmTLS認証の設定方法や動作確認を試してみましたのでブログ記事にしたいと思います。
1.はじめに
ブログを読んでいただきありがとうございます!
東京エレクトロンデバイスのJo Nishikawaです。
今回は、mTLS認証について検証してみましたのでブログを書いていきたいと思います。
これまでもNGINX Plusを利用した認証関連の検証結果などをご紹介してきました。
NGINX PlusでHttp Basic認証を検証してみた!
NGINX Plus と Okta Customer Identity Cloud(旧Auth0)の認証連携
近年、セキュリティの重要性が高まる中で、通信の暗号化と認証は必須の要素となっています。
特に、サーバーとクライアント間の相互認証を実現するmTLS認証は、強固なセキュリティを提供する手段となっていますので今回のブログで設定方法や動作のイメージをつかみたいと思います。
2.mTLSとは?
mTLSとは、Mutual TLSの略でサーバーとクライアントの両方がお互いを認証する仕組みです。
通常のTLSでは、サーバーがクライアントに対して証明書を提示し、クライアントはサーバーの正当性を確認します。
mTLS認証では、クライアントも証明書を提示し、サーバーがクライアントの正当性を確認します。これにより、TLSよりも安全な通信が実現されます。
TLSとmTLSの違いも調査したので表にしてみました。
TLSとmTLSの違い(比較表)
項目 | TLS認証 | mTLS認証 |
---|---|---|
認証対象 | サーバーのみ(クライアントはサーバー証明書を検証) | サーバー & クライアント(双方向で証明書を検証) |
証明書の種類 | サーバー証明書のみ 必要 | サーバー証明書 & クライアント証明書 が必要 |
セキュリティ強度 | 基本的な暗号化(通信内容を暗号化) | 高度なセキュリティ(なりすまし防止、ゼロトラスト環境向け) |
設定の難易度 | 比較的簡単(サーバー証明書を設定するだけ) | 設定が複雑(CA管理・証明書配布が必要) |
3.検証構成&動作確認したいこと
4.検証
STEP0:NGINX Plusをサーバーにインストール、コンテンツサーバーの用意
- 手順はこちらをご参照ください
- 実際にコンテンツを表示させるサーバーも用意します。
今回はクライアントからapp1.example.com宛にCurlでGETリクエストを行い、NGINX Plusとクライアント間でmTLS認証が成功した場合にコンテンツサーバーのコンテンツがクライアントに応答されるようにNGINX Plusを設定していきます。
STEP1:証明書の準備
- NGINX Plusをインストールしたサーバーにて以下のファイルをOpenSSLを使って作成します。
ファイル名 | 役割 |
---|---|
CA.key |
ルートCAの秘密鍵 |
CA.pem |
ルートCAの証明書(自己署名) |
SERVER.key |
サーバーの秘密鍵 |
SERVER.pem |
サーバー証明書(CAが署名) |
CLIENT1.key |
クライアントの秘密鍵 |
CLIENT1.pem |
クライアント証明書(CAが署名) |
openssl ecparam -out ./CA.key -name prime256v1 -genkey
openssl req -new -key ./CA.key -out ./CA-csr.pem -subj '/C=JP/ST=Tokyo/O=EXAMPLE COM/CN=ROOT EXAMPLE COM/emailAddress=admin@example.com'
openssl req -x509 -nodes -days 3650 -key ./CA.key -in ./CA-csr.pem -out ./CA.pem
openssl ecparam -out ./SERVER.key -name prime256v1 -genkey
openssl req -new -key ./SERVER.key -out ./SERVER-csr.pem -subj '/C=JP/ST=Tokyo/O=EXAMPLE COM/CN=app1.example.com/emailAddress=admin@example.com'
openssl ca -config ./openssl.cnf -in SERVER-csr.pem -out SERVER.pem
openssl ecparam -out ./CLIENT1.key -name prime256v1 -genkey
openssl req -new -key ./CLIENT1.key -out ./CLIENT1-csr.pem -subj '/C=JP/ST=Tokyo/O=EXAMPLE COM/CN=client1.example.com/emailAddress=admin@example.com'
openssl ca -config ./openssl.cnf -in CLIENT1-csr.pem -out CLIENT1.pem
- 証明書や鍵などを /etc/nginx/conf.d/ssl に配置します。
sudo mkdir /etc/nginx/conf.d/ssl
sudo cp SERVER.key /etc/nginx/conf.d/ssl
sudo cp SERVER.pem /etc/nginx/conf.d/ssl
sudo cp CA.pem /etc/nginx/conf.d/ssl
STEP2:NIGNX Plusの設定
- NGINX Plusの設定ファイル(default.conf)に以下の設定をします。
upstream server_group {
zone backend 64k;
server backend1:81; #app1.example.comを表示するコンテンツサーバー
}
server {
listen 443 ssl; #待ち受けポートを443に指定してSSL/TLSを有効化
ssl_certificate_key conf.d/ssl/SERVER.key; #TLSで使用する秘密鍵を指定
ssl_certificate conf.d/ssl/SERVER.pem; #TLSで使用するサーバー証明書を指定
ssl_client_certificate conf.d/ssl/CA.pem; #クライアント証明書を検証するためのCA証明書を指定
ssl_verify_client on; #クライアント証明書の検証を必須に指定
location / {
proxy_pass http://server_group;
}
}
STEP3:NIGNX Plusのリロード
- NGINX Plusの設定を反映するためにリロードを実施します。
sudo systemctl restart nginx
STEP4:動作確認
- はじめにクライアント証明書を提示してリクエストを行います。
NGINX Plusがインストールされているサーバーからのcurl結果は以下になります(一部抜粋)。
問題なくリクエストが処理され、200 OKとなっています
ubuntu@ip-x-x-x-x:~$ curl -v --cacert ./CA.pem --key ./CLIENT1.key --cert ./CLIENT1.pem https://app1.example.com --resolve app1.example.com:443:127.0.0.1
> GET / HTTP/1.1
> Host: app1.example.com
> User-Agent: curl/7.68.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.25.5
< Date: Thu, 27 Mar 2025 04:47:59 GMT
< Content-Type: application/octet-stream
< Content-Length: 65
< Connection: keep-alive
<
- 次にクライアント証明書を提示せずにリクエストを行います。
NGINX Plusがインストールされているサーバーからのcurl結果は以下になります(一部抜粋)。
クライアント証明書を提示していないため、400 エラーが出力されています。
ubuntu@ip-x-x-x-x:~$ curl -v --cacert ./CA.pem https://app1.example.com --resolve app1.example.com:443:127.0.0.1
> GET / HTTP/1.1
> Host: app1.example.com
> User-Agent: curl/7.68.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Server: nginx/1.25.5
< Date: Thu, 27 Mar 2025 04:46:13 GMT
< Content-Type: text/html
< Content-Length: 237
< Connection: close
<
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/1.25.5</center>
</body>
</html>
- 無事、期待通りの動作確認ができました。
5.まとめ
mTLS認証の動作確認が無事にできました。
最近、NGINX Plusにおける認証に関してお問い合わせをいただくことが増えてきましたので、新たに認証に特化したハンズオントレーニングを開設いたしました。
定期的にトレーニングを実施しておりますので、是非ご参加いただけますと幸いです。
お申し込みはこちらからお願いいたします。
今後も新たな動作確認や検証ができましたら、ブログを書きたいと思います!お楽しみに。