You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免CloudFormation部署栈时删除手动创建的Cognito用户池

问题描述

我在AWS控制台手动创建了一个Cognito用户池,近期打算将其添加到CloudFormation模板中,供栈内其他资源引用,但不希望CloudFormation对其进行修改或删除。不过每次部署模板时,都会看到如下变更集,其中显示该Cognito用户池被标记为删除:

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------
Operation                             LogicalResourceId                     ResourceType                          Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------
* Modify                              WebSocketConnectFunction              AWS::Lambda::Function                 False
* Modify                              WebSocketConnectIntegration           AWS::ApiGatewayV2::Integration        False
* Modify                              WebSocketDefaultFunction              AWS::Lambda::Function                 False
* Modify                              WebSocketDefaultIntegration           AWS::ApiGatewayV2::Integration        False
* Modify                              WebSocketDisconnectFunction           AWS::Lambda::Function                 False
* Modify                              WebSocketDisconnectIntegration        AWS::ApiGatewayV2::Integration        False
- Delete                              CognitoUserPool                       AWS::Cognito::UserPool                N/A

提供的template.yaml内容如下:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Web Application Backend

Parameters:
  ExistingCognitoUserPoolId:
    Type: String
    Description: ID of the existing Cognito User Pool
    Default: ap-example-2_aKzfw0K4N

Resources:
  WebSocketApi:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: WebSocketAPI
      ProtocolType: WEBSOCKET
      RouteSelectionExpression: $request.body.action

  WebSocketConnectIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref WebSocketApi
      IntegrationType: AWS_PROXY
      IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WebSocketConnectFunction.Arn}/invocations

  WebSocketDisconnectIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref WebSocketApi
      IntegrationType: AWS_PROXY
      IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WebSocketDisconnectFunction.Arn}/invocations

  WebSocketDefaultIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref WebSocketApi
      IntegrationType: AWS_PROXY
      IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WebSocketDefaultFunction.Arn}/invocations

  WebSocketConnectRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref WebSocketApi
      RouteKey: $connect
      AuthorizationType: NONE
      Target: !Sub integrations/${WebSocketConnectIntegration}

  WebSocketDisconnectRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref WebSocketApi
      RouteKey: $disconnect
      AuthorizationType: NONE
      Target: !Sub integrations/${WebSocketDisconnectIntegration}

  WebSocketDefaultRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref WebSocketApi
      RouteKey: $default
      AuthorizationType: NONE
      Target: !Sub integrations/${WebSocketDefaultIntegration}

  WebSocketConnectFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: server.wsConnectHandler
      Runtime: nodejs18.x
      CodeUri: .
      Tracing: Active

  OnConnectPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref WebSocketConnectFunction
      Principal: apigateway.amazonaws.com

  WebSocketDisconnectFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: server.wsDisconnectHandler
      Runtime: nodejs18.x
      CodeUri: .
      Tracing: Active

  OnDisconnectPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref WebSocketDisconnectFunction
      Principal: apigateway.amazonaws.com

  WebSocketDefaultFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: server.wsDefaultHandler
      Runtime: nodejs18.x
      CodeUri: .
      Tracing: Active
      Timeout: 900
      Policies:
        - Statement:
            Effect: Allow
            Action:
              - execute-api:ManageConnections
            Resource: 
              - !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/Test/POST/@connections/*

  OnDefaultPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref WebSocketDefaultFunction
      Principal: apigateway.amazonaws.com

Outputs:
  WebSocketApiUrl:
    Value: !Sub wss://${WebSocketApi}.execute-api.${AWS::Region}.amazonaws.com/Stage
    Description: URL of the WebSocket API

  CognitoUserPoolId:
    Value: !Ref ExistingCognitoUserPoolId
    Description: ID of the existing Cognito User Pool
解决方案

出现这个问题的核心原因:你的CloudFormation栈历史中曾经管理过CognitoUserPool这个逻辑资源,现在模板中移除了该资源定义,CloudFormation会默认尝试删除它。要实现仅引用已有用户池、不被CloudFormation管理的目标,按以下步骤操作:

  • 确认并清理栈的资源关联
    检查栈的历史变更记录,确认是否曾经在模板的Resources节中定义过CognitoUserPool资源。如果是,需要先将该资源从栈的管理中剥离:

    • 使用AWS CLI执行:aws cloudformation delete-stack --stack-name <你的栈名> --retain-resources CognitoUserPool,这会删除栈但保留指定的用户池资源,之后该资源将脱离CloudFormation管理。
    • 或者通过CloudFormation控制台删除栈时,勾选保留CognitoUserPool资源。
  • 正确引用已有用户池
    保持现有模板中的ExistingCognitoUserPoolId参数,栈内其他需要关联该用户池的资源(比如API Gateway授权器)直接通过!Ref ExistingCognitoUserPoolId引用即可,绝对不要在Resources节中定义该用户池资源。

  • 验证变更集
    完成上述操作后,重新生成变更集,确认CognitoUserPool的删除操作不再出现,其他资源的变更符合预期后再部署。

内容的提问来源于stack exchange,提问作者Flavio Andrade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 16:42:04