#* #* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. #* SPDX-License-Identifier: MIT-0 #* #* Permission is hereby granted, free of charge, to any person obtaining a copy of this #* software and associated documentation files (the "Software"), to deal in the Software #* without restriction, including without limitation the rights to use, copy, modify, #* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to #* permit persons to whom the Software is furnished to do so. #* #* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A #* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION #* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE #* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #* #------------------------------------------------------------------------------ # # Template: ssm-workshop-resources-episode-04.yaml # Purpose: CloudFormation template to deploy test resources for the fourth episode of the virtual workshop. # # #------------------------------------------------------------------------------ AWSTemplateFormatVersion: '2010-09-09' Description: AWS CloudFormation template to deploy test resources for the fourth episode of the virtual workshop. #----------------------------------------------------------- # Parameters #----------------------------------------------------------- Parameters : LatestAmazonLinuxAmiId : # Use public Systems Manager Parameter Type : 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' MainRegion: Type: 'String' Description: 'Main region for IAM.' Default: 'us-east-1' Conditions: IsMainRegion: !Equals [!Ref MainRegion, !Ref AWS::Region] Resources: #------------------------------------------------- # Automation Administration role for multi-account/Region Automation capabilities #------------------------------------------------- AutomationAdministrationServiceRole: Type: AWS::IAM::Role Condition: IsMainRegion Properties: RoleName: AWS-SystemsManager-AutomationAdministrationRole AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ssm.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: AssumeRole-AWSSystemsManagerAutomationExecutionRole PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - sts:AssumeRole Resource: Fn::Sub: arn:${AWS::Partition}:iam::${AWS::AccountId}:role/AWS-SystemsManager-AutomationExecutionRole - Effect: Allow Action: - organizations:ListAccountsForParent Resource: - "*" #------------------------------------------------- # Automation Execution role for multi-account/Region Automation capabilities #------------------------------------------------- AutomationExecutionServiceRole: Type: AWS::IAM::Role Condition: IsMainRegion Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com AWS: - !GetAtt AutomationAdministrationServiceRole.Arn Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole Path: "/" RoleName: AWS-SystemsManager-AutomationExecutionRole Policies: - PolicyName: passRole PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:PassRole Resource: - Fn::Sub: arn:${AWS::Partition}:iam::${AWS::AccountId}:role/AWS-SystemsManager-AutomationExecutionRole - PolicyName: getTagPermissions PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - tag:GetResources Resource: "*" - PolicyName: listResourceGroupResourcesPermissions PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - resource-groups:listGroupResources Resource: "*" #------------------------------------------------- # Automation document to run AWS-RunPatchBaseline on target resources #------------------------------------------------- AutomationDocumentRunPatchBaseline: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: description: >- This document runs the Command document ```AWS-RunPatchBaseline``` on the specified instances. schemaVersion: '0.3' assumeRole: '{{ AutomationAssumeRole }}' parameters: AutomationAssumeRole: type: String description: The ARN of the Automation service role to assume. InstallOverrideList: type: String default: "" description: >- (Optional) An https URL or an Amazon S3 path-style URL to the list of patches to be installed. This patch installation list overrides the patches specified by the default patch baseline. Operation: type: String default: Scan 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. RebootOption: type: String default: RebootIfNeeded description: >- (Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan. ResourceGroupName: description: The name of the Resource Group to target. type: String default: !Ref ManagedInstancesResourceGroup SnapshotId: type: String default: "" description: >- (Optional) The snapshot ID to use to retrieve a patch baseline snapshot. mainSteps: - name: runPatchBaseline action: 'aws:runCommand' timeoutSeconds: 7200 onFailure: Abort inputs: DocumentName: AWS-RunPatchBaseline Targets: - Key: 'resource-groups:Name' Values: - '{{ ResourceGroupName }}' Parameters: Operation: '{{ Operation }}' RebootOption: '{{ RebootOption }}' SnapshotId: '{{ SnapshotId }}' InstallOverrideList: '{{ InstallOverrideList }}' OutputS3BucketName: !Ref CommandLogsBucket OutputS3KeyPrefix: 'patching/accountid={{global:ACCOUNT_ID}}/region={{global:REGION}}/executionid={{automation:EXECUTION_ID}}' description: >- This command runs the Command document ```AWS-RunPatchBaseline``` on the specified instances. #------------------------------------------------- # Bucket used to store resource data sync data #------------------------------------------------- ResouceSyncBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub 'ssm-resource-sync-${AWS::Region}-${AWS::AccountId}' AccessControl: BucketOwnerFullControl VersioningConfiguration: Status: Enabled PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true #------------------------------------------------- # Bucket policy to add to S3 bucket to store resource data sync data #------------------------------------------------- ResouceSyncBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref ResouceSyncBucket PolicyDocument: Version: '2012-10-17' Statement: - Sid: SSMBucketPermissionsCheck Effect: Allow Principal: Service: ssm.amazonaws.com Action: s3:GetBucketAcl Resource: !GetAtt ResouceSyncBucket.Arn - Sid: SSMBucketDelivery Effect: Allow Principal: Service: ssm.amazonaws.com Action: s3:PutObject Resource: - !Join [ '', [!GetAtt ResouceSyncBucket.Arn, '/inventory/*/', 'accountid=', !Ref 'AWS::AccountId', '/*'] ] Condition: StringEquals: s3:x-amz-acl: bucket-owner-full-control #------------------------------------------------- # Resource Data Sync to aggregate inventory, patching, and compliance data in the central S3 bucket #------------------------------------------------- ResourceDataSync: Type: AWS::SSM::ResourceDataSync Properties: SyncName: inventory-ssm-workshop S3Destination: BucketName: !Ref ResouceSyncBucket BucketPrefix: inventory BucketRegion: !Ref "AWS::Region" SyncFormat: 'JsonSerDe' #------------------------------------------------- # Bucket used to store instance command logs #------------------------------------------------- CommandLogsBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub 'ssm-command-logs-${AWS::Region}-${AWS::AccountId}' AccessControl: BucketOwnerFullControl VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true #------------------------------------------------- # Resource Group to target for multi-account/multi-Region Automation #------------------------------------------------- ManagedInstancesResourceGroup: Type: AWS::ResourceGroups::Group Properties: Description: 'This is a test Resource Group for the SSM workshop' Name: ManagedInstances ResourceQuery: Type: "TAG_FILTERS_1_0" Query: ResourceTypeFilters: - "AWS::AllSupported" TagFilters: - Key: "Patch" Values: - "true" #------------------------------------------------- # IAM role and instance profile to enable Systems Manager registration on EC2 instances #------------------------------------------------- ManagedInstanceRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore Path: "/" RoleName: !Join [ '-', ['AmazonSSMManagedInstanceCore', !Ref 'AWS::Region'] ] Policies: - PolicyName: S3_Permissions PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:GetObject - s3:PutObject - s3:PutObjectAcl Resource: - !Join [ '', [!GetAtt CommandLogsBucket.Arn] ] - !Join [ '', [!GetAtt CommandLogsBucket.Arn, '/*'] ] ManagedInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: "/" Roles: - !Ref ManagedInstanceRole InstanceProfileName: !Sub 'ManagedInstanceProfile-${AWS::Region}' #------------------------------------------------- # Automation Service IAM role and State Manager Association to enable Explorer #------------------------------------------------- EnableExplorerAutomationRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:ListRoles - config:DescribeConfigurationRecorders - compute-optimizer:GetEnrollmentStatus - support:DescribeTrustedAdvisorChecks Resource: "*" - Effect: Allow Action: - ssm:UpdateServiceSetting - ssm:GetServiceSetting Resource: - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsitem/ssm-patchmanager" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsitem/EC2" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsdata/ExplorerOnboarded" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsdata/Association" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsdata/ComputeOptimizer" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsdata/ConfigCompliance" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsdata/OpsData-TrustedAdvisor" - Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":ssm:*:*:servicesetting/ssm/opsdata/SupportCenterCase" - Effect: Allow Action: - iam:CreateServiceLinkedRole Resource: Fn::Join: - '' - - 'arn:' - Ref: AWS::Partition - ":iam::*:role/aws-service-role/ssm." - Ref: AWS::URLSuffix - "/AWSServiceRoleForAmazonSSM" Condition: StringEquals: iam:AWSServiceName: ssm.amazonaws.com PolicyName: SSMQuickSetupEnableExplorerInlinePolicy RoleName: SSM-Workshop-EnableExplorerRole SystemAssociationForEnablingExplorer: Type: AWS::SSM::Association Properties: Name: AWS-EnableExplorer AssociationName: SSM-Workshop-EnableExplorer Parameters: AutomationAssumeRole: - !GetAtt EnableExplorerAutomationRole.Arn #------------------------------------------------- # VPC and required resources to enable network connectivity to AWS Systems Manager #------------------------------------------------- VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: true EnableDnsHostnames: true InstanceTenancy: default Tags: - Key: Name Value: SSM-Workshop-CF InternetGateway: Type: 'AWS::EC2::InternetGateway' Properties: Tags: - Key: Name Value: SSM-Workshop-CF VPCGatewayAttachment: Type: 'AWS::EC2::VPCGatewayAttachment' Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway SubnetPublic: Type: 'AWS::EC2::Subnet' Properties: AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: 10.0.0.0/20 MapPublicIpOnLaunch: true VpcId: !Ref VPC Tags: - Key: Name Value: SSM-Workshop-CF RouteTablePublic: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref VPC Tags: - Key: Name Value: SSM-Workshop-CF RouteTableAssociationPublic: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref SubnetPublic RouteTableId: !Ref RouteTablePublic RouteTablePublicInternetRoute: Type: 'AWS::EC2::Route' DependsOn: VPCGatewayAttachment Properties: RouteTableId: !Ref RouteTablePublic DestinationCidrBlock: '0.0.0.0/0' GatewayId: !Ref InternetGateway NetworkAclPublic: Type: 'AWS::EC2::NetworkAcl' Properties: VpcId: !Ref VPC Tags: - Key: Name Value: SSM-Workshop-CF SubnetNetworkAclAssociationPublic: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref SubnetPublic NetworkAclId: !Ref NetworkAclPublic NetworkAclEntryInPublicAllowAll: Type: 'AWS::EC2::NetworkAclEntry' Properties: NetworkAclId: !Ref NetworkAclPublic RuleNumber: 100 Protocol: -1 RuleAction: allow Egress: false CidrBlock: '0.0.0.0/0' NetworkAclEntryOutPublicAllowAll: Type: 'AWS::EC2::NetworkAclEntry' Properties: NetworkAclId: !Ref NetworkAclPublic RuleNumber: 100 Protocol: -1 RuleAction: allow Egress: true CidrBlock: '0.0.0.0/0' InstanceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: "Security Group for SSM Workshop test instances" GroupName: SSM-Workshop-CF SecurityGroupEgress: - IpProtocol: -1 FromPort: 0 ToPort: 65535 CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: SSM-Workshop-CF VpcId: !Ref VPC #------------------------------------------------- # Four Amazon Linux 2 EC2 instances using the latest AMI for Amazon Linux 2 #------------------------------------------------- LinuxEc2InstanceOne: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: !Ref LatestAmazonLinuxAmiId NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" GroupSet: - Ref: "InstanceSecurityGroup" SubnetId: Ref: "SubnetPublic" IamInstanceProfile: !Sub 'ManagedInstanceProfile-${AWS::Region}' Tags: - Key: Name Value: App1 - Key: Patch Value: 'true' LinuxEc2InstanceTwo: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: !Ref LatestAmazonLinuxAmiId NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" GroupSet: - Ref: "InstanceSecurityGroup" SubnetId: Ref: "SubnetPublic" IamInstanceProfile: !Sub 'ManagedInstanceProfile-${AWS::Region}' Tags: - Key: Name Value: App2 - Key: Patch Value: 'true' LinuxEc2InstanceThree: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: !Ref LatestAmazonLinuxAmiId NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" GroupSet: - Ref: "InstanceSecurityGroup" SubnetId: Ref: "SubnetPublic" IamInstanceProfile: !Sub 'ManagedInstanceProfile-${AWS::Region}' Tags: - Key: Name Value: Web1 - Key: Patch Value: 'true' LinuxEc2InstanceFour: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: !Ref LatestAmazonLinuxAmiId NetworkInterfaces: - AssociatePublicIpAddress: "true" DeviceIndex: "0" GroupSet: - Ref: "InstanceSecurityGroup" SubnetId: Ref: "SubnetPublic" IamInstanceProfile: !Sub 'ManagedInstanceProfile-${AWS::Region}' Tags: - Key: Name Value: Web2 - Key: Patch Value: 'true' Outputs: ResouceSyncBucketName: Description: The name of the S3 bucket used to store resource data sync details. Value: !Ref ResouceSyncBucket CommandLogsBucketName: Description: The name of the S3 bucket used to store command logs centrally. Value: !Ref CommandLogsBucket