【SRE実践知見】CloudFormation動的リファレンス完全制覇:SSM・Secrets Managerで機密情報をコードから完全に駆逐する
テックリードの私たちが、コードレビューで最も冷徹になる瞬間はいつか。それは、IaCのテンプレート内にパスワードやAPIシークレットがハードコーディングされているのを発見した時だ。
「デプロイを急いでいたので」「テスト環境だから」――そんな言い訳は、セキュリティインシデントの前には無力である。Gitリポジトリにコミットされた瞬間から、その機密情報は「漏洩リスクのある時限爆弾」と化す。
CloudFormationには、動的リファレンス(Dynamic References)という強力な機能が備わっている。これを用いれば、AWS Systems Manager (SSM) パラメータストアやAWS Secrets Managerに安全に保管された機密情報を、デプロイメントの瞬間にインラインで安全に取得し、リソースに流し込むことができる。
今回は、単なる構文の解説にとどまらない。現場の生産性を極限まで高めるエディタ環境、チーム開発の鉄則、そして明日からそのままプロダクション環境に投入できるベストプラクティス構成を伝授しよう。
—
1. 現場の生産性を爆発させる!VSCode 開発環境の極意
IaCの記述スピードと品質は、開発環境のチューニングで8割が決まる。迷いのないタイピングと、構文ミスの完全排除を実現するプロの環境構築を共有する。
必須の神プラグイン
1. AWS CloudFormation Linter (cfn-lint)
- 構文エラーやAWSリソースのプロパティ誤りを、保存する前に検知する。動的リファレンスのタイポも一発で弾く。
2. YAML / JSON Support (Red Hat)
- インデントの崩れやスキーマの不整合を視覚化。
3. AWS Toolkit for Visual Studio Code
- IDE内から直接CloudFormationスタックの状態を確認・操作できる。
開発スピードを加速させるキーボードショートカット (macOS / Windows)
- コメントアウトのトグル: `Cmd + /` (Mac) / `Ctrl + /` (Win)
- 行の複製: `Shift + Alt + Down` (Win) / `Shift + Option + Down` (Mac)
- マルチカーソル(一括置換): `Cmd + D` (Mac) / `Ctrl + D` (Win) — パラメータ名を一括変更する際に神速を発揮する。
—
2. 動的リファレンス構文の深淵
CloudFormationにおける動的リファレンスは、以下の構文パターンで記述する。
{{resolve:service-name:reference-key:version-stage}}
SSM パラメータストアの参照
平文または SecureString(KMS暗号化)されたパラメータを参照する。
SSMのSecureStringを参照する場合(バージョンを指定するのがベストプラクティス)
DatabasePassword: !Ref “{{resolve:ssm:/prod/database/password:1}}”
Secrets Manager の参照
JSON形式で格納されたシークレットから、特定のキーだけをピンポイントで抽出して参照できるのがSecrets Managerの真骨頂だ。
Secrets ManagerのJSONシークレットから特定のキー(password)の値のみを取得
ApiKey: !Ref “{{resolve:secretsmanager:prod/app/api-keys:SecretString:api_key}}”
> SREの教訓:なぜ `Parameters` セクションではなく動的リファレンスなのか?
> 従来の `Parameters` セクション経由で機密情報を渡すと、AWS Consoleのパラメータ履歴やCLIの実行ログ、さらにCloudFormationのイベントログに平文(またはマスク漏れ)で値が露出するリスクがある。動的リファレンスであれば、AWSのバックエンドがデプロイの直前・直因に値をインジェクションするため、ログやコンソールへの露出を最小限に抑えられる。
—
3. チーム開発における共有化ルール
複数人でCloudFormationをメンテするプロジェクトでは、ルールの統制がないとカオスに陥る。以下の3点をチームの規約(Definition of Done)に組み込んでほしい。
1. 命名規則の厳格化(Naming Convention)
- パスは必ず `/{Environment}/{SystemName}/{ResourceType}/{PropertyName}` の階層構造に従う。
- 例: `/production/auth-service/rds/master-password`
2. KMSキーの分離
- デフォルトの `aws/ssm` キーではなく、環境ごとに専用のカスタマー管理型KMSキー(CMK)を使用し、IAMポリシーでアクセスを厳格に制御する。
3. ローカルでの `cfn-lint` 実行の義務化
- GitのPre-commit hookに `cfn-lint` を組み込み、構文エラーや動的リファレンスのフォーマットミスがあるコードはコミットできないようにする。
—
4. 実戦投入用:ベストプラクティス構成例
それでは、RDSデータベースと、そこへ接続するECSタスク定義(シークレットを環境変数に安全に注入するパターン)を網羅した、実用的なテンプレートの全体像を示す。
このコードは、そのままプロダクション環境のCI/CDパイプラインに投入できる堅牢性を持っている。
AWSTemplateFormatVersion: ‘2010-09-09’
Description: >
Production-grade template demonstrating dynamic references
with SSM Parameter Store and Secrets Manager.
Parameters:
Environment:
Type: String
Default: prod
AllowedValues: [dev, stg, prod]
Description: Deployment environment.
Resources:
# —————————————————————————–
# RDS Database Instance (Password fetched securely via SSM Parameter Store)
# —————————————————————————–
DatabaseInstance:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceIdentifier: !Sub ‘${Environment}-core-db’
Engine: postgres
EngineVersion: ‘15.4’
DBInstanceClass: db.t4g.medium
AllocatedStorage: 50
MasterUsername: dbadmin
# 動的リファレンスにより、テンプレート内およびログにパスワードが露出しない
MasterUserPassword: !Ref “{{resolve:ssm:/prod/core/rds/password:1}}”
# 実際の設計ではVPCやサブネットグループの指定がここに入ります
PubliclyAccessible: false
Tags:
- Key: Environment
Name: !Ref Environment
# —————————————————————————–
# ECS Task Definition (API Key fetched securely via Secrets Manager)
# —————————————————————————–
AppTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ‘${Environment}-app-task’
Cpu: ‘256’
Memory: ‘512’
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
ExecutionRoleArn: !GetAtt EcsExecutionRole.Arn
ContainerDefinitions:
- Name: api-server
Image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:v1.0.0
PortMappings:
- ContainerPort: 8080
Protocol: tcp
# Secrets Managerから環境変数へ安全に機密情報をマッピング
Secrets:
- Name: EXTERNAL_API_KEY
ValueFrom: !Ref “{{resolve:secretsmanager:prod/app/keys:SecretString:external_api_key}}”
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Sub ‘/ecs/${Environment}-app’
awslogs-region: !Ref ‘AWS::Region’
awslogs-stream-prefix: api
# —————————————————————————–
# IAM Execution Role for ECS (Required to read Secrets Manager / SSM)
# —————————————————————————–
EcsExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: ‘2010-12-19’
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: ‘sts:AssumeRole’
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Policies:
- PolicyName: ReadSecretsAndParameters
PolicyDocument:
Version: ‘2010-12-19’
Statement:
- Effect: Allow
Action:
- ssm:GetParameters
- secretsmanager:GetSecretValue
- kms:Decrypt
Resource:
- !Sub ‘arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/prod/core/rds/password’
- !Sub ‘arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/prod/app/’
- !Sub ‘arn:aws:secret:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:prod/app/keys’
Outputs:
DatabaseEndpoint:
Description: The endpoint of the database
Value: !GetAtt DatabaseInstance.Endpoint.Address
Export:
Name: !Sub ‘${Environment}-CoreDBEndpoint’
—
5. テックリードからの最終メッセージ
ハードコーディングされたシークレットの排除は、もはや「努力目標」ではなく、クラウドエンジニアとしての最低限のプロトコルである。
今回紹介した動的リファレンスとSecrets Manager / SSM パラメータストアの組み合わせをマスターすれば、セキュリティと開発スピードを高い次元で両立できる。手動での運用の余地を排除し、コードによる完全な自動化とセキュアな状態を構築してこそ、真のSREと言える。
さあ、今すぐ既存のテンプレートを確認し、ハードコーディングされた機密情報をこの動的リファレンスに置き換えてほしい。あなたのクラウドインフラが、より堅牢になることを確信している。