AWS SAM模板If条件失效问题:Cognito用户池部署报错排查
问题:CloudFormation模板中
!If条件未正确生效,触发Mapping条目不存在错误 我有多个运行中的AWS CloudFormation栈,包含活跃的Cognito用户池,因各种原因无法删除这些池。现在希望通过同一模板部署新Cognito池时采用新命名规范,但部署时遇到错误。
模板代码
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: > Testing # Global Parameters Parameters: Environment: Type: String Default: dev Description: (required) Environment type AllowedValues: - dev - prod CognitoStack: Type: String Default: true Description: (required) Use default cognito or old cognito AllowedValues: - true - false Mappings: HkCognitoUserPoolFixed: heka-dev: id: 'heka_dev_cognito_user_pool' HkCognitoUserPoolClientFixed: heka-dev: id: 'heka_dev_cognito_user_pool_client' # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 300 MemorySize: 512 Runtime: python3.8 Conditions: DefaultCognito: !Equals [ !Ref CognitoStack, true ] Resources: # Cognito Stuff HkCognitoUserPool: Type: AWS::Cognito::UserPool Properties: # UserPoolName: !Sub ${AWS::StackName}_${Environment}_cognito_user_pool UserPoolName: !If [ DefaultCognito, !Sub "${AWS::StackName}_${Environment}_cognito_user_pool", !FindInMap [ HkCognitoUserPoolFixed, !Ref 'AWS::StackName', 'id' ] ] Policies: PasswordPolicy: MinimumLength: 8 UsernameAttributes: - email Schema: - AttributeDataType: String Name: email Required: true - AttributeDataType: String Name: phone_number Required: true - AttributeDataType: String Name: mrn AdminCreateUserConfig: AllowAdminCreateUserOnly: false AutoVerifiedAttributes: - email - phone_number HkCognitoUserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: UserPoolId: !Ref HkCognitoUserPool # ClientName: !Sub ${AWS::StackName}_${Environment}_cognito_user_pool_client ClientName: !If [ DefaultCognito, !Sub "${AWS::StackName}_${Environment}_cognito_user_pool_client", !FindInMap [ HkCognitoUserPoolClientFixed, !Ref 'AWS::StackName', 'id' ] ] GenerateSecret: false ExplicitAuthFlows: - ALLOW_REFRESH_TOKEN_AUTH - ALLOW_USER_SRP_AUTH - ALLOW_USER_PASSWORD_AUTH - ALLOW_CUSTOM_AUTH
部署参数与错误信息
- 部署参数:
Environment=dev;CognitoStack=true - 错误信息:
Error: Failed to create changeset for the stack: itcc-5, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state: For expression "Status" we matched expected path: "FAILED" Status: FAILED. Reason: Template error: Unable to get mapping for HkCognitoUserPoolClientFixed::itcc-5::id Create Change Set has failed: Command did not exit successfully, exit code: 1 itcc-5 has failed: Command did not exit successfully, exit code: 1
根本原因
CloudFormation在模板验证阶段会预解析所有表达式,包括!If的两个分支,无论条件是否成立。你的栈名itcc-5不存在于HkCognitoUserPoolClientFixed和HkCognitoUserPoolFixed这两个Mapping中,因此即使CognitoStack=true(走true分支),CloudFormation仍会验证else分支的!FindInMap,发现找不到对应键就抛出错误。
解决方案
方案1:用条件控制资源创建(推荐)
将新、旧Cognito资源拆分为独立资源,通过Condition控制只创建符合条件的资源,这样CloudFormation不会解析未启用的资源属性,彻底避免Mapping键缺失的问题:
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: > Testing Parameters: Environment: Type: String Default: dev Description: (required) Environment type AllowedValues: - dev - prod CognitoStack: Type: String Default: true Description: (required) Use default cognito or old cognito AllowedValues: - true - false Mappings: HkCognitoUserPoolFixed: heka-dev: id: 'heka_dev_cognito_user_pool' HkCognitoUserPoolClientFixed: heka-dev: id: 'heka_dev_cognito_user_pool_client' Globals: Function: Timeout: 300 MemorySize: 512 Runtime: python3.8 Conditions: UseNewCognito: !Equals [ !Ref CognitoStack, true ] UseOldCognito: !Equals [ !Ref CognitoStack, false ] Resources: # 新Cognito用户池(仅当UseNewCognito为true时创建) HkCognitoUserPoolNew: Type: AWS::Cognito::UserPool Condition: UseNewCognito Properties: UserPoolName: !Sub "${AWS::StackName}_${Environment}_cognito_user_pool" Policies: PasswordPolicy: MinimumLength: 8 UsernameAttributes: - email Schema: - AttributeDataType: String Name: email Required: true - AttributeDataType: String Name: phone_number Required: true - AttributeDataType: String Name: mrn AdminCreateUserConfig: AllowAdminCreateUserOnly: false AutoVerifiedAttributes: - email - phone_number # 新Cognito用户池客户端(仅当UseNewCognito为true时创建) HkCognitoUserPoolClientNew: Type: AWS::Cognito::UserPoolClient Condition: UseNewCognito Properties: UserPoolId: !Ref HkCognitoUserPoolNew ClientName: !Sub "${AWS::StackName}_${Environment}_cognito_user_pool_client" GenerateSecret: false ExplicitAuthFlows: - ALLOW_REFRESH_TOKEN_AUTH - ALLOW_USER_SRP_AUTH - ALLOW_USER_PASSWORD_AUTH - ALLOW_CUSTOM_AUTH # 旧Cognito用户池(仅当UseOldCognito为true时创建) HkCognitoUserPoolOld: Type: AWS::Cognito::UserPool Condition: UseOldCognito Properties: UserPoolName: !FindInMap [ HkCognitoUserPoolFixed, !Ref 'AWS::StackName', 'id' ] Policies: PasswordPolicy: MinimumLength: 8 UsernameAttributes: - email Schema: - AttributeDataType: String Name: email Required: true - AttributeDataType: String Name: phone_number Required: true - AttributeDataType: String Name: mrn AdminCreateUserConfig: AllowAdminCreateUserOnly: false AutoVerifiedAttributes: - email - phone_number # 旧Cognito用户池客户端(仅当UseOldCognito为true时创建) HkCognitoUserPoolClientOld: Type: AWS::Cognito::UserPoolClient Condition: UseOldCognito Properties: UserPoolId: !Ref HkCognitoUserPoolOld ClientName: !FindInMap [ HkCognitoUserPoolClientFixed, !Ref 'AWS::StackName', 'id' ] GenerateSecret: false ExplicitAuthFlows: - ALLOW_REFRESH_TOKEN_AUTH - ALLOW_USER_SRP_AUTH - ALLOW_USER_PASSWORD_AUTH - ALLOW_CUSTOM_AUTH
方案2:补充Mapping条目(临时快速解决)
如果只是临时测试,可以在Mapping中添加当前栈名itcc-5的条目,值可以随便填写(因为条件为true时不会用到):
Mappings: HkCognitoUserPoolFixed: heka-dev: id: 'heka_dev_cognito_user_pool' itcc-5: id: 'temp_dummy_id' HkCognitoUserPoolClientFixed: heka-dev: id: 'heka_dev_cognito_user_pool_client' itcc-5: id: 'temp_dummy_client_id'
这种方法适合快速验证,但长期维护所有可能的栈名会很繁琐,不推荐作为长期方案。
内容的提问来源于stack exchange,提问作者Ishan
相关产品推荐
相关产品推荐

