Skip to content

Instantly share code, notes, and snippets.

@wolfeidau
Last active November 19, 2018 01:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wolfeidau/20bd56586af451e2a2649c7b3505f923 to your computer and use it in GitHub Desktop.
Save wolfeidau/20bd56586af451e2a2649c7b3505f923 to your computer and use it in GitHub Desktop.
SSM CFN Templates which build an AMI from the RHEL base image provided by AWS.

SSM AMI Build

These templates provide the roles, and a document to build AMIs using SSM Automation.

The require:

  1. A VPC with some public subnets, in my case I am just using a default VPC.
  2. The AMI ID of the RHEL base image, this is tested with 7.2 and up.

To get the latest AMI you can run the following command.

aws ec2 --region ap-southeast-2 describe-images --owners 309956199498 --query 'Images[*].[CreationDate,Name,ImageId]' --filters "Name=name,Values=RHEL-7.?*GA*" --output table --output text | sort -r
AWSTemplateFormatVersion: "2010-09-09"
Description: 'SSM: IAM Roles, this is a versent.com.au template'
Resources:
EC2InstanceRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "ssm.amazonaws.com"
- "ec2.amazonaws.com"
Action: "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
Path: "/"
EC2InstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
- !Ref "EC2InstanceRole"
SSMRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "ssm.amazonaws.com"
- "ec2.amazonaws.com"
Action: "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
Path: "/"
Policies:
- PolicyName: "passrole"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "iam:PassRole"
Resource:
- !GetAtt "EC2InstanceRole.Arn"
LambdaRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action: "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AWSLambdaExecute"
- "arn:aws:iam::aws:policy/AmazonSSMFullAccess"
- "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
Path: "/"
Policies:
- PolicyName: "passrole"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "iam:PassRole"
Resource:
- !GetAtt "SSMRole.Arn"
Outputs:
EC2InstanceProfile:
Value: !Ref "EC2InstanceProfile"
Export:
Name: !Sub '${AWS::StackName}-EC2InstanceProfile'
SSMRoleARN:
Value: !GetAtt "SSMRole.Arn"
Export:
Name: !Sub '${AWS::StackName}-SSMRoleARN'
LambdaRoleARN:
Value: !GetAtt "LambdaRole.Arn"
Export:
Name: !Sub '${AWS::StackName}-LambdaRoleARN'
AWSTemplateFormatVersion: "2010-09-09"
Description: 'SSM: SSM Automation Document which builds a RHEL AMI, this is a versent.com.au template'
Description: "AWS CloudFormation template to automate AMI patching process"
Parameters:
ParentRoleStack:
Description: 'Stack name of parent Role stack template.'
Type: String
SubnetId:
Description: "VPC Subnet ID"
Type: "AWS::EC2::Subnet::Id"
Resources:
SSMAutomationDocument:
Type: "AWS::SSM::Document"
Properties:
DocumentType: "Automation"
Content:
schemaVersion: "0.3"
description: "Update a Linux AMI."
assumeRole: "{{AutomationAssumeRoleARN}}"
parameters:
SourceAmiId:
type: "String"
description: "The source Amazon Machine Image ID."
SubnetId:
type: "String"
description: "Subnet id"
default: !Ref "SubnetId"
InstanceProfileName:
type: "String"
description: "EC2 IAM profile that is allowed to perform RunCommand."
default:
'Fn::ImportValue': !Sub '${ParentRoleStack}-EC2InstanceProfile'
AutomationAssumeRoleARN:
type: "String"
description: "Role under which to execute this automation."
default:
'Fn::ImportValue': !Sub '${ParentRoleStack}-SSMRoleARN'
TargetAmiName:
type: "String"
description: "The name of the new AMI that will be created."
default: ami-{{SourceAmiId}}-{{global:DATE_TIME}}
InstanceType:
type: "String"
description: "Type of instance to launch as the workspace host."
default: "m4.large"
mainSteps:
- name: "launchInstance"
action: "aws:runInstances"
maxAttempts: 3
timeoutSeconds: 1200
onFailure: "Abort"
inputs:
SubnetId: "{{SubnetId}}"
ImageId: "{{SourceAmiId}}"
InstanceType: "{{InstanceType}}"
UserData: IyEvYmluL2Jhc2gNCmNkIC90bXANCmN1cmwgaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2VjMi1kb3dubG9hZHMtd2luZG93cy9TU01BZ2VudC9sYXRlc3QvbGludXhfYW1kNjQvYW1hem9uLXNzbS1hZ2VudC5ycG0gLW8gYW1hem9uLXNzbS1hZ2VudC5ycG0NCnl1bSBpbnN0YWxsIC15IGFtYXpvbi1zc20tYWdlbnQucnBt
MinInstanceCount: 1
MaxInstanceCount: 1
IamInstanceProfileName: "{{InstanceProfileName}}"
- name: "InstallAmazonCloudWatchAgent"
action: "aws:runCommand"
maxAttempts: 3
timeoutSeconds: 1200
onFailure: "Continue"
inputs:
DocumentName: "AWS-ConfigureAWSPackage"
InstanceIds:
- "{{launchInstance.InstanceIds}}"
Parameters:
name: AmazonCloudWatchAgent
action: Install
- name: "InstallRequiredPackages"
action: "aws:runCommand"
maxAttempts: 3
timeoutSeconds: 1200
onFailure: "Continue"
inputs:
DocumentName: "AWS-RunShellScript"
InstanceIds:
- "{{launchInstance.InstanceIds}}"
Parameters:
commands:
- sudo yum install -y sysstat
- sudo yum install -y openscap-scanner scap-security-guide screen aide openswan
- name: "RunOSCAPRemediate"
action: "aws:runCommand"
maxAttempts: 3
timeoutSeconds: 1200
onFailure: "Continue"
inputs:
DocumentName: "AWS-RunShellScript"
InstanceIds:
- "{{launchInstance.InstanceIds}}"
Parameters:
commands:
- sudo oscap xccdf eval --remediate --profile xccdf_org.ssgproject.content_profile_C2S --cpe /usr/share/xml/scap/ssg/content/ssg-rhel7-cpe-dictionary.xml /usr/share/xml/scap/ssg/content/ssg-rhel7-ds.xml || true
- name: "stopInstance"
action: "aws:changeInstanceState"
maxAttempts: 3
timeoutSeconds: 1200
onFailure: "Continue"
inputs:
InstanceIds:
- "{{launchInstance.InstanceIds}}"
DesiredState: stopped
- name: "createImage"
action: "aws:createImage"
maxAttempts: 3
onFailure: "Continue"
inputs:
InstanceId: "{{launchInstance.InstanceIds}}"
ImageName: "{{TargetAmiName}}"
NoReboot: true
ImageDescription: "AMI Generated from {{SourceAmiId}}"
- name: "terminateInstance"
action: "aws:changeInstanceState"
maxAttempts: 3
onFailure: "Continue"
inputs:
InstanceIds:
- "{{launchInstance.InstanceIds}}"
DesiredState: "terminated"
outputs:
- createImage.ImageId
Outputs:
SSMAutomationDocument:
Value: !Ref "SSMAutomationDocument"
Export:
Name: !Sub '${AWS::StackName}-SSMAutomationDocument'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment