このブログ記事では、SSLで暗号化されたWebサイトをNGINXでホストする際に使用するSSL秘密鍵を、安全に配布するための複数の方法について説明します。具体的な内容は次のとおりです。
- NGINXでSSLを設定する際の「標準的なアプローチ」と、潜在的なセキュリティ上の制約
- NGINXの設定とは別に保存されたパスワードを使用して、鍵を暗号化する方法
- 暗号化パスワードをディスクに保存せず安全に配布し、必要に応じて失効させる方法
多くの導入環境では、標準的なアプローチで十分です。この記事で取り上げる2つのより高度なアプローチは、攻撃者が別の方法でSSL秘密鍵を入手することを防ぎます。今後の記事では、さらにいくつかの手法についても解説します。
- HashiCorp Vaultなどのサードパーティ製シークレットストアを使用して、パスワードを安全に配布する
- VaultからNGINX Plusの「キー・バリュー・ストア」への証明書のプロビジョニングを自動化し、秘密鍵データがディスクに保存されないようにする
この投稿で紹介するアプローチは、独自に鍵を管理し、安全な鍵配布戦略を策定する必要があるユーザーを対象としています。Kubernetesなど、すでにシークレットストアと統合されている環境でNGINXを実行している場合、これらのアプローチは必要ありません。
この投稿は、NGINX Open SourceとNGINX Plusの両方を対象としています。読みやすくするため、以降は一貫して「NGINX」と表記します。
編集者注:この記事は、NGINXでSSL秘密鍵を保護する方法を解説するシリーズの第1回です。シリーズの他の記事もご覧ください。
- HashiCorp Vaultを使用したNGINXのSSL秘密鍵の保護 – HashiCorp Vaultまたはハードウェアセキュリティモジュール(HSM)を使用して、鍵保護システムを自動化し、拡張する方法について説明します
- NGINX PlusのKey-Value Storeを使用してHashiCorp Vaultの一時SSLキーを保護 – HashiCorp Vaultから一時SSLキーを生成し、NGINX PlusのインメモリKey-Value Storeに保存することで、SSLキーをディスクに保存せずに済む方法を説明します
SSL秘密鍵を保護する理由
SSL/TLSは、ネットワークトランザクションの認証、暗号化、完全性の検証に使用されます。Webサイトは、認証局(CA)が署名した公開証明書を使用して自身を認証し、対応する秘密鍵(機密として保持する必要があります)を使用して計算を行うことで、その証明書を所有していることを証明します。
秘密鍵が侵害された場合(別の主体に開示された場合)、主に2つのリスクがあります。
- リスク1:なりすまし。秘密鍵を入手した攻撃者は、ネットワークトラフィックを傍受し、中間者(MITM)攻撃を仕掛けることができます。この攻撃では、クライアントやWebサイトに気付かれることなく、すべてのトラフィックを取得して復号し、場合によっては改ざんすることもあります。
- リスク2:復号. 秘密鍵を入手し、ネットワークトラフィックを記録した攻撃者は、そのトラフィックをオフラインで復号できます。ただし、この攻撃は、Perfect Forward Secrecy(PFS)暗号を使用する接続には実行できません。
秘密鍵が侵害された場合、唯一の対処方法はCAに連絡して証明書の失効を依頼することです。その後は、クライアントが失効ステータスを確認し、それに従うことに頼らざるを得ません。
また、有効期間の短い証明書を使用することを推奨します(たとえば、Let’s Encryptの証明書は90日後に期限切れになります)。証明書の有効期限が切れる直前に、新しい秘密鍵を生成し、CAから新しい証明書を取得する必要があります。これにより、秘密鍵が侵害された場合のリスクを軽減できます。
NGINXのセキュリティ境界
NGINXのSSL秘密鍵にアクセスできるのは、どのユーザーとプロセスですか?
まず、NGINXを実行しているサーバーへのrootアクセス権を取得したユーザーは、NGINX自体が使用するすべてのリソースを読み取り、使用できます。たとえば、実行中のプロセスのメモリからSSL秘密鍵を抽出する既知の方法があります。
したがって、秘密鍵の保存方法や配布方法にかかわらず、ホストサーバー上でroot権限を持つ攻撃者から秘密鍵を保護することはできません。
次に、NGINXの設定を変更してコミットできるユーザーは、その権限をさまざまな方法で利用できます。たとえば、内部サービスへのプロキシアクセスを開放したり、認証対策を回避したりできます。また、NGINXの設定を変更して、サーバーへのrootアクセス(または同等のアクセス権)を取得することも可能です。ただし、SELinuxやAppArmorなどのツールは、その可能性の軽減に役立ちます。
したがって、NGINXの設定を変更してコミットできる攻撃者から秘密鍵を保護することは、一般に不可能です。
幸い、適切な組織では、攻撃者によるroot権限の取得やNGINX設定の変更を困難にするための堅牢なセキュリティプロセスが整備されています。
ただし、権限の低い攻撃者が秘密鍵にアクセスできる可能性のある方法は、ほかにも2つあります。
- ユーザーが正当な理由でNGINXの設定を確認する必要がある場合や、設定データベースまたはバックアップへのアクセス権を取得する場合があります。通常、NGINXの秘密鍵は設定内に保存されています。
- ユーザーが、ハイパーバイザーやシステムバックアップなどを介して、NGINXサーバーのファイルシステムにアクセスできる可能性があります。その場合、秘密鍵データを含め、ファイルシステムに保存されているあらゆるデータにアクセスされる可能性があります。
このドキュメントで説明するプロセスにより、これら2つの攻撃手法を封じることができます。
標準的なNGINX設定
まず、SSL/TLSを使用する一般的なNGINX構成を確認します。
server {
listen 443 ssl;
server_name a.dev0;
ssl_certificate ssl/a.dev0.crt;
ssl_certificate_key ssl/a.dev0.key;
location / {
return 200 "Hello from service A\n";
}
}SSL公開証明書(a.dev0.crt)と秘密鍵(a.dev0.key)は、ファイルシステム上の/etc/nginx/ssl/に保存されます。秘密鍵を読み取るのは、通常rootとして実行されるNGINXマスタープロセスのみであるため、秘密鍵には可能な限り厳格なアクセス権限を設定できます。
root@web1:/etc/nginx/ssl# ls -l a.dev0.key-r-------- 1 root root 1766 Aug 15 16:32 a.dev0.key秘密鍵は常に利用可能な状態にしておく必要があります。NGINXマスタープロセスは、NGINXソフトウェアの起動時、設定の再読み込み時、または構文チェック(nginx -t)の実行時に秘密鍵を読み取ります。
SSL/TLSの設定の詳細については、「NGINX Plus管理ガイド」を参照してください。
標準構成におけるセキュリティ上の影響
前述のとおり、実行中のコンテナ、仮想マシン、またはNGINXソフトウェアを実行しているサーバーへのrootアクセス権を取得した攻撃者は、SSL秘密鍵を読み取ることができます。
SSL秘密鍵の暗号化
NGINXは、AES256などの安全なアルゴリズムで暗号化された秘密鍵をサポートしています。
root@web1:/etc/nginx/ssl# mv a.dev0.key a.dev0.key.plainroot@web1:/etc/nginx/ssl# openssl rsa -aes256 -in a.dev0.key.plain -out a.dev0.key
writing RSA key
Enter PEM pass phrase: secure password
Verifying - Enter PEM pass phrase: secure password againその後、NGINXを起動するか、NGINXの設定を再読み込みまたはテストすると、NGINXは対話形式で復号パスワードの入力を求めます。
root@web1:/etc/nginx# nginx -tEnter PEM pass phrase: secure password
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulSSLパスワードファイルの使用
対話形式でパスワードを入力する方法は不便で、自動化も困難です。ただし、ssl_password_fileディレクティブで指定した別ファイルに保存されているパスワードのリストを使用するようにNGINXを設定できます。NGINXは秘密鍵を読み取る必要がある場合、ファイル内の各パスワードを順番に使用して鍵の復号を試みます。有効なパスワードが1つもない場合、NGINXは起動しません。
ssl_password_file /var/lib/nginx/ssl_passwords.txt;The ssl_password_fileは設定とは別に配布し、rootユーザーのみが読み取れるようにする必要があります。これは、信頼できるサーバーに配置する認証トークンとみなすことができます。NGINXが秘密鍵を復号できるのは、認証トークンが配置されたサーバー上で実行されている場合に限られます。
暗号化された鍵を別ファイルに保存する場合のセキュリティ上の影響
この方法では、NGINXの設定だけを入手しても攻撃者には役立たないため、攻撃対象領域を縮小できます。攻撃者は、さらにssl_password_fileの内容も入手する必要があります。
攻撃者が、root権限でssl_password_fileが保存されているファイルシステムにアクセスした場合(たとえば、バックアップまたはホストシステムを介してアクセスした場合)、そのファイルを読み取り、パスワードを使用してSSL秘密鍵を復号できます。
このリスクは、ssl_password_fileをRAMディスクまたはtmpfsに保存することで軽減できます。このストレージは通常、外部の攻撃者からアクセスされにくく(たとえば、サーバーの再起動時に消去されます)、システムバックアップの対象から除外できます。システムの起動時にパスワードファイルが初期化されるようにする必要があります。
SSLパスワードリストをより安全に配布する
以下では、SSLパスワードのリストを中央の配布ポイントからより安全に配布する方法について説明します。
NGINXは、SSLキーの復号が必要になるたびに中央配布ポイントに問い合わせ、パスワードをローカルディスクに保存することなく使用します。中央パスワードサーバーで認証を行うために、NGINXインスタンスはトークンを使用します。このトークンはいつでも取り消して、パスワードへのアクセスを遮断できます。
中央パスワード配布ポイントの作成
まず、パスワード配布ポイント(PDP)を作成します。このシンプルな実装では、ユーザー名とパスワードで認証するHTTPSサービスを使用して、パスワードリストを配信します。
$ curl -u dev0:mypassword https://pdpserver.local/ssl_passwords.txt
password1
password2
...その後、必要に応じてPDPで認証トークンを追加または削除することで、アクセスを許可または取り消すことができます。パスワード配布サーバーは、NGINXなどのWebサーバーを使用して実装でき、用途に適した任意の種類の認証トークンを使用できます。
次に、PDPからパスワードを取得するようにNGINXを設定します。まず、次の内容でconnector.shというシェルスクリプトを作成します。
#!/bin/sh
# Usage: connector.sh
CONNECTOR=$1
CREDS=$2
PDP_URL=$3
[ -e $CONNECTOR ] && /bin/rm -f $CONNECTOR
mkfifo $CONNECTOR; chmod 600 $CONNECTOR
while true; do
curl -s -u $CREDS -k $PDP_URL -o $CONNECTOR
doneスクリプトは、次のように呼び出してバックグラウンドプロセスとして実行する必要があります。
root@web1:~# ./connector.sh /var/run/nginx/ssl_passwords \dev0:mypassword https://pdpserver.local/ssl_passwords.txt &コネクタは、指定されたローカルパス(/var/run/nginx/ssl_passwords)に接続します。NGINXがそのパスにアクセスできるように、ssl_password_fileディレクティブを使用して設定します。
ssl_password_file /var/run/nginx/ssl_passwords;コネクターパスから読み取り、コネクターをテストします:
root@web1:~# cat /var/run/nginx/ssl_passwords
password1
password2
...NGINXがパスワードを読み取り、SSLキーを復号できることを確認します:
root@web1:~# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful中央PDP方式を使用すると、個々の秘密鍵やその他の機密データなど、NGINXが通常ディスクから読み取るあらゆるリソースを安全に配布できます。
PDPのセキュリティへの影響
このソリューションには、SSLパスワードをディスクに保存する方法と比べて、次のような利点があります。
- SSLパスワードがサーバーのファイルシステムに保存されることはありません。そのため、ファイルシステムにアクセスできる攻撃者でも、SSLパスワードに直接アクセスすることはできません。
- パスワードは中央のアクセスポイントから配布されるため、監視と監査を容易に実施できます。
- 個々のサーバーへのアクセスを一元管理できます。たとえば、サーバーを廃止した時点で、そのアクセストークンを無効にします。
ファイルシステムにアクセスできるユーザーは、PDPへのアクセスに使用する認証情報を抽出できる可能性があることに注意してください。これらの認証情報が不要になった場合は、失効させることが重要です。
まとめ
SSL秘密鍵の漏えいを防ぐ方法は数多くあり、セキュリティレベルが高くなるほど複雑さも増します。
- ほとんどの組織では、権限のないユーザーが
rootアクセス権を取得したり、NGINXの設定を閲覧したりできないように、NGINXを実行する環境へのアクセスを制限すれば十分です。 - 環境によっては、NGINX設定へのアクセスを完全に制限できない場合があるため、SSLパスワードファイルを使用できます。
- 限られたケースでは、組織がキーとパスワードをディスクに一切保存しないようにしたい場合があります。パスワード配布ポイントのプロセスは、このソリューションの概念実証を示すものです。
このシリーズの他の記事では、SSLキーを保護するために実施できる追加の手順について説明しています。
- HashiCorp Vaultを使用したNGINXのSSL秘密鍵の保護 – HashiCorp VaultをPDPとして設定し、きめ細かなアクセス制御によって、スケーラブルかつセキュアにシークレットを配布する方法を紹介します。また、ハードウェアセキュリティモジュール(HSM)に秘密鍵をリモートで保存し、必要に応じて鍵操作を実行できるAPIを公開する方法についても説明します。
- NGINX PlusのKey-Value Storeを使用してHashiCorp Vaultの一時SSLキーを保護 – HashiCorp Vaultで一時SSLキーを生成し、NGINX PlusのインメモリKey-Value Storeに保存することで、SSLキーをディスクに保存せずに済む方法を説明します。
NGINX Plusをぜひお試しください。今すぐ30日間の無料トライアルを開始するか、ユースケースについてお問い合わせください。
著者について

関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります