{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "AWS CloudFormation Sample Template for using Assertions: Create a load balanced, Auto Scaled sample website where the instances are locked down to only accept traffic from the load balancer. This example creates an Auto Scaling group behind a load balancer with a simple health check. The web site is available on port 80 or 443 based on the input. however, the instances can be configured to listen on any port (8888 by default). **WARNING** This template creates one or more Amazon EC2 instances and an Application Load Balancer. You will be billed for the AWS resources used if you create a stack from this template.", "Parameters" : { "VpcId" : { "Type" : "AWS::EC2::VPC::Id", "Description" : "VpcId of your existing Virtual Private Cloud (VPC)", "ConstraintDescription" : "must be the VPC Id of an existing Virtual Private Cloud." }, "Subnets" : { "Type" : "List", "Description" : "The list of SubnetIds in your Virtual Private Cloud (VPC)", "ConstraintDescription" : "must be a list of at least two existing subnets associated with at least two different availability zones. They should be residing in the selected Virtual Private Cloud." }, "InstanceType" : { "Description" : "WebServer EC2 instance type", "Type" : "String", "Default" : "t2.small", "AllowedValues" : [ "t2.nano", "t2.micro", "t2.small", "t2.medium", "t2.large", "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "r3.large", "r3.xlarge" ] , "ConstraintDescription" : "must be a valid EC2 instance type." }, "KeyName" : { "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances", "Type" : "AWS::EC2::KeyPair::KeyName", "ConstraintDescription" : "must be the name of an existing EC2 KeyPair." }, "SSHLocation" : { "Description" : "The IP address range that can be used to SSH to the EC2 instances", "Type": "String", "MinLength": "9", "MaxLength": "18", "Default": "0.0.0.0/0", "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." }, "UseSSL": { "AllowedValues": [ "Yes", "No" ], "ConstraintDescription": "Select Yes to create a HTTPS Listener", "Default": "No", "Description": "Select \"Yes\" to implement SSL, \"No\" to skip (default).", "Type": "String" }, "ALBSSLCertificateARN": { "Default": "", "Description": "[Optional] The ARN of the SSL certificate to be used for the Application Load Balancer", "Type": "String" }, "HostedZoneName": { "AllowedPattern": "^$|(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$", "Default": "", "Description": "[Optional] The domain name of a valid Hosted Zone on AWS.", "Type": "String" } }, "Conditions": { "UseALBSSL": { "Fn::Not": [ { "Fn::Equals": [ { "Ref": "UseSSL" }, "Yes" ] } ] } }, "Rules": { "SubnetsInVPC": { "Assertions": [ { "Assert": { "Fn::EachMemberIn": [ { "Fn::ValueOfAll": [ "AWS::EC2::Subnet::Id", "VpcId" ] }, { "Fn::RefAll": "AWS::EC2::VPC::Id" } ] }, "AssertDescription": "All subnets must in the VPC" } ] }, "ValidateHostedZone": { "RuleCondition": { "Fn::Equals": [ { "Ref": "UseSSL" }, "Yes" ] }, "Assertions": [ { "Assert":{ "Fn::Not": [ { "Fn::Equals": [ { "Ref": "ALBSSLCertificateARN" }, "" ] } ] }, "AssertDescription": "ACM Certificate value cannot be empty if SSL is required" }, { "Assert": { "Fn::Not": [ { "Fn::Equals": [ { "Ref": "HostedZoneName" }, "" ] } ] }, "AssertDescription": "Route53 Hosted Zone Name is mandatory when SSL is required" } ] } }, "Mappings" : { "AWSAMIRegionMap": { "AMI": { "AMZNLINUXHVM": "amzn-ami-hvm-2017.09.1.20171120-x86_64-gp2" }, "ap-northeast-1": { "AMZNLINUXHVM": "ami-da9e2cbc" }, "ap-northeast-2": { "AMZNLINUXHVM": "ami-1196317f" }, "ap-south-1": { "AMZNLINUXHVM": "ami-d5c18eba" }, "ap-southeast-1": { "AMZNLINUXHVM": "ami-c63d6aa5" }, "ap-southeast-2": { "AMZNLINUXHVM": "ami-ff4ea59d" }, "ca-central-1": { "AMZNLINUXHVM": "ami-d29e25b6" }, "eu-central-1": { "AMZNLINUXHVM": "ami-bf2ba8d0" }, "eu-west-1": { "AMZNLINUXHVM": "ami-1a962263" }, "eu-west-2": { "AMZNLINUXHVM": "ami-e7d6c983" }, "sa-east-1": { "AMZNLINUXHVM": "ami-286f2a44" }, "us-east-1": { "AMZNLINUXHVM": "ami-55ef662f" }, "us-east-2": { "AMZNLINUXHVM": "ami-15e9c770" }, "us-west-1": { "AMZNLINUXHVM": "ami-a51f27c5" }, "us-west-2": { "AMZNLINUXHVM": "ami-bf4193c7" } } }, "Resources" : { "WebServerGroup" : { "Type" : "AWS::AutoScaling::AutoScalingGroup", "Properties" : { "VPCZoneIdentifier" : { "Ref" : "Subnets" }, "LaunchConfigurationName" : { "Ref" : "LaunchConfig" }, "MinSize" : "2", "MaxSize" : "2", "TargetGroupARNs" : [ { "Ref" : "ALBTargetGroup" } ] }, "CreationPolicy" : { "ResourceSignal" : { "Timeout" : "PT15M" } }, "UpdatePolicy": { "AutoScalingRollingUpdate": { "MinInstancesInService": "1", "MaxBatchSize": "1", "PauseTime" : "PT15M", "WaitOnResourceSignals": "true" } } }, "LaunchConfig" : { "Type" : "AWS::AutoScaling::LaunchConfiguration", "Metadata" : { "Comment" : "Install a simple application", "AWS::CloudFormation::Init" : { "config" : { "packages" : { "yum" : { "httpd" : [] } }, "files" : { "/var/www/html/index.html" : { "content" : { "Fn::Join" : ["\n", [ "

Congratulations, you have successfully launched the AWS CloudFormation sample.

" ]]}, "mode" : "000644", "owner" : "root", "group" : "root" }, "/etc/cfn/cfn-hup.conf" : { "content" : { "Fn::Join" : ["", [ "[main]\n", "stack=", { "Ref" : "AWS::StackId" }, "\n", "region=", { "Ref" : "AWS::Region" }, "\n" ]]}, "mode" : "000400", "owner" : "root", "group" : "root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : { "content": { "Fn::Join" : ["", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource LaunchConfig ", " --region ", { "Ref" : "AWS::Region" }, "\n", "runas=root\n" ]]}, "mode" : "000400", "owner" : "root", "group" : "root" } }, "services" : { "sysvinit" : { "httpd" : { "enabled" : "true", "ensureRunning" : "true" }, "cfn-hup" : { "enabled" : "true", "ensureRunning" : "true", "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]} } } } } }, "Properties" : { "ImageId": { "Fn::FindInMap": [ "AWSAMIRegionMap", { "Ref": "AWS::Region" }, "AMZNLINUXHVM" ] }, "SecurityGroups" : [ { "Ref" : "InstanceSecurityGroup" } ], "InstanceType" : { "Ref" : "InstanceType" }, "KeyName" : { "Ref" : "KeyName" }, "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 LaunchConfig ", " --region ", { "Ref" : "AWS::Region" }, "\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource WebServerGroup ", " --region ", { "Ref" : "AWS::Region" }, "\n" ]]}} } }, "ELBSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "Allow access to the ELB", "VpcId": { "Ref": "VpcId" }, "SecurityGroupIngress": [ { "Fn::If": [ "UseALBSSL", { "IpProtocol": "tcp", "FromPort": "443", "ToPort": "443", "CidrIp": "0.0.0.0/0" }, { "IpProtocol": "tcp", "FromPort": "80", "ToPort": "80", "CidrIp": "0.0.0.0/0" } ] } ] } }, "ApplicationLoadBalancer" : { "Type" : "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties" : { "Subnets" : { "Ref" : "Subnets"}, "SecurityGroups": [ { "Ref": "ELBSecurityGroup" } ] } }, "ALBListener" : { "Type" : "AWS::ElasticLoadBalancingV2::Listener", "Properties" : { "DefaultActions" : [{ "Type" : "forward", "TargetGroupArn" : { "Ref" : "ALBTargetGroup" } }], "LoadBalancerArn" : { "Ref" : "ApplicationLoadBalancer" }, "Port": { "Fn::If": [ "UseALBSSL", 443, 80 ] }, "Protocol": { "Fn::If": [ "UseALBSSL", "HTTPS", "HTTP" ] }, "Certificates": [ { "Fn::If": [ "UseALBSSL", { "CertificateArn": { "Ref": "ALBSSLCertificateARN" } }, { "Ref": "AWS::NoValue" } ] } ] } }, "ALBTargetGroup" : { "Type" : "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties" : { "HealthCheckIntervalSeconds" : 30, "HealthCheckTimeoutSeconds" : 5, "HealthyThresholdCount" : 3, "Port" : 80, "Protocol" : "HTTP", "UnhealthyThresholdCount" : 5, "VpcId" : {"Ref" : "VpcId"} } }, "InstanceSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable SSH access and HTTP access on the inbound port", "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupId" : {"Fn::Select" : [0, {"Fn::GetAtt" : ["ApplicationLoadBalancer", "SecurityGroups"]}]} },{ "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"} } ], "VpcId" : { "Ref" : "VpcId" } } }, "RecordSet": { "Type": "AWS::Route53::RecordSetGroup", "Condition": UseALBSSL, "Properties": { "HostedZoneName": { "Fn::Join": [ "", [ { "Ref": "HostedZoneName" }, "." ] ] }, "RecordSets": [ { "Name": { "Fn::Join": [ "", [ { "Fn::Select" : [ "0", { "Fn::Split": [".", { "Fn::GetAtt": [ "ApplicationLoadBalancer", "DNSName" ] } ] } ] }, ".", { "Ref": "HostedZoneName" }, "." ] ] }, "Type": "A", "AliasTarget": { "DNSName": { "Fn::GetAtt": [ "ApplicationLoadBalancer", "DNSName" ] }, "EvaluateTargetHealth": true, "HostedZoneId": { "Fn::GetAtt": [ "ApplicationLoadBalancer", "CanonicalHostedZoneID" ] } } }, ] } } }, "Outputs" : { "URL" : { "Description" : "URL of the website", "Value" : { "Fn::Join": [ "", [ "Fn::If": [ "UseALBSSL", { "Fn::Join": [ "", [ "https://", { "Fn::Join": [ "", [ { "Fn::Select": [ "0", { "Fn::Split": [ ".", { "Fn::GetAtt": [ "ApplicationLoadBalancer", "DNSName" ] } ] } ] }, ".", { "Ref": "HostedZoneName" }, "." ] ] } ] ] }, { "Fn::Join": [ "", [ "http://", { "Fn::GetAtt": [ "ApplicationLoadBalancer", "DNSName" ] } ] ] } ] ] ] } } } }