CredStashを使ってApache/Nginx再起動時のパスフレーズ要求を無視できるようにした
背景
現在のWebサイトの多くはSSL通信、つまりhttpsによる常時接続が当たり前の時代になっています。Webサイトを構築する際にSSL証明書を取得し、それをApacheないしNginxなどのWebサーバに取り込んでSSL通信させています。ですが、SSL証明書をとりこんだWebサーバを停止して再起動する際、SSL証明書発行に使ったSSL秘密鍵に設定したパスフレーズを聞かれると思います。
手動で再起動したなら直接パスフレーズを入力すればよいのですが、問題は夜間バッチ処理などの自動化運用時に発生する一連の処理の中で起きる再起動です。
この時Webサーバは再起動に失敗し、後続の運用処理が行われなくなってしまうという問題点があります。この問題に対処する方法でよく目にするは2つあります。
①SSL秘密鍵のパスフレーズを解除する。
SSL秘密鍵のパスフレーズは解除することができます。実際、SSL証明書発行会社ですと、上記の問題があるためSSL秘密鍵にパスフレーズをつけないことを推奨することもあります。
パスフレーズを設定していない秘密鍵
パスフレーズを設定している秘密鍵(最初の方に暗号化済という説明が記載されている)
②Webサーバのモジュールを使ってパスフレーズを呼び込む
ApacheにはSSLPassPhraseDialogというディレクティブがあり、ここにパスフレーズが記載されているファイルを指定することで、Apacheの再起動時にパスフレーズ入力をApache側で自動で行ってくれます。
SSLPassPhraseDialog exec:/etc/httpd/conf.d/passphrase.sh
# cat passphrase.sh#!/bin/sh
echo '12345678'
Nginxではssl_password_fileというディレティブで同じようにパスフレーズが記載されているファイルを指定することができます。
ssl_password_file /etc/nginx/conf.d/passphrase.sh;
ですが、①にしろ②にしろどちらもセキュアな情報がサーバ内に丸見えで保存されている状態になってしまいます。SSL秘密鍵が漏洩した場合、不正なSSL証明書を発行されてしまい、自己保有されているドメインの悪用につながります。そこでタイトルにもあるとおり、CredStashというツールを用いて、パスフレーズをサーバ内に保存せず、外部から呼び出して使えるように変更いたします。ちなみに今回の記事内容は私が書いた会社ブログにより詳細な手順が書いてありますのでそちらも見ていただけますと幸いです。
CredStashについて
CredStashとは認証情報の管理や複数サーバへ簡単に共有できることのできるPython製のコマンドツールです。
特にそういった記述は見つかりませんでしたが、Python2系ではインストールに失敗しましたのでPython3系でインストールする必要があるようです。
事前準備
CredStashは認証情報をAWSのDynamoDBに暗号化して保管します。したがってAWS関係のリソースを使う必要があります。(もちろんんAWSアカウント登録必須です)ここでは、AWS KMSを使ってパスフレーズを暗号化するための暗号キーを取得します。
初期設定
暗号キーを作成しましたら、credstashをインストールして、セットアップを行います。
# pip install credstash
Collecting credstash
Downloading credstash-1.17.1-py3-none-any.whl (25 kB)
Collecting boto3>=1.1.1
Downloading boto3-1.14.27-py2.py3-none-any.whl (128 kB)
|████████████████████████████████| 128 kB 9.5 MB/s
Collecting cryptography>=2.1
Downloading cryptography-3.0-cp35-abi3-manylinux2010_x86_64.whl (2.7 MB)
|████████████████████████████████| 2.7 MB 13.3 MB/s
Collecting jmespath<1.0.0,>=0.7.1
Downloading jmespath-0.10.0-py2.py3-none-any.whl (24 kB)
Collecting s3transfer<0.4.0,>=0.3.0
Downloading s3transfer-0.3.3-py2.py3-none-any.whl (69 kB)
|████████████████████████████████| 69 kB 14.9 MB/s
Collecting botocore<1.18.0,>=1.17.27
Downloading botocore-1.17.27-py2.py3-none-any.whl (6.4 MB)
|████████████████████████████████| 6.4 MB 42.4 MB/s
Collecting six>=1.4.1
Downloading six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting cffi!=1.11.3,>=1.8
Downloading cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl (409 kB)
|████████████████████████████████| 409 kB 39.9 MB/s
Collecting docutils<0.16,>=0.10
Downloading docutils-0.15.2-py3-none-any.whl (547 kB)
|████████████████████████████████| 547 kB 40.7 MB/s
Collecting urllib3<1.26,>=1.20; python_version != "3.4"
Downloading urllib3-1.25.10-py2.py3-none-any.whl (127 kB)
|████████████████████████████████| 127 kB 42.7 MB/s
Collecting python-dateutil<3.0.0,>=2.1
Downloading python_dateutil-2.8.1-py2.py3-none-any.whl (227 kB)
|████████████████████████████████| 227 kB 43.1 MB/s
Collecting pycparser
Downloading pycparser-2.20-py2.py3-none-any.whl (112 kB)
|████████████████████████████████| 112 kB 43.8 MB/s
Installing collected packages: jmespath, docutils, urllib3, six, python-dateutil, botocore, s3transfer, boto3, pycparser, cffi, cryptography, credstash
Successfully installed boto3-1.14.27 botocore-1.17.27 cffi-1.14.0 credstash-1.17.1 cryptography-3.0 docutils-0.15.2 jmespath-0.10.0 pycparser-2.20 python-dateutil-2.8.1 s3transfer-0.3.3 six-1.15.0 urllib3-1.25.10
セットアップが完了しますとDynamoDBにcredential-storeというテーブルが作成されます。(セットアップに失敗する場合、以下の権限を付与してみてください)
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:CreateTable",
"dynamodb:DescribeTable"
],
"Effect": "Allow",
"Resource": "arn:aws:dynamodb:ap-northeast-1:<ACCOUNT NUMBER>:table/credential-store"
},
{
"Action": [
"dynamodb:ListTables"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
次に鍵と認証情報をDBへ登録するためにIAMの権限設定を行います。
最初のGitHubに書かれていますが、以下のIAMポリシーを作成してIAMロールにアタッチします。
認証情報書き込み権限付与
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"kms:GenerateDataKey"
],
"Effect": "Allow",
"Resource": "arn:aws:kms:ap-northeast-1:AWSACCOUNTID:key/KEY-GUID"
},
{
"Action": [
"dynamodb:PutItem"
],
"Effect": "Allow",
"Resource": "arn:aws:dynamodb:ap-northeast:AWSACCOUNTID:table/credential-store"
}
]
}
認証情報読み込み権限付与
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"kms:Decrypt"
],
"Effect": "Allow",
"Resource": "arn:aws:kms:ap-northeast-1:AWSACCOUNTID:key/KEY-GUID"
},
{
"Action": [
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"Effect": "Allow",
"Resource": "arn:aws:dynamodb:ap-northeast-1:AWSACCOUNTID:table/credential-store"
}
]
}
AWSACCOUNTIDとKEY-GUIDは各々の値を設定します。ここまで設定が完了できましたら、パスフレーズを暗号化してDynamoDBへ保管します。
パスフレーズ暗号化保管
credstashのオプションコマンドをputを使ってパスフレーズをDynamoDBへ保管します。
# credstash put --key alias/credstash apache_pass 12345678
nginx_pass has been stored
12345678というパスフレーズがapache_passというテーブルに暗号化して保存されました。
パスフレーズの取得
DynamoDBへ保管したパスフレーズを取得するにはcredstashのオプションコマンドgetを使って取得します。
# credstash get apache_pass
12345678
この呼び出しコマンドをシェルスクリプトファイルに書き込みWebサーバ側で呼び出せるようにします。
# cat passphrase.sh
#!/bin/bash
Apache_Pass=`credstash get apache_pass`
echo "$Apache_Pass"
こうすることでWebサーバを再起動してもパスフレーズの問い合わせがなく起動することができます。
感想
WebサーバによるSSL秘密鍵のパスフレーズの問い合わせ無視の方法は冒頭にか書かれている方法が大半でこの方法を紹介している記事は見つかりませんでした。
元々弊社でも①のSSL秘密鍵のパスフレーズを解除した上でサーバ内に秘密鍵を配置していましたが、私が見つけたパスフレーズを呼び出すディレクティブと先輩社員が使っているCredStashの2つを組み合わせることでセキュアな構築がSSL証明書設定ができたので、この記事が広まればいいなと願っています。