Generate temporary AWS creds that could be used by any client - amazon-web-services

I have a use case where I need arbitrary clients to receive AWS credentials (key and secret) that I generate and pass to it. The credentials should expire after a few minutes. The clients need to post to an s3 bucket.
The clients will not be a part of any AWS account and cannot use any multi factor auth. This seems to prevent me from using IAM roles.
It seems that the Security Token Service is what Amazon provides for similar use cases, but I can't massage it to get what I need out of it. I either need a role ARN, or to pass the session token on to the clients to use in their requests. The clients can have no concept of a session token- only AWS key/secret.
In short, I want to be able to generate a temporary AWS key/secret pair that needs no multifactor auth or session token.
Is this possible? Thanks!

This is exactly the use-case for Uploading Objects Using Pre-Signed URLs - Amazon Simple Storage Service.
Basically:
Your application determines whether the user is authorized to upload/download a file
It generates a Pre-signed URL that includes an expiration time
The clients use the URL to upload/download to S3
After the expiry time, the URL no longer works

Related

How to enable presigned S3 URL for different users?

I am trying to build a service where users are able to upload photos to an S3 database using presigned URLs given to them via API gateway. For each user, I was planning on submitting the photo information through the presigned URL and identifying the user who sent it as metadata via the ID found in the access token granted by AWS Cognito.
However, I am not sure how to secure it so that users can only upload photos as themselves and not as others. It seems to me that malicious users can simply modify the frontend code to change the user ID and submit photos as someone else.
I'm wondering if it is possible to create a presigned URL with some sort of ID so that they can only submit content as themselves? Or is there a better way?
How about this solution:-
There is one question that is not mentioned, how do you plan to differentiate legit users and non-legit users, or is it open to everyone?
Use Amazon Cognito to authenticate users.
users will try to query for URL (upload s3 through an interface), API gateway will verify authentication.
if authentication is successful; then only lambda will generate an s3 resigned URL.
This solution is a little costly however it serves you the purpose of making it secure, where if the user is authenticated then only lambda will generate a signed URL.
You should not worry about the identity of the user, or someone sending a false identity, because a sub claim will be present as part of the token, if someone tries to change that, the cognito will not verify it.
A heads up:- if you are trying to make this service global, then you can implement a backend database like dynamodb, and add a manual/automatic step to add a attribute to identity users who are privileged and add logic to lambda to find users who is privileged and then generate resigned URL exclusively for that privileged user
.https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html, https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-enable-cognito-user-pool.html

secure aws s3 objects (control access with authorizer like jwt, how a web app would normally do)

I need to secure my s3 bucket objects. In my web application I'm using aws-sdk to upload media to s3 bucket and get an http link back to access that object. This http link is public by default and I want to make it secure so that only authorized users can access the media. aws s3 allows to make the object private but it wont let anyone with the link access the object.
This link will be accessed from a mobile app where I dont want to use aws-sdk, Instead I want to execute some logic on aws side whenever someone tries to access the http link for the object.
What I would like to happen is, before the user gets access to s3 object, Some authorizer code would execute (like a jwt token authorizer) and depending on it user would be granted/denied access.
I'm currently looking into Amazon API Gateways, I believe they can be accessed as an http link and AWS Lambda could be used to secure them(where i would execute my jwt authorizer). Then these apis would have access to s3 internally.
If someone could point me in the right direction, If this is at all possible.
If I could use the same jwt token issued from my web-application to send along the request to Amazon API Gateway, that would be great.
I would make the bucket private, and place a CloudFront distribution in front of it. Using an Origin access identity to allow only CloudFront to directly access the S3 bucket.
Then to provide security I would use either CloudFront signed cookies, or Lambda#Edge with a custom JWT token validation.
The easiest solution to expose private objects in an S3 bucket is to create a pre-signed URL. Pre-signed URLs use the permissions from the service (which pre-signs the URL) to determine access and have only a limited duration in which they can be used. They can also be used to upload an object directly to S3 instead of having to proxy the upload through a lambda function.
For a download functionality and a smooth user experience, you can - for example - have a lambda function that generates a pre-signed URL and returns it as an HTTP 302 response, which should instruct the browser to automatically download the file from the new URL.
(Edit)
Following on what I've stated in the comments on this answer, if you're proxying the upload/download of the objects through services such as API Gateway or Lambda, you will be severely limited in the size of files that you are able to upload to S3. The payload size limit on an API Gateway is 10 MB and for requests to lambda your payload is capped at 6MB for synchronous invocations. If you want to upload something larger than 10 MB, you will need to use direct upload to S3 for which pre-signed URLs are the safest solution.
I know I am bit late here, but I wanted to give my opinion in case someone has the same problems.
Your mobile app should communicate with a server app (backend app) for authentication and authorization. let's say you are deploying your server app on AWS VPC. Now, it's simple to manage the files access by creating a policy which allow just your server app (IP, or VPC) to access the bucket. the authorization part will be managed on your application.

AWS Cognito get new id_token

I'm using implicit grant for one particular client (web-based admin portal) for an application that uses Cognito-integrated auth for other parts of the application (API Gateway, etc).
The problem is, the id token I get from Cognito Oauth expires after one hour, but I still need that token to send to API Gateway to signify that I have an authenticated user.
How do I get a new id token (remember, I'm using implicit grant, so I don't have a refresh token)?
Do I have to re-send the user's credentials to Cognito's auth endpoint every hour? That seems extravagantly un-secure for several reasons.
What am I missing?
Thanks in advance!
If you use implicit grant there is no way of refreshing the tokens (Storing credentials and using it to get new id tokens doesn't count here since its takes away the purpose of using OpenID Connect).
This is why the code grant is there. Unless you use code grant, refreshing the tokens are not possible.
You can use AWS Amplify library to simplify the login where it takes cares of the refreshing and other heavy liftings if you use the code grant including using federated identities to access AWS resources such as S3.

Using S3 for saving images from mobile application

I am creating a backend service which will be getting requests from an Android application regarding creating of some service requests. These service requests will contain details about the the service items and also some images related to the request. We want to use S3 for storing the images directly from the android application and getting the key of the image saved through an API call on the backend service.
The problem with this approach is the authorization of the mobile application to access the shared bucket.
If we save the access key of the shared bucket in the application, this code can be decompiled and the secret will be compromised.
Another option is to create an API on the backend service which will give back the authorization key to the mobile application before it needs to put the image to S3. In this way we can also rotate the secrets periodically.
Which of these approach is better in terms of security? Is there any other approach which I am missing? It sounds like a standard access practice of using S3 for saving files, so there must be something for this particular scenario.
You don't need to invent an API to do this - AWS provides its STS service for just this use case.
http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html
To request temporary security credentials, you can use the AWS STS API actions.
To call the APIs, you can use one of the AWS SDKs, which are available
for a variety of programming languages and environments, including
Java, .NET, Python, Ruby, Android, and iOS. The SDKs take care of
tasks such as cryptographically signing your requests, retrying
requests if necessary, and handling error responses. You can also use
the AWS STS Query API, which is described in the AWS Security Token
Service API Reference. Finally, two command line tools support the AWS
STS commands: the AWS Command Line Interface, and the AWS Tools for
Windows PowerShell.
The AWS STS API actions return temporary security credentials that
consist of an access key and a session token. The access key consists
of an access key ID and a secret key. Users (or an application that
the user runs) can use these credentials to access your resources.
When the credentials are created, they are associated with an IAM
access control policy that limits what the user can do when using the
credentials. For more information, see Using Temporary Security
Credentials to Request Access to AWS Resources.

Confused on use/ need of cognito

So since parse is shutting down we are moving our website / mobile app that we've been developing to AWS. We are primarily going to use the following services:
SNS, SES, Dynamo, S3, Lambda.
Now I am still a bit confused on:
what cognito is used for? Do we really need cognito to authenticate users and use DynamoDB, S3, SNS ? Or can we just use specific APIs for each of these services and connect directly (using Js SDK)?
If we do have to use cognito how do we save local data i.e logged in user/ identity? is that what cognito sync is for or do we have to use cookies ?
In summary why do I need cognito when I can directly connect to DynamoDB using the JavaScript SDK?!
Thank you in Advance.
Amazon Cognito can be decomposed in two sub-services: Amazon Cognito Identity and Amazon Cognito Sync.
Think of the former as an authentication service and a credentials provider. The latter is just a service to store user data and keep it synchronized between multiple devices.
What is the purpose of Amazon Cognito Identity?
Suppose that you have a table in DynamoDB. Let's say that you have a web application that will store an item on that table.
You can create an user in IAM, embed the credential information on the web application, and then put the item on the table using the AWS SDK.
There are three things going on here:
The credentials are embedded in the application
The credentials do not expire.
Every user in your application has the same access rights on your table
This may be fine for some applications, but Amazon Cognito Identity offers a solution to these common problems.
Let me explain Cognito Identity's workflow:
An user registers an account on your application, sending all the information (username, password, other data...) to your server.
The server stores the user in some back-end database (it could be a DynamoDB table) and creates a new identity on the Cognito service. This identity is then mapped to this user.
The user can now login into your application. The user logins and sends username and password to your server. (This process could be done automatically after account registration)
The server checks the username and password against your back-end database. If everything is right, then the server makes a request to Amazon Cognito for a temporary access token.
The web application receives the token and makes a request to Amazon Cognito (using that access token) to get the user credentials. These credentials are basically a temporary IAM user that was created specifically for this user. It will have an expiration (usually an hour).
The web application uses these credentials to make operations on AWS, such as putting an item on a DynamoDB table, or calling a Lambda.
When the credentials expire, the user must re-login into the application. This might be done automatically or not, depending on your application's requirements.
On the Amazon Cognito dashboard, you can configure roles and policies for your "identities" (an user in Cognito). This way you can specify which services it can access. It even allows you to create access roles for your users (Admin users may be able to access some services that normal users should not).
I should also note that Amazon Cognito can be easily adapted to support Facebook / Google+ / Amazon accounts, which will be mapped to the same identity, so the user can login via multiple sources.
What is the purpose of Amazon Cognito Sync?
Consider it like a DynamoDB table where you store information for a specific user. These information is shared between multiple devices and is always synchronized. This means that when a web application updates an user value, then the mobile application will automatically reflect this change.
There is a limit on how much user data you can store (I don't remember now), so it's not something you would use to persist information (such as an user password), but rather a mean to share information.