--- AWSTemplateFormatVersion: '2010-09-09' Description: 'This template is for the blog Monitoring Server Fleets with Advanced Amazon CloudWatch Agent Capabilities. WARNING: This template creates multiple EC2 instances, and custom CloudWatch metrics. You will be billed for the AWS resources used if you create a stack from this template' Parameters: VpcProdBlock: Type: String Default: 10.0.0.0/16 Description: The CIDR range for the Prod VPC. This should be a valid private (RFC 1918) CIDR range. CIDR block parameter must be in the form x.x.x.x/16-28 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ VpcTestBlock: Type: String Default: 10.1.0.0/16 Description: The CIDR range for the Test VPC. This should be a valid private (RFC 1918) CIDR range. CIDR block parameter must be in the form x.x.x.x/16-28 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ ProdSubnetABlock: Type: String Default: 10.0.0.0/24 Description: CidrBlock for the first prod subnet within the VPC.This should be a valid private (RFC 1918) CIDR range. CIDR block parameter must be in the form x.x.x.x/16-28 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ ProdSubnetBBlock: Type: String Default: 10.0.1.0/24 Description: CidrBlock for the second prod subnet within the VPC.This should be a valid private (RFC 1918) CIDR range. CIDR block parameter must be in the form x.x.x.x/16-28 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ TestSubnetABlock: Type: String Default: 10.1.0.0/24 Description: CidrBlock for the first test subnet within the VPC.This should be a valid private (RFC 1918) CIDR range. CIDR block parameter must be in the form x.x.x.x/16-28 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ TestSubnetBBlock: Type: String Default: 10.1.1.0/24 Description: CidrBlock for the second test subnet within the VPC.This should be a valid private (RFC 1918) CIDR range. CIDR block parameter must be in the form x.x.x.x/16-28 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ AMI: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' #Default: ami-047a51fa27710816e Description: The Amazon Linux 2 AMI ID in the region (us-east-1) Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Production Network Configuration" Parameters: - VpcProdBlock - ProdSubnetABlock - ProdSubnetBBlock - Label: default: "Test Network Configuration" Parameters: - VpcTestBlock - TestSubnetABlock - TestSubnetBBlock Resources: #VPCs VPCProd: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcProdBlock EnableDnsSupport: true EnableDnsHostnames: true VPCTest: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcTestBlock EnableDnsSupport: true EnableDnsHostnames: true #Subnets ProdSubnetA: Type: AWS::EC2::Subnet Metadata: Comment: Subnet Properties: MapPublicIpOnLaunch: true AvailabilityZone: Fn::Select: - '0' - Fn::GetAZs: Ref: AWS::Region CidrBlock: Ref: ProdSubnetABlock VpcId: Ref: VPCProd ProdSubnetB: Type: AWS::EC2::Subnet Metadata: Comment: Subnet Properties: MapPublicIpOnLaunch: true AvailabilityZone: Fn::Select: - '1' - Fn::GetAZs: Ref: AWS::Region CidrBlock: Ref: ProdSubnetBBlock VpcId: Ref: VPCProd TestSubnetA: Type: AWS::EC2::Subnet Metadata: Comment: Subnet Properties: MapPublicIpOnLaunch: true AvailabilityZone: Fn::Select: - '2' - Fn::GetAZs: Ref: AWS::Region CidrBlock: Ref: TestSubnetABlock VpcId: Ref: VPCTest TestSubnetB: Type: AWS::EC2::Subnet Metadata: Comment: Subnet Properties: MapPublicIpOnLaunch: true AvailabilityZone: Fn::Select: - '2' - Fn::GetAZs: Ref: AWS::Region CidrBlock: Ref: TestSubnetBBlock VpcId: Ref: VPCTest #IGWs and VPC attachments IGWProd: Type: AWS::EC2::InternetGateway DependsOn: VPCProd IGWTest: Type: AWS::EC2::InternetGateway DependsOn: VPCTest IGWProdAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPCProd InternetGatewayId: !Ref IGWProd IGWTestAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPCTest InternetGatewayId: !Ref IGWTest #Public Route tables ProdSubnetRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCProd Tags: - Key: Environment Value: Prod TestSubnetRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCTest Tags: - Key: Environment Value: Test #route table route entries ProdRoute1: Type: AWS::EC2::Route DependsOn: IGWProdAttachment Properties: RouteTableId: !Ref ProdSubnetRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref IGWProd TestRoute1: Type: AWS::EC2::Route DependsOn: IGWTestAttachment Properties: RouteTableId: !Ref TestSubnetRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref IGWTest #route table- subnet associations ProdSubnetARouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref ProdSubnetA RouteTableId: !Ref ProdSubnetRouteTable ProdSubnetBRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref ProdSubnetB RouteTableId: !Ref ProdSubnetRouteTable TestSubnetARouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref TestSubnetA RouteTableId: !Ref TestSubnetRouteTable TestSubnetBRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref TestSubnetB RouteTableId: !Ref TestSubnetRouteTable #Production AutoScaling Group and Launch Template ProductionASG: Type: AWS::AutoScaling::AutoScalingGroup Properties: MinSize: '2' MaxSize: '4' DesiredCapacity: '2' LaunchTemplate: LaunchTemplateId: !Ref ProductionLaunchTemplate Version: !GetAtt ProductionLaunchTemplate.LatestVersionNumber VPCZoneIdentifier: - !Ref ProdSubnetA - !Ref ProdSubnetB MetricsCollection: - Granularity: "1Minute" Metrics: - "GroupMinSize" - "GroupMaxSize" Tags: - Key: Environment Value: Production PropagateAtLaunch: true - Key: ApplicationName Value: ApplicationA PropagateAtLaunch: true ProductionLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Sub ${AWS::StackName}-launch-template-prod LaunchTemplateData: BlockDeviceMappings: - Ebs: VolumeSize: 8 VolumeType: gp3 DeleteOnTermination: true Encrypted: true DeviceName: /dev/xvdcz ImageId: !Ref AMI InstanceType: t3.micro IamInstanceProfile: Arn: !GetAtt 'BlogEC2InstanceProfile.Arn' Monitoring: Enabled: true SecurityGroupIds: - !Ref BlogEC2InstanceSecurityGroupProd UserData: Fn::Base64: | #!/bin/bash # Install all pending updates to the system yum -y update #install cloudwatch agent yum -y install amazon-cloudwatch-agent #install collectd amazon-linux-extras install collectd -y #install Apache yum -y install httpd chkconfig httpd on service httpd start /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c ssm:AmazonCloudWatch-applicationA-prod #Production AutoScaling Group and Launch Template TestASG: Type: AWS::AutoScaling::AutoScalingGroup Properties: MinSize: '2' MaxSize: '2' DesiredCapacity: '2' LaunchTemplate: LaunchTemplateId: !Ref TestLaunchTemplate Version: !GetAtt TestLaunchTemplate.LatestVersionNumber VPCZoneIdentifier: - !Ref TestSubnetA - !Ref TestSubnetB MetricsCollection: - Granularity: "1Minute" Metrics: - "GroupMinSize" - "GroupMaxSize" Tags: - Key: Environment Value: Test PropagateAtLaunch: true - Key: ApplicationName Value: ApplicationA PropagateAtLaunch: true TestLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Sub ${AWS::StackName}-launch-template-test LaunchTemplateData: BlockDeviceMappings: - Ebs: VolumeSize: 8 VolumeType: gp3 DeleteOnTermination: true Encrypted: true DeviceName: /dev/xvdcz ImageId: !Ref AMI InstanceType: t3.nano IamInstanceProfile: Arn: !GetAtt 'BlogEC2InstanceProfile.Arn' Monitoring: Enabled: true SecurityGroupIds: - !Ref BlogEC2InstanceSecurityGroupTest UserData: Fn::Base64: | #!/bin/bash # Install all pending updates to the system yum -y update #install cloudwatch agent yum -y install amazon-cloudwatch-agent #install collectd amazon-linux-extras install collectd -y #install Apache yum -y install httpd chkconfig httpd on service httpd start /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c ssm:AmazonCloudWatch-applicationA-test #ssm parameter store parameters ApplicationAProdConfig: Type: AWS::SSM::Parameter Properties: Name: AmazonCloudWatch-applicationA-prod Type: String Value: | { "agent": { "metrics_collection_interval": 10, "run_as_user": "root" }, "metrics": { "metrics_collected": { "collectd": { "metrics_aggregation_interval": 60 }, "cpu": { "measurement": ["cpu_usage_user","cpu_usage_system"], "metrics_collection_interval": 60, "totalcpu": true, "append_dimensions": { "ApplicationName": "ApplicationA", "Environment": "prod", "MetricType": "infra" } }, "mem": { "measurement": ["mem_used_percent"], "metrics_collection_interval": 60, "append_dimensions": { "ApplicationName": "ApplicationA", "Environment": "prod", "MetricType": "infra" } }, "procstat": [ { "exe": "httpd", "measurement": ["cpu_usage","memory_data","memory_swap"], "metrics_collection_interval": 60, "append_dimensions": { "ApplicationName": "ApplicationA", "Environment": "prod", "MetricType": "process" } } ] }, "append_dimensions": { "InstanceId": "${aws:InstanceId}", "AutoScalingGroupName": "${aws:AutoScalingGroupName}" }, "aggregation_dimensions": [ ["AutoScalingGroupName"], ["InstanceId"], ["Environment"] ] } } Description: SSM Parameter for ApplicationA's CloudWatch agent prod config. Tags: ApplicationName: ApplicationA ApplicationATestConfig: Type: AWS::SSM::Parameter Properties: Name: AmazonCloudWatch-applicationA-test Type: String Value: | { "agent": { "metrics_collection_interval": 10, "run_as_user": "root" }, "metrics": { "metrics_collected": { "collectd": { "metrics_aggregation_interval": 60 }, "cpu": { "measurement": ["cpu_usage_user","cpu_usage_system"], "metrics_collection_interval": 60, "totalcpu": true, "append_dimensions": { "ApplicationName": "ApplicationA", "Environment": "test", "MetricType": "infra" } }, "mem": { "measurement": ["mem_used_percent"], "metrics_collection_interval": 60, "append_dimensions": { "ApplicationName": "ApplicationA", "Environment": "test", "MetricType": "infra" } }, "procstat": [ { "exe": "httpd", "measurement": ["cpu_usage","memory_data","memory_swap"], "metrics_collection_interval": 60, "append_dimensions": { "ApplicationName": "ApplicationA", "Environment": "test", "MetricType": "process" } } ] }, "append_dimensions": { "InstanceId": "${aws:InstanceId}", "AutoScalingGroupName": "${aws:AutoScalingGroupName}" }, "aggregation_dimensions": [ ["AutoScalingGroupName"], ["InstanceId"], ["Environment"] ] } } Description: SSM Parameter for ApplicationA's CloudWatch agent test config. Tags: ApplicationName: ApplicationA #ec2 instance related BlogEC2InstanceSecurityGroupProd: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EC2 Instance Security Group for Production EC2 instances VpcId: !Ref VPCProd BlogEC2InstanceSecurityGroupTest: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EC2 Instance Security Group for Test EC2 instances VpcId: !Ref VPCTest BlogEC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: BlogInstanceProfile Path: / Roles: - !Ref BlogEC2InstanceRole BlogEC2InstanceRole: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: sts:AssumeRole