AWS Web Identity Federation, using dynamic roles for different users - amazon-web-services

Following articles on AWS Web Identity Federation I am a bit confused as to how can I ensure that each user who executes the AssumeRoleWithWebIdentity call can assume a different role? Is that even possible?
The following are the steps (ref.):
1. Mobile or Web Application needs to be configured with the IdP which gives each application a unique ID or client ID (also called audience)
2. Create an Identity Provider entity for OIDC compatible IdP in IAM.
3. Create IAM role and define the
1. Trust policy – specify the IdP (like Amazon) as the Principal (the trusted entity), and include a Condition that matches the IdP assigned app ID
2. Permission policy – specify the permissions the application can assume
4. Application calls the sign-in interface for the IdP to login
5. IdP authenticates the user and returns an authentication token (OAuth access token or OIDC ID token) with information about the user to the application
6. Application then makes an unsigned call to the STS service with the **AssumeRoleWithWebIdentity** action to request temporary security credentials.
7. Application passes the IdP’s authentication token along with the Amazon Resource Name (ARN) for the IAM role created for that IdP.
8. AWS verifies that the token is trusted and valid and if so, returns temporary security credentials (access key, secret access key, session token, expiry time) to the application that have the permissions for the role that you name in the request.
9. STS response also includes metadata about the user from the IdP, such as the unique user ID that the IdP associates with the user.
10. Using the Temporary credentials, the application makes signed requests to AWS
11. User ID information from the identity provider can distinguish users in the app for e.g., objects can be put into S3 folders that include the user ID as prefixes or suffixes. This lets you create access control policies that lock the folder so only the user with that ID can access it.
12. Application can cache the temporary security credentials and refresh them before their expiry accordingly. Temporary credentials, by default, are good for an hour.
So from the above, in step 11, I can add dynamic resource policies to resources to allow for user specific access, e.g. for S3. Although what happens for resources which don't support resource policies?
E.g. how can I ensure that one user logging in using Google for example, gets Write access (WriteRole) to DynamoDB whereas another using logging in using the same Google IdP only gets Read access (ReadRole) to DynamoDB?
Any help will be appreciated.

Related

How do I use an Access Token with AWS SDK?

I have an App client created for a Cognito User Pool. The client has an ID and secret generated. It is configured to use the Client credentials flow and has a custom scope defined. With that in place, I'm able to successfully exchange the creds for an Access Token, so far so good.
I would like to use AWS SDK to manage users (list, delete etc) in the User Pool with the server-side app client. Assuming I validated the granted token, how do I use it with AWS SDK to execute Actions I need? Is there a better way to manage User Pools from a server-side app?
If you look at Admin* level actions in the Cognito SDK (e.g. AdminDeleteUser), you will see it does not accept access tokens. It rather expects valid AWS developer credentials.
So what you probably want to do is to create an IAM role with appropriate permissions to manage the user pool (resource format: arn:aws:cognito-idp:REGION:ACCOUNT_ID:userpool/USER_POOL_ID) and let your server application assume that role. With correct permissions configured, you can call the AWS SDK directly.
You can find the list of available IAM actions here.

AWS Identity federation clarification

May I ask for some clarification on AWS IAM Identity federation for Mobile App scenario. After the App received temporary AWS credentials from STS, it uses those credentials(like Access key ID,a secret access key, and a session token) to access the AWS resource.
AWS link
Questions:
1. What happens in AWS after it received the credentials? it matches those credentials against which user? Does it creates a temporary user in the AWS account and sets the credentials for that user?
2. How the user data is preserved ? I mean if I created a Mobile Game App and want to store the player score, how the score data is preserved for days ?
What happens in AWS after it received the credentials?
Amazon verifies your credentials against the permissions assigned to those credentials. The API call that you are making is then authorized and is performed or is not authorized and the API fails.
Does it creates a temporary user in the AWS account and sets the
credentials for that user?
No. A lookup is performed based upon the Access Key and validated with the Secret Access Key.
How the user data is preserved ? I mean if I created a Mobile Game App
and want to store the player score, how the score data is preserved
for days ?
Amazon Cognito does support a limited amount of saved user data. This is stored in Key/Value pairs.
To add more functionality, use the Amazon Cognito Sync SDK.
Amazon Cognito Sync

Allow Cognito user to Write to S3

I have an embedded device that requires the ability to write to S3. I want to avoid giving the embedded device an actual AWS IAMUser. I am looking at using Cognito to gain write access to S3.
I have a user pool with a group and one user (for now). The group has an attached policy which permits access to write to a certain S3 bucket. The pool is setup so that only admins can create new users. I have managed to authenticate the cognito user and have got access to refresh tokens and the idTokens. I am looking to use these tokens to write to my s3 bucket.
I am trying to follow trying to follow the documentation but am getting confused. I think i need a federated identity pool but i have no requirement for a public provider. I just want my cognito user group to write to s3.
Is there a simple solution to allow a cognito user to write to S3 without federated identities or if not do i require a back end to serve a token for a federated identity?
I have been using warrant https://github.com/capless/warrant to authenticate as so:
from warrant.aws_srp import AWSSRP
import boto3
client = boto3.client('cognito-idp')
aws = AWSSRP(username='<username>', password='<password>', pool_id='<pool>',
client_id='<clientid>', client=client)
tokens = aws.authenticate_user()
Any tips would be greatly appreciated!
You do need a federated identity pool. In the identity provider section you choose Cognito and enter your pool ID and pool client ID. Then, you need to provide the identity pool with authenticated and unauthenticated roles. You can use these roles to provide that S3 write access.
This is the default behavior for the identity provider setup. If you want the Role to come from the group that your user is in, you will need to set the Choose role from token option in the identity provider section under where you provided your pool and client id.

Cognito: Federated Identity Id and User Attributes

Story:
I have a Cognito User Pool with Users.
This User Pool is an authentication provider in a Federated Identity Pool.
I have an S3 bucket where users are limited to uploading to a private path via a policy on the Auth Role as follows:
arn:aws:s3:::BUCKET_NAME/${cognito-identity.amazonaws.com:sub}/*
The users upload directly from the web browser via the aws javascript sdk.
Now this works great and my users are limited to where they upload. The files they upload end up with paths in the bucket looking like this:
us-east-1:0f26319c-1233-4c71-afb6-fac96a798ffb/random_file_name.txt
I then have a lambda which is triggered from this S3 bucket whenever a file is added. To clarify, the user does NOT invoke the lambda
Problem:
I would like to access the user's attributes in the user pool from the lamda. I thought that I could do this lookup using the cognito-identity sub. However, I can't seem to find a way using the SDK api's to allow this.
Using this api:
http://boto3.readthedocs.io/en/latest/reference/services/cognito-identity.html#CognitoIdentity.Client.describe_identity
I am able to get the login / the user pool but not the username associated with this Identity ID.
If I had the username, then I could use the api: http://boto3.readthedocs.io/en/latest/reference/services/cognito-idp.html?highlight=cognito#CognitoIdentityProvider.Client.admin_get_user
Any ideas how I can use the Federated Identity ID to lookup the user's attributes?
Unfortunately, I don't believe this is possible. The reason is, as far as I understand, technically the federated identity ID doesn't have to represent a user pool user. If you connected other authentication providers to the identity pool users could have completely different properties, for example.
What about storing files in
arn:aws:s3:::BUCKET_NAME/${cognito-idp.us-east-1.amazonaws.com:sub}
This will be resolved to the folder names like
f4cfd4a8-0e94-4287-8c5e-1b01538dd2a1
Using this sub of user from Cognito User Pool you can list users with that sub, for example in cli:
aws cognito-idp list-users --user-pool-id=us-east-1_ndhjGJQYE --filter "sub = 'f4cfd4a8-0e94-4287-8c5e-example'"

Authentication and Authorization to AWS resources

I was reading up per subject matter and has a query on what is the best practice to handle user's authorization to AWS resources.
Scenario:
A 2-tiers windows application that access to AWS S3 and dynamoDB.
There are 2 groups of users - Admin and Normal User. Admin has read + write access, and Normal User has just the read access.
I'm trying to see if I could avoid a 3-tiers design. At such, I would like to access AWS resources directly from my application. In another word, I do not access AWS resources thru web services (that could do my user authorization check there).
Design:
I uses Web Identity Federation (google) to authenticate user and uses STS to get temporary credentials.
I've created 2 IAM Roles - AdminRole (with write+read policy) and UserRole (with read policy).
At this point, my thoughts are stuck on what is the best practice and securely choose which role to assume from my application.
Solution 1:
Create a UserRole table in dynamoDb with UserId and Role attributes.
After user has authenticated with google, I'll check the UserRole table against the userid returned from google to get the role of this user. Assuming I've pre-setup all the user's roles in the table.
I do not want to hardcode or expose my AWS secret key onto my app, but for the above execution, I've created a secret key with a role and policy only to the [UserRole] table.
At this point, I would know which role to assume from my app when I get the temporary credential using STS.
However, with the above solution, I see that there is one security loophole. If someone is able to get hold of my application id used for my IAM role, and with some brute-force effort on my IAM roles' name, that person can easily gain temporary credential with AdminRole.
(added) Solution 2:
I create just 1 IAM role - GoogleUserRole
In the policy portion, I allow write access to admin user by using their Federated userid.
I'm still new with writing AWS policies, but I think I've read somewhere that I could have this fine-grained control to the specified user(s). This could be feasible if my users based are small, but not very feasible when my user base grows.
Welcome any thoughts and advises.
Thanks.