-
Notifications
You must be signed in to change notification settings - Fork 4.5k
cognito: Using a token for UserPoolIdentityProviderApple doesn't resolve at deploy #31378
Description
Describe the bug
I'm attempting to create a Cognito user pool using Apple as an identity provider. I created the secret key and manually saved it in Secrets Manager using the AWS console.
Originally, I attempted this:
const applePrivateKeySecret = Secret.fromSecretNameV2(this, 'ApplePrivateKey', 'TheKeyNameInSecretsManager')
const appleProvider = new UserPoolIdentityProviderApple(this, 'UserPoolIdentityProviderApple',
{
clientId: 'com.myapp',
teamId: '123456',
keyId: '123456',
privateKey: applePrivateKeySecret.secretValue.toString(),
userPool: this.userPool
})It didn't work on deploy since the secret is exposed as a string.
I also tried saving the value as a SecureString in AWS Systems Manager and retrieving it like this:
const applePrivateKeyParameter = SecretValue.ssmSecure('AppleSignInPrivateKey').toString()Which didn't give the same error regarding the value being exposed, but results in a TypeError (described just below), since apparently this token is unresolved when I attempt to deploy.
So I attempted to create a lambda that could be called by my Cognito stack to retrieve the token from Secrets Manager:
The lambda code:
import {
GetSecretValueCommand,
SecretsManagerClient
} from '@aws-sdk/client-secrets-manager'
export const handler = async (event: any = {}) : Promise <any> =>
{
try
{
const client = new SecretsManagerClient()
const command = new GetSecretValueCommand({ SecretId: 'TheKeyNameInSecretsManager' })
const response = await client.send(command)
if (response.SecretString)
{
return {
Status: 'SUCCESS',
PhysicalResourceId: 'ApplePrivateKey',
Data:
{
SecretValue: response.SecretString
}
}
}
else
{
return {
Status: 'FAILED',
Reason: 'SecretString is empty.',
}
}
}
catch (error: any)
{
return {
status: 'FAILED',
message: error?.message || 'Unknown Failure.'
}
}
}In my Cognito Stack, I retrieve the token and attempt to use it, but UserPoolIdentityProviderApple is seemingly undefined since the token never resolves.
This line will always throw an error:
this.userPool.registerIdentityProvider(appleProvider)TypeError: Cannot read properties of undefined (reading 'registerIdentityProvider')This comment on another issue seems to outline what I'm doing, more or less.
As far as I can tell, aren't tokens supposed to resolve on deployment? But this unresolved token is always causing the above error when I attempt to deploy.
What is the correct way to retrieve a secret from Secrets Manager to use in this context?
The Cognito Stack code:
import {
AccountRecovery,
CfnIdentityPool,
OAuthScope,
UserPool,
UserPoolClient,
UserPoolClientIdentityProvider,
UserPoolIdentityProviderApple
} from 'aws-cdk-lib/aws-cognito'
import {
App,
CustomResource,
Stack,
StackProps,
Token
} from 'aws-cdk-lib'
import { join } from 'path'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
import { Provider } from 'aws-cdk-lib/custom-resources'
import { Runtime } from 'aws-cdk-lib/aws-lambda'
import { Secret } from 'aws-cdk-lib/aws-secretsmanager'
export class CognitoStack extends Stack
{
public userPool: UserPool
public userPoolClient: UserPoolClient
public identityPool: CfnIdentityPool
constructor(
scope: App,
id: string,
props: StackProps
)
{
super(scope, id, props)
const applePrivateKeySecret = Secret.fromSecretNameV2(this, 'ApplePrivateKey', 'TheKeyNameInSecretsManager')
// Create a Lambda to securely retrieve the Apple private key at runtime.
const getApplePrivateKeyLambda = new NodejsFunction(this, 'GetApplePrivateKey',
{
runtime: Runtime.NODEJS_20_X,
functionName: 'getApplePrivateKey',
entry: join(__dirname, '..', 'lambda', 'getApplePrivateKey.ts')
})
// Grant access to `applePrivateKeySecret`.
applePrivateKeySecret.grantRead(getApplePrivateKeyLambda)
// Create a custom resource provider for invoking `getApplePrivateKey`.
const getApplePrivateKeyProvider = new Provider(this, 'GetApplePrivateKeyProvider',
{
onEventHandler: getApplePrivateKeyLambda
})
// Create a custom resource to call `getApplePrivateKey`.
const getApplePrivateKeyResource = new CustomResource(this, 'GetApplePrivateKeyResource',
{
serviceToken: getApplePrivateKeyProvider.serviceToken
})
// Access the secret value directly from the custom resource's attributes.
const applePrivateKey = getApplePrivateKeyResource.getAtt('ApplePrivateKey').toString()
console.log(applePrivateKey)
if (typeof applePrivateKey === 'undefined')
{
throw new Error('Failed to retrieve Apple private key.');
}
// Configure Apple as an Identity Provider.
const appleProvider = new UserPoolIdentityProviderApple(this, 'UserPoolIdentityProviderApple',
{
clientId: 'com.myapp',
teamId: '123456',
keyId: '123456',
privateKey: applePrivateKey,
userPool: this.userPool
})
// Create a Cognito User Pool.
this.userPool = new UserPool(this, 'UserPool',
{
signInAliases:
{
email: false,
phone: false,
preferredUsername: false,
username: true
}
})
// Register Apple as an Identity Provider.
this.userPool.registerIdentityProvider(appleProvider)
// Create a User Pool Client.
this.userPoolClient = new UserPoolClient(this, 'UserPoolClient',
{
userPool: this.userPool,
oAuth:
{
flows:
{
authorizationCodeGrant: true
},
scopes:
[
OAuthScope.OPENID
]
},
preventUserExistenceErrors: true,
supportedIdentityProviders:
[
UserPoolClientIdentityProvider.APPLE
]
})
// Create an Identity Pool for Federated Identities.
this.identityPool = new CfnIdentityPool(this, 'IdentityPool',
{
allowUnauthenticatedIdentities: false,
cognitoIdentityProviders:
[
{
clientId: this.userPoolClient.userPoolClientId,
providerName: this.userPool.userPoolProviderName,
serverSideTokenCheck: true
}
]
})
}
}Regression Issue
- Select this option if this issue appears to be a regression.
Last Known Working CDK Version
No response
Expected Behavior
I expected the token to resolve on deployment so I could use it to create an identity provider for Cognito.
Current Behavior
The token does not resolve and breaks the deployment. If I add a check Token.isUnresolved(), it will always be true.
Reproduction Steps
See above code please.
Possible Solution
No response
Additional Information/Context
No response
CDK CLI Version
2.156.0 (build 2966832)
Framework Version
No response
Node.js Version
20.16.0
OS
Windows 10
Language
TypeScript
Language Version
TypeScript 5.5.3
Other information
No response