Golden AMI using Cloud formation

Chinthaka Hasakelum
5 min readJun 3, 2020

I have attached the sample yml file to work with cloud formation. you guys have to just take the script and run the file.

Note: Please do the necessary changes to the scripts. update the user data as needed.

---AWSTemplateFormatVersion: '2010-09-09'Description: " This cloudformation template creates resources required to set up agolden ami pipeline.(fdp-1o82smtoh)"Parameters:productName:Type: StringDefault: ProductName-ProductVersionDescription: 'ProductName-ProductVersion combination of the product for whichyou intend to use the pipeline. You get to override this later when you triggerautomation workflow. 'productOSAndVersion:Type: StringDefault: OperatingSystemName-OperatingSystemVersionDescription: Operating system name and OS version. You get to override this laterwhen you trigger automation workflow.buildVersion:Type: StringDefault: '1'Description: Build-Version corresponding to your product. Note - This is justa default value, you get to override this later when you trigger automationworkflow.cidrVPC:Description: An available CIDR block for creating a new VPC. The size of the VPCshould be big enough to hold instances of all your golden AMIs at a timeType: StringMinLength: '9'MaxLength: '18'Default: 10.0.0.0/16AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.cidrPrivateSubnet:Description: An available CIDR block for creating a new VPC. The size of the VPCshould be big enough to hold instances of all your golden AMIs at a timeType: StringMinLength: '9'MaxLength: '18'Default: 10.0.1.0/24AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.cidrPublicSubnet:Description: An available CIDR block for creating a new VPC. The size of the VPCshould be big enough to hold instances of all your golden AMIs at a timeType: StringMinLength: '9'MaxLength: '18'Default: 10.0.2.0/24AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.ApproverUserIAMARN:Type: StringDefault: ''Description: IAM ARN of the Golden AMI approver. The approver must have AmazonSSMAutomationApproverAccesspolicy associated with it's IAM Profile .EmailID:Type: StringDefault: myemail@mycompany.comAllowedPattern: "([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)"Description: Your email ID for receiving Inspector assessment results and goldenAMI creation notification.instanceType:Type: StringDefault: t2.largeDescription: Specify the the InstanceType compatible with all your golden AMIs.This InstanceType will be used for launching continuous vulnerability assessmentof golden AMIs.continuousInspectionFrequency:Type: StringDefault: rate(1 day)Description: Frequency for setting up continuous inspection of your AMIs. Forsyntax, check - https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.htmlMetadataJSON:Type: StringDefault: '{"Account_ID_1":"region_1,region_2"}'Description: Metadata of accounts and regions for distributing the golden AMI.roleName:Type: StringDefault: goldenAMICrossAccountRoleDescription: Cross account role suffix for managing Golden AMI metadata Parametersin child account(s). This role needs to exist in each account specified in MetadataJSONparameter.Resources:VPC:Type: AWS::EC2::VPCProperties:EnableDnsSupport: 'true'EnableDnsHostnames: 'true'CidrBlock:Ref: cidrVPCsubnetPrivate:Type: AWS::EC2::SubnetProperties:CidrBlock:Ref: cidrPrivateSubnetVpcId:Ref: VPCsubnetPublic:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: trueCidrBlock:Ref: cidrPublicSubnetVpcId:Ref: VPCInternetGateway:Type: AWS::EC2::InternetGatewayPublicVPCGatewayAttachment:Type: AWS::EC2::VPCGatewayAttachmentProperties:VpcId:Ref: VPCInternetGatewayId:Ref: InternetGatewayPublicRouteTable:Type: AWS::EC2::RouteTableProperties:VpcId:Ref: VPCPublicRoute:Type: AWS::EC2::RouteDependsOn: PublicVPCGatewayAttachmentProperties:RouteTableId:Ref: PublicRouteTableDestinationCidrBlock: 0.0.0.0/0GatewayId:Ref: InternetGatewayPublicSubnetRouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId:Ref: subnetPublicRouteTableId:Ref: PublicRouteTableNAT:DependsOn: PublicVPCGatewayAttachmentType: AWS::EC2::NatGatewayProperties:AllocationId:Fn::GetAtt:- EIP- AllocationIdSubnetId:Ref: subnetPublicPrivateRouteTable:Type: AWS::EC2::RouteTableProperties:VpcId:Ref: VPCEIP:Type: AWS::EC2::EIPProperties:Domain: vpcPrivateRoute:Type: AWS::EC2::RouteGoldenAMIAutomationDoc:Type: AWS::SSM::DocumentDependsOn:- InspectorCompleteTopicProperties:DocumentType: AutomationContent:description: This automation document triggers Golden AMI creation workflow.schemaVersion: '0.3'assumeRole:Fn::GetAtt:- AutomationServiceRole- Arnparameters:sourceAMIid:type: Stringdescription: Source/Base AMI to be used for generating your golden AMIdefault: ''productName:type: Stringdescription: The syntax of this parameter is ProductName-ProductVersion.default:Ref: productNameproductOSAndVersion:type: Stringdescription: The syntax of this parameter is OSName-OSVersiondefault:Ref: productOSAndVersionAMIVersion:type: Stringdescription: Golden AMI Build version number to be created.default:Ref: buildVersionsubnetId:type: Stringdefault:Ref: subnetPrivatedescription: Subnet in which instances will be launched.securityGroupId:type: Stringdefault:Ref: secGroupdescription: Security Group that will be attached to the instance. ByDefault a security group without any inbound access is attachedinstanceType:type: Stringdescription: A compatible instance-type for launching an instancedefault:Ref: instanceTypetargetAMIname:type: Stringdescription: Name for the golden AMI to be createddefault: "{{productName}}-{{productOSAndVersion}}-{{AMIVersion}}"ApproverUserIAMARN:type: Stringdescription: IAM ARN of the user who has SSM approval permissions.default:Ref: ApproverUserIAMARNApproverNotificationArn:type: Stringdescription: SNS Topic ARN on which a notification would be publishedonce the golden AMI candidate is ready for validation.default:Ref: ApproverNotificationManagedInstanceProfile:type: Stringdescription: Instance Profile. Do not change the default value.default:Ref: ManagedInstanceProfileSSMInstallationUserData:type: Stringdescription: Base64 encoded SSM installation user-data.default: IyEvYmluL2Jhc2gNCg0KZnVuY3Rpb24gZ2V0X2NvbnRlbnRzKCkgew0KICAgIGlmIFsgLXggIiQod2hpY2ggY3VybCkiIF07IHRoZW4NCiAgICAgICAgY3VybCAtcyAtZiAiJDEiDQogICAgZWxpZiBbIC14ICIkKHdoaWNoIHdnZXQpIiBdOyB0aGVuDQogICAgICAgIHdnZXQgIiQxIiAtTyAtDQogICAgZWxzZQ0KICAgICAgICBkaWUgIk5vIGRvd25sb2FkIHV0aWxpdHkgKGN1cmwsIHdnZXQpIg0KICAgIGZpDQp9DQoNCnJlYWRvbmx5IElERU5USVRZX1VSTD0iaHR0cDovLzE2OS4yNTQuMTY5LjI1NC8yMDE2LTA2LTMwL2R5bmFtaWMvaW5zdGFuY2UtaWRlbnRpdHkvZG9jdW1lbnQvIg0KcmVhZG9ubHkgVFJVRV9SRUdJT049JChnZXRfY29udGVudHMgIiRJREVOVElUWV9VUkwiIHwgYXdrIC1GXCIgJy9yZWdpb24vIHsgPreUpdateScript:type: Stringdescription: (Optional) URL of a script to run before updates are applied.Default ("none") is to not run a script.default: nonePostUpdateScript:type: Stringdescription: (Optional) URL of a script to run after package updates areapplied. Default ("none") is to not run a script.default: noneIncludePackages:type: Stringdescription: (Optional) Only update these named packages. By default ("all"),all available updates are applied.default: allExcludePackages:type: Stringdescription: (Optional) Names of packages to hold back from updates, underall conditions. By default ("none"), no package is excluded.default: nonemainSteps:- name: startInstancesaction: aws:runInstancestimeoutSeconds: 3600maxAttempts: 1onFailure: Abortinputs:ImageId: "{{ sourceAMIid }}"InstanceType: "{{instanceType}}"MinInstanceCount: 1MaxInstanceCount: 1SubnetId: "{{ subnetId }}"SecurityGroupIds:- "{{ securityGroupId }}"UserData: "{{SSMInstallationUserData}}"IamInstanceProfileName: "{{ ManagedInstanceProfile }}"- name: updateOSSoftwareaction: aws:runCommandmaxAttempts: 3timeoutSeconds: 3600onFailure: Abortinputs:DocumentName: AWS-RunShellScriptInstanceIds:- "{{startInstances.InstanceIds}}"Parameters:commands:- set -e- '[ -x "$(which wget)" ] && get_contents=''wget $1 -O -'''- '[ -x "$(which curl)" ] && get_contents=''curl -s -f $1'''- eval $get_contents https://aws-ssm-downloads-{{global:REGION}}.s3.amazonaws.com/scripts/aws-update-linux-instance > /tmp/aws-update-linux-instance- chmod +x /tmp/aws-update-linux-instance- "/tmp/aws-update-linux-instance --pre-update-script '{{PreUpdateScript}}'--post-update-script '{{PostUpdateScript}}' --include-packages '{{IncludePackages}}'--exclude-packages '{{ExcludePackages}}' 2>&1 | tee /tmp/aws-update-linux-instance.log"- name: stopInstanceaction: aws:changeInstanceStatetimeoutSeconds: 1200maxAttempts: 1onFailure: Abortinputs:InstanceIds:- "{{ startInstances.InstanceIds }}"DesiredState: stopped- name: createImageaction: aws:createImagetimeoutSeconds: 1200maxAttempts: 1onFailure: Continueinputs:InstanceId: "{{ startInstances.InstanceIds }}"ImageName: "{{ targetAMIname }}"NoReboot: trueImageDescription: AMI created by EC2 Automation- name: TagTheAMIaction: aws:createTagstimeoutSeconds: 1200maxAttempts: 1onFailure: Continueinputs:ResourceType: EC2ResourceIds:- "{{ createImage.ImageId }}"Tags:- Key: ProductOSAndVersionValue: "{{productOSAndVersion}}"- Key: ProductNameValue: "{{productName}}"- Key: versionValue: "{{AMIVersion}}"- Key: AMI-TypeValue: Golden- name: terminateFirstInstanceaction: aws:changeInstanceStatetimeoutSeconds: 1200maxAttempts: 1onFailure: Continueinputs:InstanceIds:- "{{ startInstances.InstanceIds }}"DesiredState: terminated- name: createInstanceFromNewImageaction: aws:runInstancestimeoutSeconds: 1200maxAttempts: 1onFailure: Abortinputs:ImageId: "{{ createImage.ImageId }}"InstanceType: "{{instanceType}}"MinInstanceCount: 1MaxInstanceCount: 1SubnetId: "{{ subnetId }}"SecurityGroupIds:- "{{ securityGroupId }}"IamInstanceProfileName: "{{ ManagedInstanceProfile }}"- name: TagNewinstanceaction: aws:createTagstimeoutSeconds: 1200maxAttempts: 1onFailure: Continueinputs:ResourceType: EC2ResourceIds:- "{{ createInstanceFromNewImage.InstanceIds }}"Tags:- Key: TypeValue: "{{createImage.ImageId}}-{{productOSAndVersion}}/{{productName}}/{{AMIVersion}}"- Key: Automation-Instance-TypeValue: Golden- name: sleepaction: aws:sleepinputs:- name: updateLatestVersionValueaction: aws:invokeLambdaFunctiontimeoutSeconds: 1200maxAttempts: 1onFailure: Abortinputs:FunctionName:Ref: AppendParamLambdaPayload: '{"parameterName":"/GoldenAMI/latest", "valueToBeCreatedOrAppended":"{{createImage.ImageId}}"}'outputs:- createImage.ImageId

Above CF script will create and ssm document in AWS Systems manager. With the help of SSM document, you guys can run a execution in AWS.

--

--