AWS Cloud Operations & Migrations Blog

Using State Manager over cfn-init in CloudFormation and its benefits

Introduction

If you have deployed Amazon Elastic Compute Cloud (EC2) instances via AWS CloudFormation, you most likely want to install software or configure the operating system of the instance. To accomplish this, you may have used cfn-init, one of the CloudFormation helper scripts available to AWS customers since February 2012. However, since that time AWS has released many new features and services in response to customer feedback. One of these services is AWS Systems Manager. In this blog post, we show a simpler and more robust way of performing instance configuration using AWS Systems Manager State Manager for Amazon EC2 instances deployed through AWS CloudFormation.

Overview of State Manager

Systems Manager State Manager is a scalable configuration management service that automates the process of keeping your Amazon EC2 and on-premises infrastructure in a state that you define. With State Manager you can bootstrap EC2 instances with software at start-up, configure network settings, join Windows instances to a Microsoft Active Directory domain, and run scripts on Windows or Linux managed instances. To execute these tasks with State Manager, you create an association, which maps an automation or command document to target instances. With State Manager, we can run many of the same tasks as you would with cfn-init but with multiple added benefits:

  1. Centralized logs in Amazon Simple Storage Service (S3)
  2. Cleaner CloudFormation templates
  3. Configuration compliance visibility
  4. Improved auditing with AWS CloudTrail integration
  5. Running configuration on a schedule after initial provisioning
  6. Ability to configure new instances launched using tags
  7. Rate and error control settings

In this post, we focus on the first four benefits. The first benefit is ability to centralize logs in Amazon S3 for troubleshooting. Cfn-init dumps logs locally on an EC2 instance, requiring you to remote into the instance to troubleshoot. In contrast, when you create a State Manager association you can centralize log output to an Amazon S3 bucket. This allows you to easily troubleshoot at scale without having to log in into each instance in a CloudFormation stack.

The second benefit is simplified CloudFormation templates. With cfn-init, you would need to specify a metadata section within the resource in your CloudFormation template that details the tasks cfn-init would run. You would then need to point cfn-init at boot-up to read the metadata information. If part of your configuration required downloading scripts, this would take multiple steps to achieve. However, State Manager has a native CloudFormation resource type, which helps to reduce the complexity within your CloudFormation template. There are many Systems Manager documents that can automatically download scripts from GitHub or Amazon S3 using the aws:downloadContent plugin and then execute them. This allows you to decouple your configuration scripts from CloudFormation and download and execute them in one step.

The third benefit is the ability to ensure the instance stays within your defined configuration because cfn-init only runs at creation or update (if configured properly for update) of a CloudFormation stack. Depending on the configuration tool used, you can also get compliance information with State Manager. The final benefit is that all actions are tracked via CloudTrail, which provides improved auditing over cfn-init.

In summary, it would be a recommended practice to use CloudFormation to define AWS resources. If those resources are instances, use Systems Manager to configure them. Now, that we have covered the benefits of this pattern, let’s now see how we can put it into practice. In the next section we will see how to  run an Ansible playbook on an Amazon Linux 2 instance that is stored on GitHub via State Manager

Figure 1: Using CloudFormation and State Manager Together

Using State Manager in CloudFormation to install NGNIX

State Manager has a CloudFormation resource type of AWS::SSM::Association, which creates a State Manager association. We can view this resource type as a trigger mechanism for configuration scripts or automation workflows for our instances deployed by CloudFormation. This resource type comes with a property called WaitForSuccessTimeoutSeconds that causes CloudFormation to wait until the association is successfully applied by State Manager. In this example we create an association that runs the AWS-ApplyAnsiblePlaybooks command document on our target instance.

  AnsibleAssociation:
    Type: AWS::SSM::Association
    Properties:
      # Here using the AWS-ApplyAnsiblePlaybooks
      Name: AWS-ApplyAnsiblePlaybooks
      # This will cause CloudFormation to wait for the association to apply
      WaitForSuccessTimeoutSeconds: 120
      Targets:
        - Key: InstanceIds
          Values: [ !Ref EC2Instance ]
      OutputLocation:
        S3Location: 
          OutputS3BucketName: !Ref SSMAssocLogs
          OutputS3KeyPrefix: 'logs/'
      Parameters:
        # Getting an Ansible Playbook from a GitHub Location
        SourceType:
          - 'GitHub'
        # At a minimum must include the following GitHub repo information, if using a private repo 
        # would want to include a GitHub Token
        SourceInfo:
          - '{"owner":"<Insert your GitHub Owner Name>",
              "repository":"<Insert your GitHub Repo>",
              "path":"",
              "getOptions":"branch:master" }'
        # Installing Ansible and its dependencies
        InstallDependencies:
          - 'True'
        # Playbook file we want to run
        PlaybookFile:
          - 'playbook.yml'
        ExtraVariables:
          - 'SSM=True'
        Check:
          - 'False'
        Verbose:
          - '-v'

The CloudFormation stack created by this template creates an association between the command document and the EC2 istance. Once the EC2 instance registers with the Systems Manager service, it runs the command document which downloads the Ansible playbook from GitHub, installs Ansible and then runs the playbook.  The resource type then signals CloudFormation of success or failure .

While this is a simple example to illustrate the pattern using Ansible, we could also run a script from a remote location using the AWS-RunRemoteScript or other Systems Manager documents that run scripts. This example focuses on a one-time trigger to configure the instance. However, what if we want to ensure configuration throughout the lifecycle of the instance?

With State Manager we can also set it to run on a schedule, we can pass a cron expression to the resource that runs the association every day. If your scripts were written in an idempotent manner,we could run it to ensure configuration of our instance. State Manager also supports using configuration management tools that already handle idempotency, such as PowerShell Desired State Configuration (PowerShell DSC), Chef, SaltStack, or Ansible. We already demonstrated the AWS-ApplyAnsiblePlaybooks document, but there are many others documents such as AWS-ApplyDSCMofs for PowerShell DSC, AWS-ApplyChefRecipes for Chef recipes or AWS-RunSaltState (Blog Post) for Salt states. Some of the public Systems Manager documents also allow for reporting on compliance drift such as the AWS-RunInSpecChecks or AWS-ApplyDSCMofs.

More Samples of Using State Manager with CloudFormation

I always find it helpful to have many working examples as I learn a new pattern or service. In this blog post, we provided one example of how State Manager can be used instead of cfn-init to configure instances deployed by CloudFormation. We have created a repository of several CloudFormation templates demonstrating various ways to use the AWS::SSM::Association resource type. There are examples of running a bash script and joining an Active Directory domain. We hope to post more examples in the future. You can also request an example by submitting an issue to the repo.

Conclusion

There are many patterns that you can explore between CloudFormation and State Manager, but we recommend using CloudFormation to define your AWS Resources and Systems Manager to perform configuration management. Whether you are new to AWS CloudFormation or using it for some time, start to think about using State Manager instead of cfn-init. State Manager helps simplify complex CloudFormation templates, makes it easier to use existing configuration management tools within CloudFormation, and makes it easier to troubleshoot issues across multiple nodes.

Author bio

   Aaron Lima is a Sr. Solutions Architect with Amazon Web Services based in the New York area. Aaron is responsible for assisting customers with their AWS for Windows architectures and migrations. Aaron is an IT professional with over two decades of experience, as a one-time customer he is passionate about helping and enabling customers take advantage of the AWS Cloud. Aaron’s primary focus is on Management and Governance within AWS. Aaron loves talking about AWS Systems Manager, AWS CloudFormation, AWS Config and automating infrastructure deployment and operations.