Ok, so I am new to AWS. I want to make an app that will store a small amount of user data. S3 seems to be the way to store data. Is there a way to make multiple storage spaces automatically with S3? Lets say I make an android app and people install it on their phone. Will they each automatically get an S3 storage space? how do I do that? thanks
You can create a S3 Bucket to your project with folders (depending on the architecture, can be one for customer). On this way, you will have an instance of the s3 service with all your user data.
Amazon S3 is simply an object-storage system. How you use it is totally up to you.
If you wish to store information on a per user basis, then you need to consider security in addition to how the data is stored.
If the intention is that a user can access some information that is private to them (as opposed to being publicly visible to anyone), then you first need to control access to data.
For public information, no authentication is necessary
For private information, something needs to determine what they are allowed to access, and then grant access
You should not give permanent AWS Credentials (Access Key, Secret Key) to every user. These credentials are only for your IT operations staff (you!) and for your applications.
This leaves two options:
Your central server could generate temporary access credentials using the AWS Secure Token Service, while specifying what access rights they have (eg access to a particular S3 bucket and path, or to other AWS services such as DynamoDB). OR
Generate pre-signed URLs for specific objects stored in Amazon S3.
Based upon your use-case, it seems a better fit to use pre-signed URLs. Basically, the flow is:
Your app would send a request to your central server, requesting access to an object.
The server (or rather, the app you have written that is running on a central server) verifies their identity and confirms that they should be allowed access to the object stored in Amazon S3.
The central server then generates a pre-signed URL that grants time-limited access to an object in Amazon S3 and sends the URL back to the client app
The client app then uses the URL to retrieve the data from Amazon S3
Only the app running on your central server requires AWS credentials. It then uses those credentials to generate pre-signed URLs that can be used by the client apps.
By the way, the app on the central server doesn't actually need to be running on a server. You could use AWS API Gateway to send requests to AWS Lambda functions, which can perform the logic and send back the response. This would be a serverless solution, but still with centralized logic.
Related
I'm using flask as backend for REST APIs. I have a database which contains users and images information uploaded by them. All the images are stored in a S3 bucket like "bucket_name/user_1/img1.jpg". I want to allow the users to download all the images that are only specific to them i.e in folder "user_1" and they shouldn't have access to "user_2" images. Also the bucket and it's contents are private.
Image table has image_path (like "bucket_name/user_1/img1.jpg") which can be accessed by flask app only. REST APIs are used by android app.
So when the user on android app fetches his image (using GET request), he should be able to download all the images. How to deliver those images?
Using aws cloudfront and oai
flask using boto3 generate_presigned_url()
make the bucket contents public (which I definitely don't want)
How this android -- flask -- aws flow should work?
There are two ways you can achieve this.
You could use pre-signed URLs, or
Provide temporary credentials that permit access to their folder.
Pre-Signed URLs
Keep all content private. Then, when a client (eg Android app) requires access to an object, your application should verify that they are entitled to access the object by checking the database. If they are permitted access, then the application should generate a pre-signed URL that grants time-limited access to the object.
Creating a pre-signed URL only takes a couple of lines of code and does not require a call to AWS. Thus, it is very fast to create and the application retains full control over who is permitted access to which objects.
Temporary Credentials
Since your users are permitted to access all content within their folder, you could create Temporary Security Credentials using the Security Token Service. A policy can be assigned to these credentials that permits access to s3://bucket_name/user_1/*. Then, the Android app can use these credentials to directly call the AWS API to download content (or upload, or do whatever permission you have assigned).
This allows the app to directly communicate with AWS rather than having to call your servers for every object access.
If you are using federated authentication (eg trusting Facebook), you might want to use Amazon Cognito to Get Credentials.
I have a bucket in Amazon S3 and I have Lambda functions that generates JSON files for this bucket. I am using the S3 files in my mobile app. Until recently, I gave public access to these S3 files for simplicity. But now I want these S3 objects to be accessible with a simple authentication. I’ve examined all AWS tutorials but couldn’t find an easy way to implement this. I don’t want to use Cognito service since my app doesn’t need authentication and since my S3 files are not user-related, they are used for app. I want these S3 objects to be accessible by http request to a url which includes simple key like this:
https://s3.eu-central-1.amazonaws.com/<bucket name>/<object name>?<key>
where key can be a combination of region, aws access key, secret access key or other values of the user that i define (I am using Retrofit to fetch json data from S3 bucket) I’ve looked at the presigned url option but an example for android-sdk doesn’t exists there, and most of the methods that can be used for this purpose are deprecated. Isn’t there an easy way for this? Or should I host my json files in other service/place?
If you say no to Cognito then you are just complicating things for yourself. This is exactly the case where you want to use Cognito. The fact that you don't require your users to authenticate and that the S3 content is not user specific doesn't mean that Cognito is not suitable in this scenario.
All you have to do is to create Cognito identity pool and choose to support unauthenticated entities. Create an IAM policy that allows reading from that specific S3 bucket and let unauthenticated users to assume that IAM role by attaching it to those unauthenticated entities.
Authentication then happens automatically during the initialization of SDK in your application. That is all that you need to do to allow access to that S3 bucket only from your application.
And you get access metrics even for unauthenticated users as a bonus. And if you later decide that you want your application to support authentication as well, then you don't need to change almost anything in your setup.
So I have an Android chat application where users can create profile photos. These photos are sent to my Node JS backend where I upload them to my AWS S3 bucket. I store the key to their image in my SQL database under an "image_path" column in the "user" table.
Now whenever a user accesses a chatroom full of multiple other users in the app, they should be able to see other users' profile photos. Currently, upon joining a chatroom, a list of all users and their "image_path" is returned to the client. I am thinking about how to show the profile images to the user in an effective manner without violating best security practices.
The first solution I am thinking of is the following:
Make S3 bucket read-public
Client can now directly access other users' profile pictures via a "bucket-name.s3.amazonaws.com/image_path" request.
My concern with this method is that S3 displays the following warning, which makes me think something is egregiously wrong with this approach:
You have provided public access to this bucket. We highly recommend that you never grant any kind of public access to your S3 bucket.
The second solution I am thinking of:
When retrieving users in a chatroom, iterate through each user, create a pre-signed URL from each user's "image_path" that expires after X time, and return that to the client instead
There are some problems I see with this. First, what if the user stays in the chat room for a period of time longer than the pre-signed url's expiry time? Implementing refresh logic for this sounds like a headache. Furthermore, generating all the pre-signed URLs seems like it'll supposedly take a long time in the backend.
Which of these two methods are recommended? Is there any other option I should consider?
UPDATE: So currently I am currently resorting to the first method and it is working fine - however, still want to know what the best practice is. I have thought of another method, and that is securing AWS credentials in my client and then using those credentials to retrieve the user object, while making the bucket private. However, this introduces the issue of storing additional credentials client-side which adds security issues, but I'm wondering if this is a viable option as well.
I want to use Microsoft Azure Storage Android API to upload images made by phone camera.
Here's like to it:
https://github.com/azure/azure-storage-android
Here's my question: Account name and key are stored in string inside app, so anyone could decompile it, get these credentials and then, for example, upload lots of data which would cost me money.
So is it safe to use this on android app?
What are my other options?
You should not store the keys in your application. You're right that somebody could decompile your app and get the keys. Furthermore, if you ever have to change your account key for whatever reasons your users would need to download your application again.
What you should do is make use of Shared Access Signature (SAS) when somebody needs to upload the images. You could use Azure Mobile Service or write your own web service to get SAS (with write permission) on demand and use that in your application to upload images in your storage account.
You are right. If you are shipping the credentials to your Azure storage account in your app, then well, anyone has the credentials and can do anything with it.
Typically you would create an intermediate web service (e.g. hosted on Azure websites) which accesses Azure storage and limit the amount of data each user may upload. The app communicates only with your web service and hence does not need to know about the credentials to the storage account.
Obviously you will need some kind of user management built into your web service, e.g. custom accounts, Google login (most Android users will have a Google account), OpenID, OAuth, ...
I am building an Android application that will send reports to a server. These reports are plain JSON files stored on Amazon S3.
The Amazon user only has the PutObject permission on a specific S3 bucket.
The documentation states that we should use the Token Vending Machine mechanism instead of hardcoded keys within the application.
I cannot see the advantage of this method.
I get that a hacker could decompile my app to find the keys. But his only choice then is to send files to the bucket, nothing else (no file listing, no file retrieval).
If I use the anonymous TVM, the process is:
Get a token valid for 24 hours
Use this token to send files to the bucket
A hacker could also call the TVM server to request unlimited tokens and send files to my bucket. It does not seem to solve this problem.
What is the real advantage in using TVM?
You can attach different authorizations to each mobile UID, giving your finer control over what you allow people to access. You can also control how much AWS access the TVM has using policies. You can also stop it any given time. If they get your keys, you will have to disable the whole account. If you are OK with that, you probably don't need to use the TVM.