Help us understand the problem. What is going on with this article?

credstashを用いてApacheのSSL秘密鍵のパスフレーズ問い合わせ無視できるようにしてみた

背景

SSL証明書を入れているApacheを再起動した場合、秘密鍵のパスフレーズの入力が求められます。
手動再起動なら人の手でパスフレーズを入力すればよいのですが、バッチ処理などでApacheの再起動を自動で行う場合は途中で失敗してしまいます。
解決方法としては、パスフレーズを解除した秘密鍵を配置するか、SSLPassPhraseDialogというApacheのディレクティブ内にexec:/etc/httpd/conf.d/passphrase.shと書き、パスフレーズを表示させるシェルスクリプトを読み込ませるというものがあります。

passphrase.sh
#!/bin/sh
echo 'パスフレーズ'

ですがどちらにしてもセキュリティ的に不安な面がありますので、credstashとAWSリソースのKMSを使うことでパスフレーズ問題をクリアするようにしました。

credstashについて

credstashですが日本語情報が少なく、配布元GitHubからの説明になりますが認証情報の管理及び共有システムといえます。(https://github.com/fugue/credstash)
使い方としては、認証情報をAWSのKMS(Key Management Service)を用いて暗号化し、鍵と認証情報の組み合わせをDynamoDBテーブルに保存するといったことが可能になります。
特に推奨バージョンは書かれていませんでしたが、Python2系ですとpipのインストールができなかったので少なくとも3系でインストールする必要があります。

事前準備

credstashをインストールする前に暗号化に使用するKMSのキーを作成します。
KMSのメニュー画面からカスタマー管理型のキーを選択し、キーの作成を選択します。image.png
設定についてはデフォルトのままで問題ありませんが、エイリアスの部分はcredstashとします。image.png
キーの作成が完了しましたらcredstashのインストールへ移ります。

インストール方法と初期設定

pipを用いてインストールします。
pip install credstash
初めてcredstashを使用する場合、credstash setupでDynamoDBにcredential-storeというテーブルが作成されます。
image.png

次に鍵と認証情報をDBへ登録するためにIAMの権限設定を行います。
GitHubに書かれていますが、以下のIAMポリシーを作成してIAMロールにアタッチします。

secret-writer
{
  "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"
    }
  ]
}
secret-reader
{
  "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"
    }
  ]
}

AWSACCOUNTIDKEY-GUIDの箇所は各々の数値を記載してください。(KEY-GUIDはKMSに記載されているキーIDのことです)
またcredstash setupでDynamoDBのテーブル作成に失敗する場合は、以下のIAMポリシーもIAMロールにアタッチしてください。

Setup
{
    "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": "*"
        }
    ]
}

パスフレーズの暗号化

putコマンドを使用して、パスフレーズを暗号化してDynamoDBに保存します。
credstash -r ap-northeast-1 put --key alias/credstash "任意の認証情報名" "パスフレーズ"
テーブル名をapache_passphraseと設定しましたら、このようにDynamoDBに保存されます。image.png

パスフレーズの復号

復号はgetコマンドを使用します。
credstash -r ap-northeast-1 get "任意の認証情報名"

apache側で読み込み

冒頭のpassphrase.shを以下のように書き換えます。

passphrase.sh
#!/bin/sh
Apache_Pass=`credstash -r ap-northeast-1 get apache_passphrase`

echo "$Apache_Pass"

apacheの再起動を行い、パスフレーズを聞かれることなく起動できましたら成功です。

引っかかりポイント

実は弊社の環境で、上記のスクリプトでapacheを再起動してもcredstashが機能せず、再起動に失敗しました。
apacheを動かしているサーバのPythonが2.6系だったのですが、2.6系ですとcredstashのインストールができなかったため、pyenvを用いてPythonを3.6系に変更しました。
その時に環境変数回りで問題があったのか、起動できないという問題がありました。
回避方法として、passphrase.shの中身を以下のように修正したらcredstashが上手く動き、apacheの再起動に成功しました。

passphrase.sh
#!/bin/sh
Apache_Pass=`/root/.pyenv/shims/credstash -r ap-northeast-1 get apache_passphrase`

echo "$Apache_Pass"

所感

ApacheでのSSL秘密鍵によるパスフレーズ問題はネット上でも、パスフレーズそのものを解除するか直接パスフレーズを埋め込んで読み込むしかなかったので、これを使えばよりセキュアなApache構築が可能になりますので、この情報が広まってほしいと願っています。
credstashはPython製のコマンドラインツールですが、GoやRubyなどで作られたものもありますので、自身の好みの言語を選択するのもの良いのかもしれません。

おまけ 2020/7/24追記

Nginxではどのように行えばよいのか類似モジュールがないか調べましたが以下のディレクティブを記載すれば同じようにパスフレーズを無視してできることを確認できました。
ssl_password_file
少しだけSSLPassPhraseDialogとは記法が異なりますので注意が必要です。

nginx.conf
http {
    ssl_password_file /etc/nginx/conf.d/passphrase.sh;

    server {
        server_name www1.example.com;
        ssl_certificate_key /etc/keys/first.key;
    }

    server {
        server_name www2.example.com;

        # named pipe can also be used instead of a file
        ssl_password_file /etc/keys/fifo;
        ssl_certificate_key /etc/keys/second.key;
    }
}
passphrase.sh
#!/bin/bash

Nginx_Pass=`/root/.pyenv/shims/credstash get nginx_pass`

echo "$Nginx_Pass"

Screenshot 2020-07-24 16:44:30.png
NginxでもSSL通信ができることを確認できました。

Yuhta
ヘルステック系の会社でインフラのお仕事をしております。
embrace
全国で110,000人以上の医療介護従事者の方にご利用いただいている医療介護連携SNS「メディカルケアステーション(MCS)」の企画・開発・運営をしています。医療介護従事者の多職種、多施設連携や、患者・家族とのコミュニケーションツールとしてだけでなく、医療治療支援も提供することで社会的課題の解決を目指しています。https://www.medical-care.net
https://www.embrace.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした