本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
CloudFormation 範本Rules語法
Rules
區段是 CloudFormation 範本的選用部分,可啟用自訂驗證邏輯。包含時,本節包含規則函數,可在 CloudFormation 建立或更新任何資源之前驗證參數值。
當標準參數限制條件不足時,規則很有用。例如,啟用 SSL 時,必須提供憑證和網域名稱。規則可以確保符合這些相依性。
語法
Rules
本節使用以下語法:
JSON
範本的 Rules
區塊包含了金鑰名稱 Rules
,後面接著單一冒號。您必須使用大括號來括住所有規則宣告。如果您宣告多個規則,則會以逗號分隔。對於每項規則,您會在引號中宣告其邏輯名稱,後面依序接著冒號和括號,括號之中是規則條件與宣告。
{
"Rules": {
"LogicalRuleName1
": {
"RuleCondition": {
"rule-specific intrinsic function
": "Value
"
},
"Assertions": [
{
"Assert": {
"rule-specific intrinsic function
": "Value
"
},
"AssertDescription": "Information about this assert
"
},
{
"Assert": {
"rule-specific intrinsic function
": "Value
"
},
"AssertDescription": "Information about this assert
"
}
]
},
"LogicalRuleName2
": {
"Assertions": [
{
"Assert": {
"rule-specific intrinsic function
": "Value
"
},
"AssertDescription": "Information about this assert
"
}
]
}
}
}
YAML
Rules:
LogicalRuleName1
:
RuleCondition:
rule-specific intrinsic function
: Value
Assertions:
- Assert:
rule-specific intrinsic function
: Value
AssertDescription: Information about this assert
- Assert:
rule-specific intrinsic function
: Value
AssertDescription: Information about this assert
LogicalRuleName2
:
Assertions:
- Assert:
rule-specific intrinsic function
: Value
AssertDescription: Information about this assert
規則欄位
Rules
區段可以包含下列欄位。
- 邏輯 ID (也稱為邏輯名稱)
-
每個規則的唯一識別符。
RuleCondition
(選用)-
決定規則何時生效的屬性。如果您未定義規則條件,則該規則的宣告一律生效。對於每個規則,您只能定義一個規則條件。
Assertions
(必要)-
指定特定參數可接受值的一或多個陳述式。
Assert
-
必須評估為 的條件
true
。 AssertDescription
-
當宣告失敗時,會顯示一則訊息。
規則特定的內部函數
若要定義您的規則,您必須使用規則特定的函數,這些函數只能在範本的 Rules
區段中使用。雖然這些函數可以巢狀化,但規則條件或宣告的最終結果必須是 true
或 false
。
下列規則函數可供使用:
這些函數用於規則的條件或聲明。條件屬性會判斷 CloudFormation 是否套用聲明。若條件計算結果為 true
,CloudFormation 會評估宣告以驗證在佈建產品建立或更新時,某個參數值是否有效。如果參數值無效,CloudFormation 不會建立或更新堆疊。如果條件評估為 false
,CloudFormation 便不會檢查參數值,而直接繼續運作堆疊。
範例
有條件地驗證參數值
在下列範例中,兩個規則會檢查 InstanceType
參數的值。視環境參數 (test
或 prod
) 的值而定,使用者必須針對 a1.medium
參數指定 a1.large
或 InstanceType
。InstanceType
與 Environment
參數必須在同一個範本的 Parameters
區塊中宣告。
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'
交互參數驗證
下列範例範本示範使用 規則進行跨參數驗證。他們會建立在負載平衡器後方 Auto Scaling 群組上執行的範例網站。網站可在連接埠 80 或 443 上使用,具體取決於輸入參數。Auto Scaling 群組中的執行個體可設定為接聽任何連接埠 (預設值為 8888)。
此範本中的規則會在堆疊建立之前驗證輸入參數。它們會驗證所有子網路是否屬於指定的 VPC,並確保當 UseSSL
參數設定為 時Yes
,會提供 SSL 憑證 ARN 和託管區域名稱。
注意
如果您從此範本建立堆疊,則需要支付所使用的 AWS 資源費用。
JSON
{ "AWSTemplateFormatVersion": "2010-09-09", "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." }, "InstanceType": { "Description": "WebServer EC2 instance type", "Type": "String", "Default": "t2.micro", "AllowedValues": ["t2.micro", "t3.micro"], "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"], "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::Equals": [{"Ref": "UseSSL"}, "Yes"]} }, "Rules": { "SubnetsInVPC": { "Assertions": [ { "Assert": {"Fn::EachMemberEquals": [{"Fn::ValueOf": ["Subnets", "VpcId"]}, {"Ref": "VpcId"}]}, "AssertDescription": "All subnets must be 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": { "us-east-1": {"AMZNLINUXHVM": "ami-0ff8a91507f77f867"}, "us-west-1": {"AMZNLINUXHVM": "ami-0bdb828fd58c52235"}, "eu-west-1": {"AMZNLINUXHVM": "ami-047bb4163c506cd98"}, "ap-southeast-1": {"AMZNLINUXHVM": "ami-08569b978cc4dfa10"} } }, "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 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.micro AllowedValues: - t2.micro - t3.micro 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: !Equals - !Ref UseSSL - 'Yes' Rules: SubnetsInVPC: Assertions: - Assert: 'Fn::EachMemberEquals': - 'Fn::ValueOf': - Subnets - VpcId - Ref: VpcId AssertDescription: All subnets must be 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: us-east-1: AMZNLINUXHVM: ami-0ff8a91507f77f867 us-west-1: AMZNLINUXHVM: ami-0bdb828fd58c52235 eu-west-1: AMZNLINUXHVM: ami-047bb4163c506cd98 ap-southeast-1: AMZNLINUXHVM: ami-08569b978cc4dfa10 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: !Sub | [main] stack=${AWS::StackId} region=${AWS::Region} mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Sub |- [cfn-auto-reloader-hook] triggers=post.update path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${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::Sub: |- #!/bin/bash -xe yum update -y aws-cfn-bootstrap /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region} /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${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