AWS CloudFormation(クラウドフォーメーション)は、VPCやEC2、S3バケットといったAWSリソースの構成をYAMLまたはJSONのテンプレートに書き、その内容どおりにリソースを作成・更新・削除するAWSのサービスです。インフラをコードで管理するIaC(Infrastructure as Code)を、AWS純正の仕組みで実現します。
実務でつまずくのはテンプレートの文法より、プロパティを1行変えただけでEC2インスタンスやDBが作り直される、スタックを消したらS3バケットの削除で失敗する、といった更新時の挙動です。本記事は書き方とスタック操作の基本に加えて、更新で何が置き換わるのかをリソース定義から確認し、消してはいけないリソースを守る設定までを扱います。仕様・上限値は2026年9月26日時点のAWS公式ドキュメントで確認したものです。
まとめ:CloudFormationの要点
- テンプレート(設計図)から作ったリソースのまとまりを「スタック」と呼び、作成・更新・削除はスタック単位で行います。更新前の差分確認には「変更セット」を使います。
- テンプレートで必須なのは
Resourcesセクションだけです。AWSTemplateFormatVersionに書ける値は2010-09-09のみです。 - AWSのリソースを扱う限りCloudFormation自体の利用料はかからず、作ったリソースの料金だけが発生します。
- 更新で最も危ないのは「置換(Replacement)」です。EC2の
ImageId・SubnetId、VPCのCidrBlock、RDSのDBNameなどを変えると、リソースは新しいIDで作り直されます。 DeletionPolicyはスタック削除時の保護で、置換には効きません。置換時に古いリソースを残すにはUpdateReplacePolicy: Retainを併記します。ただし、置換そのものや新リソースへの参照の切り替えは防げません。- AWSだけを対象にするならCloudFormation、複数クラウドや外部SaaSまでまとめて管理するならTerraform、プログラミング言語で書きたいならCDKを選びます。
以下、仕組み、テンプレートの書き方、スタック操作、更新で消える条件、既存リソースの取り込み、他ツールとの使い分けの順に解説します。
CloudFormationの仕組み:テンプレート・スタック・変更セットの関係
CloudFormationを理解するには、3つの用語の関係を押さえれば足ります。テンプレートに「あるべき構成」を書き、CloudFormationがそれを読んでAWSの各サービスAPIを呼び、できあがったリソース群をスタックとして記録します。サーバーやネットワークを用意する作業全般はプロビジョニングと呼ばれ、CloudFormationはそれをテンプレート駆動で自動化する道具です。
| 用語 | 実体 | 操作の単位 |
|---|---|---|
| テンプレート | YAML/JSONのテキストファイル | Gitでバージョン管理 |
| スタック | 1つのテンプレートから作られたリソース群 | 作成・更新・削除 |
| 変更セット | 更新前に計算される差分の一覧 | 確認してから実行 |
スタックは作成したリソースの物理IDを覚えています。テンプレートからリソースの定義を消して更新すれば、そのリソースは実際に削除されます。コンソールで手作業した場合と違い、「何を作ったか」の記録が消えないのがCloudFormationの価値です。
料金:AWSリソースの管理は追加料金なし、カスタム拡張は従量課金
CloudFormationの料金ページには、AWS::* と Alexa::* 名前空間のリソースをCloudFormationで扱うことに追加料金はかからない、と書かれています。支払うのは、テンプレートで作ったEC2インスタンスやロードバランサーなどの通常料金だけです。AWSのリソースだけを扱う通常の使い方なら、CloudFormationそのものへの請求は発生しません。
課金対象になるのは、外部ベンダーが登録したサードパーティのリソースタイプと、デプロイ前にリソース定義を検査するカスタムHooksです。ハンドラ操作1回あたり0.0009米ドル、1回の操作が30秒を超えた部分に1秒あたり0.00008米ドルがかかり、無料枠はアカウントあたり月1,000ハンドラ操作です。テンプレートの部品を再利用する「モジュール」の利用は無料です。
上限値:1テンプレート500リソース・本文51,200バイト
テンプレートを大きく育てると、次の上限に当たります。いずれもCloudFormationユーザーガイドのクォータのページに載っている値です。
| 項目 | 上限 |
|---|---|
| 1テンプレートのリソース数 | 500 |
| パラメータ数/出力数/マッピング数 | 各200 |
| テンプレート本文(リクエストに直接渡す場合) | 51,200バイト |
| テンプレート本文(S3に置いて渡す場合) | 1MB |
| アカウント・リージョンあたりの有効なスタック数 | 既定2,000(引き上げ可能) |
| パラメータ値の大きさ | 4,096バイト |
51,200バイトは、AWS CLIの deploy コマンドでも判定に使われています。テンプレートがこれを超えると --s3-bucket の指定が必要になります。500リソースに近づいたら、ネットワーク・データベース・アプリケーションのようにライフサイクルの違う単位でスタックを分けるのが定石です。すでに肥大化したスタックは、2025年2月6日に提供が始まったスタックリファクタリングを使うと、リソースを作り直さずに別スタックへ移したり、論理IDを付け替えたりできます。
テンプレートの書き方:セクション構成とVPC・EC2・S3の記述例
テンプレートは、決められた名前のトップレベルセクションで構成します。実務でよく使うのは次の6つです。
| セクション | 必須 | 書く内容 |
|---|---|---|
AWSTemplateFormatVersion |
任意 | 値は 2010-09-09 のみ |
Parameters |
任意 | スタック作成時に渡す値 |
Mappings |
任意 | リージョン別などの固定表 |
Conditions |
任意 | 作る/作らないの条件 |
Resources |
必須 | 作成するリソースの定義 |
Outputs |
任意 | 他スタックや利用者に渡す値 |
次のテンプレートは、VPC・サブネット・EC2インスタンス・S3バケットを作る例です。環境名が prod のときだけインスタンスタイプを大きくし、AMIはSystems Managerのパブリックパラメータから最新のAmazon Linux 2023を引きます。cfn-lint 1.57.0(2026年9月時点の最新)で東京リージョン向けに検査し、エラー・警告ともゼロでした。
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC, isolated subnet, EC2 and S3 bucket (sample)
Parameters:
EnvName:
Type: String
AllowedValues: [dev, prod]
Default: dev
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Conditions:
IsProd: !Equals [!Ref EnvName, prod]
Resources:
AppVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
AppSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref AppVpc
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [0, !GetAZs '']
AppInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref LatestAmiId
InstanceType: !If [IsProd, t3.small, t3.micro]
SubnetId: !Ref AppSubnet
Tags:
- Key: Name
Value: !Sub '${EnvName}-app'
LogBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
VersioningConfiguration:
Status: Enabled
Outputs:
VpcId:
Value: !Ref AppVpc
Export:
Name: !Sub '${AWS::StackName}-VpcId'
BucketArn:
Value: !GetAtt LogBucket.Arn
AMI IDをテンプレートに直書きしないのは、AMI IDがリージョンごとに異なり、しかも定期的に新しいIDへ差し替わるためです。パブリックパラメータを参照すれば、同じテンプレートを東京でも大阪でもそのまま使えます。ただしこの書き方には更新時の落とし穴があり、後述の「置換」の章で扱います。構文ミスや存在しないプロパティ名は、デプロイ前にcfn-lintによるテンプレート検証で機械的に見つけられます。
組み込み関数:Ref・GetAtt・Sub・If・ImportValue の使い分け
リソース同士をつなぐのは組み込み関数です。上のテンプレートで使ったものを中心に、役割を整理します。
!Ref:パラメータの値、またはリソースの主ID(VPCならVPC ID)を返します。依存関係もこれで決まり、AppSubnetはAppVpcの作成完了を待ってから作られます。!GetAtt:主ID以外の属性を返します。S3バケットのARNは!GetAtt LogBucket.Arnで取ります。!Sub:文字列に${EnvName}や${AWS::StackName}を埋め込みます。!If/!Equals:Conditionsで定義した条件によって値を切り替えます。リソースごと作らない場合は、リソース直下にCondition: IsProdと書きます。!ImportValue:別スタックがOutputsのExportで公開した値を取り込みます。どこかのスタックに取り込まれている間は、エクスポートした値の変更も、エクスポート元スタックの削除もできません。
最後の制約はスタック分割の設計に効きます。ネットワーク層のVPC IDのように、一度作ったらまず変えない値だけをエクスポートの対象にしてください。
YAMLとJSONの選び方
機能差はありません。人が読み書きするならYAMLを選びます。コメントを書け、!Ref のような短縮記法が使えるためです。JSONは、スクリプトやCDKのようなツールが生成・加工する場合に向きます。1つのリポジトリ内でどちらかに揃えておけば、差分レビューが楽になります。
スタックの作成・更新・削除:AWS CLIでの手順
スタックの操作はマネジメントコンソールからもできますが、手順を再現しやすいのはAWS CLIです。以下はAWS CLIの認証情報・実行権限・対象リージョンを設定し、先のテンプレートを template.yml として保存した状態で実行します。日常の作成と更新には aws cloudformation deploy を使います。
aws cloudformation deploy \
--stack-name my-app-dev \
--template-file template.yml \
--parameter-overrides EnvName=dev
deploy は、指定したスタック名が存在しなければ新規作成、存在すれば更新として動きます。内部では変更セットを作成して実行しており、完了まで待ってから終了します。テンプレートでIAMロールやポリシーを作る場合は --capabilities CAPABILITY_IAM(名前付きのIAMリソースなら CAPABILITY_NAMED_IAM)を付けないと InsufficientCapabilities エラーで止まります。
削除は次のコマンドです。スタックが作ったリソースは、後述の DeletionPolicy で保護したものを除いてまとめて削除されます。この例の LogBucket は Retain 指定のため残り、スタックの管理対象から外れます。保存データなどの料金は引き続き発生するため、検証後の保管・削除は別途判断してください。
aws cloudformation delete-stack --stack-name my-app-dev
変更セットで「置換」の有無を確認する手順
本番スタックの更新では、deploy に --no-execute-changeset を付けて、変更セットを作るだけで止めます。
aws cloudformation deploy \
--stack-name my-app-prod \
--template-file template.yml \
--parameter-overrides EnvName=prod \
--no-execute-changeset
aws cloudformation describe-change-set \
--stack-name my-app-prod \
--change-set-name '表示された変更セット名に置換' \
--query 'Changes[].ResourceChange.[LogicalResourceId,Action,Replacement]' \
--output table
見るべきは Replacement 列です。値は True・False・Conditional の3つで、True はリソースが新しいIDで作り直されることを意味します。Conditional は、変更後の値次第で置換になる場合です。データを持つリソースに True か Conditional が付いていたら、実行を止めて原因のプロパティを確認します。問題がなければ execute-change-set で適用します。
作成失敗時のROLLBACK_COMPLETEとスタックの再作成手順
新規作成が途中で失敗すると、CloudFormationは作りかけのリソースを消して ROLLBACK_COMPLETE 状態にします。この状態のスタックに許される操作は削除だけです。テンプレートを直して同じスタック名で deploy し直しても更新はできないので、いったん delete-stack してから作り直します。
失敗のたびに最初から作り直すのが遅い場合は、deploy に --disable-rollback を付けます。成功したリソースは残り、失敗したリソースだけが CREATE_FAILED や UPDATE_FAILED のまま残るので、テンプレートを直して続きから再実行できます。開発環境向けの使い方で、本番では通常のロールバックを残すほうが安全です。
スタック更新で置換されるプロパティとデータを消さない設定
更新時の「置換」では、古いリソースの削除によるデータ消失に注意が必要です。公式ドキュメントは更新の挙動を、中断なしの更新・一部中断を伴う更新・置換の3種類に分けています。置換では新しいリソースを先に作り、参照先を付け替えたあとで古いリソースを削除します。データを持つリソースなら、中身は新しいリソースに引き継がれません。
置換を引き起こすプロパティの例:EC2・VPC・RDS・S3
どのプロパティが置換を起こすかは、リソースタイプのスキーマで createOnlyProperties(作成時にしか設定できない値)として定義されています。cfn-lint 1.57.0 に同梱されている東京リージョンのスキーマ(1,591リソースタイプ)から、よく使うリソースの該当プロパティを抜き出しました。
| リソースタイプ | 変更すると置換になる主なプロパティ |
|---|---|
AWS::EC2::Instance |
ImageId/SubnetId/KeyName/AvailabilityZone/PrivateIpAddress |
AWS::EC2::VPC |
CidrBlock |
AWS::EC2::Subnet |
VpcId/CidrBlock/AvailabilityZone |
AWS::RDS::DBInstance |
DBName/MasterUsername/StorageEncrypted/KmsKeyId |
AWS::DynamoDB::Table |
TableName |
AWS::S3::Bucket |
BucketName |
AWS::IAM::Role |
RoleName/Path |
EC2インスタンスの InstanceType はこの一覧に入っていませんが、置換されないとは限りません。EBSをルートボリュームに使うインスタンスでは新旧タイプの互換性によって再起動で済むか置換になるかが決まり、インスタンスストアをルートにするインスタンスは必ず置換されます。一方、KeyName を差し替えるだけでインスタンスは作り直され、既定設定のEBSルートボリュームは旧インスタンスと一緒に削除されます。キーペアの交換をテンプレートで行ってはいけない理由がこれです。
名前を固定したリソースには別の制約もあります。BucketName や RoleName を明示したリソースは、同じ名前のまま置換が必要な更新をかけると失敗します。置換するには、名前も別の値に変える必要があります。名前を指定しなければCloudFormationがスタック名入りの一意な名前を自動で付けるので、外部から名前で参照される必要がないリソースは名前を書かないほうが更新に強くなります。
SSMパラメータのAMI参照が起こすEC2の置換
前の章のテンプレートで使った AWS::SSM::Parameter::Value 型のパラメータは、スタックの作成時だけでなく更新のたびにParameter Storeの最新値を取り直します。公式ドキュメントには、更新時に「既存の値を使用」を選んでも、それはパラメータのキーを使い続けるという意味であり、CloudFormationは常に最新の値を取得する、と明記されています。
その結果、AWSが新しいAmazon Linux 2023のAMIを公開した後に、たとえばタグを1つ変えるだけの更新をかけると、ImageId の値も変わったと判定され、インスタンスが置換されます。開発環境では最新AMIへの自動追従として便利ですが、状態を持つ本番サーバーでは事故になります。本番ではAMI IDを固定値のパラメータで渡すか、変更セットで AppInstance の Replacement が True になっていないかを毎回確認してください。
DeletionPolicyとUpdateReplacePolicyの違い
リソースを守る属性は2つあり、効く場面が違います。
| 属性 | 効く場面 | 指定できる値 |
|---|---|---|
DeletionPolicy |
スタック削除、テンプレートからの定義削除 | Delete/Retain/RetainExceptOnCreate/Snapshot |
UpdateReplacePolicy |
更新による置換で古いリソースが消えるとき | Delete/Retain/Snapshot |
DeletionPolicyの公式リファレンスは、この属性が更新で物理リソースが置き換わる場合には適用されないと明記しています。DeletionPolicy: Retain だけを書いたS3バケットは、スタック削除からは守られても、置換からは守られません。データを持つリソースには2つを揃えて書くのが原則で、先のテンプレートの LogBucket はそうしています。
既定値にも例外があります。DeletionPolicy を書かなければ削除されるのが原則ですが、AWS::RDS::DBCluster と、DBClusterIdentifier を指定しない AWS::RDS::DBInstance は既定で Snapshot です。S3バケットは中身が空でないと削除できない仕様のため、Retain を付けていないバケットにオブジェクトが残っていると、スタック削除が DELETE_FAILED で止まります。
コンソールで作った既存リソースをCloudFormation管理へ移す手段
CloudFormationを後から導入する現場では、手作業で作ったリソースがすでに動いています。作り直さずにスタックの管理下へ入れる方法と、入れた後にテンプレートと実物のずれを見張る方法を分けて説明します。
既存リソースの取り込み:IaCジェネレーター・リソースインポート・自動インポート
公式ドキュメントが挙げる取り込み方は次の3つです。テンプレートを一から書く手間が小さい順に並べています。
- IaCジェネレーター(2024年2月5日提供開始):リージョン内のリソースをスキャンし、CloudFormationで管理されていないリソースからテンプレートを生成します。スキャン結果は30日間有効で、1テンプレートに含められるのは500リソースまでです。生成したテンプレートでそのままスタックへ取り込むことも、CDKアプリへ移行することもできます。
- リソースインポート:既存リソースの定義を自分でテンプレートに書き、インポート用の変更セットで取り込みます。取り込むリソースには、値は何でもよいので
DeletionPolicyを必ず付けます。 - 自動インポート:
create-change-setに--import-existing-resourcesを付けると、テンプレートに書いたカスタム名と一致する既存リソースを自動で取り込みます。この場合のDeletionPolicyはRetainかRetainExceptOnCreateに限られます。
どの方法でも、取り込みの時点で DeletionPolicy の指定が必要ですが、指定しただけで削除を防げるわけではありません。手動インポートでは Delete も指定できるため、残す必要があるリソースには Retain を選びます。取り込み後もしばらくは Retain のまま運用し、テンプレートと実物の一致を確かめてから外すのが安全です。コンソールでの操作をその場でコード化したい場合は、AWS Console-to-Codeも候補になります。
ドリフト検出と2025年11月のドリフト対応変更セット
スタック管理下のリソースをコンソールやCLIで直接変更すると、テンプレートと実物がずれます。これをドリフトと呼び、ドリフト検出はテンプレートやパラメータで明示した期待値と、リソースの実際のプロパティ値を比べます。ただし対応していないリソースは NOT_CHECKED になり、親スタックからの検出ではネストされたスタックの中は調べられません。すべてのリソースの KMSKeyId プロパティも対象外です。
従来の変更セットは「前回のテンプレート」と「新しいテンプレート」しか比べないため、障害対応で手動変更した設定が次のデプロイで上書きされるかどうかを、実行前に知る手段がありませんでした。2025年11月18日に追加されたドリフト対応変更セットは、実際の状態・前回デプロイした状態・新しいテンプレートの3者を比べます。create-change-set に --deployment-mode REVERT_DRIFT を指定して作り、手動変更が上書きされるかどうかを実行前に確認できます。
CloudFormationとTerraform・CDK・SAMの使い分け
AWSのIaCツールとして比較されるのは、Terraform、AWS CDK、AWS SAMの3つです。CDKとSAMは最終的にCloudFormationのテンプレートを生成してCloudFormationでデプロイするので、競合というより上位の書き方です。独立した選択肢として比べるべきはTerraformだけです。
| ツール | 記述 | 状態の保存先 | 対象 |
|---|---|---|---|
| CloudFormation | YAML/JSON | AWS側(スタック) | AWS・拡張経由の外部リソース |
| Terraform | HCL | stateファイル(S3やHCP Terraform) | AWS・Azure・Google Cloud・SaaS |
| AWS CDK | TypeScript・Python等 | CloudFormationのスタック | AWS |
| AWS SAM | YAML(CloudFormationの拡張) | CloudFormationのスタック | AWS(サーバーレス中心) |
実務の分かれ目は状態管理です。CloudFormationはスタックの状態をAWSが保持するので、stateファイルの置き場所やロックを自分で設計する必要がありません。Terraformはstateを自分で管理する代わりに、AWS以外のクラウドやDNS・監視SaaSまで1つのコードで扱えます。
テンプレートが数百行を超えてループや共通化が欲しくなったらAWS CDK、LambdaとAPI Gatewayが中心の構成なら AWS::Serverless::Function などの短縮記法が使えるAWS SAMが向きます。どちらを選んでも、デプロイの実体と置換のルールはCloudFormationのままなので、本記事の変更セットと保護属性の知識はそのまま使えます。
CloudFormationを選ぶべきでないケース
次の条件に当てはまるなら、CloudFormationを主軸にしないほうがよい、というのが筆者の判断です。
- AWSとAzureやGoogle Cloudを併用していて、ネットワークやDNSを1つのコードで管理したい場合。CloudFormationでも拡張を通じてAWS以外を扱えますが、必要なリソースタイプの対応状況や、独自実装の保守負担を確認する必要があります。
- Datadog・PagerDuty・GitHubなど、SaaS側の設定も含めてコード化したい場合。CloudFormationのサードパーティ拡張は対応するSaaSが限られ、ハンドラ操作ごとの課金もかかります。
- チームが既にTerraformのモジュール資産とstate運用を持っている場合。AWSのためだけに2系統のIaCを並走させると、レビューと権限設計が二重になります。
逆に、AWS単独で、状態管理の仕組みを自前で持ちたくないチームにとっては、stateファイルの置き場所もロックも設計せずに済むCloudFormation(またはCDK)は、stateの保存先とロックを別途設計せずに導入できる選択肢です。
大規模運用で使う関連機能
複数アカウント・複数リージョンへ同じテンプレートを展開するならCloudFormation StackSets、開発環境でのデプロイ待ちを短くしたいなら2026年6月30日に提供が始まったCloudFormation Expressモードが選択肢になります。Expressモードはリソースの安定化を待たずに完了とみなす代わりに、既定でロールバックが無効になる点に注意が必要です。テンプレートの変更をGitへのプッシュから自動デプロイする方法は2つあります。2023年11月26日に提供が始まったGit同期は、GitHub・GitHub Enterprise・GitLab・Bitbucketのリポジトリとスタックを直接つなぎます。承認や複数環境への段階展開を挟みたい場合は、AWS CodePipelineのCloudFormationアクションで変更セットの作成と実行を分ける構成が向きます。
よくある質問
CloudFormationの読み方は?
「クラウドフォーメーション」と読みます。AWSの公式ドキュメントやCLIでは cloudformation、略称として「CFn」も使われます。ファイル名や記事で「CFnテンプレート」とあれば、CloudFormationのテンプレートのことです。なお「cfn-lint」「cfn-signal」のように、関連ツールやヘルパースクリプトの名前にも cfn という接頭辞が使われています。
CloudFormationの利用に料金はかかりますか?
AWS:: で始まるAWSのリソースを作る限り、CloudFormation自体の利用料はかからず、作成したEC2やRDSなどの通常料金だけを支払います。課金されるのはサードパーティのリソースタイプとカスタムHooksで、ハンドラ操作1回0.0009米ドル、無料枠は月1,000操作です。
テンプレートを自動で作成する方法はありますか?
すでにAWS上にあるリソースからなら、CloudFormationのIaCジェネレーターで生成できます。リージョン内をスキャンし、CloudFormationで管理されていないリソースを選んでテンプレートにします(1テンプレート500リソースまで)。これから作る構成を自動生成したいなら、TypeScriptやPythonで書いてテンプレートを出力するAWS CDKを使う方法もあります。生成されたテンプレートは、デプロイ前にcfn-lintで検査しておくと安心です。
スタックを削除するとリソースはどうなりますか?
スタックが作ったリソースはまとめて削除されます。残したいリソースには DeletionPolicy: Retain を付けます。RDSのDBクラスターと、クラスターに属さないDBインスタンスは既定でスナップショットを取ってから削除されます。中身の残ったS3バケットは削除できず、スタック削除が DELETE_FAILED で止まります。
本番環境のスタックを安全に更新するには?
deploy に --no-execute-changeset を付けて変更セットだけを作り、describe-change-set で各リソースの Replacement を確認してから実行します。DBやバケットには DeletionPolicy と UpdateReplacePolicy の両方に Retain を指定すれば、削除時や置換時に古いリソースを残せます。ただし、置換や新リソースへのデータ移行を制御する設定ではありません。