使用AWS CDK创建Cognito栈时遭遇InvalidParameterException错误求助
Cognito身份池创建报错:Invalid Cognito Identity Provider
问题描述
作为AWS CloudFormation与CDK新手,在创建测试栈时持续收到以下错误:
Invalid Cognito Identity Provider (Service: AmazonCognitoIdentity; Status Code: 400; Error Code: InvalidParameterException; Request ID: 7db28b4b-373b-4808-9c8d-1d197b0be542; Proxy: null)
原代码如下:
const cdk = require('aws-cdk-lib'); const ec2 = require('aws-cdk-lib/aws-ec2'); const apigateway = require('aws-cdk-lib/aws-apigateway'); const cognito = require('aws-cdk-lib/aws-cognito'); const iam = require('aws-cdk-lib/aws-iam'); const { Stack } = require('aws-cdk-lib'); class MyCdkStack extends Stack { constructor(scope, id, props) { super(scope, id, props); // Create a VPC for the EC2 instance const vpc = new ec2.Vpc(this, 'MyVPC', { maxAzs: 2 // Use 2 availability zones }); const sg = new ec2.SecurityGroup(this, 'MySSHSecurityGroup', { vpc, description: 'Allow Outbound SSH access', securityGroupName: 'My SSH Security Group', allowAllOutbound: true // Allow all outbound traffic }); // Allow SSH access from a specific IP range sg.addIngressRule(ec2.Peer.ipv4('anipaddress/32'), ec2.Port.tcp(22), 'Allow inbound SSH access from here'); sg.addIngressRule(ec2.Peer.ipv4('anipaddress/32'), ec2.Port.tcp(22), 'Allow inbound SSH access from here 2'); ///////////////////// // Create a Cognito user pool const userPool = new cognito.UserPool(this, 'MyUserPool', { userPoolName: 'My User Pool', selfSignUpEnabled: true, autoVerify: { email: true }, signInAliases: { email: true }, passwordPolicy: { minLength: 8, requireDigits: true, requireLowercase: true, requireUppercase: true, requireSymbols: true } }); const userPoolClient = new cognito.CfnUserPoolClient(this, "MyUserPoolClient", { userPoolId: userPool.ref, explicitAuthFlows: ["ADMIN_NO_SRP_AUTH"], generateSecret: false, readAttributes: [ "preferred_username", "website", "email", "name", "zoneinfo", "phone_number", "phone_number_verified", "email_verified", ], writeAttributes: ["name", "zoneinfo", "phone_number"], }); // Create a Cognito identity pool const identityPool = new cognito.CfnIdentityPool(this, 'MyIdentityPool', { identityPoolName: 'My Identity Pool', allowUnauthenticatedIdentities: false, cognitoIdentityProviders: [{ clientId: userPoolClient.ref, providerName: userPool.userPoolProviderName, }] }); // Create an API Gateway REST API const restApi = new apigateway.RestApi(this, 'MyRestApi', { restApiName: 'My Rest API', deployOptions: { stageName: 'prod' } }); const sg2 = new ec2.SecurityGroup(this, 'MyAPIGatewaySecurityGroup', { vpc, description: 'Allow port 80 traffic from the API Gateway', securityGroupName: 'My API Gateway Security Group', allowAllOutbound: true // Allow all outbound traffic }); // Allow port 80 traffic from the API Gateway sg2.addIngressRule( ec2.Peer.ipv4(`${restApi.restApiId}.execute-api.${cdk.Stack.of(this).region}.amazonaws.com/32`), ec2.Port.tcp(80), 'Allow port 80 traffic from the API Gateway' ); const keyName = 'my-key-pair'; // Create an EC2 key pair for SSH access const key = new ec2.CfnKeyPair(this, 'MyKeyPair', { keyName, }); // Associate the key pair with the EC2 instance const instance = new ec2.Instance(this, 'MyEC2Instance', { instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.MICRO), machineImage: new ec2.AmazonLinuxImage(), vpc, securityGroup: sg2, key, userData: ec2.UserData.custom(` #!/bin/bash echo "Hello, world!" > /var/www/html/index.html `) }); // Create a Cognito authorizer const authorizer = new apigateway.CfnAuthorizer(this, 'MyCognitoAuthorizer', { name: 'My-Cognito-Authorizer', identitySource: 'method.request.header.Authorization', restApiId: restApi.restApiId, type: apigateway.AuthorizationType.COGNITO, providerArns: [userPool.userPoolArn] }); // Create a resource and method for the API Gateway and Add the Cognito authorizer to the method const resource = restApi.root.addResource('my-resource'); const method = resource.addMethod('GET', new apigateway.HttpIntegration(`http://${instance.instancePublicIp}`), { authorizationType: apigateway.AuthorizationType.COGNITO, authorizer: authorizer }); // Create an IAM role for authenticated users const authenticatedRole = new iam.Role(this, 'MyAuthenticatedRole', { assumedBy: new iam.FederatedPrincipal('cognito-identity.amazonaws.com', { StringEquals: { 'cognito-identity.amazonaws.com:aud': identityPool.ref }, 'ForAnyValue:StringLike': { 'cognito-identity.amazonaws.com:amr': 'authenticated' } }, 'sts:AssumeRoleWithWebIdentity') }); // Create an IAM role for unauthenticated users const unauthenticatedRole = new iam.Role(this, 'MyUnauthenticatedRole', { assumedBy: new iam.FederatedPrincipal('cognito-identity.amazonaws.com', { StringEquals: { 'cognito-identity.amazonaws.com:aud': identityPool.ref }, 'ForAnyValue:StringLike': { 'cognito-identity.amazonaws.com:amr': 'unauthenticated' } }, 'sts:AssumeRoleWithWebIdentity') }); // Grant permissions to the authenticated role authenticatedRole.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'execute-api:Invoke' ], resources: [ method.methodArn ] })); // Grant permissions to the unauthenticated role unauthenticatedRole.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'cognito-identity:GetId', 'cognito-identity:GetOpenIdToken' ], resources: [ `arn:aws:cognito-identity:${this.region}:${this.account}:identitypool/${identityPool.ref}` ] })); // Set the roles for authenticated and unauthenticated users new cognito.CfnIdentityPoolRoleAttachment(this, 'MyIdentityPoolRoles', { identityPoolId: identityPool.ref, roles: { authenticated: authenticatedRole.roleArn, unauthenticated: unauthenticatedRole.roleArn } }); } } module.exports = { MyCdkStack } // const app = new cdk.App(); // new MyStack(app, 'MyStack');
问题原因
报错源于Cognito身份池配置的用户池提供者参数错误:
- 使用底层
CfnIdentityPool构造时,cognitoIdentityProviders中的providerName需要传入用户池的完整ARN,而非userPoolProviderName(该属性是简化的提供者名称,不符合身份池的参数要求)。 - 更推荐使用CDK的L2构造
IdentityPool,它会自动处理用户池和客户端的关联,避免手动配置错误。
解决方案
修正方案1:使用L2构造IdentityPool(推荐)
替换原有的CfnIdentityPool代码,改用更简洁的L2构造,自动关联用户池和客户端:
// 替换原有的CfnUserPoolClient和CfnIdentityPool创建代码 const userPoolClient = new cognito.UserPoolClient(this, "MyUserPoolClient", { userPool: userPool, authFlows: { adminUserPassword: true // 对应原ADMIN_NO_SRP_AUTH }, generateSecret: false, readAttributes: new cognito.ClientAttributes() .withStandardAttributes({ preferredUsername: true, website: true, email: true, name: true, zoneinfo: true, phoneNumber: true, phoneNumberVerified: true, emailVerified: true }), writeAttributes: new cognito.ClientAttributes() .withStandardAttributes({ name: true, zoneinfo: true, phoneNumber: true }) }); // 使用L2 IdentityPool构造 const identityPool = new cognito.IdentityPool(this, 'MyIdentityPool', { identityPoolName: 'My Identity Pool', allowUnauthenticatedIdentities: false, cognitoUsers: [ cognito.UserPoolAuthenticationProvider.userPool(userPool, userPoolClient) ] });
修正方案2:修复CfnIdentityPool的providerName参数
如果坚持使用底层构造,将providerName替换为用户池的ARN:
const identityPool = new cognito.CfnIdentityPool(this, 'MyIdentityPool', { identityPoolName: 'My Identity Pool', allowUnauthenticatedIdentities: false, cognitoIdentityProviders: [{ clientId: userPoolClient.ref, providerName: userPool.userPoolArn, // 替换为用户池ARN serverSideTokenCheck: true // 建议添加,增强安全性 }] });
额外提示
- 原代码中API Gateway安全组的Ingress规则配置错误:API Gateway的IP地址并非固定的
restApiId.execute-api...格式,无法通过该方式限制访问。如果需要API Gateway访问VPC内的EC2,建议使用API Gateway VPC端点或者将EC2放在公有子网并使用弹性IP,同时开放对应端口给0.0.0.0/0(或更窄范围)。 - 尽量优先使用CDK的L2构造(如
UserPoolClient、IdentityPool),而非底层Cfn*构造,减少手动配置错误。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

