Example Automation Documents

Example Automation Documents

Automation Document for Step 1

Important: The below example uses the Automation assume role property, so you must replace the ARN with the appropriate ARN for your account. Alternatively, you can remove that property of the document and Automation will assume the permissions of the user initiating the Automation workflow.

description: >
  ## NYCLoft-R Launch an EC2 instance using aws:runInstances

  The purpose of this document is to launch an EC2 instance using the Automation action ```aws:runInstances```.

  For a list of available Automation actions, see [Systems Manager Automation Actions Reference](https://docs.aws.amazon.com/en_us/systems-manager/latest/userguide/automation-actions.html).
schemaVersion: '0.3'
assumeRole: 'arn:aws:iam::REDACTED:role/AmazonSSMRoleForAutomationAssumeQuickSetup'
outputs:
  - launchEc2Instance.InstanceIds
parameters:
  imageId:
    type: String
    default: '{{ ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2 }}'
    description: >
      (Optional) The AMI ID to use for launching the instance. The default value
      uses the latest released Amazon Linux AMI ID.
mainSteps:
  - name: launchEc2Instance
    action: 'aws:runInstances'
    inputs:
      ImageId: '{{ imageId }}'
      InstanceType: t2.micro
      IamInstanceProfileName: AmazonSSMRoleForInstancesQuickSetup

Automation Document for Steps 2-4

Important: The below example uses the Automation assume role property, so you must replace the ARN with the appropriate ARN for your account.

description: >-
  ## Title: LaunchInstanceAndCheckState

  -----

  **Purpose**: This Automation document first launches an Amazon EC2 instance
  using the AMI ID provided in the parameter ```imageId```. The second step of
  this document continuously checks the instance status check value for the
  launched instance until the status ```ok``` is returned.


  ## Parameters:

  -----

  Name | Type | Description | Default Value

  ------------- | ------------- | ------------- | -------------

  assumeRole | String | The ARN of the role that allows Automation to perform
  the actions on your behalf. | -

  imageId  | String | (Optional) The AMI ID to use for launching the instance.
  The default value uses the latest Amazon Linux AMI ID available. | {{
  ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2 }}
schemaVersion: '0.3'
assumeRole: '{{ assumeRole }}'
outputs:
  - launchEc2Instance.OutputPayload
  - PatchInstance.CommandId
  - PatchInstance.Output
parameters:
  imageId:
    type: String
    default: '{{ ssm:/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2 }}'
    description: >
      (Optional) The AMI ID to use for launching the instance. The default value
      uses the latest released Amazon Linux AMI ID.
  tagValue:
    type: String
    default: LaunchedBySsmAutomation
    description: >-
      (Optional) The tag value to add to the instance. The default value is
      LaunchedBySsmAutomation.
  instanceType:
    type: String
    default: t2.micro
    description: >-
      (Optional) The instance type to use for the instance. The default value is
      t2.micro.
  instanceIAMrole:
    type: String
    default: AmazonSSMRoleForInstancesQuickSetup
    description: >-
      (Optional) The name of the IAM Instance Profile role which grants
      permissions to Systems Manager. The default value is
      AmazonSSMRoleForInstancesQuickSetup.
  assumeRole:
    type: String
    default: 'arn:aws:iam::REDACTED:role/AmazonSSMRoleForAutomationAssumeQuickSetup'
    description: >-
      The ARN of the role that allows Automation to perform the actions on your
      behalf.
  s3BucketName:
    type: String
    default: 'nycloft-builders-{{ automation:EXECUTION_ID }}'
    description: >
      (Required) The name of the S3 bucket to create. The name of the bucket
      must be globally unique.
  Operation:
    type: String
    default: Install
    description: >-
      (Required) The update or configuration to perform on the instance. The
      system checks if patches specified in the patch baseline are installed on
      the instance. The install operation installs patches missing from the
      baseline.
mainSteps:
  - name: launchEc2Instance
    action: 'aws:executeScript'
    inputs:
      Runtime: python3.6
      Handler: launch_instance
      Script: |-
        def launch_instance(events, context):
          import boto3
          ec2 = boto3.client('ec2')

          image_id = events['image_id']
          tag_value = events['tag_value']
          instance_type = events['instance_type']
          instance_iam_role = events['instance_iam_role']

          tag_config = {'ResourceType': 'instance', 'Tags': [{'Key':'Name', 'Value':tag_value}]}

          res = ec2.run_instances(ImageId=image_id, IamInstanceProfile={'Name':instance_iam_role}, InstanceType=instance_type, MaxCount=1, MinCount=1, TagSpecifications=[tag_config])

          instance_id = res['Instances'][0]['InstanceId']

          print('[INFO] 1 EC2 instance is successfully launched', instance_id)

          return { 'InstanceId' : instance_id }
      InputPayload:
        image_id: '{{ imageId }}'
        tag_value: '{{ tagValue }}'
        instance_type: '{{ instanceType }}'
        instance_iam_role: '{{ instanceIAMrole }}'
    outputs:
      - Name: Payload
        Selector: $.Payload
        Type: StringMap
      - Name: InstanceId
        Selector: $.Payload.InstanceId
        Type: String
    description: >-
      **About This Step**


      This step first launches an EC2 instance using the ```aws:executeScript```
      action and the provided python script.
  - name: waitForInstanceStatusOk
    action: 'aws:executeScript'
    inputs:
      Runtime: python3.6
      Handler: poll_instance
      Script: |-
        def poll_instance(events, context):
          import boto3
          import time

          ec2 = boto3.client('ec2')

          instance_id = events['InstanceId']

          print('[INFO] Waiting for instance status check to report ok', instance_id)

          instance_status = "null"

          while True:
            res = ec2.describe_instance_status(InstanceIds=[instance_id])

            if len(res['InstanceStatuses']) == 0:
              print("Instance status information is not available yet")
              time.sleep(5)
              continue

            instance_status = res['InstanceStatuses'][0]['InstanceStatus']['Status']

            print('[INFO] Polling to get status of the instance', instance_status)

            if instance_status == 'ok':
              break

            time.sleep(10)

          return {'Status': instance_status, 'InstanceId': instance_id}
      InputPayload: '{{ launchEc2Instance.Payload }}'
    description: >
      **About This Step**


      The python script continuously polls the instance status check value for
      the instance launched in Step 1 until the ```ok``` status is returned.
  - name: createS3Bucket
    action: 'aws:executeAwsApi'
    inputs:
      Service: s3
      Api: CreateBucket
      Bucket: '{{ s3BucketName }}'
    description: |
      **About This Step**

      The S3 API action CreateBucket is called to create a new S3 bucket.
  - name: PatchInstance
    action: 'aws:runCommand'
    inputs:
      DocumentName: AWS-RunPatchBaseline
      InstanceIds:
        - '{{ launchEc2Instance.InstanceId }}'
      Parameters:
        Operation: '{{Operation}}'
      OutputS3BucketName: '{{ s3BucketName }}'
      OutputS3KeyPrefix: patching
    description: >
      **About This Step**


      This step runs the Command document ```AWS-RunPatchBaseline``` on the
      managed instance launched in Step 1.