DevOps.Academy
CoursesCurriculumPricing

    Loading…

    ↑ ↓ move · ↵ open · Ctrl K anywhere

    ◔My learningSign in
    DevOps.Academy

    Free, hands-on DevOps lessons. Made with care in India.

    Learn

    All coursesLinux roadmapCurriculumMy learning

    Academy

    PricingCertificates

    Legal

    PrivacyTermsContact

    devops.rajeev.pro

    AWS for DevOpsLesson 16 of 17
    Your progress · 0%
    On this page
    1. Why not click
    2. A template
    3. Deploy it as a stack
    4. Change sets: preview before you change
    5. Drift: when someone clicks in the console
    6. CDK and Terraform
    7. Systems Manager: run the fleet
    8. AWS CI/CD services
    9. Clean up
    10. Nested stacks keep one system understandable
    11. StackSets and CDK solve different repetition problems
    ↖ Course roadmap
    Lesson 16 · Automation & IaC

    Automation and IaC: CloudFormation, CDK and Systems Manager

    Deploy a template as a CloudFormation stack, preview updates with a change set, catch manual edits with drift detection, and know where CDK and Systems Manager fit.

    35 min read · intermediate · hands-on

    By the end of this lesson you'll be able to

    0 of 6 complete

    Why not click

    Lessons 3 to 5 built servers, networks and load balancers by clicking. Clicking doesn't scale: you can't review it, repeat it in another Region, or know what changed last Tuesday. Infrastructure as code describes resources in files that live in git, go through pull requests, and deploy the same way every time.

    On AWS you have two families:

    ToolWritesDeploys through
    CloudFormationYAML or JSON templatesCloudFormation stacks
    AWS CDKTypeScript, Python, Java, Go…generates CloudFormation
    TerraformHCLits own engine and state file (the Terraform course)

    This lesson uses CloudFormation, because it's built in and everything else on AWS builds on it. Everything below ran in a real account and was deleted afterwards.

    A template

    AWSTemplateFormatVersion: '2010-09-09'
    Description: DevOps Academy - a versioned bucket and a config parameter
    Parameters:
      Environment:
        Type: String
        AllowedValues: [dev, prod]
        Default: dev
    Resources:
      AssetsBucket:
        Type: AWS::S3::Bucket
        Properties:
          VersioningConfiguration:
            Status: Enabled
          PublicAccessBlockConfiguration:
            BlockPublicAcls: true
            BlockPublicPolicy: true
            IgnorePublicAcls: true
            RestrictPublicBuckets: true
      LogLevelParam:
        Type: AWS::SSM::Parameter
        Properties:
          Name: !Sub /academy/${Environment}/log-level
          Type: String
          Value: info
    Outputs:
      BucketName:
        Value: !Ref AssetsBucket
    
    SectionHolds
    Parametersinputs, so one template serves dev and prod
    Resourceswhat to create: a logical ID, a Type, and its Properties
    Outputsvalues to show or pass to other stacks

    !Ref and !Sub are intrinsic functions: !Ref AssetsBucket becomes the bucket's real name, and !Sub fills ${Environment} into the string. No bucket name is set, so CloudFormation generates a unique one.

    Deploy it as a stack

    $ aws cloudformation validate-template --template-body file://stack.yaml --query 'Parameters[].ParameterKey' --output text
    Environment
    $ aws cloudformation create-stack --stack-name academy-iac --template-body file://stack.yaml \
        --parameters ParameterKey=Environment,ParameterValue=dev
    $ aws cloudformation wait stack-create-complete --stack-name academy-iac
    $ aws cloudformation describe-stacks --stack-name academy-iac --query 'Stacks[0].[StackStatus,Outputs[0].OutputValue]' --output text
    CREATE_COMPLETE	academy-iac-assetsbucket-2hizm9a4hixg
    
    aws cloudformation validate-template --template-body file://stack.yaml --query 'Parameters[].ParameterKey' --output text
    • awsthe AWS command line
    • --querypick fields from the JSON response
    • --outputoutput format

    The Events tab: every step CloudFormation took, newest first. Read it bottom-up when something fails.© Screenshot: DevOps Academy

    The Events tab: every step CloudFormation took, newest first. Read it bottom-up when something fails.© Screenshot: DevOps Academy

    (1) The bucket and (2) the parameter, each with the logical ID from the template and the real (physical) ID AWS gave it.© Screenshot: DevOps Academy

    (1) The bucket and (2) the parameter, each with the logical ID from the template and the real (physical) ID AWS gave it.© Screenshot: DevOps Academy

    The stack keeps the exact template it was deployed from.© Screenshot: DevOps Academy

    The stack keeps the exact template it was deployed from.© Screenshot: DevOps Academy

    If a resource fails to create, CloudFormation rolls back: it deletes everything it made in that attempt, so you're never left with half a stack. The reason is in the Events tab, on the first CREATE_FAILED line.

    Change sets: preview before you change

    Edit the template: add a tag to the bucket and change the log level to warn. Then ask CloudFormation what it would do, without doing it:

    $ aws cloudformation create-change-set --stack-name academy-iac --change-set-name add-tag-warn-logs \
        --template-body file://stack-v2.yaml --parameters ParameterKey=Environment,UsePreviousValue=true
    $ aws cloudformation describe-change-set --stack-name academy-iac --change-set-name add-tag-warn-logs \
        --query 'Changes[].ResourceChange.[Action,LogicalResourceId,Replacement]' --output text
    Modify	AssetsBucket	False
    Modify	LogLevelParam	False
    
    aws cloudformation create-change-set --stack-name academy-iac --change-set-name add-tag-warn-logs \
    • awsthe AWS command line

    (1) Both resources will be modified in place, nothing replaced. (2) Execute change set applies it.© Screenshot: DevOps Academy

    (1) Both resources will be modified in place, nothing replaced. (2) Execute change set applies it.© Screenshot: DevOps Academy

    The column to read is Replacement. Some property changes can't be done in place, so CloudFormation creates a new resource and deletes the old one: for a database, that means a new, empty database. A change set is how you see that before it happens.

    $ aws cloudformation execute-change-set --stack-name academy-iac --change-set-name add-tag-warn-logs
    $ aws cloudformation wait stack-update-complete --stack-name academy-iac
    $ aws ssm get-parameter --name /academy/dev/log-level --query Parameter.Value --output text
    warn
    
    aws cloudformation execute-change-set --stack-name academy-iac --change-set-name add-tag-warn-logs
    • awsthe AWS command line
    aws ssm get-parameter --name /academy/dev/log-level --query Parameter.Value --output text
    • --querypick fields from the JSON response
    • --outputoutput format

    Drift: when someone clicks in the console

    Now someone "quickly fixes" the value by hand, outside the template:

    $ aws ssm put-parameter --name /academy/dev/log-level --value debug --overwrite
    $ DID=$(aws cloudformation detect-stack-drift --stack-name academy-iac --query StackDriftDetectionId --output text)
    $ aws cloudformation describe-stack-resource-drifts --stack-name academy-iac \
        --query 'StackResourceDrifts[].[LogicalResourceId,StackResourceDriftStatus]' --output text
    AssetsBucket	IN_SYNC
    LogLevelParam	MODIFIED
    
    aws ssm put-parameter --name /academy/dev/log-level --value debug --overwrite
    • awsthe AWS command line

    (1) The parameter changed by hand is MODIFIED. (2) The bucket still matches the template.© Screenshot: DevOps Academy

    (1) The parameter changed by hand is MODIFIED. (2) The bucket still matches the template.© Screenshot: DevOps Academy

    Drift is a problem waiting for the next deploy: the next update sets warn again and the manual fix silently disappears. Either put the change in the template, or undo it. In production, block console edits of stack-managed resources with IAM, and run drift detection on a schedule.

    CDK and Terraform

    AWS CDK writes the same stack in a programming language:

    const bucket = new s3.Bucket(this, 'AssetsBucket', {
      versioned: true,
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
    });
    new ssm.StringParameter(this, 'LogLevelParam', {
      parameterName: `/academy/${props.environment}/log-level`,
      stringValue: 'info',
    });
    

    cdk synth turns it into a CloudFormation template and cdk deploy deploys it as a stack, with change sets behind the scenes. Its constructs bundle good defaults (like Block Public Access above), and loops and functions replace copy-paste. Terraform works across clouds and keeps its own state; teams that already use it for GitHub, Cloudflare or Datadog often use it for AWS too. Pick one per team and stick to it.

    Systems Manager: run the fleet

    IaC creates servers; AWS Systems Manager works on them once they run, through the SSM agent that Amazon Linux already has (the instance needs a role with AmazonSSMManagedInstanceCore):

    FeatureDoes
    Run Commandruns a document (such as AWS-RunShellScript) on many instances at once, by tag, and records the output
    Session Managera shell in the browser or CLI with no SSH port or keys (lesson 3), every session logged
    Patch Managerscans and installs OS patches on a schedule, by patch baseline and maintenance window
    Parameter Storeconfiguration values like /academy/dev/log-level (lesson 15 covers secrets)
    $ aws ssm send-command --document-name AWS-RunShellScript --targets Key=tag:Name,Values=academy-web \
        --parameters 'commands=["systemctl is-active nginx"]'
    
    aws ssm send-command --document-name AWS-RunShellScript --targets Key=tag:Name,Values=academy-web \
    • awsthe AWS command line

    AWS CI/CD services

    The CI/CD course used GitHub Actions. AWS has its own pipeline services, common in companies that keep everything inside AWS:

    ServiceLike
    CodeBuilda build runner: runs buildspec.yml in a container, pay per minute
    CodePipelinethe workflow: source → build → deploy stages, with manual approvals
    CodeDeploydeploys to EC2, Auto Scaling groups, ECS or Lambda, with rolling or blue/green strategies

    Many teams mix them: GitHub Actions for CI, assuming an AWS role with OIDC (lesson 2), then cloudformation deploy or CodeDeploy for the release.

    Clean up

    $ aws cloudformation delete-stack --stack-name academy-iac
    $ aws cloudformation wait stack-delete-complete --stack-name academy-iac
    $ aws ssm get-parameter --name /academy/dev/log-level
    An error occurred (ParameterNotFound) when calling the GetParameter operation:
    
    aws cloudformation delete-stack --stack-name academy-iac
    • awsthe AWS command line

    Deleting the stack deleted the bucket and the parameter with it. One catch: CloudFormation can't delete a bucket that still has objects, so empty it first, or set DeletionPolicy: Retain on data you mean to keep.

    In production

    Every resource comes from code in git and reaches AWS through a pipeline, never from a laptop. Review change sets in pull requests, turn on termination protection for important stacks, set DeletionPolicy: Retain and UpdateReplacePolicy: Retain on databases and buckets, detect drift on a schedule, and split big systems into stacks per layer (network, data, app).

    Nested stacks keep one system understandable

    A nested stack is a child stack created by a parent. Put network, application and monitoring in separate templates, then pass outputs such as a subnet ID between them. Use StackSets when the same template must be copied across accounts or Regions.

    Resources:
      Network:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: https://example.invalid/network.yaml
          Parameters: {EnvironmentName: academy-demo}
    Outputs:
      VpcId: {Value: !GetAtt Network.Outputs.VpcId}
    

    Replace the example URL with a real reviewed template URL before deploying; it is not claimed output. Validate with cfn-lint, inspect the change set, and delete the demonstration stack.

    StackSets and CDK solve different repetition problems

    StackSets applies one CloudFormation template to many accounts or Regions. CDK generates CloudFormation from typed constructs. Bootstrap once, inspect cdk synth, review cdk diff, and deploy only after approval.

    $ cfn-lint parent.yaml network.yaml
    $ cdk synth > template.json
    $ cdk diff
    
    cdk synth > template.json
    • >write output to a file, replacing it
    ⌘
    Mini mission

    Template, change set, drift, delete

    Deploy this lesson's template as a stack, preview and execute a change with a change set, change the parameter by hand and catch it with drift detection, then delete the stack and prove its resources are gone.

    Input: An AWS account and the AWS CLIOutput: CREATE_COMPLETE, a change set with Replacement False, LogLevelParam MODIFIED in drift detection, then ParameterNotFound after deletion
    Reveal one safe solution
    $ aws cloudformation create-stack --stack-name academy-iac --template-body file://stack.yaml
    $ aws cloudformation wait stack-create-complete --stack-name academy-iac
    $ sed -e 's/Value: info/Value: warn/' stack.yaml > stack-v2.yaml
    $ aws cloudformation create-change-set --stack-name academy-iac --change-set-name warn-logs \
        --template-body file://stack-v2.yaml --parameters ParameterKey=Environment,UsePreviousValue=true
    $ aws cloudformation wait change-set-create-complete --stack-name academy-iac --change-set-name warn-logs
    $ aws cloudformation describe-change-set --stack-name academy-iac --change-set-name warn-logs \
        --query 'Changes[].ResourceChange.[Action,LogicalResourceId,Replacement]' --output text
    $ aws cloudformation execute-change-set --stack-name academy-iac --change-set-name warn-logs
    $ aws cloudformation wait stack-update-complete --stack-name academy-iac
    $ aws ssm put-parameter --name /academy/dev/log-level --value debug --overwrite
    $ DID=$(aws cloudformation detect-stack-drift --stack-name academy-iac --query StackDriftDetectionId --output text)
    $ sleep 20; aws cloudformation describe-stack-resource-drifts --stack-name academy-iac \
        --query 'StackResourceDrifts[].[LogicalResourceId,StackResourceDriftStatus]' --output text
    $ aws cloudformation delete-stack --stack-name academy-iac && aws cloudformation wait stack-delete-complete --stack-name academy-iac
    
    aws cloudformation create-stack --stack-name academy-iac --template-body file://stack.yaml
    • awsthe AWS command line
    sed -e 's/Value: info/Value: warn/' stack.yaml > stack-v2.yaml
    • >write output to a file, replacing it
    aws cloudformation delete-stack --stack-name academy-iac && aws cloudformation wait stack-delete-complete --stack-name academy-iac
    • &&run the next command only if this one worked

    Everything in this stack is free: an empty bucket and a standard parameter. If drift detection still says DETECTION_IN_PROGRESS, wait a few more seconds and ask again.

    Try it yourself

    0 of 6 steps done

    Run each task in your own account or terminal, then tick it off.

    Knowledge check

    Quick check

    Question 1 of 5

    What is a CloudFormation stack?

    Go deeper

    Official reading for this lesson

    • DocsWhat is AWS CloudFormation?AWS Docs ↗
    • DocsUpdate stacks using change setsAWS Docs ↗
    • DocsDetect unmanaged configuration changes (drift)AWS Docs ↗
    • DocsAWS CDK developer guideAWS Docs ↗
    • DocsAWS Systems ManagerAWS Docs ↗

    Or get every quiz answer right and it completes itself.

    ← PreviousSecurity and secrets: KMS, Secrets Manager and threat detectionNext lesson →Cost basics and the course project