Reglas - AWS CloudFormation

Reglas

La sección opcional Rules valida un parámetro o una combinación de parámetros pasados a una plantilla durante una creación de pila o actualización de pila. Para utilizar reglas de plantilla, declare explícitamente Rules en su plantilla seguido de una aserción. Utilice la sección de reglas para validar los valores de los parámetros antes de crear o actualizar recursos.

Trabajar con reglas

Cada regla de plantilla consta de dos propiedades:

  • Condición de regla (opcional): determina cuándo surte efecto una regla.

  • Aserciones (obligatorias): describen qué valores pueden especificar los usuarios para un parámetro determinado.

Una regla puede incluir una propiedad RuleCondition y necesariamente debe incluir una propiedad Assertions. Para cada regla, sólo puede definir una condición de regla. Puede definir una o más aserciones dentro de la Assertions propiedad. Si no se define la condición de regla, las declaraciones de la regla surten efecto en todos los casos.

Funciones intrínsecas específicas de la regla

Para definir una condición de regla y las aserciones, utilice las funciones intrínsecas específicas de reglas, que son funciones que solo se pueden utilizar en la sección Rules de una plantilla. Puede anidar funciones, pero el resultado final de una condición de regla o una declaración debe ser verdadero o falso.

Puede utilizar las siguientes funciones intrínsecas específicas de reglas para definir las condiciones de regla y las declaraciones:

Las funciones intrínsecas específicas de la regla se utilizan en la condición o aserciones de una regla. La propiedad de condición determina si AWS CloudFormation aplicará las declaraciones. Si la condición se evalúa en true, AWS CloudFormation evalúa las declaraciones para comprobar si el valor de un parámetro es válido en el momento de crear o actualizar un producto provisionado. Si el valor de un parámetro no es válido, AWS CloudFormation no crea o actualizar la pila. Si la condición se evalúa en false, AWS CloudFormation no comprueba el valor del parámetro y procede a llevar a cabo la operación de la pila.

Sintaxis

JSON

La sección Rules de una plantilla consta del nombre de clave Rules, seguido de un único signo de dos puntos. Debe utilizar llaves para incluir todas las declaraciones de reglas. Si se declaran varias reglas, deben delimitarse mediante comas. Para cada regla, se declara un nombre lógico entre comillas seguido de un signo de dos puntos y de las llaves que contienen la condición de regla y las declaraciones.

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

Ejemplos

Comprobación condicional del valor de un parámetro

En el siguiente ejemplo, las dos reglas comprueban el valor del InstanceType parámetro. En función del valor del parámetro entorno (test o prod), el usuario debe especificar a1.medium o a1.large para el parámetro InstanceType. Los parámetros InstanceType y Environment deben declararse en la sección Parameters de la misma plantilla.

Ejemplo 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" } ] } } }

Ejemplo 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'

Validación de parámetros cruzados

El siguiente ejemplo de plantilla crea un sitio web de ejemplo que utiliza Amazon EC2 Auto Scaling y Elastic Load Balancing y está configurado para utilizar varias zonas de disponibilidad. La plantilla también contiene alarmas de Cloudwatch que ejecutan las políticas de escalado para agregar o eliminar instancias del grupo de Auto Scaling cuando se superan los umbrales definidos. Esta plantilla crea una o varias instancias de Amazon EC2.

nota

Se le facturarán los recursos de AWS que utilice si crea una pila a partir de esta plantilla.

Ejemplo 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" ] } ] ] } ] } ] ] } } } }

Ejemplo 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