1. Pengenalan CloudFormation
AWS CloudFormation adalah layanan AWS yang memungkinkan Anda mendefinisikan infrastruktur cloud sebagai kode (Infrastructure as Code / IaC). Dengan CloudFormation, Anda dapat mendeskripsikan seluruh sumber daya AWS β EC2, RDS, VPC, S3, dan lainnya β dalam file template yang version-controlled, reproducible, dan auditable.
Konsep utamanya sederhana: Anda menulis template (dalam format YAML atau JSON) yang mendefinisikan infrastruktur yang diinginkan, lalu CloudFormation akan membuat, memperbarui, atau menghapus resource tersebut secara otomatis sesuai template. Ini menghilangkan konfigurasi manual melalui console dan memastikan infrastruktur dapat direplikasi secara konsisten.
Mengapa CloudFormation?
| Keunggulan | Penjelasan |
|---|---|
| Infrastructure as Code | Infrastruktur didefinisikan dalam kode yang bisa di-review, version, dan audit |
| Reproducibility | Buat environment identik berkali-kali dengan template yang sama |
| Automation | Provisioning dan teardown infrastruktur sepenuhnya otomatis |
| Dependency Management | CloudFormation otomatis menentukan urutan pembuatan resource |
| Rollback | Jika deploy gagal, semua perubahan di-rollback secara otomatis |
| Change Tracking | Setiap perubahan infrastructure tercatat dan bisa di-audit |
| Drift Detection | Detect perubahan manual di luar CloudFormation |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β AWS CloudFormation β β β β ββββββββββββββββ ββββββββββββββββββββββββββββββββ β β β Template ββββββΊβ CloudFormation Service β β β β (YAML/JSON) β β β β β ββββββββββββββββ β 1. Parse template β β β β 2. Validate resources β β β β 3. Create change set β β β β 4. Execute changes β β β β 5. Track stack state β β β ββββββββββββ¬ββββββββββββββββββββ β β β β β βββββββββββββββββββββΌβββββββββββββββ β β βΌ βΌ βΌ β β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββ β β β EC2 Instances β β RDS Database β β S3 Bucket β β β β VPC/Subnets β β ElastiCache β β IAM Roles β β β β Security Grps β β Lambda Funcs β β CloudWatch β β β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββ β β β β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β Stack: men-track semua resource yang dibuat β β β β - Resource physical IDs β β β β - Status (CREATE_COMPLETE, UPDATE_IN_PROGRESS) β β β β - Event history β β β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Perbandingan CloudFormation dengan tools IaC lain:
| Fitur | CloudFormation | Terraform | Pulumi |
|---|---|---|---|
| Vendor | AWS only | Multi-cloud | Multi-cloud |
| Bahasa | YAML/JSON | HCL | Python/TypeScript/Go |
| State Management | Managed oleh AWS | Self-managed | Managed atau self |
| Cost | Gratis (bayar resource) | Open-source | Open-source |
| Custom Resources | Lambda-backed | Providers | Native code |
Jika infrastruktur Anda 100% AWS, CloudFormation adalah pilihan yang sangat baik karena terintegrasi penuh dengan seluruh layanan AWS dan tidak memerlukan state management eksternal. Jika multi-cloud, pertimbangkan Terraform atau Pulumi.
2. Konsep Dasar: Resources, Parameters, Outputs
CloudFormation template terdiri dari beberapa komponen utama yang masing-masing memiliki peran penting dalam mendefinisikan infrastruktur Anda.
Bagian Utama Template
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β CLOUDFORMATION TEMPLATE β β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β AWSTemplateFormat β β Description β β β β Version: '2010-09' β β "Deskripsi template..." β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β Parameters β β Mappings β β β β - Input untuk user β β - Lookup tables β β β β - Type validation β β - Region-based configs β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β Conditions β β Resources β β β β β - If/else logic β β - AWS resources (REQUIRED) β β β β - Environment flag β β - Core dari template β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β β β Outputs β β Transform (opsional) β β β β - Export values β β - Macros, SAM, etc. β β β β - Stack exports β β β β β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Resources β Komponen Wajib
Resources adalah satu-satunya bagian wajib dalam template. Setiap resource merepresentasikan satu AWS service resource yang akan dibuat. Setiap resource memiliki tipe (misalnya AWS::EC2::Instance) dan properti spesifik.
Resources:
# EC2 Instance
WebServer:
Type: AWS::EC2::Instance
Properties:
InstanceType: t3.micro
ImageId: ami-0c55b159cbfafe1f0
KeyName: my-key-pair
SecurityGroups:
- !Ref WebSecurityGroup
Tags:
- Key: Name
Value: MyWebServer
# Security Group
WebSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP and SSH
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
# S3 Bucket
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-app-bucket-unique-name
VersioningConfiguration:
Status: Enabled
Tags:
- Key: Environment
Value: Production
Parameters β Input dari User
Parameters memungkinkan Anda membuat template yang fleksibel dengan nilai yang bisa di-custom saat deploy. Parameter mendukung tipe data, default value, allowed values, dan constraints.
Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
- t3.large
Description: Pilih tipe EC2 instance
EnvironmentName:
Type: String
AllowedValues:
- dev
- staging
- production
Description: Nama environment
ConstraintDescription: Harus dev, staging, atau production
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: Nama EC2 Key Pair untuk SSH
DBPassword:
Type: String
NoEcho: true
MinLength: 8
MaxLength: 64
Description: Password untuk database RDS
AllowedPattern: '[a-zA-Z0-9]*'
ConstraintDescription: Password harus alphanumeric
Outputs β Nilai yang Di-ekspor
Outputs mendefinisikan nilai yang akan ditampilkan setelah stack selesai dibuat, dan bisa di-export untuk digunakan oleh stack lain.
Outputs:
InstancePublicIP:
Description: IP Public dari EC2 instance
Value: !GetAtt WebServer.PublicIp
Export:
Name: !Sub '${AWS::StackName}-InstanceIP'
BucketARN:
Description: ARN dari S3 bucket
Value: !GetAtt AppBucket.Arn
Export:
Name: !Sub '${AWS::StackName}-BucketARN'
SecurityGroupId:
Description: ID Security Group
Value: !Ref WebSecurityGroup
Export:
Name: !Sub '${AWS::StackName}-SGId'
WebsiteURL:
Description: URL website
Value: !Sub 'http://${WebServer.PublicDnsName}'
Export:
Name: !Sub '${AWS::StackName}-URL'
Mappings β Lookup Tables
Mappings memungkinkan lookup berdasarkan region atau parameter, seperti tabel referensi statis.
Mappings:
RegionMap:
us-east-1:
AMI: ami-0c55b159cbfafe1f0
InstanceType: t3.micro
us-west-2:
AMI: ami-0c55b159cbfafe1f0
InstanceType: t3.small
ap-southeast-1:
AMI: ami-0c55b159cbfafe1f0
InstanceType: t3.micro
eu-west-1:
AMI: ami-0c55b159cbfafe1f0
InstanceType: t3.medium
Conditions β Logika Kondisional
Conditions memungkinkan Anda membuat resource secara kondisional berdasarkan parameter atau pseudo-parameter.
Conditions:
IsProduction: !Equals [!Ref EnvironmentName, production]
IsUSRegion: !Contains
- !Ref 'AWS::Region'
- us
CreateMonitoring: !Or
- !Condition IsProduction
- !Equals [!Ref EnableMonitoring, 'true']
Resources:
# Hanya dibuat di production
AlarmTopic:
Type: AWS::SNS::Topic
Condition: IsProduction
Properties:
TopicName: !Sub '${EnvironmentName}-alerts'
# Dibuat berdasarkan kondisi
CloudWatchAlarm:
Type: AWS::CloudWatch::Alarm
Condition: CreateMonitoring
Properties:
AlarmName: HighCPU
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 300
EvaluationPeriods: 2
Threshold: 80
3. Menulis Template YAML
YAML adalah format yang paling direkomendasikan untuk CloudFormation templates karena lebih mudah dibaca dan ditulis dibanding JSON. Berikut contoh template lengkap untuk membuat infrastruktur web server.
Template Lengkap: Web Server Stack
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Web Server Stack - VPC, EC2, RDS, S3'
# ==============================
# PARAMETERS
# ==============================
Parameters:
VpcCIDR:
Type: String
Default: 10.0.0.0/16
Description: CIDR block untuk VPC
PublicSubnet1CIDR:
Type: String
Default: 10.0.1.0/24
PublicSubnet2CIDR:
Type: String
Default: 10.0.2.0/24
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
- t3.large
EnvironmentName:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- production
# ==============================
# RESOURCES
# ==============================
Resources:
# --- VPC ---
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-VPC'
- Key: Environment
Value: !Ref EnvironmentName
# --- Internet Gateway ---
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-IGW'
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# --- Public Subnet 1 ---
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnet1CIDR
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-PublicSubnet1'
# --- Public Subnet 2 ---
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnet2CIDR
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-PublicSubnet2'
# --- Route Table ---
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-PublicRT'
PublicRoute:
Type: AWS::EC2::Route
DependsOn: IGWAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
Subnet1RTAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
Subnet2RTAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
# --- Security Group ---
WebServerSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP and SSH
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-WebSG'
# --- EC2 Instance ---
WebServer:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
ImageId: !FindInMap [RegionMap, !Ref 'AWS::Region', AMI]
KeyName: my-key-pair
SubnetId: !Ref PublicSubnet1
SecurityGroupIds:
- !Ref WebServerSG
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from CloudFormation!</h1>" > /var/www/html/index.html
Tags:
- Key: Name
Value: !Sub '${EnvironmentName}-WebServer'
# --- S3 Bucket ---
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${EnvironmentName}-app-assets-${AWS::AccountId}'
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- Id: TransitionToIA
Status: Enabled
Transitions:
- TransitionInDays: 90
StorageClass: STANDARD_IA
Tags:
- Key: Environment
Value: !Ref EnvironmentName
# ==============================
# MAPPINGS
# ==============================
Mappings:
RegionMap:
us-east-1:
AMI: ami-0c55b159cbfafe1f0
us-west-2:
AMI: ami-0c55b159cbfafe1f0
ap-southeast-1:
AMI: ami-0c55b159cbfafe1f0
# ==============================
# OUTPUTS
# ==============================
Outputs:
VPCId:
Description: VPC ID
Value: !Ref VPC
Export:
Name: !Sub '${AWS::StackName}-VPCId'
WebServerPublicIP:
Description: Public IP Web Server
Value: !GetAtt WebServer.PublicIp
WebsiteURL:
Description: URL Website
Value: !Sub 'http://${WebServer.PublicDnsName}'
BucketName:
Description: Nama S3 Bucket
Value: !Ref AppBucket
Syntax Penting dalam YAML
| Syntax | Fungsi | Contoh |
|---|---|---|
!Ref | Referensi ke resource/parameter | !Ref MyBucket |
!GetAtt | Get attribute dari resource | !GetAtt MyBucket.Arn |
!Sub | String substitution | !Sub '${AWS::StackName}-bucket' |
!Join | Join string | !Join ['-', ['prefix', val]] |
!Select | Select index dari list | !Select [0, !GetAZs ''] |
!FindInMap | Lookup dari mappings | !FindInMap [Map, Key, Val] |
!If | Kondisional | !If [Condition, TrueVal, FalseVal] |
!ImportValue | Import dari stack lain | !ImportValue Shared-VPCId |
4. Menulis Template JSON
JSON juga didukung penuh oleh CloudFormation. Meskipun lebih verbose dan sulit dibaca, JSON berguna untuk integrasi dengan tools yang menghasilkan JSON secara otomatis.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "S3 Bucket Template - JSON Format",
"Parameters": {
"BucketName": {
"Type": "String",
"Description": "Nama S3 Bucket",
"MinLength": 3,
"MaxLength": 63,
"AllowedPattern": "[a-z0-9.-]*"
},
"Environment": {
"Type": "String",
"Default": "dev",
"AllowedValues": ["dev", "staging", "production"]
},
"EnableVersioning": {
"Type": "String",
"Default": "true",
"AllowedValues": ["true", "false"]
}
},
"Resources": {
"S3Bucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": {"Ref": "BucketName"},
"VersioningConfiguration": {
"Status": {
"Fn::If": [
"IsVersioningEnabled",
"Enabled",
"Suspended"
]
}
},
"Tags": [
{
"Key": "Environment",
"Value": {"Ref": "Environment"}
},
{
"Key": "ManagedBy",
"Value": "CloudFormation"
}
]
}
},
"BucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"Properties": {
"Bucket": {"Ref": "S3Bucket"},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSSLRequestsOnly",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": {
"Fn::Sub": "arn:aws:s3:::${S3Bucket}/*"
},
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
}
}
},
"Conditions": {
"IsVersioningEnabled": {
"Fn::Equals": [{"Ref": "EnableVersioning"}, "true"]
}
},
"Outputs": {
"BucketARN": {
"Description": "ARN S3 Bucket",
"Value": {"Fn::GetAtt": ["S3Bucket", "Arn"]}
},
"BucketName": {
"Description": "Nama S3 Bucket",
"Value": {"Ref": "S3Bucket"}
}
}
}
Pastikan JSON valid sebelum deploy. Kesalahan syntax seperti koma yang hilang atau bracket yang tidak seimbang akan menyebabkan deploy gagal. Gunakan tool seperti cfn-lint atau aws cloudformation validate-template untuk validasi.
5. Intrinsic Functions
CloudFormation menyediakan berbagai intrinsic functions yang memungkinkan Anda melakukan manipulasi data langsung dalam template tanpa memerlukan script tambahan.
Fungsi Manipulasi String
# Sub β substitusi variabel
BucketName: !Sub
- '${Env}-bucket-${AccountId}'
- Env: !Ref EnvironmentName
AccountId: !Ref 'AWS::AccountId'
# Join β gabungkan string
FullName: !Join
- '-'
- - !Ref Project
- !Ref Environment
- !Ref Component
# Select β pilih dari list
AZ: !Select [0, !GetAZs '']
# Split β pecah string
Subnets:
Fn::Split:
- ','
- !Ref SubnetList
# Transform β ubah case
Upper: !Transform
- String
- !Ref Environment
- ToUpper
Fungsi Lookup dan Referensi
# GetAtt β ambil attribute resource Endpoint: !GetAtt MyLoadBalancer.DNSName ARN: !GetAtt MyLambda.Arn # FindInMap β lookup dari Mappings AMI: !FindInMap - RegionMap - !Ref 'AWS::Region' - AMI # ImportValue β import dari stack lain VPCId: !ImportValue SharedStack-VPCId # GetAZs β list availability zones AZs: !GetAZs !Ref 'AWS::Region' # Ref β referensi ke parameter atau pseudo-parameter StackName: !Ref 'AWS::StackName' Region: !Ref 'AWS::Region' AccountId: !Ref 'AWS::AccountId' NotificationARNs: !Ref 'AWS::NotificationARNs'
Fungsi Kondisional dan Logika
# If β kondisional InstanceType: !If - IsProduction - m5.large - t3.micro # Equals β perbandingan Condition: !Equals [!Ref Env, 'production'] # And / Or / Not β logika boolean ComplexCondition: !And - !Equals [!Ref Env, 'prod'] - !Equals [!Ref Region, 'us-east-1'] # Contains β cek keanggotaan IsUSRegion: !Contains - [us-east-1, us-west-2, us-east-2] - !Ref 'AWS::Region' # EachMemberEquals β semua anggota sama AllProdRegions: !EachMemberEquals - !Ref 'AWS::Region' - us-east-1
Fungsi Lainnya
# Base64 β encode base64
UserData: !Base64 |
#!/bin/bash
yum install -y httpd
systemctl start httpd
# Cidr β hitung CIDR blocks
VPCCIDR: 10.0.0.0/16
Subnet1CIDR: !Select [0, !Cidr [!Ref VPCCIDR, 6, 8]]
Subnet2CIDR: !Select [1, !Cidr [!Ref VPCCIDR, 6, 8]]
# Output: 10.0.0.0/24, 10.0.1.0/24, dst.
# ImportValue
SharedVPC: !ImportValue Shared-VPC-ID
# Transform (macros)
Macros: !Transform
- Name: MyMacro
- { Input: 'some value' }
- !Ref 'AWS::NoValue'
Pseudo Parameters
| Pseudo Parameter | Deskripsi | Contoh Nilai |
|---|---|---|
AWS::AccountId | ID akun AWS | 123456789012 |
AWS::Region | Region saat ini | ap-southeast-1 |
AWS::StackId | ID stack | arn:aws:cloudformation:... |
AWS::StackName | Nama stack | my-web-stack |
AWS::URLSuffix | Domain suffix AWS | amazonaws.com |
AWS::Partition | AWS partition | aws |
AWS::NotificationARNs | ARN SNS untuk notifikasi | arn:aws:sns:... |
6. Membuat dan Mengelola Stack
Stack adalah kumpulan resource AWS yang dibuat dan dikelola sebagai satu unit. Setiap stack memiliki lifecycle sendiri β dari CREATE hingga DELETE β dan semua perubahan dikelola melalui update.
CLI Commands untuk Stack
# Validasi template
aws cloudformation validate-template \
--template-body file://template.yaml
# Buat stack baru
aws cloudformation create-stack \
--stack-name my-web-stack \
--template-body file://template.yaml \
--parameters ParameterKey=InstanceType,ParameterValue=t3.micro \
ParameterKey=EnvironmentName,ParameterValue=dev \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
--tags Key=Project,Value=MyApp Key=Environment,Value=Dev
# Cek status stack
aws cloudformation describe-stacks \
--stack-name my-web-stack \
--query 'Stacks[0].StackStatus'
# Output dari stack
aws cloudformation describe-stacks \
--stack-name my-web-stack \
--query 'Stacks[0].Outputs'
# Update stack
aws cloudformation update-stack \
--stack-name my-web-stack \
--template-body file://template-v2.yaml \
--parameters ParameterKey=InstanceType,ParameterValue=t3.small
# Rollback manual jika update stuck
aws cloudformation continue-update-rollback \
--stack-name my-web-stack
# Delete stack
aws cloudformation delete-stack \
--stack-name my-web-stack
# Tunggu stack selesai
aws cloudformation wait stack-create-complete \
--stack-name my-web-stack
# List semua stack
aws cloudformation list-stacks \
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE
Stack Events
Setiap perubahan pada stack mencatat event. Anda bisa melihat event untuk debugging dan monitoring.
# Lihat event stack aws cloudformation describe-stack-events \ --stack-name my-web-stack \ --query 'StackEvents[*].[Timestamp,LogicalResourceId,ResourceStatus,ResourceStatusReason]' \ --output table # Output contoh: # | 2026-06-26T10:00:00Z | WebServer | CREATE_COMPLETE | - | # | 2026-06-26T09:58:00Z | WebServer | CREATE_IN_PROGRESS| - | # | 2026-06-26T09:57:00Z | WebSecurityGroup | CREATE_COMPLETE | - | # | 2026-06-26T09:55:00Z | VPC | CREATE_COMPLETE | - | # | 2026-06-26T09:50:00Z | my-web-stack | CREATE_IN_PROGRESS| - |
Stack Lifecycle States
CREATE_IN_PROGRESS βββΊ CREATE_COMPLETE
β β
βΌ βΌ
CREATE_FAILED UPDATE_IN_PROGRESS
β βββββββββ΄ββββββββ
βΌ βΌ βΌ
DELETE_COMPLETE UPDATE_COMPLETE UPDATE_ROLLBACK
β IN_PROGRESS
βΌ β
DELETE_IN_PROGRESS βΌ
UPDATE_ROLLBACK_
COMPLETE
Status lain:
- REVIEW_IN_PROGRESS (untuk stack policy review)
- IMPORT_IN_PROGRESS (untuk import resources)
- IMPORT_ROLLBACK_IN_PROGRESS
7. Change Sets
Change Sets memungkinkan Anda melihat dampak dari perubahan yang akan dilakukan SEBELUM mengupdate stack. Ini seperti "dry run" yang sangat berguna untuk review perubahan infrastruktur sebelum diterapkan ke production.
Membuat dan Menggunakan Change Sets
# Buat change set dari template yang sudah ada aws cloudformation create-change-set \ --stack-name my-web-stack \ --change-set-name add-rds-database \ --template-body file://template-with-rds.yaml \ --parameters ParameterKey=InstanceType,ParameterValue=t3.small \ --capabilities CAPABILITY_IAM # Cek status change set aws cloudformation describe-change-set \ --stack-name my-web-stack \ --change-set-name add-rds-database # Lihat detail perubahan aws cloudformation describe-change-set \ --stack-name my-web-stack \ --change-set-name add-rds-database \ --query 'Changes[*].[Type,ResourceChange.Action,ResourceChange.LogicalResourceId,ResourceChange.ResourceType]' # Preview perubahan # Action types: # Add β Resource baru akan dibuat # Modify β Resource akan diubah # Remove β Resource akan dihapus # Execute change set (terapkan perubahan) aws cloudformation execute-change-set \ --stack-name my-web-stack \ --change-set-name add-rds-database # Hapus change set jika tidak jadi aws cloudformation delete-change-set \ --stack-name my-web-stack \ --change-set-name add-rds-database # List semua change sets aws cloudformation list-change-sets \ --stack-name my-web-stack
Contoh Output Change Set
Change Set: add-rds-database Stack: my-web-stack Status: CREATE_COMPLETE Changes: ββββββββββββββββββββ¬ββββββββββ¬ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββ β Type β Action β LogicalResourceId β ResourceType β ββββββββββββββββββββΌββββββββββΌββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββ€ β Resource β Add β DatabaseSubnetGroup β AWS::RDS:: β β β β β DBSubnetGroup β β Resource β Add β RDSDatabase β AWS::RDS:: β β β β β DBInstance β β Resource β Modify β WebServerSG β AWS::EC2:: β β β β β SecurityGroup β β Resource β Add β DatabaseSecurityGroup β AWS::EC2:: β β β β β SecurityGroup β β Resource β Add β DBSubnet1 β AWS::EC2::Subnet β β Resource β Add β DBSubnet2 β AWS::EC2::Subnet β ββββββββββββββββββββ΄ββββββββββ΄ββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββ
Gunakan --no-execute-change-set saat membuat change set agar tidak langsung dijalankan. Review perubahan terlebih dahulu, lalu execute secara manual jika sudah yakin. Ini adalah practice yang sangat disarankan untuk environment production.
8. Stack Sets untuk Multi-Region
Stack Sets memungkinkan Anda deploy CloudFormation stack ke beberapa akun AWS dan/atau region secara bersamaan dari satu template. Ini sangat berguna untuk organisasi yang menjalankan infrastruktur di banyak region atau akun.
Konsep Stack Sets
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β STACK SET β β "SharedSecurityPolicies" β β β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β Admin Account (Management Account) β β β β - Mengelola template β β β β - Mengatur deployment targets β β β βββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ β β β β β ββββββββββββββββββΌβββββββββββββββββ β β βΌ βΌ βΌ β β ββββββββββββββ ββββββββββββββ ββββββββββββββ β β β Account A β β Account B β β Account C β β β β us-east-1 β β us-east-1 β β eu-west-1 β β β β β β us-west-2 β β β β β β Stack: β β Stack: β β Stack: β β β β ββββββββββ β β ββββββββββ β β ββββββββββ β β β β βIAM Roleβ β β βIAM Roleβ β β βIAM Roleβ β β β β βSG β β β βSG β β β βSG β β β β β ββββββββββ β β ββββββββββ β β ββββββββββ β β β ββββββββββββββ ββββββββββββββ ββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Commands untuk Stack Sets
# Buat Stack Set aws cloudformation create-stack-set \ --stack-set-name SharedSecurityPolicies \ --template-body file://shared-policies.yaml \ --description "Security policies untuk semua akun" \ --permission-model SELF_MANAGED \ --administration-role-arn arn:aws:iam::123456789012:role/AWSCloudFormationStackSetAdministrationRole \ --execution-role-name AWSCloudFormationStackSetExecutionRole # Deploy ke target accounts/regions aws cloudformation create-instances-from-stack-set \ --stack-set-name SharedSecurityPolicies \ --accounts '["111111111111","222222222222"]' \ --regions '["us-east-1","us-west-2","eu-west-1"]' # Cek status deployment aws cloudformation list-stack-instances \ --stack-set-name SharedSecurityPolicies # Update Stack Set aws cloudformation update-stack-set \ --stack-set-name SharedSecurityPolicies \ --template-body file://shared-policies-v2.yaml \ --accounts '["111111111111","222222222222"]' \ --regions '["us-east-1","us-west-2"]' # Hapus Stack Set aws cloudformation delete-stack-instances \ --stack-set-name SharedSecurityPolicies \ --accounts '["111111111111"]' \ --regions '["us-east-1"]' \ --retain-resources NONE aws cloudformation delete-stack-set \ --stack-set-name SharedSecurityPolicies
9. Drift Detection
Drift Detection adalah fitur CloudFormation yang mendeteksi apakah resource dalam stack telah diubah secara manual di luar CloudFormation. Perubahan manual ini disebut "drift" dan bisa menyebabkan ketidaksesuaian antara state aktual infrastruktur dengan state yang tercatat di CloudFormation.
Mengapa Drift Detection Penting?
| Aspek | Penjelasan |
|---|---|
| Konsistensi | Pastikan infrastruktur sesuai template, bukan diubah manual |
| Security | Detect perubahan keamanan yang tidak diinginkan (misalnya SG dibuka) |
| Compliance | Memastikan infrastruktur comply dengan standar organisasi |
| Troubleshooting | Mencari tahu mengapa stack gagal update karena perubahan manual |
| Audit | Melacak siapa yang mengubah infrastruktur di luar prosedur |
Menjalankan Drift Detection
# Mulai drift detection
aws cloudformation detect-stack-resource-drift \
--stack-name my-web-stack
# Atau deteksi drift untuk semua resource dalam stack
DRIFT_DETECTION_ID=$(aws cloudformation detect-stack-drift \
--stack-name my-web-stack \
--query 'StackDriftDetectionId' \
--output text)
echo "Detection ID: $DRIFT_DETECTION_ID"
# Cek status drift detection
aws cloudformation describe-stack-drift-detection-status \
--stack-drift-detection-id $DRIFT_DETECTION_ID
# Lihat detail drift
aws cloudformation describe-stack-resource-drifts \
--stack-name my-web-stack \
--stack-resource-drift-status-filters MODIFIED DELETED
# Output detail drift:
# StackResourceDrift:
# - LogicalResourceId: WebSecurityGroup
# ResourceType: AWS::EC2::SecurityGroup
# StackResourceDriftStatus: MODIFIED
# ActualProperties: '{"SecurityGroupIngress": [...443, 80, 22...]}'
# ExpectedProperties: '{"SecurityGroupIngress": [...80, 443, 22...]}'
# PropertyDifferences:
# - PropertyPath: "/SecurityGroupIngress/1/FromPort"
# ExpectedValue: "443"
# ActualValue: "8443"
# DifferenceType: NOT_EQUAL
# Batch detect untuk semua stack
aws cloudformation list-stack-resource-drifts \
--stack-name my-web-stack \
--stack-resource-drift-status-filters MODIFIED
Perbedaan Resource Status
| Status | Arti |
|---|---|
IN_SYNC | Resource sesuai dengan template β tidak ada drift |
MODIFIED | Resource telah diubah secara manual di luar CloudFormation |
DELETED | Resource telah dihapus secara manual di luar CloudFormation |
Auto-Remediation untuk Drift
# Option 1: Update stack untuk sync kembali ke template
# CloudFormation akan mengembalikan resource ke state template
aws cloudformation update-stack \
--stack-name my-web-stack \
--use-previous-template
# Option 2: Import resource yang di-drift
# Jika ingin mengadopsi perubahan manual ke template
aws cloudformation import-resources-to-stack \
--stack-name my-web-stack \
--resource-identifiers \
'ResourceType=AWS::EC2::SecurityGroup,LogicalResourceId=WebServerSG,ResourceIdentifier=sg-0123456789abcdef'
# Option 3: Auto-remediation dengan EventBridge
# Trigger drift detection otomatis via schedule
aws events put-rule \
--name "MonthlyDriftDetection" \
--schedule-expression "cron(0 1 1 * ? *)" \
--description "Deteksi drift bulanan"
# Script remediation otomatis
cat << 'EOF' > remediate-drift.sh
#!/bin/bash
STACK_NAME=$1
DRIFT_ID=$(aws cloudformation detect-stack-drift \
--stack-name $STACK_NAME \
--query 'StackDriftDetectionId' --output text)
aws cloudformation wait stack-drift-detection-complete \
--stack-drift-detection-id $DRIFT_ID
DRIFT_STATUS=$(aws cloudformation describe-stack-drift-detection-status \
--stack-drift-detection-id $DRIFT_ID \
--query 'DetectionStatus' --output text)
if [ "$DRIFT_STATUS" = "DETECTION_COMPLETE" ]; then
MODIFIED=$(aws cloudformation describe-stack-resource-drifts \
--stack-name $STACK_NAME \
--stack-resource-drift-status-filters MODIFIED \
--query 'length(StackResourceDrifts)' --output text)
if [ "$MODIFIED" -gt "0" ]; then
echo "Drift detected! Resources modified: $MODIFIED"
aws cloudformation update-stack \
--stack-name $STACK_NAME \
--use-previous-template
fi
fi
EOF
Tidak semua resource type didukung oleh drift detection. Beberapa properti juga tidak bisa di-detect. Selalu cek dokumentasi AWS untuk resource type yang ingin Anda monitor. Drift detection tersedia gratis β Anda hanya membayar untuk API calls.
10. Nested Stacks
Nested Stacks memungkinkan Anda membuat stack dari stack lain β template induk (parent) mereferensikan child stack melalui AWS::CloudFormation::Stack. Ini membantu memecah template besar menjadi modul-modul yang lebih kecil dan reusible.
Konsep Nested Stacks
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β PARENT STACK: MainInfrastructure β β β β βββββββββββββββββββββββββββββββββββββββββββββββββββ β β β Resources: β β β β VPCStack: β β β β Type: AWS::CloudFormation::Stack β β β β TemplateURL: templates/vpc.yaml β β β β β β β β ComputeStack: β β β β Type: AWS::CloudFormation::Stack β β β β TemplateURL: templates/compute.yaml β β β β Parameters: β β β β VPCId: !GetAtt VPCStack.Outputs.VPCId β β β β β β β β DatabaseStack: β β β β Type: AWS::CloudFormation::Stack β β β β TemplateURL: templates/database.yaml β β β β Parameters: β β β β VPCId: !GetAtt VPCStack.Outputs.VPCId β β β β β β β β MonitoringStack: β β β β Type: AWS::CloudFormation::Stack β β β β TemplateURL: templates/monitoring.yaml β β β βββββββββββββββββββββββββββββββββββββββββββββββββββ β β β β Child Stacks: β β ββββββββββββ ββββββββββββ ββββββββββββ βββββββββββββ β β VPC β β Compute β β Database β βMonitoringββ β β Stack β β Stack β β Stack β β Stack ββ β ββββββββββββ ββββββββββββ ββββββββββββ βββββββββββββ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Template Parent (main.yaml)
AWSTemplateFormatVersion: '2010-09-09'
Description: Main Infrastructure Stack
Parameters:
EnvironmentName:
Type: String
Default: dev
Resources:
VPCStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/vpc.yaml
Parameters:
VpcCIDR: 10.0.0.0/16
EnvironmentName: !Ref EnvironmentName
ComputeStack:
Type: AWS::CloudFormation::Stack
DependsOn: VPCStack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/compute.yaml
Parameters:
VPCId: !GetAtt VPCStack.Outputs.VPCId
SubnetId: !GetAtt VPCStack.Outputs.PublicSubnet1
InstanceType: t3.micro
DatabaseStack:
Type: AWS::CloudFormation::Stack
DependsOn: VPCStack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/database.yaml
Parameters:
VPCId: !GetAtt VPCStack.Outputs.VPCId
SubnetIds: !GetAtt VPCStack.Outputs.PrivateSubnetIds
DBPassword: !Ref DBPassword
Outputs:
VPCId:
Value: !GetAtt VPCStack.Outputs.VPCId
WebServerIP:
Value: !GetAtt ComputeStack.Outputs.PublicIP
DatabaseEndpoint:
Value: !GetAtt DatabaseStack.Outputs.Endpoint
11. Best Practices
Struktur Template
| Best Practice | Penjelasan |
|---|---|
| Pisahkan environment | Gunakan parameter untuk mengontrol perbedaan dev/staging/prod |
| Gunakan nested stacks | Pecah template besar menjadi modul-modul kecil |
| Parameterize nilai | Jangan hardcode β gunakan parameters untuk values yang berubah |
| Output semua values | Export values penting untuk digunakan stack lain |
| Gunakan mappings | Untuk region-specific values seperti AMI IDs |
| Description yang jelas | Tulis description yang informatif untuk setiap template |
Keamanan
# 1. Gunakan NoEcho untuk secrets
DBPassword:
Type: String
NoEcho: true
MinLength: 12
# 2. Gunakan AWS Secrets Manager
DBSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Sub '${EnvironmentName}/database/credentials'
GenerateSecretString:
SecretStringTemplate: '{"username": "admin"}'
GenerateStringKey: password
PasswordLength: 32
ExcludeCharacters: '"@/\'
# 3. Gunakan KMS untuk encryption
EncryptedBucket:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref KMSKey
# 4. VPC Endpoints untuk akses private
VPCEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
VpcId: !Ref VPC
RouteTableIds:
- !Ref PrivateRouteTable
# 5. Stack policy untuk proteksi resource kritis
# Simpan sebagai stack-policy.json:
# {
# "Statement": [
# {
# "Effect": "Deny",
# "Action": "Update:*",
# "Principal": "*",
# "Resource": "LogicalResourceId/DatabaseInstance",
# "Condition": {
# "StringEquals": {"ResourceType": "AWS::RDS::DBInstance"}
# }
# }
# ]
# }
Organisasi dan Naming
Rekomendasi Struktur Project:
βββ templates/
β βββ main.yaml # Parent stack
β βββ vpc.yaml # VPC resources
β βββ compute.yaml # EC2, ECS, Lambda
β βββ database.yaml # RDS, DynamoDB
β βββ monitoring.yaml # CloudWatch, SNS
β βββ security.yaml # IAM, KMS, Secrets
βββ parameters/
β βββ dev.json # Parameters untuk dev
β βββ staging.json # Parameters untuk staging
β βββ production.json # Parameters untuk production
βββ scripts/
β βββ deploy.sh # Deployment script
β βββ validate.sh # Template validation
β βββ drift-check.sh # Drift detection
βββ README.md
βββ .github/
βββ workflows/
βββ deploy.yml # CI/CD pipeline
CI/CD dengan CloudFormation
# GitHub Actions: Deploy CloudFormation
name: Deploy CloudFormation
on:
push:
branches: [main]
paths:
- 'templates/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate templates
run: |
for f in templates/*.yaml; do
echo "Validating $f..."
aws cloudformation validate-template \
--template-body file://$f
done
deploy:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Dev
run: |
aws cloudformation deploy \
--template-file templates/main.yaml \
--stack-name my-app-dev \
--parameter-overrides file://parameters/dev.json \
--capabilities CAPABILITY_IAM \
--tags Environment=Dev Project=MyApp
- name: Run Tests
run: |
# Test endpoints
curl -f http://$(aws cloudformation describe-stacks \
--stack-name my-app-dev \
--query 'Stacks[0].Outputs[?OutputKey==`WebServerIP`].OutputValue' \
--output text)/health
- name: Deploy to Production
if: github.ref == 'refs/heads/main'
run: |
aws cloudformation deploy \
--template-file templates/main.yaml \
--stack-name my-app-production \
--parameter-overrides file://parameters/production.json \
--capabilities CAPABILITY_IAM \
--no-fail-on-empty-changeset \
--tags Environment=Production Project=MyApp
Cost Optimization Tips
| Tip | Detail |
|---|---|
| Gunakan CAPABILITY_AUTO_EXPAND | Untuk macro dan transforms β hati-hati karena bisa mengubah resource secara tidak terduga |
| Set termination protection | Hindari stack production terhapus secara tidak sengaja |
| Gunakan change sets | Selalu review perubahan sebelum execute |
| Monitoring drift | Jalankan drift detection secara berkala (weekly/monthly) |
| Tag semua resources | Memudahkan tracking cost per project/team |
| Cleanup unused stacks | Hapus stack yang sudah tidak digunakan untuk menghemat cost |
Gunakan CloudFormation Designer (tersedia di AWS Console) untuk visualisasi template secara grafis. Sangat membantu untuk memahami dependency antar resource, terutama untuk template yang kompleks dengan banyak resource.
12. Quiz Pemahaman
π Quiz: Pemahaman CloudFormation
1. Komponen manakah yang WAJIB ada dalam CloudFormation template?
2. Apa fungsi !Ref dalam CloudFormation?
3. Fitur apa yang mendeteksi perubahan manual pada resource AWS?
4. Untuk apa NoEcho: true digunakan pada parameter?
5. Apa keuntungan utama Change Sets?