😀

CloudFormationのSSM Parameter動的参照でversion指定が不要に!

に公開

はじめに

Cloudformationを使用してコード化していくと、コード量が増えたきたり、あるいはCIのデプロイフローに組み込みたくないコードを分離するなど、スタックを分割するケースが存在します。そしてスタックを分割すると、スタック間での名称やArn等の値の受け渡しを行いたいケースが存在するかと思います。
そういったケースではSSM Parameterの動的参照(dynamic reference)を使用すると、値の受け渡しが可能になりますが、今回はその際の参照方法に変更があり、今まで必須だったversionの指定が不要になったため、そちらについて紹介したいと思います。
 また、あわせてクロススタック参照(cross-stack reference)を使用した値の受け渡しと、どのような挙動の違いがあるかについても記載できればと思います。

SSM Parameterの動的参照とは?

SSMとは、SystemManagerを指しAWSでインフラストラクチャを表示および制御するために使用できます。
 そしてParameterとは、SSMの一機能であるParameterStoreに保存された値のことで、この値はスタック間でやり取りすることが出来ます。ParameterStoreとは設定データ管理と機密管理のための安全な階層型ストレージを提供します。今回は触れませんが、値はプレーンテキストだけでなく、暗号化されたデータとしても保存できるため、パスワードやアクセストークンの管理にも使用可能です。
 そして動的参照をを使用すると、上記SSMParameterStoreに格納された値をテンプレートに格納します。

それでは以下にCloudformationを使用した定義例と参照例を記載します。
定義側のスタックと参照側のスタックは以下の構成になっております。

定義側スタック: S3Bucketに関する定義
参照側スタック: GlueのDatabase,Tableに関する定義。 TableのLocationにS3Bucket名を指定しているためそこで参照する

定義側

SSM Parameterに関する定義はそれぞれ以下のようになっています。

  • (a)Type:AWS::SSM::Parameterを指定
  • (b)ParameterStore上に保存するキー名
  • (c)型を指定. 他にStringList,SecureString が指定可能です。
  • (d)保存したい値を指定。今回はS3のBucket名を保存しています。
Resources:
  S3:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Delete # cfn delete時にS3Bucketを消す
    Properties:
      BucketName: !Sub "${ProjectName}-bucket"
      # ----------- S3に関する定義は省略 -----------

  S3FirehoseBucketNameSSM:
    Type: "AWS::SSM::Parameter"                         # (a)
    Properties:
      Name: !Sub "/${ProjectName}/S3FirehoseBucketName" # (b)
      Type: String                                      # (c)
      Value: !Ref "S3"                                  # (d)

上記をaws cliでdeployすると以下のように、キー名と値が保存されます。

pm_1_store-value.png

参照側

以下(a)部分が参照に関する定義です。
ちなみに!Sub${ProjectName}参照用のため今回の動的参照には関係ありません。
以前なら{{resolve:ssm:/${ProjectName}/S3FirehoseBucketName:3}}のように、versionの指定が必須でしたが、今回のアップデートで不要になりました。
そしてversionを指定しない場合Parameterの最新versionを参照します。

  
  GlueTable:
    Type: "AWS::Glue::Table"
    Properties:
        # ----------  一部省略 -------------
        StorageDescriptor:
          # ----------  一部省略 -------------
          Location: !Sub
            - "s3://${S3Bucket}/${S3Dir}"
            - S3Bucket: !Sub "{{resolve:ssm:/${ProjectName}/S3FirehoseBucketName}}" # (a)
              S3Dir: !Ref "S3FirehoseDir"

参照時のルール

参照時のルールは以下のようになっています。
{{resolve:service-name:reference-key}}
service-name:
 値が保管および管理されるサービスを指定します。

  • ssm: Systems Manager パラメータストアのプレーンテキストパラメータ。
  • ssm-secure: Systems Manager パラメータストアの安全な文字列パラメータ。

reference-key:
動的参照におけるリファレンスキーです。
以前までは、以下のようにparameter-nameとversionが必要でした。
{{resolve:ssm:parameter-name:version}}

今回から以下のようにversionを省略できます。そして省略した場合はParameterStoreに保存された値の最新を参照します。
{{resolve:ssm:parameter-name}}

(注) 2021/7/16現在日本語版の公式ドキュメントだと、項目versionについて必須となっていますが不要です。
英語版のドキュメントではRequiredからOptionalに変わっていることを確認できます。

参考: 公式ドキュメント- SSM parameters

参照値更新時のクロススタック参照との挙動の比較

少し余談にはなりますが、Cloudformationのスタック間の値のやり取りについてクロススタック参照でも可能です。こちらを使用した場合と比較して、参照値更新時の挙動の違いを以下で紹介します。

クロススタック参照例

先ほどと同じ様にに定義側では「S3Bucketに関する定義」を、参照側では「GlueのDatabase,Tableに関する定義」をしてTableのLocationでS3Bucket名を参照します。

定義側

上記に記載したS3FirehoseBucketNameがスタック上にExportされる際のキー名となります。

Resources:
  S3:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Delete
    Properties:
      # --------  S3に関する定義は省略 -----------
      BucketName: !Sub "${ProjectName}-bucket"

Outputs:
  S3FirehoseBucketName:
    Value: !Ref "S3"
    Export:
      Name: S3FirehoseBucketName

参照側

参照側では!ImportValueを使用してキー名を指定して参照します。

  # Glue table
  GlueTable:
    Type: "AWS::Glue::Table"
    Properties:
      # ----------  一部省略 -------------
      StorageDescriptor:
          # ----------  一部省略 -------------
          Location: !Sub
            - "s3://${S3Bucket}/${S3Dir}"
            - S3Bucket: !ImportValue "S3FirehoseBucketName"
              S3Dir: !Ref "S3FirehoseDir"

参照値更新の比較

以下の様にS3のBucket名を${ProjectName}-bucketから${ProjectName}-bucket-updatedに変更します。

  S3:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Delete
    Properties:
      # --------  S3に関する定義は省略 -----------
      BucketName: !Sub "${ProjectName}-bucket-updated"

これをaws cliを使用してdeployします。

クロススタック参照の場合

定義側(スタックS3)のdeployすると以下のように、Export S3FirehoseBucketName cannot be updated as it is in use by dummy-cross-ref-project というエラーが発生しています。
既に参照されている場合そのまま更新することはできません。更新する際には参照側で削除した上で、再度更新する必要があります。

cross_4_s3-update-log.png

動的参照の場合

定義側(スタックS3)のdeployします。すると以下のように、問題なくdeployができます。

pm_4_s3-update-log.png

SystemManagerのParameterStoreを確認すると、以下のように値が更新されていることが確認できます。

pm_6_resolve-value-updated.png

そして参照側を更新すると、、以下のように参照側(Glue)のLocation情報が
最新の値に更新されていることが確認できます。

pm_7_glue-updated.png

最後に

いかがでしたでしょうか?
動的な参照はスタックテンプレートに対して最大60個と制限はありますが、変更頻度が高い値をスタック間で受け渡ししたい場合、非常に便利かと思います。
もしよければ使ってみてください。

また、今回のサンプルに使用した定義ファイルや実行コマンドについては以下レポジトリに載せています。

https://github.com/kohei789/aws-ssm-parameter-store-example

参考文献

Discussion