如何将值赋予在模板堆栈中创建的参数?

问题描述

我在部署 CloudFormation 模板时遇到以下错误

Failed to create the stack.
An error occurred (ValidationError) when calling the CreateStack operation: Parameters: [Clusterarn,TaskRoleArn,Env,subnets,ExecRoleArn,ClusterLogGroup,ContainerSG] must have values

我不知道如何将值赋予指定的参数,因为它们是在堆栈中创建的。例如,ContainerSG 和 LogGroup:

Parameters:

  ContainerSG:
    Description: The container security group
    Type: String

  ClusterLogGroup:
    Description: The cluster log group
    Type: String

Resources

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Join [ '/',['/aws','ecs',!Ref Env]]

  ContainerSecurityGroup:
    Type :  AWS::EC2::SecurityGroup
    Properties : 
       GroupDescription :  "ECS Containers Security Group"
       VpcId :  '{{resolve:ssm:/ca/config/network/vpc_id:1}}'
       GroupName: security-group-cmr
       SecurityGroupIngress :
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.49.63.0/24
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.93.0.0/16
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.97.0.0/16
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.50.128.0/21
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.50.144.0/24
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  172.25.0.0/16

最重要的问题是,我如何为与 CloudFormation 模板内的堆栈一起创建的参数赋予值?

希望有人对此提供帮助。谢谢。

编辑:这是完整的 cloudformation 文件,在管道中指定了一些参数(内存、构建编号等),这就是它们不需要在模板中归因于它们的任何值的原因:

Description: "Generic Research Template for Application ECS Cluster with an ECS Service"
Parameters:
  Env:
    Description: the runtime environment
    Type: String
    AllowedValues:
      - dev
      - uat
      - prod
  ServiceName:
    Description: The service name
    Type: String
  BuildNumber:
    Description: The bitbucket build number
    Type: String
  AppCode:
    Description: The application's app code
    Type: String
  subnets:
    Description: Choose which db subnets for the instance
    Type: List<AWS::EC2::subnet::Id>
  ContainerPort:
    Description: The container port
    Type: String
    Default: 8080
  DesiredCount:
    Description: The number of desired tasks for this service
    Type: Number
    Default: 1
  ClusterLogGroup:
    Description: The cluster log group
    Type: String
  cpu:
    Description: allocated cpu credits
    Type: Number
    Default: 1024
  Memory:
    Description: hard cap for memory
    Type: String
    Default: 2048
  Clusterarn:
    Description: The ECS Cluster ARN
    Type: String
  ExecRoleArn:
    Description: The ARN of the cluster execution role
    Type: String
  TaskRoleArn:
    Description: The ARN of the cluster task role
    Type: String
  ContainerSG:
    Description: The container security group
    Type: String
  Excludetaskdef:
    Description: Flag indiciating that the task deFinition resource should not be created as part of this stack
    Type: Number
    AllowedValues:
      - 0
      - 1
    Default: 0
Conditions:
  Includetaskdef: !Equals [!Ref Excludetaskdef,0]
Resources:  
  ECSService:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: !Sub ${Env}-${AppCode}-${ServiceName}-service
      Cluster: !Ref Clusterarn
      TaskDeFinition: !Ref TaskDeFinition
      DeploymentConfiguration:
        MinimumHealthyPercent: 0
        MaximumPercent: 100
      DesiredCount: !Ref DesiredCount
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: disABLED
          subnets:
            - !Select [0,!Ref subnets ]
            - !Select [1,!Ref subnets ]
          SecurityGroups:
            - !Ref ContainerSG
  TaskDeFinition:
    Type: AWS::ECS::TaskDeFinition
    Condition: Includetaskdef
    Properties:
      Family: !Sub ${Env}-${AppCode}-${ServiceName}
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      cpu: !Ref cpu
      Memory: !Ref Memory
      ExecutionRoleArn: !Ref ExecRoleArn
      TaskRoleArn: !Ref TaskRoleArn
      ContainerDeFinitions:
        - Name: !Sub ${Env}-${AppCode}-${ServiceName}
          Image: !Sub 558043318296.dkr.ecr.us-east-1.amazonaws.com/com.cambridge.gir/${AppCode}-${ServiceName}:${BuildNumber}
          Essential: True
          PortMappings:
            - ContainerPort: !Ref ContainerPort
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref ClusterLogGroup
              awslogs-region: us-east-1
              awslogs-stream-prefix: !Ref ServiceName
          Environment:
            - Name: Environment
              Value: !Ref Env
            - Name: Timezone
              Value: "-Duser.timezone=America/New_York"
  ClusterKmsKey:
    Type: AWS::KMS::Key
    Properties:
      Description: "Encrypts secrets for apps in the cluster"
      KeyPolicy:
        Version: '2012-10-17'
        Id: !Sub ${Env}-${AppCode}-kms-key
        Statement:
          - Sid: 'Enable IAM User Permission'
            Effect: 'Allow'
            Principal:
              AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
            Action:
              - kms:*
            Resource: '*'
          - Sid: 'Allow ECS Tasks to use the key'
            Effect: 'Allow'
            Principal:
              Service: 'ecs-tasks.amazonaws.com'
            Action:
              - 'kms:GenerateDataKey'
              - 'kms:Encrypt'
              - 'kms:Decrypt'
            Resource: '*'
          - Sid: 'Allow SNS to use the key'
            Effect: 'Allow'
            Principal:
              Service: 'sns.amazonaws.com'
            Action:
              - 'kms:GenerateDataKey'
              - 'kms:Encrypt'
              - 'kms:Decrypt'
            Resource: '*'
          - Sid: 'Allow SQS to use the key'
            Effect: 'Allow'
            Principal:
              Service: 'sqs.amazonaws.com'
            Action:
              - 'kms:GenerateDataKey'
              - 'kms:Encrypt'
              - 'kms:Decrypt'
            Resource: '*'
          - Sid: 'Allow ES to use the key'
            Effect: 'Allow'
            Principal:
              Service: 'es.amazonaws.com'
            Action:
              - 'kms:GenerateDataKey'
              - 'kms:Encrypt'
              - 'kms:Decrypt'
            Resource: '*'
  EcsCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${Env}-${AppCode}-ecs-cluster
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Join [ '/',!Ref Env,!Ref AppCode]]
  ContainerSecurityGroup:
    Type :  AWS::EC2::SecurityGroup
    Properties : 
       GroupDescription :  "ECS Containers Security Group"
       VpcId :  '{{resolve:ssm:/ca/config/network/vpc_id:1}}'
       GroupName :  !Sub   ${Env}-${ServiceName}-sg
       SecurityGroupIngress :
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.49.63.0/24
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.93.0.0/16
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.97.0.0/16
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.50.128.0/21
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  10.50.144.0/24
        -  IpProtocol :  tcp
           FromPort :  8080
           ToPort :  8080
           CidrIp :  172.25.0.0/16
  ClusterExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${Env}-${AppCode}-execution-role
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
        - 'arn:aws:iam::aws:policy/AmazonSSMFullAccess'
        - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
      Policies:
        - PolicyName: !Sub ${Env}-${AppCode}-execution-role-policy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Sid: AllowSecretsAccessForContainers
                Effect: Allow
                Action:
                  - 'kms:Decrypt'
                  - 'ssm:GetParameters'
                Resource:
                  - !Sub "arn:aws:ssm:*:*:parameter/${Env}/${AppCode}/*"
                  - !GetAtt ClusterKmsKey.Arn
              - Sid: AllowECRPull
                Effect: Allow
                Action:
                  - "ecr:GetAuthorizationToken"
                  - "ecr:BatchCheckLayerAvailability"
                  - "ecr:GetDownloadUrlForLayer"
                  - "ecr:BatchGetimage"
                Resource:
                  - "*"
  FargateTaskRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${Env}-${AppCode}-fargate-task-role
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: 'sts:AssumeRole'

解决方法

如果全部在一个文件中,则不需要任何参数。

您可以随时转到 CloudFormation 文档中所有资源的返回部分。在这种情况下,我们可以看到当您使用 LogGroup 时,Ref function 会返回它的名称。有时可以使用 Ref 函数,有时需要使用 Fn:GetAtt 函数来获取资源的一些更奇特的属性。

这个 cheat sheet 也非常有助于了解何时使用 Ref 或何时使用 GetAtt。

例如,您可以使用 !Ref LogGroup 获取日志组的名称或使用 !Ref ContainerSecurityGroup 获取安全组的名称。