[AWS Basics] CloudFormation concepts
Template
YAML hoặc JSON formated text file
Có thể save .json, .yaml, .template, .txt,…
CloudFormation sử dụng các template nhưng blueprint để xây dựng các AWS resources.
AWSTemplateFormatVersion: 'version date' (optional) # version of the CloudFormation template. Only accepted value is '2010-09-09'
Description: 'String' (optional) # a text description of the Cloudformation template
Metadata: 'template metadata' (optional) # objects that provide additional information about the template
Parameters: 'set of parameters' (optional) # a set of inputs used to customize the template
Rules: 'set of rules' (optional) # a set of rules to validate the parameters provided at deployment/update
Mappings: 'set of mappings' (optional) # a mapping of keys and associated values
Conditions: 'set of conditions' (optional) # conditions that control whether certain resources are created
Transform: 'set of transforms' (optional) # for serverless applications
Resources: 'set of resources' (required) # a components of your infrastructure
Hooks: 'set of hooks' (optional) # Used for ECS Blue/Green Deployments
Outputs: 'set of outputs' (optional) # values that are returned whenever you view your stack's properties
Một số ví dụ đơn giản:
- Format version: latest version là 2010-09-09 và đang là giá trị valid duy nhất hiện tại:
AWSTemplateFormatVersion: "2010-09-09"
- Description: cho phép include comment về template
Description: AWS CloudFormation workshop - Resources (uksb-1q9p31idr).
- Metadata: cung cấp các thông tin cho các tools khác là đang interact với cloudformation template
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: 'Amazon EC2 Configuration'
Parameters:
- InstanceType
ParameterLabels:
InstanceType:
default: 'Type of EC2 Instance'
- Parameter: input custom values cho template
Parameters:
InstanceType:
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t2.small
Description: 'Enter t2.micro or t2.small. Default is t2.micro.'
- Resource: declare resource
Resources:
WebServerInstance:
Type: 'AWS::EC2::Instance'
Properties:
InstanceType: !Ref InstanceType
ImageId: <replace with AMI ID ami-xxxxx>
Intrinsic functions
- Ref:
No Ref:
AmiID:
Type: AWS::EC2::Image::Id
Description: 'The ID of the AMI.'
With Ref:
Resources:
WebServerInstance:
Type: AWS::EC2::Instance
Properties:
# Use !Ref function in ImageId property
ImageId: !Ref AmiID
InstanceType: !Ref InstanceType
- Fn::Join và Fn:Sub: Để giúp quản lý AWS resources, bạn có thể assign metadata cho mỗi resource dưới dạng tags. Bạn có thể sử dụng hàm Fn::Join để tạo tag như sau:
Resources:
WebServerInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AmiID
InstanceType: !Ref InstanceType
Tags:
- Key: Name
Value: !Join [ '-', [ !Ref InstanceType, webserver ] ]
- Key: InstanceType
Value: !Sub ${InstanceType}
Xem thêm các functions tại đây:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
Pseudo parameters
- Là các parameter mà đã được định nghĩa bởi AWS, không declare trong template, sử dụng như argument cho Ref function:
Outputs:
MyStacksRegion:
Value: !Ref "AWS::Region"
Xem thêm tại đây: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html
Mapping
Mappings:
AnExampleMap:
TopLevelKey01:
Key01: Value01
Key02: Value02
TopLevelKey02:
AnotherKey: AnExampleValue
TopLevelKey03:
AFinalKey: ADifferentValue
Ví dụ: define 2 môi trường là test và prod:
→ Phần parameter:
Parameters:
EnvironmentType:
Description: 'Specify the Environment type of the stack.'
Type: String
Default: Test
AllowedValues:
- Test
- Prod
ConstraintDescription: 'Specify either Test or Prod.'
→ Tạo EnvironmentToInstanceType trong phần mapping:
Mappings:
EnvironmentToInstanceType: # Map Name
Test: # Top level key
InstanceType: t2.micro # Second level key
Prod:
InstanceType: t2.small
→ Tiếp theo, modify InstanceType:
Resources:
WebServerInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AmiID
InstanceType: !FindInMap
- EnvironmentToInstanceType # Map Name
- !Ref EnvironmentType # Top Level Key
- InstanceType # Second Level Key
→ Update Tags:
Tags:
- Key: Name
Value: !Join [ '-', [ !Ref EnvironmentType, webserver ] ]
Outputs:
Cho phép get access tới information về resource trong stack
Resources:
WebServerInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AmiID
InstanceType: !FindInMap [EnvironmentToInstanceType, !Ref EnvironmentType, InstanceType]
Tags:
- Key: Name
Value: !Join [ '-', [ !Ref EnvironmentType, webserver ] ]
WebServerEIP:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
InstanceId: !Ref WebServerInstance
Outputs:
WebServerPublicDNS:
Description: 'Public DNS of EC2 instance'
Value: !GetAtt WebServerInstance.PublicDnsName
WebServerElasticIP:
Description: 'Elastic IP assigned to EC2'
Value: !Ref WebServerEIP
Linting and testing:
cfn-lint:
pip install cfn-lint
taskcat: for testing:
pip install taskcat
cfn-flip: convert JSON → YAML và ngược lại
pip install cfn-flip
Helper scripts:
cfn-init: )(~userdata)
đọc metadata từ AWS::CloudFormation::Init
và:
Fetch và parse metadata từ CloudFormation
Install packages
Write files to disk
Enable/disable và start/stop services
VD:
Cài đặt HTTPD và PHP packages:
WebServerInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages:
yum:
httpd: []
php: []
Tạo index.php
WebServerInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages: \\
{...}
files:
/var/www/html/index.php:
content: |
<!DOCTYPE html>
<html>
<body>
<center>
<?php
# Get the instance ID from meta-data and store it in the $instance_id variable
$url = "<http://169.254.169.254/latest/meta-data/instance-id>";
$instance_id = file_get_contents($url);
# Get the instance's availability zone from metadata and store it in the $zone variable
$url = "<http://169.254.169.254/latest/meta-data/placement/availability-zone>";
$zone = file_get_contents($url);
?>
<h2>EC2 Instance ID: <?php echo $instance_id ?></h2>
<h2>Availability Zone: <?php echo $zone ?></h2>
</center>
</body>
</html>
mode: 000644
owner: apache
group: apache
Start và enable httpd:
WebServerInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages:
{...}
files:
{...}
services:
sysvinit:
httpd:
enabled: true
ensureRunning: true
Gọi cfn-init script:
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
# Update aws-cfn-bootstrap to the latest
yum install -y aws-cfn-bootstrap
# Call cfn-init script to install files and packages
/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region
cfn-hub: detect các thay đổi trong resource metadata và thực hiện các actions khi sự thay đổi được detect. Điều này cho phép bạn cập nhật cấu hình trên các phiên bản Amazon EC2 đang chạy của mình thông qua hành động API UpdateStack.
WebServerInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages:
{...}
files:
/var/www/html/index.php:
{...}
/etc/cfn/cfn-hup.conf:
content: !Sub |
[main]
stack=${AWS::StackId}
region=${AWS::Region}
interval=1
mode: 000400
owner: root
group: root
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
content: !Sub |
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
runas=root
services:
{...}
enable và start cfn-hup trong phần services của temaplate:
WebServerInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages:
{...}
files:
/var/www/html/index.php:
{...}
/etc/cfn/cfn-hup.conf:
{...}
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
{...}
services:
sysvinit:
httpd:
enabled: true
ensureRunning: true
cfn-hup:
enabled: true
ensureRunning: true
files:
- /etc/cfn/cfn-hup.conf
- /etc/cfn/hooks.d/cfn-auto-reloader.conf
Xem thêm: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-helper-scripts-reference.html
Condition
Parameters:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
EnvType:
Description: Specify the Environment type of the stack.
Type: String
AllowedValues:
- test
- prod
Default: test
ConstraintDescription: Specify either test or prod.
Add thêm condition sau vào phần Conditions của template:
Conditions:
IsProduction: !Equals
- !Ref EnvType
- prod
Lúc này ta có thể viết được đoạn code sử dụng condition như sau:
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref LatestAmiId
InstanceType: t2.micro
MountPoint:
Type: AWS::EC2::VolumeAttachment
Properties:
InstanceId: !Ref EC2Instance
VolumeId: !Ref Volume
Device: /dev/sdh
Condition: IsProduction
Volume:
Type: AWS::EC2::Volume
Properties:
Size: 2
AvailabilityZone: !GetAtt EC2Instance.AvailabilityZone
Encrypted: true
Condition: IsProduction
Định nghĩa condition ở property level:
Giả sử bạn muốn tạo một EC2 instance type là t2.micro cho test env, t2.small cho production env, có thể define condition ở resource property level cho InstanceType property.
Parameters:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
EnvType:
Description: Specify the Environment type of the stack.
Type: String
AllowedValues:
- test
- prod
Default: test
ConstraintDescription: Specify either test or prod.
Conditions:
IsProduction: !Equals
- !Ref EnvType
- prod
Tại phần resource:
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref LatestAmiId
InstanceType: !If [IsProduction, t2.small, t2.micro]
Resource dependency:
VD1:
Parameters:
EmailAddress:
Description: Enter an email address to subscribe to your Amazon SNS topic.
Type: String
Resources:
SNSTopic:
Type: AWS::SNS::Topic
Properties:
Tags:
- Key: Name
Value: Resource-dependencies-workshop
SNSTopicSubscription:
Type: AWS::SNS::Subscription
Properties:
Endpoint: !Ref EmailAddress
Protocol: email
TopicArn: !Ref SNSTopic
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Workshop Security Group
Tags:
- Key: Name
Value: Resource-dependencies-workshop
SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !GetAtt SecurityGroup.GroupId
IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
VD2:
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
Tags:
- Key: Name
Value: Resource-dependencies-workshop
SNSTopic:
Type: AWS::SNS::Topic
DependsOn: S3Bucket
Properties:
Tags:
- Key: Name
Value: Resource-dependencies-workshop
Dynamic references:
Có thể sử dụng dynamic reference trong CloudFormation template để refer tới các value store ở AWS services như SSM,..
Dynamic reference cho Parameter Store:
Xem thêm + làm theo lab ở đây: https://catalog.workshops.aws/cfn101/en-US/intermediate/templates/dynamic-references
Code: git clone <https://github.com/aws-samples/cfn101-workshop
\>
Stack:
là một deployment của CloudFormation template. Bạn có thể tạo nhiều stack từ 1 template duy nhất.
Stack bao gồm một collection các AWS resource mà bạn có thể quản lý như single unit.
Nested stacks:
Nested stack resource:
Resources:
NestedStackExample:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: 'Path/To/Template'
Parameters:
ExampleKey: ExampleValue
Tạo nested stack:
main.yml:
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation workshop - Nested stacks - Root template (uksb-1q9p31idr).
Parameters:
S3BucketName:
AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-.]*[0-9a-zA-Z])*$
ConstraintDescription: Bucket name can include numbers, lowercase letters, uppercase letters, periods (.), and hyphens (-). It cannot start or end with a hyphen (-).
Description: S3 bucket name for the Nested Stacks. S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
Type: String
AvailabilityZones:
Type: List<AWS::EC2::AvailabilityZone::Name>
Description: The list of Availability Zones to use for the subnets in the VPC. Select 2 AZs.
VPCName:
Type: String
Description: The name of the VPC.
Default: cfn-workshop-vpc
VPCCidr:
Type: String
Description: The CIDR block for the VPC.
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
Default: 10.0.0.0/16
PublicSubnet1Cidr:
Type: String
Description: The CIDR block for the public subnet located in Availability Zone 1.
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
Default: 10.0.0.0/24
PublicSubnet2Cidr:
Type: String
Description: The CIDR block for the public subnet located in Availability Zone 2.
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
Default: 10.0.1.0/24
EnvironmentType:
Description: 'Specify the Environment type of the stack.'
Type: String
Default: Test
AllowedValues:
- Dev
- Test
- Prod
ConstraintDescription: 'Specify either Dev, Test or Prod.'
Resources:
# Create VPC resource in the main template"
VpcStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/vpc.yaml
TimeoutInMinutes: 20
Parameters:
AvailabilityZones:
Fn::Join:
- ','
- !Ref AvailabilityZones
VPCCidr: !Ref VPCCidr
VPCName: !Ref VPCName
PublicSubnet1Cidr: !Ref PublicSubnet1Cidr
PublicSubnet2Cidr: !Ref PublicSubnet2Cidr
# 3. Create IAM resource in the main template"
IamStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/iam.yaml
TimeoutInMinutes: 10
# Create EC2 resource in main template"
EC2Stack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/ec2.yaml
TimeoutInMinutes: 20
Parameters:
EnvironmentType: !Ref EnvironmentType
VpcId: !GetAtt VpcStack.Outputs.VpcId
SubnetId: !GetAtt VpcStack.Outputs.PublicSubnet1
WebServerInstanceProfile: !GetAtt IamStack.Outputs.WebServerInstanceProfile
# Output the `WebsiteURL` in the main template
Outputs:
WebsiteURL:
Value: !GetAtt EC2Stack.Outputs.WebsiteURL
ec2.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation workshop - Nested stacks - EC2 template.
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: 'Amazon EC2 Configuration'
Parameters:
- AmiID
ParameterLabels:
AmiID:
default: 'Amazon Machine Image ID'
Parameters:
EnvironmentType:
Description: 'Specify the Environment type of the stack.'
Type: String
Default: Test
AllowedValues:
- Dev
- Test
- Prod
ConstraintDescription: 'Specify either Dev, Test or Prod.'
AmiID:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Description: 'The ID of the AMI.'
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
VpcId:
Type: AWS::EC2::VPC::Id
Description: 'The VPC ID'
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: 'The Subnet ID'
WebServerInstanceProfile:
Type: String
Description: 'Instance profile resource ID'
Mappings:
EnvironmentToInstanceType:
Dev:
InstanceType: t2.nano
Test:
InstanceType: t2.micro
Prod:
InstanceType: t2.small
Resources:
WebServerInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
packages:
yum:
httpd: []
php: []
files:
/var/www/html/index.php:
content: |
<!DOCTYPE html>
<html>
<body>
<center>
<?php
# Get the instance ID from meta-data and store it in the $instance_id variable
$url = "http://169.254.169.254/latest/meta-data/instance-id";
$instance_id = file_get_contents($url);
# Get the instance's availability zone from metadata and store it in the $zone variable
$url = "http://169.254.169.254/latest/meta-data/placement/availability-zone";
$zone = file_get_contents($url);
# Get the instance AMI ID and store it in the $ami_id variable
$url = "http://169.254.169.254/latest/meta-data/ami-id";
$ami_id = file_get_contents($url);
?>
<h2>EC2 Instance ID: <?php echo $instance_id ?></h2>
<h2>Availability Zone: <?php echo $zone ?></h2>
<h2>AMI ID: <?php echo $ami_id ?></h2>
</center>
</body>
</html>
mode: 000644
owner: apache
group: apache
/etc/cfn/cfn-hup.conf:
content: !Sub |
[main]
stack=${AWS::StackId}
region=${AWS::Region}
interval=1
mode: 000400
owner: root
group: root
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
content: !Sub |
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
runas=root
services:
sysvinit:
httpd:
enabled: true
ensureRunning: true
cfn-hup:
enabled: true
ensureRunning: true
files:
- /etc/cfn/cfn-hup.conf
- /etc/cfn/hooks.d/cfn-auto-reloader.conf
Properties:
SubnetId: !Ref SubnetId
IamInstanceProfile: !Ref WebServerInstanceProfile
ImageId: !Ref AmiID
InstanceType: !FindInMap [EnvironmentToInstanceType, !Ref EnvironmentType, InstanceType]
SecurityGroupIds:
- !Ref WebServerSecurityGroup
Tags:
- Key: Name
Value: !Join [ ' ', [ !Ref EnvironmentType, Web Server ] ]
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
# Update aws-cfn-bootstrap to the latest
yum install -y aws-cfn-bootstrap
# Call cfn-init script to install files and packages
/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
# Call cfn-signal script to send a signal with exit code
/opt/aws/bin/cfn-signal --exit-code $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
CreationPolicy:
ResourceSignal:
Count: 1
Timeout: PT10M
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable HTTP and HTTPS access
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
VpcId: !Ref VpcId
WebServerEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
InstanceId: !Ref WebServerInstance
Outputs:
WebServerPublicDNS:
Description: 'Public DNS of EC2 instance'
Value: !GetAtt WebServerInstance.PublicDnsName
WebServerElasticIP:
Description: Elastic IP associated with the web server EC2 instance
Value: !Ref WebServerEIP
WebsiteURL:
Value: !Sub http://${WebServerEIP}
Description: Application URL
vpc.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation workshop - Nested stacks - VPC template.
Parameters:
AvailabilityZones:
Type: List<AWS::EC2::AvailabilityZone::Name>
Description: The list of Availability Zones to use for the subnets in the VPC.
VPCName:
Type: String
Description: The name of the VPC.
VPCCidr:
Type: String
Description: The CIDR block for the VPC.
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
PublicSubnet1Cidr:
Type: String
Description: The CIDR block for the public subnet located in Availability Zone 1.
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
PublicSubnet2Cidr:
Type: String
Description: The CIDR block for the public subnet located in Availability Zone 2.
AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$
ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCidr
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: !Ref VPCName
VPCPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref PublicSubnet1Cidr
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !Ref AvailabilityZones]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: PublicSubnet1
- Key: subnet-type
Value: Public
VPCPublicSubnet1RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: PublicSubnet1
VPCPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet1RouteTable
SubnetId:
Ref: VPCPublicSubnet1
VPCPublicSubnet1DefaultRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPublicSubnet1RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: VPCIGW
DependsOn:
- VPCGW
VPCPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref PublicSubnet2Cidr
VpcId: !Ref VPC
AvailabilityZone: !Select [1, !Ref AvailabilityZones]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: PublicSubnet2
- Key: subnet-type
Value: Public
VPCPublicSubnet2RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: PublicSubnet2
VPCPublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet2RouteTable
SubnetId:
Ref: VPCPublicSubnet2
VPCPublicSubnet2DefaultRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref VPCPublicSubnet2RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref VPCIGW
DependsOn:
- VPCGW
VPCIGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: VPCIGW
VPCGW:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: VPC
InternetGatewayId:
Ref: VPCIGW
Outputs:
VpcId:
Value: !Ref VPC
PublicSubnet1:
Value: !Ref VPCPublicSubnet1
PublicSubnet2:
Value: !Ref VPCPublicSubnet2
iam.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation workshop - Nested stacks - IAM template.
Resources:
SSMIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
WebServerInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref SSMIAMRole
Outputs:
WebServerInstanceProfile:
Value: !Ref WebServerInstanceProfile
Layered stacks
Ví dụ, nếu bạn có kế hoạch cho nhiều workload deployed bằng nhiều template nhưng mỗi EC2 instance thì đều expected enable SSM. Tương tự như thế, thì bạn muốn deploy 1 VPC bằng 1 stack và sau đó sử dụng nó trong nhiều stacks và workload. Điều này sẽ không đạt được khi sử dụng Nested Stack → bạn cần dùng Layered stack.
Với Layered stack thì sẽ sử dụng Export để tạo global variables có thể import vào bất cứ stack nào.
Ví dụ:
Outputs:
VpcId:
Value: !Ref VPC
Export:
Name: cfn-workshop-VpcId
PublicSubnet1:
Value: !Ref VPCPublicSubnet1
Export:
Name: cfn-workshop-PublicSubnet1
PublicSubnet2:
Value: !Ref VPCPublicSubnet2
Export:
Name: cfn-workshop-PublicSubnet2
và import trong ec2.yml:
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable HTTP and HTTPS access
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
VpcId: !ImportValue cfn-workshop-VpcId
Deploy các package
Refer tới local files:
PythonFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: cfn-workshop-python-function
Description: Python Function to return specific TimeZone time
Runtime: python3.8
Role: !GetAtt LambdaBasicExecutionRole.Arn
Handler: lambda_function.handler
Code: lambda/ # <<< This is a local directory
Zips up the local file
Upload lên S3 bucket
Generate một template mới, local path sẽ được thay thế bằng S3 URI
File template mới:
PythonFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: cfn-workshop-python-function
Description: Python Function to return specific TimeZone time
Runtime: python3.8
Role:
Fn::GetAtt:
- LambdaBasicExecutionRole
- Arn
Handler: lambda_function.handler
Code:
S3Bucket: example-bucket-name
S3Key: cfn-workshop-package-deploy/1234567890
TracingConfig:
Mode: Active
Policy as code:
Tham khảo và làm demo tại: https://catalog.workshops.aws/cfn101/en-US/intermediate/templates/policy-as-code-with-guard
Stack Policy:
Parameters:
SNSTopicTagValue:
Description: Tag value for your Amazon SNS topic
Type: String
Default: Topic-Tag-1
MinLength: 1
MaxLength: 256
Resources:
SNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: Topic-1
Tags:
- Key: TagSNS
Value: !Ref SNSTopicTagValue
Resources:
SNSTopic:
DeletionPolicy: Retain
Type: AWS::SNS::Topic
Properties:
TopicName: Topic-2
Change sets:
Khi update stack và cần xem trước các thay đổi thfi sẽ tạo change set trước khi apply thay đổiStack set:
Cho phép tạo stack cross regions bằng 1 CloudFormation template
Stack set là regional resource