【AWS】CloudFormation ~ 認証情報の扱い ~

■ はじめに

 Github の OAuthToken などの認証情報が
AWS Systems Manager パラメータストアで管理されていて、
それをAWS CloudFormation から取得する際に
色々とトラブルあり、勉強になることがあったので、
AWS CloudFormationでの認証情報の扱いについて、メモっておく

目次

【0】認証情報について
 1)認証情報の扱い
 2)AWS内の動的なリファレンス
【1】SSM パラメータ
 1)構文
 2)サンプル
【2】SSM Secure String パラメータ
 1)構文
 2)サンプル
 3)使用上の注意
 4)補足:実際にあったトラブル
【3】Secrets Manager のシークレット
 1)構文
 2)サンプル

【0】認証情報について

1)認証情報の扱い

公式サイトの「AWS CloudFormation ベストプラクティス」より抜粋

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/security-best-practices.html#creds

テンプレートに認証情報を埋め込まない
~~~~~~
AWS CloudFormation テンプレートに機密情報を埋め込むのではなく、
スタックテンプレートで 動的なリファレンス を使用することをお勧めします。
動的なリファレンスにより、

AWS Systems Manager パラメータストアや AWS Secrets Manager など
の他のサービスで保存、管理されている外部値を参照するための
シンプルで強力な方法が提供されます。
~~~~~~

 なお、AWS Systems Manager パラメータストア、
AWS Secrets Manager の詳細は、以下の関連記事を参照のこと。

機密データの管理 ~ パラメータストア 編 ~
https://dk521123.hatenablog.com/entry/2020/01/31/231636
機密データの管理 ~ Secrets Manager 編 ~
https://dk521123.hatenablog.com/entry/2020/03/12/220717

2)AWS内の動的なリファレンス

* AWSサービス 内の動的なリファレンスについては、以下の通り。

[1] SSM パラメータ
[2] SSM Secure String パラメータ
[3] Secrets Manager のシークレット

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/dynamic-references.html

※SSM について

* SSM = Simple Systems Manager(現 Systems Manager)

【1】SSM パラメータ

* AWS Systems Manager パラメータストアに格納されている
 プレーンテキスト値を取得する

1)構文

{{resolve:ssm:<parameter-name>:<version>}}

パラメータの説明

* parameter-name
 => パラメータ名
* version
 => パラメータストアのバージョン (任意)

補足:「バージョン (任意)」について

* 2021/12/28現在、日本語訳だとversion は「必須」となっているが
 英語だと「Optional(任意)」になっている

2)サンプル

  MyS3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      AccessControl: '{{resolve:ssm:S3AccessControl}}' 

【2】SSM Secure String パラメータ

* AWS Systems Manager パラメータストアに格納されている
 安全な文字列を取得する

1)構文

{{resolve:ssm-secure:<parameter-name>:<version>}}

パラメータの説明

* parameter-name
 => パラメータ名
* version
 => パラメータストアのバージョン (任意)

2)サンプル

  MyIAMUser:
    Type: AWS::IAM::User
    Properties:
      UserName: 'MyUserName'
      LoginProfile:
        Password: '{{resolve:ssm-secure:IamUserPassword}}'

3)使用上の注意

* サポートしているリソースがある
 => 逆に言うと、サポートされていないリソースでは使えない...

SSM Secure String パラメータをサポートしているリソース

Resource Property Type Properties
AWS::DirectoryService::MicrosoftAD - Password
AWS::DirectoryService::SimpleAD - Password
AWS::ElastiCache::ReplicationGroup - AuthToken
AWS::IAM::User LoginProfile Password
AWS::KinesisFirehose::DeliveryStream RedshiftDestinationConfiguration Password
AWS::OpsWorks::App 送信元 Password
AWS::OpsWorks::Stack CustomCookbooksSource Password
AWS::OpsWorks::Stack RdsDbInstances DbPassword
AWS::RDS::DBCluster - MasterUserPassword
AWS::RDS::DBInstance - MasterUserPassword
AWS::Redshift::Cluster - MasterUserPassword

4)補足:実際にあったトラブル

冒頭「■ はじめに」で触れているが、
Github の OAuthToken を
AWS Systems Manager パラメータストアで管理されていて、
それをAWS CloudFormation から取得しようとした際に
以下の「エラー内容」が表示されてしまった

エラー内容

SSM Secure reference is not supported in: [AWS::CodePipeline::Pipeline/Properties/Stages]

エラーになる例

Stages:
  -
    Name: Source
    Actions:
      - 
        Name: SourceAction
        ActionTypeId:
          Category: Source
          Owner: ThirdParty
          Provider: GitHub
          Version: 1
        Configuration:
          Owner: !Ref GithubOwner
          Repo: !Ref GithubRepository
          Branch: !Ref GithubBranch
          # ★ここ★
          OAuthToken: {{resolve:ssm-secure:GithubAccessToken}}

原因

リソース「AWS::CodePipeline::Pipeline」では、
SSM Secure String パラメータをサポートしていないため

解決案

SSM Secure String パラメータではなく
Secrets Manager のシークレットで管理するように置き換える

https://eoins.medium.com/securing-github-tokens-in-a-serverless-codepipeline-dc3a24ddc356

【3】Secrets Manager のシークレット

*  AWS Secrets Manager に保存されている
 シークレットの値を取得する

1)構文

{{resolve:secretsmanager:<secret-id>:<secret-string>:<json-key>:<version-stage>:<version-id>}}

パラメータの説明

* secret-id
 => シークレットの一意の識別子(必須)
* secret-string
 => 現在、サポートされている値は SecretString のみ(任意)
 => デフォルトも「SecretString」
* json-key
 => 値を取得するキーと値のペアのキー名を指定(任意)
 => json-key を指定しない場合、シークレットテキスト全体を取得
* version-stage
 => シークレットのバージョン(任意)
 => 使用する場合は、version-id を指定できない
* version-id
 => シークレットのバージョンの固有 ID (任意)

2)サンプル

  MyRDSInstance:
    Type: 'AWS::RDS::DBInstance'
    Properties:
      DBName: MyRDSInstance
      AllocatedStorage: '20'
      DBInstanceClass: db.t2.micro
      Engine: mysql
      MasterUsername: '{{resolve:secretsmanager:MyRDSSecret:SecretString:username}}'
      MasterUserPassword: '{{resolve:secretsmanager:MyRDSSecret:SecretString:password}}'

参考文献

https://techblog.nhn-techorus.com/archives/17674

関連記事

AWS CloudFormation ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2021/10/26/224812
AWS CloudFormation ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2021/12/01/170326
AWS CloudFormation ~ 組み込み関数 ~
https://dk521123.hatenablog.com/entry/2021/12/04/202519
AWS CloudFormation ~ 疑似パラメータ ~
https://dk521123.hatenablog.com/entry/2021/12/05/134313
AWS CloudFormation ~ DeletionPolicy 属性 ~
https://dk521123.hatenablog.com/entry/2021/12/27/211328
CloudFormation で Github/CodePipeline/CodeBuild を構築する
https://dk521123.hatenablog.com/entry/2021/12/26/155956
機密データの管理 ~ パラメータストア 編 ~
https://dk521123.hatenablog.com/entry/2020/01/31/231636
機密データの管理 ~ Secrets Manager 編 ~
https://dk521123.hatenablog.com/entry/2020/03/12/220717