0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CFnテンプレートの Dynamic Reference を再評価させる小手先テクニック

Last updated at Posted at 2025-11-15

Dynamic Reference を、sam deploy の度に必ず再評価させる

Lambda の環境変数に Dynamic Reference{{resolve:ssm:...}}{{resolve:secretsmanager:...}})を使っていると、
sam deploy のたびに常に最新値を読んでほしいのに、実際には更新されない」
という状況に遭遇することがあります。

この記事では、AWS SAM で定義した環境変数に対して、

  • ビルド時刻(buildtime)をダミーの環境変数として追加
  • sam deploy のたびに buildtime の値を変える

というシンプルな工夫で、毎回 Dynamic Reference を確実に評価させる方法をまとめます。

背景:Dynamic Reference と Lambda 環境変数

まず前提として、Lambda の環境変数に Dynamic Reference を書くとき、SAM テンプレートはだいたいこんなイメージになります。

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...
      Environment:
        Variables:
          DB_PASSWORD: '{{resolve:secretsmanager:my-app/db-password:SecretString:password}}'

ここで押さえておきたいポイントは以下の 2 つです。

  1. Dynamic Reference は CloudFormation がデプロイ時に評価する

    • テンプレート内の {{resolve:...}}スタックの作成・更新時に解決されて、具体的な値に置き換えられます
    • つまり Lambda の環境変数として保存されるのは「すでに解決された平文の値」です(もちろん KMS によって暗号化されて保存されますが、中身は“固定された値”)。
  2. CloudFormation は「テンプレート上の差分」がなければリソースを更新しない

    • 同じ template.yamlsam deploy しても、環境変数ブロックに差分がなければ Lambda Function の設定更新が起きません
    • その結果、Secrets Manager 側で値が変わっていても、「テンプレートに変化がない」場合は Lambda の環境変数は更新されません。

この挙動のせいで、

「Secret はローテーションされたのに、Lambda は古い値のまま」

という事象が起きることがあります。

解決したいこと

やりたいことはシンプルです。

  • DB_PASSWORD のような Dynamic Reference を含む環境変数について
  • sam deploy を実行するたびに、
  • 毎回 CloudFormation に Lambda の環境変数ブロックを“更新対象”として認識させる

= つまり、デプロイのたびに Dynamic Reference を再評価させたい、という要件です。

方針:buildtime をダミーの環境変数として仕込む

CloudFormation が「リソースを更新するかどうか」を判定するときに見ているのは、テンプレート上のプロパティの差分です。
なので逆に言えば、

Lambda の Environment.Variables毎回変わる値 を 1 個紛れ込ませる

ことで、「毎回差分がある」状態を強制的に作ることができます。

そこで利用するのが buildtime(ビルド時刻) を表すダミーの環境変数です。

  • この環境変数自体は Lambda コード側では使いません
  • 「毎回値が変わる」ことだけが目的です

実装例

1. テンプレートに Parameter を追加する

まず、template.yaml にビルド時刻を受け取るための Parameter を定義します。

Parameters:
  BuildTime:
    Type: String
    Description: "Unique value for each build/deploy to force env var update"

2. Lambda の Environment に BuildTime を含める

次に、Lambda Function の Environment にこの BuildTime をダミー変数として追加します。

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...
      Environment:
        Variables:
          # Dynamic Reference を使った本命の環境変数
          DB_PASSWORD: '{{resolve:secretsmanager:my-app/db-password:SecretString:password}}'

          # ダミー用途の buildtime 環境変数(コードからは使わない)
          BUILD_TIME: !Ref BuildTime

これで、BuildTime の値が変わるたびに Environment.Variables が変化し、
Lambda Function の設定が必ず更新されるようになります。

当然そのタイミングで DB_PASSWORD の Dynamic Reference も再評価され、
Secrets Manager / SSM Parameter Store の最新値が環境変数に反映されます。

3. CodeBuild から BuildTime を渡す

最後に、実際のデプロイ時に BuildTime に毎回異なる値を渡します。

ここでは AWS CodeBuild からデプロイすること を想定し、CodeBuild が毎回ユニークな値として持っている CODEBUILD_START_TIME(例: build_start_time 環境変数にマッピング)をそのまま渡す例にします。

例えば、buildspec.yml は次のように書けます。

version: 0.2

phases:
  build:
    commands:
      - sam build
      - sam deploy \
          --stack-name my-stack \
          --capabilities CAPABILITY_IAM \
          --parameter-overrides BuildTime=${CODEBUILD_START_TIME}

CODEBUILD_START_TIME は各ビルドごとに異なる値(ビルド開始時刻)になるため、毎回 BuildTime の値も変わります。
もし自分で build_start_time という環境変数を CodeBuild の環境変数として定義しているなら、単に ${build_start_time} に置き換えても問題ありません。

これで、

  • sam deploy のたびに BUILD_TIME が変わる
  • Environment.Variables に差分が出る
  • CloudFormation が Lambda Function を更新
  • Dynamic Reference も再評価される

というループが完成します。

このやり方のメリット・デメリット

メリット

  • Dynamic Reference が毎回必ず評価されるので、

    • Secrets Manager / SSM Parameter Store 側の値更新が Lambda に確実に反映される
  • 実装は非常にシンプル

    • Parameter 1 個
    • Environment に変数 1 個
    • sam deploy--parameter-overrides を足すだけ

デメリット / 注意点

  • sam deploy のたびに Lambda Function の 設定が毎回更新される ため、

    • Lambda のバージョン/エイリアス運用をしている場合は、バージョンがどんどん増える
    • CloudFormation の履歴上も毎回差分が残る
  • 「Dynamic Reference の再評価」が目的なので、
    「本当にそこまで頻繁に更新が必要か?」は要件と相談する必要がある

    • 例えば Secrets のローテーションが月 1 回なら、そのタイミングだけこの仕組みを使う、という運用もあり

まとめ

  • Dynamic Reference は便利だが、「デプロイ時に一度だけ評価される」という性質がある

  • CloudFormation はテンプレートに差分がないと Lambda Function を更新してくれない

  • そこで、

    1. buildtime を表すダミー Parameter を用意し
    2. Lambda の Environment に BUILD_TIME を追加し
    3. sam deploy のたびに違う値を渡す

    とすることで、sam deploy のたびに Lambda の環境変数ブロックに差分が生まれ、
    Dynamic Reference が毎回必ず再評価されるようになる

Dynamic Reference を SSM / Secrets Manager と組み合わせてガチガチにセキュア運用していると、
「値は変わっているはずなのに、Lambda が更新されていない」系のハマりどころはそこそこ出てきます。

同じような状況で悩んでいる方の参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?