I have a Cognito User Pool and an API Gateway using Cognito User Pool authorizer. Each user in the pool is assigned to a group with an IAM role. With this setup at hand, the client authenticates with Cognito and then sends ID Token to the API Gateway, which authorizes the request and passes it to a Lambda function. The lambda then executes other services (DynamoDB and S3). My question is which credentials do I need to use in the lambda?
One option is to use ID Token passed to the lambda from API Gateway to get temporary credentials from STS. This basically allows me to use user's group IAM Role to access other AWS resources and would look as follows:
var credentials = new CognitoAWSCredentials(
"us-east-1:...", // Identity pool ID
RegionEndpoint.USEast1 // Region
);
credentials.AddLogin(
"cognito-idp.us-east-1.amazonaws.com/us-east-...", // User pool ID
"eyJraWQiOiJi..." // ID token
);
// use credentials to access AWS services
Another option is to use the execution role assigned to the Lambda function, but it almost feels like this is better suited for other scenarios... perhaps those where lambda is executed as part of an event? I also don't seem to understand how to get ahold of those credentials within lambda itself.
Is there something else I'm missing? What's a good approach to take here?
Update
What I had above was almost right, but not quite. First of all, figure out if your users will need unauthorized access. If so, go to your identity pool and enable unauthorized access.
To get access/secret keys for unauthorized users you'd do something like this (Using C# SDK, but the following concepts apply to other languages):
var client = new AmazonCognitoIdentityClient(
new AnonymousAWSCredentials(), // We're making public API calls
RegionEndpoint.USEast1); // Your Region
var identityId = await client.GetIdAsync(new GetIdRequest
{
AccountId = "****", // AWS account ID
IdentityPoolId = "us-east-1:****" // Identity Pool ID
});
var credentials = await client.GetCredentialsForIdentityAsync(new GetCredentialsForIdentityRequest()
{
IdentityId = identityId.IdentityId
});
// Use credentials.Credentials when calling AWS services
The above will issue credentials with permissions defined by the Unauthenticated IAM Role defined in your Identity Pool.
To get credentials for authenticated users you'll do this:
var client = new AmazonCognitoIdentityClient(
new AnonymousAWSCredentials(), // We're making public API calls
RegionEndpoint.USEast1); // Your region
var getIdentityIdRequest = new GetIdRequest
{
AccountId = "****", // AWS Account ID
IdentityPoolId = "us-east-1:****" // Identity Pool ID
};
getIdentityIdRequest.Logins.Add(
"cognito-idp.us-east-1.amazonaws.com/us-east-1****", // User Pool ID
idToken); // ID Token
var identityId = await client.GetIdAsync(getIdentityIdRequest);
var getCredentialsRequest = new GetCredentialsForIdentityRequest()
{
IdentityId = identityId.IdentityId
};
getCredentialsRequest.Logins.Add(
"cognito-idp.us-east-1.amazonaws.com/us-east-1****",
idToken);
var credentials = await client.GetCredentialsForIdentityAsync(getCredentialsRequest);
// Use credentials.Credentials when calling AWS services
You'll need the ID Token for this, so authenticate first and grab the ID token from the response. If the user holding the ID token belongs to a group in Cognito with an assigned IAM Role, the credentials returned from the above code will be for that role. If the user isn't assigned to a group or the group has no role, you'll get credentials for Authenticated User IAM Role assigned to the Identity Pool.
Also, as was suggested by @thomasmichaelwallace, the above can be done either from Lambda or from outside API Gateway/Lambda but only if you're using AWS_IAM Authorizer because it's the only one that accepts secret and access keys for authorization. If you're just using Cognito Authorizer, like i was, you'll need to pass ID token to your lambda and have your lambda gets credentials.