Table of Contents
AWS Cloud Formation
1st Example
Create a ec2 instance and security group tied together with !Ref
and an s3 bucket.
Resources: Ec2Instance: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: ami-07d9160fa81ccffb5 # Amazon Linux AMI in Ireland Tags: - Key: Name Value: AJS - simple EC2 example - Key: email Value: myname@company.co.uk - Key: BuiltBy Value: CloudFormation - Key: JoinTest Value: !Join [ ":", [ Join, Example, in, YAML ] ] SecurityGroups: - !Ref SecurityGroupSSH SecurityGroupSSH: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow SSH SecurityGroupIngress: - IpProtocol: tcp FromPort: '22' ToPort: '22' CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: AJS - Allow SSH S3BucketExample: Type: AWS::S3::Bucket Properties: AccessControl: PublicRead BucketName: ajs-bucket WebsiteConfiguration: IndexDocument: index.html Tags: - Key: Name Value: AJSTestBucket - Key: builtby Value: CloudFormation
2nd Example
Adding in Mappings, Parameters, UserData and an Outputs section.
Parameters: ServiceName: Description: "Stack Name" Type: String InstanceTypePara: Type: String Default: t2.micro AllowedValues: - t2.micro - m1.small - m1.large Description: EC2 instances SSHkey: Description: AJS ssh key Type: AWS::EC2::KeyPair::KeyName Mappings: RegionMap: eu-west-1: AMI: ami-07d9160fa81ccffb5 # Amazon Linux AMI in Ireland TEXT: Test Text from Mapping us-east-1: AMI: ami-655a0a20 # Us East 1 Resources: Ec2Instance: Type: AWS::EC2::Instance Properties: InstanceType: Ref: InstanceTypePara ImageId: !FindInMap - RegionMap - !Ref 'AWS::Region' - AMI # ami-07d9160fa81ccffb5 # Amazon Linux AMI in Ireland KeyName: !Ref SSHkey Tags: - Key: Name Value: !Ref ServiceName - Key: email Value: myname@company.co.uk - Key: BuiltBy Value: CloudFormation - Key: JoinTest Value: !Join [ ":", [ Join, Example, in, YAML ] ] - Key: BuiltInRegion Value: !Ref AWS::Region - Key: MappingTest Value: !FindInMap - RegionMap - !Ref 'AWS::Region' - TEXT SecurityGroups: - !Ref SecurityGroupSSH UserData: !Base64 | #!/bin/bash -xe yum update -y yum install httpd -y service httpd start SecurityGroupSSH: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow SSH SecurityGroupIngress: - IpProtocol: tcp FromPort: '22' ToPort: '22' CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: AJS - Allow SSH SecurityGroupHttp: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow http SecurityGroupIngress: - IpProtocol: tcp FromPort: '80' ToPort: '80' CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: AJS - Allow http S3BucketExample: Type: AWS::S3::Bucket Properties: AccessControl: PublicRead BucketName: ajs-bucket WebsiteConfiguration: IndexDocument: index.html Tags: - Key: Name Value: AJSTestBucket - Key: builtby Value: CloudFormation Outputs: InstanceDNS: Description: DNS name of instance Value: !GetAtt - Ec2Instance - PublicDnsName WebsiteURL: Description: Web site URL Value: !Sub - 'http://${EC2Instance.PublicDnsName}' BucketURL: Description: BucketURL Value: !GetAtt - S3BucketExample - WebsiteURL BucketARN: Description: BucketARN Value: !GetAtt - S3BucketExample - Arn
3rd example with Parameters, Mappings, and !Refs
Parameters: Environment: Description: Environment parameters Type: String Default: Development AllowedValues: - Production - Development Mappings: AMIRegions_Map: eu-west-1: Development: ami-123456 Production: ami-654321 eu-west-2: Development: ami-123321 Production: ami654456 us-east-1: Development: ami-321123 Production: ami456456 Resources: WebEC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !FindInMap [AMIRegions_Map, !Ref "AWS::Region", !Ref Environment] InstanceType: t2.micro
BIG Example
From a course.
[ec2-user@ip-10-96-10-231 ~]$ aws cloudformation get-template --stack-name qls-1577787-84859361afe35637-AppLayerWebSite-1P4CE84PXN67F --query TemplateBody --output text AWSTemplateFormatVersion: "2010-09-09" Description: > Template to build the Web Tier for Lab 1 Parameters: VPCID: Description: VPC ID from the Base Networking Stack Type: String PUBSUBA: Description: Public Subnet A ID Type: String PUBSUBB: Description: Public Subnet B ID Type: String AppNamePram: Description: App Being Installed Type: String AppVerPram: Description: "App Verson" Type: String CodeBucketPram: Description: "Bucket Name that the Application Package is Saved" Type: String CodeObjectKeyPram: Description: "Object Key to be Installed" Type: String # Calling out the CORRECT version of the package to be installed via CodeDeploy # Help fight the eventual consistency of S3 # CodePackageETagPram: # Description: "Etag of the Package to be installed" # Type: String KeyName: Type: AWS::EC2::KeyPair::KeyName Description: Keyname for the keypair that Qwiklab will use to launch EC2 instances ApiElbDns: Type: String Description: The DNS Name of the ELB in Front of the API Tier SaveElbDns: Type: String Description: The DNS Name of the ELB in Front of the Save Tier Mappings: AmazonLinuxAMI: us-east-1: AMI: ami-08111162 us-east-2: AMI: ami-06547163 us-west-1: AMI: ami-1b0f7d7b us-west-2: AMI: ami-f0091d91 eu-west-1: AMI: ami-31328842 eu-central-1: AMI: ami-e2df388d ap-northeast-1: AMI: ami-f80e0596 ap-northeast-2: AMI: ami-6598510b ap-southeast-1: AMI: ami-c9b572aa ap-southeast-2: AMI: ami-f2210191 sa-east-1: AMI: ami-1e159872 Resources: # Networking AppTierSG: Type: AWS::EC2::SecurityGroup DependsOn: - MadLibSiteELB Properties: GroupDescription: Security Group for Web Tier VpcId: !Ref VPCID Tags: - Key: "Name" Value: "MadLib Web Tier SG" - Key: "ENV" Value: "Production" - Key: "App" Value: "MadLib Site" SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref ELBsg ELBsg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security Group Web Tier ELB VpcId: !Ref VPCID Tags: - Key: "Name" Value: "ELB SG" - Key: "ENV" Value: "Production" - Key: "App" Value: "Madlib Site - Public" SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 MadLibSiteELB: Type: "AWS::ElasticLoadBalancing::LoadBalancer" DependsOn: - ELBsg Properties: CrossZone: true HealthCheck: HealthyThreshold: 2 Interval: 60 Target: HTTP:80/site/index.html Timeout: 59 UnhealthyThreshold: 10 LoadBalancerName: MadLib-Site Listeners: - InstancePort: 80 InstanceProtocol: HTTP LoadBalancerPort: 80 Protocol: HTTP Scheme: internet-facing SecurityGroups: - !Ref ELBsg Subnets: - !Ref PUBSUBA - !Ref PUBSUBB # IAM Setup CodeDeployRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Statement: - Effect: "Allow" Principal: Service: - 'codedeploy.amazonaws.com' Action: - 'sts:AssumeRole' Path: '/' Policies: - PolicyName: "CodeDeployRole" PolicyDocument: Statement: - Effect: "Allow" Action: ['autoscaling:CompleteLifecycleAction', 'autoscaling:DeleteLifecycleHook', 'autoscaling:DescribeAutoScalingGroups', 'autoscaling:DescribeLifecycleHooks', 'autoscaling:PutLifecycleHook', 'autoscaling:RecordLifecycleActionHeartbeat', 'autoscaling:CreateAutoScalingGroup', 'autoscaling:UpdateAutoScalingGroup', 'autoscaling:EnableMetricsCollection', 'autoscaling:DescribeAutoScalingGroups', 'autoscaling:DescribePolicies', 'autoscaling:DescribeScheduledActions', 'autoscaling:DescribeNotificationConfigurations', 'autoscaling:DescribeLifecycleHooks', 'autoscaling:SuspendProcesses', 'autoscaling:ResumeProcesses', 'autoscaling:AttachLoadBalancers', 'autoscaling:PutScalingPolicy', 'autoscaling:PutScheduledUpdateGroupAction', 'autoscaling:PutNotificationConfiguration', 'autoscaling:PutLifecycleHook', 'autoscaling:DescribeScalingActivities', 'autoscaling:DeleteAutoScalingGroup', 'ec2:DescribeInstances', 'ec2:DescribeInstanceStatus', 'ec2:TerminateInstances', 'tag:GetTags', 'tag:GetResources', 'sns:Publish', 'cloudwatch:DescribeAlarms', 'elasticloadbalancing:DescribeLoadBalancers', 'elasticloadbalancing:DescribeInstanceHealth', 'elasticloadbalancing:RegisterInstancesWithLoadBalancer', 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'] Resource: '*' AppRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Statement: - Effect: "Allow" Principal: Service: - 'ec2.amazonaws.com' Action: - 'sts:AssumeRole' Path: '/' Policies: - PolicyName: MabLib-App-Policy PolicyDocument: Statement: - Effect: Allow Action: ['s3:List*', 's3:Get*'] Resource: '*' # Code Deploy InstProfMadLibSite: Type: "AWS::IAM::InstanceProfile" DependsOn: - AppRole Properties: Roles: - !Ref AppRole InstanceProfileName: MadLib-AppRole MadLibsSite: Type: "AWS::CodeDeploy::Application" WebAppDeplyGroup: Type: "AWS::CodeDeploy::DeploymentGroup" DependsOn: - MadLibsSite - CodeDeployRole Properties: # AlarmConfiguration: # AlarmConfiguration ApplicationName: !Ref MadLibsSite DeploymentConfigName: !Ref WebAppDeplyConfig DeploymentGroupName: WebAppDeplyGroup AutoScalingGroups: - !Ref WebServersAutoScalingGroup Deployment: Description: !Sub | Deploying App ${AppNamePram} Version-${AppVerPram} IgnoreApplicationStopFailures: true Revision: RevisionType: S3 S3Location: Bucket: !Ref CodeBucketPram Key: !Ref CodeObjectKeyPram BundleType: Zip # Would Suggest you use this feature to ensure that the correct package gets deployed # ETag: !Ref CodePackageETagPram Ec2TagFilters: - Key: App Value: !Ref AppNamePram Type: "KEY_AND_VALUE" ServiceRoleArn: !GetAtt CodeDeployRole.Arn WebAppDeplyConfig: Type: "AWS::CodeDeploy::DeploymentConfig" DependsOn: - MadLibsSite Properties: DeploymentConfigName: !Ref AppNamePram MinimumHealthyHosts: Type: "FLEET_PERCENT" Value: 50 WebServersAutoScalingGroup: Type: "AWS::AutoScaling::AutoScalingGroup" DependsOn: - WebServersLaunchConfig - AppTierSG - MadLibSiteELB UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: 'true' Properties: Cooldown: 60 DesiredCapacity: 2 HealthCheckGracePeriod: 60 LaunchConfigurationName: !Ref WebServersLaunchConfig LoadBalancerNames: - !Ref MadLibSiteELB MaxSize: 4 MinSize: 1 VPCZoneIdentifier: - !Ref PUBSUBA - !Ref PUBSUBB Tags: - Key: "Name" Value: "MadLib Web Tier - AutoScaled" PropagateAtLaunch: true - Key: "ENV" Value: "Prod" PropagateAtLaunch: true - Key: "App" Value: !Ref AppNamePram PropagateAtLaunch: true # AutoScaling WebServersLaunchConfig: Type: "AWS::AutoScaling::LaunchConfiguration" DependsOn: - AppTierSG - AppRole Properties: IamInstanceProfile: !Ref InstProfMadLibSite ImageId: !FindInMap [AmazonLinuxAMI, !Ref "AWS::Region", AMI] InstanceMonitoring: true InstanceType: t2.micro KeyName: !Ref KeyName SecurityGroups: - !Ref AppTierSG UserData: 'Fn::Base64': !Sub | #!/bin/bash -ex # Env Setup echo "export APITierELBDNS=${ApiElbDns}" >> ~/.bashrc echo "export SaveTierELBDNS=${SaveElbDns}" >> ~/.bashrc source ~/.bashrc # Updates & Install yum update -y yum install -y ruby wget cd /home/ec2-user wget https://aws-codedeploy-${AWS::Region}.s3.amazonaws.com/latest/install chmod +x ./install ./install auto Outputs: WebTierDNS: Description: "DNS Name for the ELB infront of the Site Tier" Value: !GetAtt MadLibSiteELB.DNSName [ec2-user@ip-10-96-10-231 ~]$
Outputs and Exports
You can now create and export values from one stack and make use of them in other stacks without going to the trouble of creating custom CloudFormation resources. The first stack exports values like this: Outputs: TSSG: Value: !Ref TroubleShootingSG Export: Name: AccountSG YAML The other stacks then reference them using the new ImportValue function: EC2Instance: Type: AWS::EC2::Instance Properties: SecurityGroups: - !ImportValue AccountSG