规则 - AWS CloudFormation
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

规则

可选的 Rules 部分验证在堆栈创建或堆栈更新过程中传递给模板的参数或参数组合。要使用模板规则,请在模板中明确声明 Rules,然后进行断言。在创建或更新资源之前,请使用规则部分验证参数值。

使用规则

每个模板规则由两个属性组成:

  • 规则条件(可选)— 确定规则的生效时间。

  • 断言(必选)— 描述用户可为特定参数指定的值。

规则可以包含 RuleCondition 属性,且必须包含 Assertions 属性。对于每个规则,您只能定义一个规则条件。您可以在 Assertions 属性中定义一个或多个断言。如果您未定义规则条件,则规则的断言始终生效。

特定于规则的内部函数

要定义规则条件和断言,可使用特定于规则的内部函数,只能在模板的 Rules 部分中使用这些函数。您可以嵌套函数,但规则条件或断言的最终结果必须为 true 或 false。

可以使用以下特定于规则的内部函数来定义规则条件和断言:

特定于规则的内部函数在规则的条件或断言中使用。条件属性确定 AWS CloudFormation 是否应用断言。如果条件的计算结果为 true,则 AWS CloudFormation 将评估断言以验证在创建或更新预配置产品时参数值是否有效。如果参数值无效,则 AWS CloudFormation 不会创建或更新堆栈。如果条件的计算结果为 false,则 AWS CloudFormation 不会检查参数值并继续堆栈操作。

语法

JSON

模板的Rules 部分由后跟冒号的密钥名称 Rules 组成。必须使用括号将所有规则声明括起来。如果您声明多个规则,则可用逗号将它们分隔开。对于每个规则,您必须声明一个用引号引起来的逻辑名称,后跟冒号以及将规则条件和断言括起来的括号。

{ "Rules": { "Rule01": { "RuleCondition": { "rule-specific intrinsic function": "Value01" }, "Assertions": [ { "Assert": { "rule-specific intrinsic function": "Value02" }, "AssertDescription": "Information about this assert" }, { "Assert": { "rule-specific intrinsic function": "Value03" }, "AssertDescription": "Information about this assert" } ] }, "Rule02": { "Assertions": [ { "Assert": { "rule-specific intrinsic function": "Value04" }, "AssertDescription": "Information about this assert" } ] } } }

YAML

Rules: Rule01: RuleCondition: rule-specific intrinsic function: Value01 Assertions: - Assert: rule-specific intrinsic function: Value02 AssertDescription: Information about this assert - Assert: rule-specific intrinsic function: Value03 AssertDescription: Information about this assert Rule02: Assertions: - Assert: rule-specific intrinsic function: Value04 AssertDescription: Information about this assert

示例

按条件验证参数值

在以下示例中,两个规则检查 InstanceType 参数的值。根据环境参数(testprod)的值,用户必须为 InstanceType 参数指定 a1.mediuma1.large。必须在同一模板的 InstanceType 部分中声明 EnvironmentParameters 参数。

示例 JSON

{ "Rules": { "testInstanceType": { "RuleCondition": { "Fn::Equals": [ { "Ref": "Environment" }, "test" ] }, "Assertions": [ { "Assert": { "Fn::Contains": [ [ "a1.medium" ], { "Ref": "InstanceType" } ] }, "AssertDescription": "For a test environment, the instance type must be a1.medium" } ] }, "prodInstanceType": { "RuleCondition": { "Fn::Equals": [ { "Ref": "Environment" }, "prod" ] }, "Assertions": [ { "Assert": { "Fn::Contains": [ [ "a1.large" ], { "Ref": "InstanceType" } ] }, "AssertDescription": "For a production environment, the instance type must be a1.large" } ] } } }

示例 YAML

Rules: testInstanceType: RuleCondition: !Equals - !Ref Environment - test Assertions: - Assert: 'Fn::Contains': - - a1.medium - !Ref InstanceType AssertDescription: 'For a test environment, the instance type must be a1.medium' prodInstanceType: RuleCondition: !Equals - !Ref Environment - prod Assertions: - Assert: 'Fn::Contains': - - a1.large - !Ref InstanceType AssertDescription: 'For a production environment, the instance type must be a1.large'

交叉参数验证

以下模板示例将创建运用 Amazon EC2 Auto Scaling 和 Elastic Load Balancing 的示例网站,并配置为使用多个可用区。模板还将包含 CloudWatch 警报,在超过定义阈值的情况下,其将执行扩展策略以添加或从 Auto Scaling 组中删除实例。本模板将创建一个或多个 Amazon EC2 实例。

注意

如果您通过本模板创建堆栈,那么会针对 AWS 资源向您收取相应费用。

示例 JSON

{ "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 health check. The web site is available on port 80 or 443 based on the input." "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<AWS::EC2::Subnet::Id>", "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", [ "<h1>Congratulations, you have successfully launched the AWS CloudFormation sample.<h1>" ] ] }, "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" ] } ] ] } ] } ] ] } } } }

示例 YAML

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 health check. The web site is available on port 80 or 443 based on the input. 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 <AWS::EC2::Subnet::Id>' 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: !Not - !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: !Equals - !Ref UseSSL - 'Yes' Assertions: - Assert: !Not - !Equals - !Ref ALBSSLCertificateARN - '' AssertDescription: ACM Certificate value cannot be empty if SSL is required - Assert: !Not - !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: !Join - |+ - - >- <h1>Congratulations, you have successfully launched the AWS CloudFormation sample.<h1> mode: '000644' owner: root group: root /etc/cfn/cfn-hup.conf: content: !Join - '' - - | [main] - stack= - !Ref 'AWS::StackId' - |+ - region= - !Ref 'AWS::Region' - |+ mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Join - '' - - | [cfn-auto-reloader-hook] - | triggers=post.update - > path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init - 'action=/opt/aws/bin/cfn-init -v ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource LaunchConfig ' - ' --region ' - !Ref 'AWS::Region' - |+ - | runas=root 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: !FindInMap - AWSAMIRegionMap - !Ref 'AWS::Region' - AMZNLINUXHVM SecurityGroups: - !Ref InstanceSecurityGroup InstanceType: !Ref InstanceType KeyName: !Ref KeyName UserData: !Base64 'Fn::Join': - '' - - | #!/bin/bash -xe - | yum update -y aws-cfn-bootstrap - '/opt/aws/bin/cfn-init -v ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource LaunchConfig ' - ' --region ' - !Ref 'AWS::Region' - |+ - '/opt/aws/bin/cfn-signal -e $? ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource WebServerGroup ' - ' --region ' - !Ref 'AWS::Region' - |+ ELBSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Allow access to the ELB VpcId: !Ref VpcId SecurityGroupIngress: - !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: !If - UseALBSSL - 443 - 80 Protocol: !If - UseALBSSL - HTTPS - HTTP Certificates: - !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: !Select - 0 - !GetAtt - ApplicationLoadBalancer - SecurityGroups - IpProtocol: tcp FromPort: '22' ToPort: '22' CidrIp: !Ref SSHLocation VpcId: !Ref VpcId RecordSet: Type: 'AWS::Route53::RecordSetGroup' Condition: UseALBSSL Properties: HostedZoneName: !Join - '' - - !Ref HostedZoneName - . RecordSets: - Name: !Join - '' - - !Select - '0' - !Split - . - !GetAtt - ApplicationLoadBalancer - DNSName - . - !Ref HostedZoneName - . Type: A AliasTarget: DNSName: !GetAtt - ApplicationLoadBalancer - DNSName EvaluateTargetHealth: true HostedZoneId: !GetAtt - ApplicationLoadBalancer - CanonicalHostedZoneID Outputs: URL: Description: URL of the website Value: !Join - '' - - !If - UseALBSSL - !Join - '' - - 'https://' - !Join - '' - - !Select - '0' - !Split - . - !GetAtt - ApplicationLoadBalancer - DNSName - . - !Ref HostedZoneName - . - !Join - '' - - 'http://' - !GetAtt - ApplicationLoadBalancer - DNSName