I have an existing Cognito User Pool that I manually created in the AWS Console. I recently added it to my CloudFormation template to be referenced by other resources in my stack, but I don't want CloudFormation to modify or delete it. However, every time I deploy my template, I see the following changeset indicating that the Cognito User Pool is marked for deletion:
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
How did it initially end up under CloudFormation management if you created it through the console? The output suggests that it was managed by CloudFormation at some point and now is not present in the template anymore.
If you don't want to modify or delete it through your template, why do you need it in there in the first place?
I would either:
or
RETAIN
IMO it's always a good idea to have all you resources as IaC and no resources created through clicking in the console.
See the documentation on importing existing resources into CloudFormation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import.html