AWSTemplateFormatVersion: '2010-09-09' Conditions: SendData: Fn::Equals: - Ref: SendAnonymousData - 'Yes' UseExistingBucket: Fn::Equals: - Ref: DBRBucketInput - 'Yes' UseExistingBucketNot: Fn::Equals: - Ref: DBRBucketInput - 'No' Description: (SO0010) - Cost Optimization Monitor - AWS CloudFormation Template for AWS Solutions Builder Cost Optimization Tool - Monitor - **WARNING** This template creates AWS resources. You will be billed for the AWS a stack from this template. Mappings: AmiMap: ap-northeast-1: HVM64: ami-9f0c67f8 ap-northeast-2: HVM64: ami-94bb6dfa ap-south-1: HVM64: ami-9fc7b0f0 ap-southeast-1: HVM64: ami-4dd6782e ap-southeast-2: HVM64: ami-28cff44b cn-north-1: HVM64: ami-29934444 eu-central-1: HVM64: ami-211ada4e eu-west-1: HVM64: ami-c51e3eb6 sa-east-1: HVM64: ami-bb40d8d7 us-east-1: HVM64: ami-9be6f38c us-east-2: HVM64: ami-38cd975d us-west-1: HVM64: ami-b73d6cd7 us-west-2: HVM64: ami-1e299d7e Function: KibanaUser: Password: kibanacosttoo! UserName: kibana ec2instanceSizing: elasticsearch: Large: m4.xlarge Medium: m4.large Small: t2.large esRegion2Type: ap-northeast-1: type: elasticsearchm3 ap-northeast-2: type: elasticsearchm4 ap-south-1: type: elasticsearchm4 ap-southeast-1: type: elasticsearchm3 ap-southeast-2: type: elasticsearchm3 cn-north-1: type: elasticsearchm3 eu-central-1: type: elasticsearchm3 eu-west-1: type: elasticsearchm3 sa-east-1: type: elasticsearchm3 us-east-1: type: elasticsearchm3 us-east-2: type: elasticsearchm4 us-west-1: type: elasticsearchm3 us-west-2: type: elasticsearchm3 esinstanceSizing: elasticsearchm3: Large: m3.xlarge.elasticsearch Medium: m3.large.elasticsearch Small: m3.medium.elasticsearch elasticsearchm4: Large: m4.xlarge.elasticsearch Medium: m4.large.elasticsearch Small: m4.large.elasticsearch esmasterSizing: elasticsearchm3: Large: m3.medium.elasticsearch Medium: t2.small.elasticsearch Small: t2.small.elasticsearch elasticsearchm4: Large: m4.large.elasticsearch Medium: t2.small.elasticsearch Small: t2.small.elasticsearch instanceCount: elasticsearch: Large: '8' Medium: '4' Small: '2' Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Proxy Configuration Parameters: - ProxyUsername - ProxyPass - SSHLocation - KeyName - Label: default: Amazon ES Domain Configuration Parameters: - ElasticsearchDomainName - ClusterSize - Label: default: Amazon S3 Bucket Configuration Parameters: - DBRBucketInput - DBRBucketName - Label: default: Network Settings Parameters: - VPCCidrparameter - Subnet1Cidrparameter - Subnet2Cidrparameter - Label: default: Send anonymous data to AWS Parameters: - SendAnonymousData ParameterLabels: ClusterSize: default: Cluster Size DBRBucketInput: default: Use existing bucket? DBRBucketName: default: Existing S3 bucket name ElasticsearchDomainName: default: Domain Name KeyName: default: SSH Key ProxyPass: default: Password ProxyUsername: default: User Name PubSubnet: default: Subnet Network SSHLocation: default: Access CIDR Block SendAnonymousData: default: Send Anonymous Usage Data Subnet1Cidrparameter: default: 1st Subnet Network Subnet2Cidrparameter: default: 2nd Subnet Network VPCCidrparameter: default: VPC CIDR block VpcCidr: default: VPC CIDR Block Outputs: BucketName: Description: Bucket for storing Detailed Billing Records Value: Fn::If: - UseExistingBucket - Ref: DBRBucketName - Ref: S3DBRBucket ConsolidatedDashboardURL: Description: Consolidated Account Dashboard Value: Fn::Join: - '' - - http:// - Fn::GetAtt: - ELB - DNSName - /_plugin/kibana/#/dashboard/Consolidated-Account-Dashboard?_g=%28refreshInterval:%28display:Off,pause:!f,section:0,value:0%29,time:%28from:now%2FM,mode:quick,to:now%2FM%29%29 SingleDashboardURL: Description: Single Account Dashboard Value: Fn::Join: - '' - - http:// - Fn::GetAtt: - ELB - DNSName - /_plugin/kibana/#/dashboard/Single-Account-Dashboard?_g=%28refreshInterval:%28display:Off,pause:!f,section:0,value:0%29,time:%28from:now%2FM,mode:quick,to:now%2FM%29%29 UUID: Description: Newly created random anonymous UUID. Value: Fn::GetAtt: - CreateUniqueID - UUID Parameters: ClusterSize: AllowedValues: - Small - Medium - Large Default: Small Description: 'Amazon ES cluster size: small, medium, large' Type: String DBRBucketInput: AllowedValues: - 'Yes' - 'No' Default: 'No' Description: Select Yes if you want to use an existing S3 bucket to store detailed billing reports Type: String DBRBucketName: Description: If you selected Yes for the previous parameter, type the name of existing S3 bucket name that you want to use to store billing reports. If you selected No, leave this field empty Type: String ElasticsearchDomainName: AllowedPattern: '[a-z][a-z0-9\-]+' Default: comdomain Description: 'Name for the Amazon ES domain that this template will create. Note: Domain names must start with a lowercase letter and must be between 3 and 28 characters. Valid characters are a-z (lowercase only), 0-9, and - (hyphen)' Type: String KeyName: ConstraintDescription: must be the name of an existing EC2 KeyPair. Description: Existing Amazon EC2 key pair for SSH access to the instances to the Nginx proxy server Type: AWS::EC2::KeyPair::KeyName ProxyPass: AllowedPattern: ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&+=])(?=\S+$).{6,}$ ConstraintDescription: Must contain at least 1 Upper/Lower alphanumeric characters, number and !@#$%& (Mininum lenght is 6) Description: Password for dashboard access via the proxy server MaxLength: '41' MinLength: '6' NoEcho: 'true' Type: String ProxyUsername: Description: User name for dashboard access via the proxy server Type: String SSHLocation: AllowedPattern: (\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. Description: IP address range that can access the Nginx proxy server MaxLength: '18' MinLength: '9' Type: String SendAnonymousData: AllowedValues: - 'Yes' - 'No' Default: 'No' Description: Send anonymous data to AWS Type: String Subnet1Cidrparameter: AllowedPattern: (\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. Default: 10.250.250.0/24 Description: IP address range for subnet created in AZ1 MaxLength: '18' MinLength: '9' Type: String Subnet2Cidrparameter: AllowedPattern: (\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. Default: 10.250.251.0/24 Description: IP address range for subnet created in AZ2 MaxLength: '18' MinLength: '9' Type: String VPCCidrparameter: AllowedPattern: (\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. Default: 10.250.0.0/16 Description: CIDR block for VPC MaxLength: '18' MinLength: '9' Type: String Resources: CreateUniqueID: Properties: CreateUniqueID: 'true' Region: Ref: AWS::Region ServiceToken: Fn::GetAtt: - SolutionHelper - Arn Type: Custom::LoadLambda ELB: Properties: CrossZone: 'true' HealthCheck: HealthyThreshold: '3' Interval: '30' Target: TCP:80 Timeout: '5' UnhealthyThreshold: '5' Instances: - Ref: ProxyServer1 - Ref: ProxyServer2 Listeners: - InstancePort: '80' LoadBalancerPort: '80' Protocol: HTTP LoadBalancerName: Fn::Join: - '' - - cost-optim-elb- - Ref: AWS::Region SecurityGroups: - Fn::GetAtt: - ELBSecurityGroup - GroupId Subnets: - Ref: VPCPubSub1 - Ref: VPCPubSub2 Type: AWS::ElasticLoadBalancing::LoadBalancer ELBSecurityGroup: Properties: GroupDescription: ELB - Port 80 access SecurityGroupIngress: - CidrIp: Ref: SSHLocation FromPort: '80' IpProtocol: tcp ToPort: '80' VpcId: Ref: VPC Type: AWS::EC2::SecurityGroup IGW: Properties: Tags: - Key: Name Value: Monitor VPC IGW Type: AWS::EC2::InternetGateway IGWToInternet: Properties: InternetGatewayId: Ref: IGW VpcId: Ref: VPC Type: AWS::EC2::VPCGatewayAttachment MyElasticsearchDomain: Properties: AccessPolicies: Statement: - Action: es:* Condition: IpAddress: aws:SourceIp: - Ref: ProxyServer1EIP - Ref: ProxyServer2EIP Effect: Allow Principal: AWS: '*' Resource: Fn::Join: - '' - - 'arn:aws:es:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - :domain/ - Ref: ElasticsearchDomainName - /* Sid: IP restriction - Action: es:* Effect: Allow Principal: AWS: Fn::Join: - '' - - Fn::GetAtt: - ProxyServerRole - Arn Resource: Fn::Join: - '' - - 'arn:aws:es:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - :domain/ - Ref: ElasticsearchDomainName - /* Sid: EC2-Role restriction Version: '2012-10-17' AdvancedOptions: rest.action.multi.allow_explicit_index: 'true' DomainName: Ref: ElasticsearchDomainName EBSOptions: EBSEnabled: 'true' VolumeSize: '20' VolumeType: gp2 ElasticsearchClusterConfig: DedicatedMasterCount: '3' DedicatedMasterEnabled: 'true' DedicatedMasterType: Fn::FindInMap: - esmasterSizing - Fn::FindInMap: - esRegion2Type - Ref: AWS::Region - type - Ref: ClusterSize InstanceCount: Fn::FindInMap: - instanceCount - elasticsearch - Ref: ClusterSize InstanceType: Fn::FindInMap: - esinstanceSizing - Fn::FindInMap: - esRegion2Type - Ref: AWS::Region - type - Ref: ClusterSize ZoneAwarenessEnabled: 'true' ElasticsearchVersion: '2.3' Type: AWS::Elasticsearch::Domain ProxyServer1: CreationPolicy: ResourceSignal: Timeout: PT15M DependsOn: VPCPubSubnet1RouteTableAssociation Metadata: AWS::CloudFormation::Init: configSets: Monitor_install: - install_cfn - install_nginx - configure_nginx - install_awsdbrparser - install_estool - populate_es configure_nginx: commands: 0-setup: command: /tmp/setup.nginx cwd: /home/ec2-user install_awsdbrparser: commands: 0-git_clone: command: git clone https://github.com/awslabs/aws-detailed-billing-parser.git cwd: /home/ec2-user 1-python_setup: command: python setup.py install cwd: /home/ec2-user/aws-detailed-billing-parser 2-dbr_setup: command: /tmp/setup.dbr cwd: /home/ec2-user install_cfn: files: /etc/cfn/cfn-hup.conf: content: Fn::Join: - "" - - "[main]\n" - "stack=" - Ref: AWS::StackId - "\n" - "region=" - Ref: AWS::Region - "\n" group: root mode: '000400' owner: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: Fn::Join: - "" - - "[cfn-auto-reloader-hook]\n" - "triggers=post.update\n" - "path=Resources.ProxyServer1.Metadata.AWS::CloudFormation::Init\n" - "action=/opt/aws/bin/cfn-init -v " - " --stack " - Ref: AWS::StackName - " --resource ProxyServer1 " - " --configsets Monitor_install " - " --region " - Ref: AWS::Region - "\n" group: root mode: '000400' owner: root services: sysvinit: cfn-hup: enabled: 'true' ensureRunning: 'true' files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf install_estool: commands: 0-git_clone: command: wget https://s3.amazonaws.com/solutions-reference/cost-optimization/v2/es_tools-0.1.4.tar.gz cwd: /home/ec2-user 1-python_setup: command: pip install es_tools-0.1.4.tar.gz cwd: /home/ec2-user 2-kibana_index: command: wget https://s3.amazonaws.com/solutions-reference/cost-optimization/v2/export.json cwd: /tmp/ 3-import_dashboard: command: sh /tmp/es.sh install_nginx: files: /etc/nginx/default.d/default.conf: content: Fn::Join: - "" - - "location / {\n" - " resolver resolver-ip;\n" - " set $es " - Fn::GetAtt: - MyElasticsearchDomain - DomainEndpoint - ";\n" - " auth_basic 'Restricted';\n" - " auth_basic_user_file /etc/nginx/conf.d/kibana.htpasswd;\n" - " proxy_pass_request_headers off;\n" - " proxy_set_header Host $host;\n" - " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n" - " proxy_pass http://$es;" - "}\n" group: root mode: '000644' owner: root /tmp/crontab: content: Fn::Join: - "" - - "#Content to include in the user crontab.\n" - "#You can just create the file first and then copy to the crontab folder\n" - "\n" - "#Without this path the user wont find the dbrparser program\n" - "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/dbrparser/.local/bin:/home/dbrparser/bin\n" - "\n" - "# m h dom mon dow usercommand\n" - "00 23 * * * /home/dbrparser/dbr-job/job.sh >>/home/dbrparser/dbr-job/job.log\n" - "30 23 1 * * /home/dbrparser/dbr-job/job.sh -pm >>/home/dbrparser/dbr-job/job.log\n" group: root mode: '000400' owner: root /tmp/es.sh: content: Fn::Join: - "" - - "#!/bin/bash -v\n" - "\n" - "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/ec2-user/.local/bin:/home/ec2-user/bin\n" - "es-import -r" - Ref: AWS::Region - " -e " - Fn::GetAtt: - MyElasticsearchDomain - DomainEndpoint - " -p 80 -f /tmp/export.json" group: root mode: '000700' owner: root /tmp/setup.dbr: content: Fn::Join: - "" - - "adduser dbrparser\n" - "mkdir /home/dbrparser/dbr-job\n" - "cp /tmp/crontab /home/dbrparser/crontab\n" - "cp /home/ec2-user/aws-detailed-billing-parser/job.sh /home/dbrparser/dbr-job\n" - "sed -i 's/bucket-123456/" - Fn::If: - UseExistingBucket - Ref: DBRBucketName - Fn::GetAtt: - S3DBRBucket - DomainName - "/g' /home/dbrparser/dbr-job/job.sh\n" - "sed -i 's:.s3.amazonaws.com::g' /home/dbrparser/dbr-job/job.sh\n" - "sed -i 's/123456789012/" - Ref: AWS::AccountId - "/g' /home/dbrparser/dbr-job/job.sh\n" - "sed -i 's#/mnt/jobs#/home/dbrparser/dbr-job#g' /home/dbrparser/dbr-job/job.sh\n" - "sed -i 's/elastic-search-host.endopoint.name/" - Fn::GetAtt: - MyElasticsearchDomain - DomainEndpoint - "/g' /home/dbrparser/dbr-job/job.sh\n" - "chown -R dbrparser:dbrparser /home/dbrparser/dbr-job\n" - "chmod +x /home/dbrparser/dbr-job/job.sh\n" - "#try the initial import with awsauth option\n" - "# the initial import still doesn't work but leaving this code in for future reference\n" - "cp /home/dbrparser/dbr-job/job.sh /home/dbrparser/dbr-job/jobawsauth.sh\n" - "sed -i 's#--delete-index \ufffdbi#--delete-index \ufffdbi --awsauth#g' /home/dbrparser/dbr-job/jobawsauth.sh\n" - "crontab -u dbrparser /home/dbrparser/crontab\n" - "\n" group: root mode: '000700' owner: root /tmp/setup.nginx: content: Fn::Join: - "" - - "#!/bin/bash\n" - "yum update -y\n" - "sed -i 's/elastic-search-host.endopoint.name/" - Fn::GetAtt: - MyElasticsearchDomain - DomainEndpoint - "/g' /etc/nginx/default.d/default.conf\n" - "nameserver=$(cat /etc/resolv.conf | grep nameserver | cut -d ' ' -f 2)\n" - "sed -i 's/resolver-ip/'$nameserver'/g' /etc/nginx/default.d/default.conf\n" group: root mode: '000700' owner: root packages: yum: git: [] nginx: [] services: sysvinit: nginx: enabled: 'true' populate_es: commands: 0-run_dbrparser: command: su - dbrparser -c '/home/dbrparser/dbr-job/jobawsauth.sh >>/home/dbrparser/dbr-job/jobawsauth.log' cwd: /home/dbrparser/dbr-job Properties: IamInstanceProfile: Ref: ProxyServerInstanceProfile ImageId: Fn::FindInMap: - AmiMap - Ref: AWS::Region - HVM64 InstanceType: Fn::FindInMap: - ec2instanceSizing - elasticsearch - Ref: ClusterSize KeyName: Ref: KeyName NetworkInterfaces: - AssociatePublicIpAddress: 'true' DeviceIndex: '0' GroupSet: - Ref: ProxyServerSecurityGroup SubnetId: Ref: VPCPubSub1 UserData: Fn::Base64: Fn::Join: - "" - - "#!/bin/bash -xe\n" - "yum update -y aws-cfn-bootstrap\n" - "/opt/aws/bin/cfn-init -v " - " --stack " - Ref: AWS::StackName - " --resource ProxyServer1 " - " --configsets Monitor_install " - " --region " - Ref: AWS::Region - "\n" - "/opt/aws/bin/cfn-signal -e $? " - " --stack " - Ref: AWS::StackName - " --resource ProxyServer1 " - " --region " - Ref: AWS::Region - "\n" - "# Create a new username/password for nginx\n" - "printf " - Ref: ProxyUsername - ":`openssl passwd -apr1 " - Ref: ProxyPass - "` >> /etc/nginx/conf.d/kibana.htpasswd\n" - "# Remove the default location from nginx config\n" - "sed -ri '/location \\//,/.*\\}/d' /etc/nginx/nginx.conf\n" - "service nginx restart" Type: AWS::EC2::Instance ProxyServer1Alarm: Properties: AlarmActions: - Fn::Join: - '' - - 'arn:aws:automate:' - Ref: AWS::Region - :ec2:recover AlarmDescription: Trigger a recovery when instance status check fails for 15 consecutive minutes. ComparisonOperator: GreaterThanThreshold Dimensions: - Name: InstanceId Value: Ref: ProxyServer1 EvaluationPeriods: '15' MetricName: StatusCheckFailed_System Namespace: AWS/EC2 Period: '60' Statistic: Minimum Threshold: '0' Type: AWS::CloudWatch::Alarm ProxyServer1EIP: DependsOn: VPCPubSubnet1RouteTableAssociation Properties: Domain: vpc Type: AWS::EC2::EIP ProxyServer1EIPAssoc: Properties: AllocationId: Fn::GetAtt: - ProxyServer1EIP - AllocationId InstanceId: Ref: ProxyServer1 Type: AWS::EC2::EIPAssociation ProxyServer2: CreationPolicy: ResourceSignal: Timeout: PT15M DependsOn: VPCPubSubnet2RouteTableAssociation Metadata: AWS::CloudFormation::Init: configSets: Monitor_install: - install_cfn - install_nginx - configure_nginx configure_nginx: commands: 0-setup: command: /tmp/setup.nginx cwd: /home/ec2-user install_cfn: files: /etc/cfn/cfn-hup.conf: content: Fn::Join: - "" - - "[main]\n" - "stack=" - Ref: AWS::StackId - "\n" - "region=" - Ref: AWS::Region - "\n" group: root mode: '000400' owner: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: Fn::Join: - "" - - "[cfn-auto-reloader-hook]\n" - "triggers=post.update\n" - "path=Resources.ProxyServer2.Metadata.AWS::CloudFormation::Init\n" - "action=/opt/aws/bin/cfn-init -v " - " --stack " - Ref: AWS::StackName - " --resource ProxyServer2 " - " --configsets Monitor_install " - " --region " - Ref: AWS::Region - "\n" group: root mode: '000400' owner: root services: sysvinit: cfn-hup: enabled: 'true' ensureRunning: 'true' files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf install_nginx: files: /etc/nginx/default.d/default.conf: content: Fn::Join: - "" - - "location / {\n" - " resolver resolver-ip;\n" - " set $es " - Fn::GetAtt: - MyElasticsearchDomain - DomainEndpoint - ";\n" - " auth_basic 'Restricted';\n" - " auth_basic_user_file /etc/nginx/conf.d/kibana.htpasswd;\n" - " proxy_pass_request_headers off;\n" - " proxy_set_header Host $host;\n" - " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n" - " proxy_pass http://$es;" - "}\n" group: root mode: '000644' owner: root /tmp/setup.nginx: content: Fn::Join: - "" - - "sed -i 's/elastic-search-host.endopoint.name/" - Fn::GetAtt: - MyElasticsearchDomain - DomainEndpoint - "/g' /etc/nginx/default.d/default.conf\n" - "nameserver=$(cat /etc/resolv.conf | grep nameserver | cut -d ' ' -f 2)\n" - "sed -i 's/resolver-ip/'$nameserver'/g' /etc/nginx/default.d/default.conf\n" group: root mode: '000700' owner: root packages: yum: git: [] nginx: [] services: sysvinit: nginx: enabled: 'true' Properties: IamInstanceProfile: Ref: ProxyServerInstanceProfile ImageId: Fn::FindInMap: - AmiMap - Ref: AWS::Region - HVM64 InstanceType: Fn::FindInMap: - ec2instanceSizing - elasticsearch - Ref: ClusterSize KeyName: Ref: KeyName NetworkInterfaces: - AssociatePublicIpAddress: 'true' DeviceIndex: '0' GroupSet: - Ref: ProxyServerSecurityGroup SubnetId: Ref: VPCPubSub2 UserData: Fn::Base64: Fn::Join: - "" - - "#!/bin/bash -xe\n" - "yum update -y aws-cfn-bootstrap\n" - "/opt/aws/bin/cfn-init -v " - " --stack " - Ref: AWS::StackName - " --resource ProxyServer2 " - " --configsets Monitor_install " - " --region " - Ref: AWS::Region - "\n" - "/opt/aws/bin/cfn-signal -e $? " - " --stack " - Ref: AWS::StackName - " --resource ProxyServer2 " - " --region " - Ref: AWS::Region - "\n" - "# Create a new username/password for nginx\n" - "printf " - Ref: ProxyUsername - ":`openssl passwd -apr1 " - Ref: ProxyPass - "` >> /etc/nginx/conf.d/kibana.htpasswd\n" - "# Remove the default location from nginx config\n" - "sed -ri '/location \\//,/.*\\}/d' /etc/nginx/nginx.conf\n" - "service nginx restart" Type: AWS::EC2::Instance ProxyServer2Alarm: Properties: AlarmActions: - Fn::Join: - '' - - 'arn:aws:automate:' - Ref: AWS::Region - :ec2:recover AlarmDescription: Trigger a recovery when instance status check fails for 15 consecutive minutes. ComparisonOperator: GreaterThanThreshold Dimensions: - Name: InstanceId Value: Ref: ProxyServer2 EvaluationPeriods: '15' MetricName: StatusCheckFailed_System Namespace: AWS/EC2 Period: '60' Statistic: Minimum Threshold: '0' Type: AWS::CloudWatch::Alarm ProxyServer2EIP: DependsOn: VPCPubSubnet2RouteTableAssociation Properties: Domain: vpc Type: AWS::EC2::EIP ProxyServer2EIPAssoc: Properties: AllocationId: Fn::GetAtt: - ProxyServer2EIP - AllocationId InstanceId: Ref: ProxyServer2 Type: AWS::EC2::EIPAssociation ProxyServerInstanceProfile: Properties: Path: / Roles: - Ref: ProxyServerRole Type: AWS::IAM::InstanceProfile ProxyServerRole: Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - ec2.amazonaws.com Version: '2012-10-17' Path: / Policies: - PolicyDocument: Statement: - Action: - s3:GetObject Effect: Allow Resource: Fn::Join: - '' - - 'arn:aws:s3:::' - Fn::If: - UseExistingBucket - Ref: DBRBucketName - Ref: S3DBRBucket - '*' Version: '2012-10-17' PolicyName: ProxyServerRole Type: AWS::IAM::Role ProxyServerSecurityGroup: Properties: GroupDescription: Enable HTTP access via port 80 locked down to the load balancer + SSH access SecurityGroupIngress: - CidrIp: Ref: SSHLocation FromPort: '80' IpProtocol: tcp ToPort: '80' - CidrIp: Ref: SSHLocation FromPort: '22' IpProtocol: tcp ToPort: '22' - FromPort: '80' IpProtocol: tcp SourceSecurityGroupId: Fn::GetAtt: - ELBSecurityGroup - GroupId ToPort: '80' VpcId: Ref: VPC Type: AWS::EC2::SecurityGroup S3DBRBucket: Condition: UseExistingBucketNot Type: AWS::S3::Bucket DeletionPolicy: Retain S3DBRBucketPolicy: Condition: UseExistingBucketNot Properties: Bucket: Ref: S3DBRBucket PolicyDocument: Statement: - Action: - s3:GetBucketAcl - s3:GetBucketPolicy Effect: Allow Principal: AWS: '386209384616' Resource: Fn::Join: - '' - - 'arn:aws:s3:::' - Ref: S3DBRBucket - Action: s3:PutObject Effect: Allow Principal: AWS: '386209384616' Resource: Fn::Join: - '' - - 'arn:aws:s3:::' - Ref: S3DBRBucket - /* Version: '2012-10-17' Type: AWS::S3::BucketPolicy SendingAnonymousData: Condition: SendData Properties: SendAnonymousData: Fn::Join: - "" - - "{ 'Solution' : '" - "SO00010" - "', " - "'UUID' : '" - Fn::GetAtt: - CreateUniqueID - UUID - "', " - "'Data': {" - "'ClusterSize': '" - Ref: ClusterSize - "'" - "}" - "}" ServiceToken: Fn::GetAtt: - SolutionHelper - Arn Type: Custom::LoadLambda SolutionHelper: Properties: Code: S3Bucket: Fn::Join: - '' - - solutions- - Ref: AWS::Region S3Key: library/solution-helper/v3/solution-helper.zip Description: This function creates a CloudFormation custom lambda resource that creates custom lambda functions by finding and replacing specific values from existing lambda function code. Handler: solution-helper.lambda_handler Role: Fn::GetAtt: - SolutionHelperRole - Arn Runtime: python2.7 Timeout: '300' Type: AWS::Lambda::Function SolutionHelperRole: Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com Version: '2012-10-17' Path: / Policies: - PolicyDocument: Statement: - Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Effect: Allow Resource: Fn::Join: - '' - - 'arn:aws:logs:' - Ref: AWS::Region - ':' - Ref: AWS::AccountId - :log-group:/aws/lambda/* Version: '2012-10-17' PolicyName: Solution_Helper_Permissions Type: AWS::IAM::Role VPC: Properties: CidrBlock: Ref: VPCCidrparameter Tags: - Key: Name Value: Monitor VPC Type: AWS::EC2::VPC VPCPubSub1: Properties: AvailabilityZone: Fn::Select: - '0' - Fn::GetAZs: '' CidrBlock: Ref: Subnet1Cidrparameter Tags: - Key: Network Value: Public - Key: Name Value: Monitor VPC Subnet VpcId: Ref: VPC Type: AWS::EC2::Subnet VPCPubSub2: Properties: AvailabilityZone: Fn::Select: - '1' - Fn::GetAZs: '' CidrBlock: Ref: Subnet2Cidrparameter Tags: - Key: Network Value: Public - Key: Name Value: Monitor VPC Subnet VpcId: Ref: VPC Type: AWS::EC2::Subnet VPCPubSubnet1RouteTableAssociation: Properties: RouteTableId: Ref: VPCRouteTable SubnetId: Ref: VPCPubSub1 Type: AWS::EC2::SubnetRouteTableAssociation VPCPubSubnet2RouteTableAssociation: Properties: RouteTableId: Ref: VPCRouteTable SubnetId: Ref: VPCPubSub2 Type: AWS::EC2::SubnetRouteTableAssociation VPCPublicRoute: Properties: DestinationCidrBlock: 0.0.0.0/0 GatewayId: Ref: IGW RouteTableId: Ref: VPCRouteTable Type: AWS::EC2::Route VPCRouteTable: Properties: Tags: - Key: Network Value: Public - Key: Name Value: Monitor VPC VpcId: Ref: VPC Type: AWS::EC2::RouteTable