DynamoDB fine-grain access with Lambda - amazon-web-services

I'm trying to access user data in DynamoDB table using identity level fine grained access. For user authentication I'm using Developer Authenicated Identities.
To accomplish that my policy includes:
{
"Action": [
"dynamodb:GetItem",
"dynamodb:UpdateItem"
],
"Effect": "Allow",
"Resource": "arn:aws:dynamodb:eu-west-1:817949094961:table/Users",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${cognito-identity.amazonaws.com:sub}"
]
}
}
}
When trying to access user's data from DynamoDB table - in a Lambda function I'm getting following error:
Error in updateUser: AccessDeniedException: User:
arn:aws:sts::12312313:assumed-role/LambdAuthEditAccount/awslambda_123_20160410184653936
is not authorized to perform: dynamodb:UpdateItem on resource:
arn:aws:dynamodb:eu-west-1:12312312:table/Users"}
However it works just fine when accessing DynamoDB directly from the client browser using JS API - fine-grain access control works correctly. The policy block above is added to both user authenticated role and the role assumed by Lambda function.
I'm wondering if the role assumed by the Lambda (included in the error above) shouldn't resolve to user authenticated role?

Above policy will not work for the role assumed by lambda function, since it requires the id token issued by Cognito to assume the role and get credentials.
You can try the following approach:
1) Pass the identity id and the token (received from GetOpenIdTokenForDeveloperIdentity) to the lambda function.
2) Call getCredentialsforIdentity from lambda function and pass the identity id and above token in logins map.
3) Use these credentials to access to dynamoDB.

Related

S3 Bucket Policy to allow S3 Access to Current Authenicated user in AWS Console?

I have an application where I am using Cognito to authenticate users and giving temporary access to AWS Console but that user is able to see all other buckets, I want that user just should be able to see or access buckets created by him.
Currently, I have given S3FullAccess Policy to Cognito users. Can anyone suggest which policy I should attach?
As per my R&D, I can some policies are there that can restrict particular user or allow particular user but my users will be dynamic, so I cannot hard-code the values and also policies like allowing/restricting access to particular buckets, I want only users who create buckets should be able to access not other users.
This is something which i found
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::bucket-name",
"Condition": {
"StringLike": {
"s3:prefix": [
"",
"home/",
"home/${aws:userid}/*"
]
}
}
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket-name/home/${aws:userid}",
"arn:aws:s3:::bucket-name/home/${aws:userid}/*"
]
}
]
}
But this is listing all buckets and the only accessible bucket is what put in the code above, I want for new user, it should show nothing and as it creates, it should show that only
This is not going to be easy and you will need to create your own policy and enforce some conventions. You have 3 options.
But first, if each user just needs their own S3 space look at S3 Prefix [here](
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-3-roles-and-policies/) Also, you can do this on the S3 resource bucket. I have a template for doing this here in gitlab
Now back to answering your question.
Option 1; They will need to set a tag when they create the bucket where an "owner" tag is equal to their identity. I striked this one out because despite being listed in the IAM policy I'm pretty sure it doesn't work with S3.
Option 2: The prefix of the bucket name is equal to their identity.
Then you can use the feature of variables and tags in IAM Policy. Read here
Note that coginto users are web federated identities so the variable aws:username is not aviable for you. Use the aws:userid variable and the value will be role id:caller-specified-role-name where role id is the unique id of the role and the caller-specified-role-name is specified by the RoleSessionName parameter passed to the AssumeRoleWithWebIdentity request
Option 3: Use IAM Access Policy
I can not find a link to the how to at the moment. But from here is a detailed description.
Q: How do I control what a federated user is allowed to do when signed in to the console?
When you request temporary security credentials for your federated
user using an AssumeRole API, you can optionally include an access
policy with the request. The federated user’s privileges are the
intersection of permissions granted by the access policy passed with
the request and the access policy attached to the IAM role that was
assumed. The access policy passed with the request cannot elevate the
privileges associated with the IAM role being assumed. When you
request temporary security credentials for your federated user using
the GetFederationToken API, you must provide an access control policy
with the request. The federated user’s privileges are the intersection
of the permissions granted by the access policy passed with the
request and the access policy attached to the IAM user that was used
to make the request. The access policy passed with the request cannot
elevate the privileges associated with the IAM user used to make the
request. These federated user permissions apply to both API access and
actions taken within the AWS Management Console.
The nice thing about this approach is you programmatically create the access policy.

IAM Policy Cognito Variables for DynamoDB LeadingKeys Restriction

My setup:
- Mobile Hub
- Cognito User Pool
- Api Gateway
- DynamoDB
What I got working so far:
The User can sign up/in with the Cognito User Pool and get an Id and AccessToken.
The IdToken is used with the Api Gateway Cognito Authorizer to access the Api Gateway.
The Mapping of the user sub into the integration message to DynamoDb works.
"userId": {
"S": "$context.authorizer.claims.sub"
}
Restricting the access to non user rows in a DynamoDb Table does not work.
The DynamoDb tables were created using Mobile Hubs Protected Table feature, which creates the following policy:
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${cognito-identity.amazonaws.com:sub}"
]
}
}
But thats not working, because this expression returns the Identity User Id and NOT the User Pool Sub. At first I'm not using Identity Pools and second I want to use the User Sub here.
I found out
${cognito-idp.<REGION>.amazonaws.com/<POOL-ID>:sub} should do the trick, but thats not working too.
If I hardcode the Condition to use the Sub of my test user, everything works as expected, so the Policy itself is okay, it's only the expression to get the sub of the current user is not working correctly.
Is it possible to debug the IAM Policys to see what the values of the expressions are at runtime?
Any Ideas, hints, suggestions?
Thanks in advance.
I got the answer now from an AWS Dev. You are only able to use the
${cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXX:sub}
variable if you configure the Cognito User Pool as an open ID Connect provider directly against IAM.
But there is a big problem, because you need to update the SSL Thumbprint of the service endpoint if the certificate changes in the Open ID Connector configuration. But you are not able to tell when the aws certificate has changed.
I finally figured this out by using aws:PrincipalTags
Pre-req is making sure that the IAM role that the Cognito User assumes has sts:TagSession assume role policy permission. This allows principal tags to be passed after successful login to Cognito.
On the Cognito Identity Pool, open Authentication Providers and find the Cognito provider. Make sure that Attributes for access control uses the default mappings which maps username to sub, or you have a custom rule set that passes the sub property to a PrincipalTag.
Finally you can use the tag passed in the filter of the role to only allow access to resources by that sub.
{
"Action": [
"dynamodb:UpdateItem",
"dynamodb:Query",
"dynamodb:PutItem",
"dynamodb:GetItem"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": "${aws:PrincipalTag/username}"
}
},
"Effect": "Allow",
"Resource": "arn:aws:dynamodb:*:*:table/MyTableName",
"Sid": ""
}

Access Cognito User ID variable in IAM role definied for API Gateway execution role?

With the recent release of API Gateway Cognito Custom Authorizers, I'm attempting to use Cognito, API Gateway and S3 together for authenticated access control without Lambdas.
Authorizing with API Gateway works as it should (with Trust Relationships for the API Gateway execution role set correctly) but I can't seem to get the resource policy to capture the Cognito User ID Sub variable for fine grain access control to S3 resources based on User ID.
Here's the current flow I'm trying to accomplish:
Authenticate with Cognito and get valid token
Send token to API Gateway to gain access to S3 bucket (through AWS Service integration type)
Fine grain access to only User ID's directory
Return S3 object (based on API endpoint)
Here's my current resource policy for the API Gateway execution role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cognito-idp:*",
"cognito-sync:*",
"cognito-identity:*"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:Get*",
],
"Resource": [
"arn:aws:s3:::mybucket/${cognito-identity.amazonaws.com:sub}/*"
]
}
]
}
Everything works as it should but this IAM variable (in the policy attached to the API Gateway execution role) doesn't seem to be right.
I came across this StackOverflow article and tried using both formats us-east-1:xxxx-xxxx-xxxx-xxxx and xxxx-xxxx-xxxx-xxxx but both didn't seem to work. I'm using the sub attribute found in the Cognito User Pool User info. If I hard code the folder in S3 to the Cognito User ID Sub it works just fine.
How do I get the Cognito variable to work in the API Gateway's execution role policy?
Here are a couple other articles I found related to the question on the AWS forums:
Cognito IAM variables not working for assumed-role policies
What cognito information can we use as IAM Variables?
That's not the sub that the variable expects. There is no way to use cognito user pool attributes in policy. The sub that you want is the cognito identity id which is the id of the user in the cognito Identity (federated identity pool). You can get this ID by using the get id method. I would suggest you store this ID as a custom attribute variable in your cognito user pool so you don't have to keep making the call.
You can read more about this identity id here.

Targetting federated SAML users in IAM role policies

We're currently using G Suite as an IDP for our AWS SAML access that assumes a role within a handful account to give our G Suite users access to certain AWS resources. Each account has a similarly named role that the G Suite user can assume to give them access to certain resources in that account which is all working as expected.
I'm looking into whether I can configure that assumed role to give more fine-grained access to certain users for certain resources, without having to assign completely different roles to different users within G Suite itself.
For example, if the role assumed within the account is called "assumed_gsuite_ro" and doesn't give access to IAM, you get errors in the IAM console as such:
User: arn:aws:sts::0012345678900:assumed-role/assumed_gsuite_ro/matt#domain.com is not authorized to perform: iam:GetAccountSummary on resource: *
So I'd like to add something as such to the assumed_gsuite_ro role policy to give just my federated user access to that in IAM:
...
{
"Sid": "IAMTest",
"Effect": "Allow",
"Action": [
"iam:GetAccountSummary",
"iam:ListAccountAliases"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:sts::0012345678900:assumed-role/assumed_gsuite_ro/matt#domain.com"
}
}
}
...
However, this doesn't work as apparently the SourceArn doesn't match. Is there a value of the condition I can use that will allow me to target the specific federated user that AWS seems to know about? I was thinking something like aws:userid or aws:username might work, but I'm not sure what the values of those would be in this case.
Having delved a bit deeper and found this page in the AWS documentation which describes how the values of aws:userid is made up in a SAML/federated context, I've determined the following works:
"Condition": {
"StringLike": {
"aws:userid": "AROAROLEID:matt#domain.com"
}
}
Where AROAROLEID is the value of the "role ID" for the name of the role you're assuming (assumed_gsuite_ro in my example) which according to this page you can only get from a get-role call to the AWS CLI (it's the value of RoleId).

Unable to sts:AssumeRoleWithWebIdentity for a Cognito user

I have a simple use case to authenticate a user using AWS Cognito and the assume a role to be able to do something useful (read from S3 in my case). Apparently I am missing something very obvious.
I am using pure web http client with cognito authentication (so Cognito can federate other identity providers) and the backend receive only the id_token.
I could get session credentials using getCredentialsForIdentity, apparently this credentials have assigned permissions from the role defined by the Cognito identity pool (in my case Cognito_demoidpoolAuth_Role)
My idea was creating another role which the federated web identity could assume.
So I created a new role for Web Identity, the role to access the data has Trust Relationship with following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "eu-central-1:500a5721-abca-xxxx-xxxx-c15625a7xxxx"
}
}
}
]
}
Following code should assume the role needed to read from the bucket
WebIdentityFederationSessionCredentialsProvider credProvider = new WebIdentityFederationSessionCredentialsProvider(
idToken,
null,
"arn:aws:iam::535544306598:role/docmgr-test-role" );
under the hood this object calls assumeRoleWithWebIdentity and I get following exception:
com.amazonaws.services.securitytoken.model.AWSSecurityTokenServiceException:
Not authorized to perform sts:AssumeRoleWithWebIdentity (Service: AWSSecurityTokenService;
Status Code: 403; Error Code: AccessDenied; Request ID: 059e56ee-25c8-11e8-8852-f7ca4d49742b)
Calling directly STS assumeRoleWithWebIdentity with the id_token ends with the same result, so apparently I have set wrong policy or trying to do things wrong way.