CloudFormationでインフラを安全に、保守しやすく、再利用しやすく管理するための実践ガイドです。


目次

  1. スタック設計
  2. テンプレートの書き方
  3. パラメータと設定値の管理
  4. シークレット管理
  5. データ保護と削除対策
  6. 変更管理とデプロイ
  7. 再利用性(ネスト・モジュール・StackSets)
  8. セキュリティとIAM
  9. 検証・テスト・ポリシー適用
  10. ドリフト管理と運用
  11. 命名・タグ付け
  12. CI/CD
  13. よくあるアンチパターン
  14. チェックリスト

1. スタック設計

ライフサイクルと所有者でスタックを分割する

変更頻度と担当チームが異なるリソースを、同じスタックに入れないようにします。

レイヤー例変更頻度
ネットワークVPC、サブネット、ルートテーブル、NAT Gateway低
セキュリティ / 共通基盤IAMロール、KMSキー、共通セキュリティグループ低〜中
データRDS、DynamoDB、S3(データ保管用)低
アプリケーションECS、Lambda、ALB、API Gateway高
  • ステートフルなリソース(DB、S3など)とステートレスなリソースを分ける。 アプリのデプロイでデータ層のリソースが誤って置き換えられる事故を防げます。
  • 1スタックが大きくなりすぎないようにする。リソース数の上限(1スタック500リソース)に近づくのは、分割すべきサインです。
  • スタックが小さすぎてもスタック間の依存関係が複雑になるので、「一緒にデプロイ・削除されるもの」を1単位にするのが目安です。

スタック間の連携方法を選ぶ

方法特徴向いているケース
Outputs + Export / Fn::ImportValue強い結合。参照されている間はExport元を変更・削除できない変更がほぼない基盤値(VPC IDなど)
SSM Parameter Store 経由疎結合。値の更新が自由変更の可能性がある値、チームをまたぐ連携
ネストスタックのパラメータ受け渡し親子間で完結1つのアプリを構成する部品同士

注意: Export は一度他のスタックから参照されると、値の変更や削除ができなくなります。気軽に多用すると、リファクタリング時に身動きが取れなくなります。


2. テンプレートの書き方

形式

  • YAMLを推奨。コメントが書け、可読性が高く、短縮形の組み込み関数(!Ref, !Sub, !GetAtt)が使えます。
  • AWSTemplateFormatVersion: "2010-09-09" と Description を必ず記述します。

基本構成例

AWSTemplateFormatVersion: "2010-09-09"
Description: "Application stack for my-app"
 
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label: { default: "Environment" }
        Parameters: [Environment]
 
Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, stg, prod]
    Description: "Deployment environment"
 
Conditions:
  IsProd: !Equals [!Ref Environment, prod]
 
Mappings:
  EnvConfig:
    dev:  { InstanceClass: db.t4g.micro }
    stg:  { InstanceClass: db.t4g.medium }
    prod: { InstanceClass: db.r6g.large }
 
Resources:
  # ...
 
Outputs:
  # ...

書き方のポイント

  • !Sub を !Join より優先する。 読みやすく、ミスが減ります。
    # 良い例
    BucketName: !Sub "${AWS::StackName}-${Environment}-logs"
    # 読みにくい例
    BucketName: !Join ["-", [!Ref AWS::StackName, !Ref Environment, "logs"]]
  • ハードコードを避け、擬似パラメータを使う。 AWS::Region、AWS::AccountId、AWS::Partition、AWS::StackName など。
    # ARNのパーティションもハードコードしない(GovCloud・中国リージョン対応)
    Resource: !Sub "arn:${AWS::Partition}:s3:::${MyBucket}/*"
  • AMI IDをハードコードしない。 SSMの公開パラメータを参照します。
    Parameters:
      LatestAmiId:
        Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
        Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
  • 条件分岐(Conditions)は最小限に。 環境差分が大きいなら、テンプレートを分けるかパラメータで吸収する方が保守しやすいことが多いです。
  • 繰り返しの記述には AWS::LanguageExtensions トランスフォームの Fn::ForEach が使えます。ただし可読性とのバランスを考えます。
  • DependsOn は、暗黙的な依存(!Ref / !GetAtt)で表現できない場合にのみ使います。

3. パラメータと設定値の管理

  • パラメータには制約を付ける。 AllowedValues、AllowedPattern、MinLength、MaxLength、ConstraintDescription で不正な入力を防ぎます。
  • AWS固有のパラメータ型を使う。 AWS::EC2::VPC::Id、AWS::EC2::Subnet::Id、List<AWS::EC2::SecurityGroup::Id> などを使うと、デプロイ前に存在チェックが行われます。
  • 環境ごとの値はパラメータファイルで管理する。
    params/
      dev.json
      stg.json
      prod.json
    
  • パラメータ数が多くなりすぎたら、Mappings や SSM Parameter Store への移行を検討します。
  • 機密値をパラメータで受け取る場合は NoEcho: true を付けます(ただし後述の動的参照の方が推奨)。

4. シークレット管理

  • パスワードやAPIキーをテンプレート・パラメータファイルに直接書かない。
  • 動的参照(Dynamic References)を使う。
    # Secrets Manager
    MasterUserPassword: !Sub "{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"
     
    # SSM Parameter Store(SecureString)
    ApiKey: "{{resolve:ssm-secure:/my-app/prod/api-key}}"
  • RDSなどは、ManageMasterUserPassword: true を使ってパスワード管理をサービス側(Secrets Manager)に任せるのが最も安全です。
  • NoEcho は値をマスクするだけで、テンプレートの Metadata や Outputs に書くと漏れます。シークレットをOutputsに出力しないでください。

5. データ保護と削除対策

DeletionPolicy / UpdateReplacePolicy

ステートフルなリソースには必ず設定します。

Database:
  Type: AWS::RDS::DBInstance
  DeletionPolicy: Snapshot        # スタック削除時にスナップショットを取得
  UpdateReplacePolicy: Snapshot   # 置換更新時にもスナップショットを取得
  Properties:
    DeletionProtection: true      # サービス側の削除保護も併用
    # ...
 
DataBucket:
  Type: AWS::S3::Bucket
  DeletionPolicy: Retain
  UpdateReplacePolicy: Retain
ポリシー動作
Deleteリソースを削除(多くのリソースのデフォルト)
Retainリソースを残す
RetainExceptOnCreate作成失敗時のロールバックでは削除し、それ以外は残す(ゴミリソースが残りにくい)
Snapshotスナップショット取得後に削除(RDS、EBS、ElastiCacheなど対応リソースのみ)

重要: UpdateReplacePolicy を忘れがちです。プロパティ変更で置換(Replacement)が発生すると、DeletionPolicy だけでは古いリソースが削除されてしまいます。

その他の保護機能

  • スタックの削除保護(Termination Protection) を本番スタックで有効にする。
  • スタックポリシー で、特定リソースの更新・置換を禁止する。
    {
      "Statement": [
        { "Effect": "Allow", "Action": "Update:*", "Principal": "*", "Resource": "*" },
        { "Effect": "Deny", "Action": ["Update:Replace", "Update:Delete"], "Principal": "*",
          "Resource": "LogicalResourceId/Database" }
      ]
    }
  • 物理名(BucketName、TableName など)の固定はなるべく避ける。 名前を固定すると、置換が必要な変更が「名前の重複」で失敗します。固定が必要な場合は、置換が起きる変更に注意します。

6. 変更管理とデプロイ

変更セット(Change Sets)を必ず使う

  • 本番では update-stack を直接実行せず、変更セットを作成 → 内容確認 → 実行 の流れにします。
  • 特に Replacement: True のリソースがないかを必ず確認します。
  • aws cloudformation deploy を使う場合も、--no-execute-changeset で事前確認できます。
aws cloudformation create-change-set \
  --stack-name my-app-prod \
  --change-set-name release-001 \
  --template-body file://template.yaml \
  --parameters file://params/prod.json
 
aws cloudformation describe-change-set \
  --stack-name my-app-prod \
  --change-set-name release-001

ロールバック設定

  • ロールバックトリガー:CloudWatchアラームを指定し、デプロイ後の監視期間中にアラームが発火したら自動ロールバックします。
  • 開発環境では --disable-rollback や「失敗時に保持」オプションを使うと、失敗したリソースをその場で調査できます(本番では使わない)。

コンソールでの手動変更を禁止する

  • CloudFormationが管理するリソースを、コンソールやCLIで直接変更しないでください。ドリフトの原因になり、次回デプロイで予期しない上書きや失敗が起きます。
  • 緊急対応で手動変更した場合は、必ずテンプレートに反映します。

既存リソースの取り込み・移動

  • 手動で作ったリソースは リソースインポート でスタックに取り込めます(DeletionPolicy の指定が必須)。
  • 既存環境からテンプレートを作るには IaCジェネレーター が使えます。
  • スタック間でリソースを移すときは、Retain で切り離してから別スタックにインポートするか、スタックリファクタリング機能を使います。

7. 再利用性(ネスト・モジュール・StackSets)

仕組み用途
ネストスタック1つのアプリを部品(ネットワーク、ALB等)に分け、親スタックからまとめてデプロイ
CloudFormation モジュール組織標準のリソース構成(例:暗号化済みS3バケット)をレジストリに登録し、リソースのように使う
StackSets複数アカウント・複数リージョンへ同じスタックを展開(AWS Organizations と連携)
AWS SAM / CDKサーバーレスや複雑な構成の記述量を減らす高レベルの抽象化
  • ネストスタックは深くしすぎない(2〜3階層まで)。デバッグが難しくなります。
  • StackSets では、サービスマネージド権限 + 自動デプロイ を使うと、新規アカウントにも自動で展開されます。同時実行数・失敗許容数を設定して段階的に展開します。
  • 共通テンプレートはバージョン管理し、変更時の影響範囲を把握できるようにします。

8. セキュリティとIAM

  • CloudFormation サービスロールを使う。 デプロイ実行者に広い権限を与えず、--role-arn で指定したロールにリソース操作権限を持たせます。実行者には cloudformation:* と iam:PassRole のみ付与する構成が理想です。
  • 最小権限の原則。 テンプレート内のIAMポリシーで "Action": "*" や "Resource": "*" を避けます。
  • IAMリソースを含むテンプレートでは CAPABILITY_IAM / CAPABILITY_NAMED_IAM が必要です。これは「IAMを変更する」ことの明示的な承認なので、レビューの対象にします。
  • 暗号化をデフォルトにする。 S3、EBS、RDS、SNS、SQS などで暗号化を有効にし、必要に応じてKMSカスタマーマネージドキーを使います。
  • S3バケットには PublicAccessBlockConfiguration を必ず設定します。
  • CloudTrail で CloudFormation API の呼び出しを記録します。

9. 検証・テスト・ポリシー適用

ツール目的
aws cloudformation validate-template構文チェック(最低限)
cfn-lintリソース仕様に基づく詳細な静的解析。必須で導入したい
cfn-guard組織のルール(ポリシー・アズ・コード)で検証
cfn-nag / Checkovセキュリティ観点の静的解析
taskcat複数リージョンへの実デプロイテスト
CloudFormation Hooksデプロイ時にサーバー側でルールを強制(違反をブロック/警告)
pip install cfn-lint
cfn-lint templates/**/*.yaml

cfn-guard ルールの例:

# すべてのS3バケットでバージョニングを必須にする
AWS::S3::Bucket {
  Properties.VersioningConfiguration.Status == "Enabled"
}
  • これらをpre-commitフックとCIの両方に組み込みます。
  • Hooks はクライアント側のチェックを回避されても効くため、組織全体のガードレールとして有効です。

10. ドリフト管理と運用

  • ドリフト検出を定期的に実行する。 AWS Config のマネージドルール(cloudformation-stack-drift-detection-check)で自動化できます。
  • ドリフトが見つかったら、「テンプレートに反映する」か「デプロイで元に戻す」かを判断し、放置しません。
  • スタックイベントを EventBridge に連携し、失敗(UPDATE_ROLLBACK_COMPLETE、UPDATE_ROLLBACK_FAILED など)を通知します。
  • UPDATE_ROLLBACK_FAILED になった場合は、原因を解消してから continue-update-rollback を実行します(必要に応じて特定リソースをスキップ)。
  • サービスクォータ(スタック数、Export数、リソース数など)を把握しておきます。

11. 命名・タグ付け

命名規則

  • スタック名:<システム名>-<環境>-<レイヤー>(例:myapp-prod-network)
  • 論理ID:役割がわかるPascalCase(例:PublicSubnet1、AppSecurityGroup)
  • 論理IDは安易に変えない。 論理IDの変更は「削除して新規作成」として扱われます。

タグ付け

  • スタックレベルのタグは、対応するリソースに自動で伝播します。
  • 最低限のタグを統一します。
タグキー例
Environmentprod
Project / Systemmyapp
Ownerplatform-team
CostCenter1234
ManagedByCloudFormation
  • aws:cloudformation:stack-name などのタグは自動付与されるため、手動で付ける必要はありません。

12. CI/CD

推奨パイプライン

[Pull Request]
   ├─ cfn-lint
   ├─ cfn-guard / セキュリティスキャン
   └─ 変更セット作成(差分をPRにコメント)
        ↓ レビュー・承認
[main マージ]
   ├─ dev へデプロイ
   ├─ 自動テスト
   ├─ stg へデプロイ
   └─ 手動承認 → prod へ変更セット実行
  • テンプレートとパラメータファイルは Gitで管理 し、Gitを唯一の正(Single Source of Truth)にします。
  • Git同期(Git sync) を使うと、リポジトリの変更をCloudFormationが直接検知してデプロイできます。
  • CodePipeline、GitHub Actions(aws-actions/aws-cloudformation-github-deploy)などでデプロイを自動化します。
  • CIからのデプロイはOIDC連携のIAMロールを使い、長期アクセスキーを使わないようにします。
  • 本番デプロイには承認ステップを入れます。

推奨ディレクトリ構成例

.
├── templates/
│   ├── network.yaml
│   ├── security.yaml
│   ├── database.yaml
│   └── app.yaml
├── params/
│   ├── dev/
│   ├── stg/
│   └── prod/
├── rules/            # cfn-guard ルール
├── .cfnlintrc
└── .github/workflows/

13. よくあるアンチパターン

アンチパターン問題点対策
全リソースを1スタックに詰め込む変更の影響範囲が大きく、上限にも達しやすいライフサイクルで分割
変更セットを見ずに本番更新意図しないリソース置換でデータ消失変更セットのレビューを必須化
DeletionPolicy 未設定のDBスタック削除・置換でデータ消失Snapshot / Retain を設定
パスワードをパラメータファイルに記載Gitに機密情報が残る動的参照・Secrets Manager
コンソールで手動変更ドリフト、次回デプロイで上書き変更はすべてテンプレート経由
Export の多用相互依存で変更・削除できなくなるSSM Parameter Storeで疎結合に
ARN・アカウントID・リージョンのハードコード他環境で再利用できない擬似パラメータを使用
物理名の固定置換が必要な更新が失敗する自動生成名を使う
管理者権限でデプロイ誤操作・侵害時の影響が大きいサービスロール+最小権限

14. チェックリスト

デプロイ前に確認する項目です。

テンプレート

  • cfn-lint でエラー・警告がない
  • ポリシーチェック(cfn-guard など)を通過している
  • リージョン・アカウントID・ARNのハードコードがない
  • パラメータに適切な型と制約が付いている

データ保護

  • ステートフルなリソースに DeletionPolicy と UpdateReplacePolicy を設定した
  • 本番スタックで削除保護を有効にした
  • 重要リソースにスタックポリシーを設定した

セキュリティ

  • シークレットは動的参照で取得している
  • IAMポリシーが最小権限になっている
  • 暗号化を有効にした
  • サービスロールでデプロイしている

デプロイ

  • 変更セットで差分を確認し、Replacement を把握した
  • ロールバックトリガーを設定した(本番)
  • 必須タグを付与した

運用

  • ドリフト検出を定期実行している
  • スタックの失敗イベントを通知している

参考リンク

0件のページ