AWS Cognito Post Authentication Lambda Trigger - groupConfiguration - amazon-web-services

Is it possible, via a post-authentication lambda to alter the list of groups exposed by the AWS Cognito Identity token?
The documentation for the post-authenticaion Lambda states the following:
"....
groupConfiguration structure – contains group-related information that can override group-related claims in the identity token."
Full docs: http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-post-auth
The AWS Cognito Identity token exposes the current payload:
{
sub: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
cognito:groups: [
"group1",
"group2"
],
iss: "https://cognito-idp.*****/**-****-1_********",
cognito:username: "Google_*****************",
.....
}
What I would like to to, via a post-authentication lambda is to alter the list of cognito-groups.
Any suggestions on how to do this?

There is a mixup in the documentation. This is not currently supported. We are actively working to fix it.

Related

AWS Cognito: where is the metadata URL of Cognito User Pool?

I'm trying to use AWS Cognito as an authorizer for my REST API in AWS API Gateway.
It asks me to fill in the Issuer URL:
Digging through the AWS Cognito User Pool page, there is no such thing.
I found a related answer here: AWS: Cognito integration with a beta HTTP API in API Gateway?
and I quote:
Issuer URL: Check the metadata URL of your Cognito User Pool
(construct the URL in this format :: https://cognito-idp.
[region].amazonaws.com/[userPoolId]/.well-known/openid-configuration
:: look for a claim named "issuer". Copy its Value and paste it here.
I can of course build the url as said above.
But still, where is the metadata URL of my Cognito User Pool????
Am I missing something really basic and being absolutely silly by asking this question?
Where is it??
This is driving me crazy.
The issuer URL of a Cognito User Pool has the following format:
https://cognito-idp.[region].amazonaws.com/[userPoolId]
As you stated correctly, you can get it from Cognito's well-known metadata endpoint, which is available at
https://cognito-idp.[region].amazonaws.com/[userPoolId]/.well-known/openid-configuration
This file is JSON-formatted and contains an issuer field, which contains the URL mentioned above. The whole file looks like this:
{
"authorization_endpoint":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/authorize",
"id_token_signing_alg_values_supported":[
"RS256"
],
"issuer":"https://cognito-idp.[region].amazonaws.com/[userPoolId]",
"jwks_uri":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/.well-known/jwks.json",
"response_types_supported":[
"code",
"token"
],
"scopes_supported":[
"openid",
"email",
"phone",
"profile"
],
"subject_types_supported":[
"public"
],
"token_endpoint":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/token",
"token_endpoint_auth_methods_supported":[
"client_secret_basic",
"client_secret_post"
],
"userinfo_endpoint":"https://cognito-idp.[region].amazonaws.com/[userPoolId]/userInfo"
}

CDK AWS Is it possible to grant a role access to a specific method or is it only possible to grant for the whole API?

I have the following
let lambdaFunction = <some lambda construct here>
lambdaFunction.grantInvoke(props.invocationRole);
And that grants hydra the ability to invoke that lambda, but what if I had an api endpoint method?
let endpoint = resource.addMethod(method['method'], lambdaIntegration, {
authorizationType: AuthorizationType.IAM,
requestValidator: props.requestValidator,
requestModels: {'application/json': props.validationModel}
})
Is it possible to grant the role that I have access to just this endpoint access or do I have to do it on the api gateway resource level?
I have no experience with API Gateway, however it looks like it does support access control using the specificity of a particular endpoint.
Reference Docs:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html
Using the CDK, you can apply a policy with the same structure as the examples in the docs.

Best way to authorize gateway access to IAM and Cognito using CDK

Using CDK, I have a gateway rest api lambda which I want to be accessible to;
Members of a cognito user pool
Other lambdas in my stack
As far as I know there is no way to add 2 authorizers to the same gateway resource method?
So this means I have 2 options;
Create custom Lambda authoriser which verifies tokens for cognito and IAM
Add 2 separate recourses to my api and call a different endpoint from my client vs my lambdas. E.g:
/external/route1 with cognito authorizer
/internal/route1 with iam authorizer
Which of these approaches is better? I imagine option 2 is easier to setup. Are there any CDK examples or constructs that could help me with this?
You can run Cognito authorizers down the whole stack and then check the scopes per internal service. At a gateway, Cognito authorizers will validate the token and check the scopes against what you've specified. I don't know about CDK, but if you're using Pulumi Crosswalk, it's really trivial to setup Cognito Authorizers in APIGW, something like this:
const api = new awsx.apigateway.API(<NAME>, {
routes: [{
path: <PATH>,
method: <METHOD>,
eventHandler: <LAMBDA>,
authorizers: [awsx.apigateway.getCognitoAuthorizer({
providerARNs: [<USERPOOL>],
methodsToAuthorize: ['<RESOURCE>/<SCOPE>']
})]
}]
});

Serverless Framework AWS Fine-Grained Access Control

I am attempting secure my AWS API such that DynamoDB rows can only be accessed by the corresponding authenticated Cognito user by implementing fine grained access control in my Serverless Framework config (serverless.yml)
See example of what I am attempting in the AWS Documentation
I have tried to convert the Cloudformation syntax to Serverless without success; when I try something like the following expression in my policy statement:
Condition:
ForAllValues:StringEquals:
dynamodb:LeadingKeys: ["${cognito-identity.amazonaws.com:sub}"]
I then get an error:
Invalid variable reference syntax for variable cognito-identity.amazonaws.com:sub. You can only reference env vars, options, & files. You can check our docs for more info.
Is this even possible in Serverless? Or is it Cloudformation and SAM only?
I was encountring same problem and solve it this way:
Condition:
ForAnyValue:StringLike:
"dynamodb:LeadingKeys":
- !Join ["", [ "$", "{cognito-identity.amazonaws.com:sub}" ]]
That's not very clean, but as per now variables syntax collides with AWS params syntax. See this for more details - https://github.com/serverless/serverless/issues/2601
It is possible in serverless. If I were you I will use AWS Lambda to verify the id_token which is sent to the user.
In this scenario, you should first transfer the key to AWS Lambda function using Api Gateway or other methods. Then follow this guide to verify the token. The code can be found in: https://github.com/awslabs/aws-support-tools/tree/master/Cognito/decode-verify-jwt
After verifying it you can add your code here:
......
if claims['aud'] != app_client_id:
print('Token was not issued for this audience')
return False
# now we can use the claims
# add your code here #
print(claims)
return claims

AWS Lambda: Give Lambda same role as signed in user

Im building a serverless application using the following AWS technologies:
AWS Cognito
AWS Lambda
AWS API gateway
AWS IAM
All requests from the client (programmed in Angular2) go through API gateway.
I have created a IAM role for signed in users: Cognito_MyApp_Auth.
I use a Cognito User Pool Authorizer to make sure all calls to my API are from valid signed-in users.
Question: How can I grant the Lambda function the same permission as the signed in user?
Use case: A signed in user may only create, edit or delete in his own S3 bucket, so granting Lambda full permission to S3 is not an option.
Cognito_MyApp_Auth does not set different permissions from user to user. It only defines the permissions for any signed user. So you should allow access to all buckets in this role's policy. (However, I'd limit this access to buckets starting with a specific prefix.)
Fortunately, when Lambda is invoked via Cognito SDK, using Cognito provided credentials, context object passed to handler carries Cognito identity used to invoke the Lambda.
For Node.js you can see how to get this information:
http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html#nodejs-prog-model-context-example
if (typeof context.identity !== 'undefined') {
console.log('Cognito
identity ID =', context.identity.cognitoIdentityId);
}
Once you have the identity id, you can set up your own logic to limit the user's access to her own bucket.
This was the case when you call the Lambda directly from the application using Cognito SDK. If you use API Gateway, there is a good post from an AWS employee: https://forums.aws.amazon.com/thread.jspa?messageID=717379
There is no direct way to grant the Lambda function the same permissions as the signed in user; however, you should be able to implement your use case using Cognito identity pools and policy using the cognito-identity context variable.
For this approach, you won't use Cognito user pools nor the Cognito user pool authorizer. Instead, you use a Cognito identity pool for federated identity. Set the authorization on you API methods as AWS_IAM. Don't use Lambda as the integration, but instead use the AWS proxy to integrate directly to S3. Set the integration request to use the caller's identity.
To cal the API you'll need to use Cognito to get temporary credentials and then sign your API request with them.
With this approach, the S3 call is made with Cognito identity context, so you can attach policy which uses cognito-identity variables to the IAM role associated with authenticated users in your Cognito identity pool.
For example:
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
]
"Resource": [
"arn:aws:s3:::BUCKET_FOR_USER_${cognito-identity.amazonaws.com:sub}/*"
]
}
See this post for a similar use case.