Regras - AWS CloudFormation

Regras

A seção Rules opcional valida um parâmetro ou uma combinação de parâmetros repassados para um modelo durante uma criação de pilha ou atualização de pilha. Para usar regras de modelo, declare explicitamente Rules em seu modelo seguidas de uma declaração. Use a seção de regras para validar valores de parâmetro antes de criar ou atualizar recursos.

Trabalhar com regras

Cada regra de modelo consiste em duas propriedades:

  • Condição da regra (opcional): determina quando uma regra entra em vigor.

  • Declarações (obrigatória): descreve quais valores os usuários podem especificar para um determinado parâmetro.

Uma regra pode incluir uma propriedade RuleCondition e deve incluir uma propriedade Assertions. Para cada regra, você pode definir apenas uma condição de regra. Você pode definir uma ou mais declarações dentro da propriedade Assertions. Se você não definir uma condição de regra, as declarações da regra sempre entram em vigor.

Funções intrínsecas específicas de regras

Para definir a condição e declarações de uma regra, você usa funções intrínsecas específicas de regras, que são funções que podem ser usadas apenas na seção Rules de um modelo. Você pode aninhar funções, mas o resultado final de uma condição de regra ou declaração deve ser verdadeiro ou falso.

Você pode usar as seguintes funções intrínsecas específicas de regra para definir condições de regra e declarações:

Funções intrínsecas específicas de regras são usadas na condição ou nas declarações de uma regra. A propriedade da condição determina se o AWS CloudFormation se aplica a asserções. Se a condição for avaliada como true, o AWS CloudFormation avaliará as asserções para verificar se um valor de parâmetro é válido quando um produto provisionado for criado ou atualizado. Se o valor de um parâmetro for inválido, o AWS CloudFormation não criará nem atualizará a pilha. Se a condição for avaliada como false, o AWS CloudFormation não verificará o valor do parâmetro e prosseguirá com a operação de pilha.

Sintaxe

JSON

A seção Rules de um modelo consiste no nome da chave Rules, seguido por dois-pontos. Você deve usar chaves para delimitar todas as declarações de regras. Se você declarar várias regras, elas serão separadas por vírgulas. Para cada regra, você declara um nome lógico entre aspas seguido por uma vírgula e chaves que incluem a condição da regra e as declarações.

{ "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

Exemplos

Verificar condicionalmente um valor de parâmetro

No exemplo a seguir, as duas regras verificam o valor do parâmetro InstanceType. Dependendo do valor do parâmetro de ambiente (test ou prod), o usuário deve especificar a1.medium ou a1.large para o parâmetro InstanceType. Os parâmetros InstanceType e Environment já devem estar declarados na seção Parameters do mesmo modelo.

Exemplo em 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" } ] } } }

Exemplo em 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'

Validação de parâmetros cruzados

O seguinte exemplo de modelo cria uma amostra de site que usa o Amazon EC2 Auto Scaling e o Elastic Load Balancing, e está configurado para usar várias zonas de disponibilidade. O modelo também contém alarmes do CloudWatch que executam políticas de escalabilidade para adicionar ou remover instâncias do grupo de Auto Scaling quando os limites definidos são ultrapassados. Esse modelo cria uma ou mais instâncias do Amazon EC2.

nota

Você será cobrado pelos recursos da AWS usados se criar uma pilha com base nesse modelo.

Exemplo em 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::EachMemberEquals": [ { "Fn::ValueOf": [ "Subnets", "VpcId" ] }, { "Ref": "VpcId" } ] }, "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" ] } ] ] } ] } ] ] } } } }

Exemplo em 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::EachMemberEquals': - 'Fn::ValueOf': - Subnets - VpcId - Ref: VpcId 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