CloudFormationでパスワードを自動生成してテンプレート内で利用する

CloudFormationでパスワードを取り扱う場合、パスワードをどこに保存するか悩ましいです。 パラメータストアに保存しておいて参照するというのもよい方法ですが、 もっとサクッと作りたい!と、いうことで、CloudFormationでパスワードを自動生成する方法を紹介します。
2019.09.28

CloudFormationでパスワードを取り扱う場合、パスワードをどこに保存するか悩ましいです。

たとえば、CloudFormationでIAM Userを作りたい場合、IAM Userのパスワードはどこに保存しましょう?

CloudFormationテンプレート内にハードコーディングするのは、セキュリティの観点から好ましくありません。

パラメータストアSecureStringに保存しておいて参照するというのは、よい方法だと思います。

いやしかし、別途パラメータストアを作るのが面倒くさいのです。(個人の感想です)

もっとサクッと作りたい!と、いうことで、CloudFormationでパスワードを自動生成する方法を紹介します。

CloudFormationでパスワードを自動生成する

結論から言うと、Secrets Managerの機能を使うことで、簡単にパスワードを生成することができます。

Secrets Managerでは、CloudFormationでシークレットを構築する際、ランダムな文字列を生成する機能が備わっています。

パスワードの生成ルールはGenerateSecretStringプロパティで細かく指定することができます。

具体的にCloudFormationテンプレートをあげると、次のように使用できます。

---
AWSTemplateFormatVersion: '2010-09-09'

Resources:
  SampleSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      GenerateSecretString:
        GenerateStringKey: password
        PasswordLength: 32
        SecretStringTemplate: '{}'

Outputs:
  GetSecretValueByCLI:
    Value: !Sub |+
        aws secretsmanager get-secret-value
          --secret-id ${SampleSecret}
          --region ${AWS::Region}
          --query SecretString

実際にCloudFormationでシークレットを構築すると、ランダムな文字列が生成されていることがわかります。

ついでに、AWS CLIでSecrets Managerの値を取得するコマンドを出力するよう仕込んでいるので、こっちも確認します。

実際にコマンドを実行してみます。

$ aws secretsmanager get-secret-value \
  --secret-id arn:aws:secretsmanager:us-west-2:123456789012:secret:SampleSecret-nQQ16yTl7F79-yYVzIl \
  --region us-west-2 \
  --query SecretString
"{\"password\":\"xxxxxxxxxxxxxxxxxxxxxxxxx\"}"

CLIでもランダムな文字列が生成されていることが確認できます。

Secrets Managerの値を取得してCloudFormationで利用する

CloudFormationでは、パラメータストアSecrets Managerに格納された値を動的に参照する機能がサポートされています。

この機能を利用することで、CloudFormationテンプレート内でSecrets Managerの値を利用できます。

具体的にCloudFormationテンプレートをあげると、次のように利用できます。

---
AWSTemplateFormatVersion: '2010-09-09'

Resources:
  SampleSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      GenerateSecretString:
        GenerateStringKey: password
        PasswordLength: 32
        SecretStringTemplate: '{}'
  SampleUser:
    Type: AWS::IAM::User
    Properties:
      Path: "/"
      LoginProfile:
        Password: !Sub "{{resolve:secretsmanager:${SampleSecret}:SecretString:password::}}"

Outputs:
  GetSecretValueByCLI:
    Value: !Sub |+
        aws secretsmanager get-secret-value
          --secret-id ${SampleSecret}
          --region ${AWS::Region}
          --query SecretString
  IAMUserName:
    Value: !Ref SampleUser

実際にCloudFormationでIAM Userを構築すると、パスワードでコンソールログイン可能なユーザーができていることがわかります。

パスワードにSecrets Managerの値が使われていることを確かめる

IAM Userが構築できたので、本当にSecrets Managerの値がパスワードとして設定されているのか確かめてみます。

ユーザー名とパスワードを入力して、マネジメントコンソールにログインします。パスワードは、Secrets Managerの値からコピーしてきます。

問題なくログインできて、パスワードが期待通り設定できていることがわかりました。

終わりに

CloudFormationでパスワードの扱いに迷っていましたが、Secrets Managerで自動生成できることがわかり、サクッと作ることができるようになりました。 CloudFormationでパスワードを取り扱うことがあれば、ぜひお試しください。