AWS Cloud Formation

Force an string value instead of integer (join two strings with nothing, “”):-

!Join ["", ["00", "1002899"]]

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

From:- https://aws.amazon.com/blogs/aws/aws-cloudformation-update-yaml-cross-stack-references-simplified-substitution/

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
 
aws/aws-cloudformation.txt · Last modified: 2021/03/09 13:19 by andrew