Using S3 for saving images from mobile application - amazon-web-services

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.

Related

Suggestion: Integrating Amazon Cognito with AWS DynamoDB

I've built an application which is connected with Amazon Cognito to take the sign in and sign-ups of users. Currently, application support three different subscriptions (Free, Basic, Premium). If the user signs in for basic Subscriptions, I want to give them least access to DynamoDB for download the parts of applications which is required to run the application service.
How to connect DynamoDB with Cognito directly
I am not sure, what's the best approach to follow this scenario?
(Please note- this is not a mobile-based application, so do not give suggestion to use AWS Amplify or relatable services)
When I was first learning about Cognito, I had made the same set of assumptions you are currently making. I knew that User Pools could act as my application's user directory, and Identity Pools would magically unlock all my authorization needs. I was mistaken :)
At the risk of oversimplifying, AWS Cognito exists to answer two questions:
Who are you? (authentication)
What can you do? (authorization)
Cognito addresses these concerns with two distinct offerings: User Pools (authentication) and Identity Pools (authorization).
At a high level, User Pools let you handle user registration, authentication, account recovery, and supports authentication with third-party identity providers like Facebook, Google, etc. Sounds like you might have this part figured out.
Cognito Identity Pools, on the other hand, provides a way to authorize users to use various AWS services. You can think of it as a vending machine for handing out AWS credentials. For example, if you needed to give your users access to upload a file to an S3 bucket or to invoke an endpoint in API Gateway, you could do so with an Identity Pool. You can even allow item-level access to DynamoDB based on an Amazon Cognito ID. However, this might not work the way you expect since your application users are probably not directly connecting to DynamoDB.
In most web/mobile applications, users are not connecting directly to DynamoDB. Instead, they are interacting with a web/mobile app that communicates to the back-end of your application via an API. That API would then communicate with DynamoDB. If your stack is in AWS, the path may look something like this:
Client (web/mobile app) <-> API Gateway <-> Lambda <-> DynamoDB
In this architecture, your users would authenticate via Cognito. Cognito would then authorize the user to make calls to API Gateway. API Gateway would execute your lambda, which would then interact with DynamoDB. The "user" of DynamoDB in this example is your Lambda, not the user of your application.
That last bit is important, so I'll repeat it: Unless your users are directly connecting to DynamoDB (not recommended), they are not the "user" operating on DynamoDb. Therefore, restricting DynamoDB access based on a user's Cognito ID is not going to be an option for you.
So, what can you do? Your application needs to provide the business logic around what effect your users can have on DynamoDB. Perhaps free users have read-only access to a specific partition, while premium users can modify the same partition. That logic has to be handled directly by you.
I know you said you weren't looking for Amplify suggestions since your application is not mobile-based. However, Amplify offers SDKs that aren't specific to mobile development. The folks at Serverless have made a fantastic tutorial on building a full-stack serverless web app, which includes a very readable chapter on serverless auth with Cognito. They use Amplify in a web app to integrate with Cognito, S3, and API Gateway. If that's something you are trying to do, I'd recommend checking it out.

How a mobile app should authenticate to AWS

I'm developing a mobile app that must access some AWS resources, so it needs authentication to AWS endpoint. The app doesn't manage users (sign-in, sign-out, register and so on).
My first solution was to create a IAM user dedicated to the mobile app and embed its credentials in the mobile app code. The app authenticate itself to AWS using the embedded credentials. It works, however AWS suggests to avoid embedding credentials directly in the app.
I think a better solution is Cognito. Because I don't need users management, I should use unauthenticated (guest) identity to request temporary AWS credentials.
However I don't understand why a guest Cognito identity is more secure than an embedded credentials. The mobile app receive a temporary AWS credentials by sending a Cognito Identity Pool ID, that is a long-term "number" embedded in the mobile app. If someone is able to find this Identity Pool ID, she can receive AWS credentials and access AWS resources as my official mobile app. It seems there's no difference between embedded AWS long-term credentials and huest Cognito access.
Why Cognito solution is better than embedded AWS credentials?
If you are creating unauthenticated access using identity pool, you are allowing public to access your AWS resources. Make sure you write your policy carefully and it won't matter if you use a single IAM user or cognito unauthenticated access as far as security is concerned.
Using federated identity will provide you benefits like getting statistics on usage and adding triggers to events. Also keep in mind that creating a single IAM user and then allowing multiple people to use these credentials is a "hack" way of doing what cognito federated unauthenticated idenity was designed to do. You might run into unexpected complications later if AWS decides to throttle this behavior of IAM.

To call AWS SDK APIs using secret key credentials versus using cognito credentials

In the AWS Xamarin SDK docs, the Amazon Cognito Identity API documentation for GetOpenIdTokenForDeveloperIdentity() says in its second paragraph that "You must use AWS Developer credentials to call this API."
Now, the general idea is to try to never expose API secrets & keys in the source code especially if there are other mechanisms available. AWS provides the IAM mechanism so that we can assume a role and then we can define which privileges can be assumed by that role.
But this text mentioned in bold above, does it mean i cannot use IAM roles and/or policies to call those APIs? Does it mean i HAVE TO include my accessKey and secretKey in my application source code?
Edit:
AWS provides the Cognito mechanism through which we can requested temporary credentials via
`credentials = new CognitoAWSCredentials ("IDENTITY_POOL_ID", "REGION_NAME");`
without directly using Developer credentials like the accesskey and secretkey etc.
But this text mentioned in bold above, does it mean i cannot use the credentials obtained via cognito because these credentials were not produced with Developer credentials?
Trying to figure out this new cognito thing.
You can use IAM roles to call this API, same way you would call any other AWS sigv4 API. Purpose of the text is to emphasize that unlike other Cognito unauth APIs (getId, getOpenIdToken, getCredetialsForIdentity) you will need to call GetOpenIdTokenForDeveloperIdentity from your server and with AWS credentials. These credentials can be obtained with IAM user or IAM roles.
Edit:
Cognito is meant for vending credentials on the client side applications, for eg: Mobile apps. Typically credentials are vended after federating with social identity providers, eg: Facebook, google, Amazon etc.
The API 'GetOpenIdTokenForDeveloperIdentity' was introduced to allow you to federate with Cognito with your own authentication system. If you don't have your own authentication system, you should not be using this API. This API is meant to be called from your server side application. Of course you can use Cognito to get the credentials on server side and call GetOpenIdTokenForDeveloperIdentity, but that's not what Cognito is meant for. Simpler will be to just use credentials with help of IAM on server side.

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.

Most secure solution to upload to S3 via mobile app

I need to upload files on AWS S3 via a mobile app. I found 2 solutions to deal with it.
Both solutions work, but I am not competent enough to determine what is the most secure one.
Using temporary credentials provided by Secure Token Service (STS) Amazon Web Services.
My server asks for temporary credentials (with restricted rights) to STS using the AWS account access_key_id & secret_access_key
My server then send the temporary credentials (access_key_id, secret_access_key & session_token) to the mobile app
The mobile app send the file on S3 using the temporary credentials with a specific request signature (computed on the mobile side)
Using permanent credentials (AWS account access_key_id & secret_access_key)
My server directly create a request signature (using the AWS account access_key_id & secret_access_key) and send the request "elements/structure" (included the generated signature, the needed headers,...) to the mobile app
The mobile app send the file on S3 using the "elements" with the signature provided by the server
The second solution is simpler. But that solution seems to be less secure:
the account access_key_id is exposed and the signature directly generated with the account secret_access_key.
The digest algorithm used to generate the signature is HMAC-SHA1. Is it secure enough ?
The second solution expose temporary credentials with expiration: it is much more secure to expose limited credentials. If the HMAC-SHA1 algorithm is secure enough to make the secret_access_key impossible to retrieve, I do not see why I would chose this solution.
Thank you for your inputs
Your temporary solution is essentially a Token Vending Machine. This is our recommended method for getting credentials onto the device for use with our AWS Mobile SDKs. The inherent benefit of shipping temporary credentials is that they could be used to access other services besides S3.