1

I'm implementing an iOS app with group-chat support, where users can add photos, other files.

Decided on AWS S3 as storage back end, using Cognito Federated Identities to authenticate upload/downloads - data pumped to/from S3, not via our servers.

So far

my implementation allows a user/identity to upload & download to their their own folder on an S3 bucket (example policy arn:aws:s3:::mybucket/users/${cognito-identity.amazonaws.com:sub}/* the variable being the identityID/user_id).

However

I've not been able to find a secure way that allows only participants in a group-chat to upload/download from that group-chat's folder on S3.

Any ideas?

some thoughts on a possible flow:

  1. first, user upload photo to own folder, [ I know how ]
  2. then, the system copies over the photo into the group-chat's folder [ I know how ]
  3. associate group-chat folder with the identities of participants [ not sure how - there could be thousands of groups & participants ]
    • EDIT 1: as @MyStackRunnethOver suggest, could use one IAM role/credential to manage all upload/download request for users (that belong to said group) [ big security concern if credential compromised ].
  4. EDIT 1: could use PreSigned URLs: files uploaded to user's own folder, presigned url stored on group-chat entries [ max url-life 7days though ]
    • client caching helps until participants join/leave a group frequently
    • requires server-side scheduled job to renew expired PreSigned URLs

Any commends/ideas appreciated

1 Answers1

1

Your question boils down to:

"Given that users are part of groups, how can I give users access to group-specific subdirectories based on group membership?"

As I see it, you have two options:

  1. Give each user the "key" to all directories they're a member of. This could mean adding a permission to that user for each group, or providing them with access to a new IAM role for each group. This is the "come up with a way to have fine-grained permissions for S3" strategy.

  2. Don't distribute any directory-specific keys. Instead, when a user requests a certain directory, check whether they're in the group that directory belongs to. This is the "build a fine-grained data storage system around S3" strategy.

I recommend the latter approach, because instead of having an IAM role or a credential per user or per group, you give all your users one credential: the credential needed to make requests of your S3 wrapper. If you keep track of which groups your users are in, all your wrapper needs to do is check the user -> groups mapping to see if a request should be fulfilled. The front end can use the same mapping to prettify the UI: a user is only shown the option to upload / download from the groups they are a member of. In this case, I would envision the mapping as a Dynamo table that is updated whenever a user signs up, joins a group, leaves a group, or deletes their account. You can identify your users by their Cognito credentials, which include user-specific fields.

MyStackRunnethOver
  • 4,872
  • 2
  • 28
  • 42
  • thank you @MyStackRunnethOver for a thorough reply. With regards to security in option 2, any practices on securing one-credential-to-rule-them-all? Although comms via HTTPS, the credentials could be compromised on the app (somehow). – Lactose.Int.Robot Mar 17 '20 at 20:00
  • A Cognito ID pool to provide AWS credentials. I believe when the front end uses credentials to make a call to the backend, the back end can figure out the Cognito identity (user) responsible, and thus decide whether to respond. Alternatively, you can have the user pass their Cognito *User* Pool token with the request, which **will** contain information on their identity. You'd just have to validate it on the back end. But I'm pretty sure there's an automatic mechanism using just the ID pool credentials – MyStackRunnethOver Mar 17 '20 at 20:52
  • Thank you @MyStackRunnethOver. Cognito User Pools seem to offer more features than **Federated Identity** (which I'm using - it's free & light-weight). Yes, you're right, my user requests contain their Federated Identity so I do perform validations server-side. However, I thought once app has the IAM credential and **user -> group mapping**, the backend is no longer involved in that request and client-side calls AWS directly? – Lactose.Int.Robot Mar 17 '20 at 21:17
  • You **need** something on the back end to check whether the requester is allowed to do what they're requesting - thus there needs to be a layer around S3, on the back-end, to decide whether requests should be allowed or rejected based on the requester's identity – MyStackRunnethOver Mar 17 '20 at 21:39
  • 1
    OK - done it - using Option 2 and wrapping S3 requests to validate user's identity and group-access rights. Thanks a lot @MyStackRunnethOver - will accept your answer. – Lactose.Int.Robot Mar 27 '20 at 14:06
  • I apologize in advance for the noob question, but could you elaborate on what you mean by "S3 wrapper?" Is this wrapper server side? What AWS resources does this wrapper use, e.g. Lambda function? Can you point to any code examples? – JJJSchmidt Jun 01 '20 at 21:29
  • Not a noob question. It's ambiguous because there's no one answer. Think of it as a back-end service which stands in between the front end and S3 itself. It handles requests for a user to get and put files in the folder of a group chat, but it is what handles deciding if the user is allowed to do so, so it "wraps" the functionality of S3 in an authorization layer. The reason it's back-end is because it validates user credentials to determine permissions - you don't want that logic on the front end :) – MyStackRunnethOver Jun 01 '20 at 21:34
  • If I had to spitball a design in 30s or less, I would make it a service fronted by API Gateway, with a **get** function and a **put** function, both requiring some credentials to be passed from the front end. API Gateway triggers a Lambda which validates the credentials, then either declines to let the user do the thing, or hits S3 and returns the result - it probably generates a bunch of signed URL's to allow the user to download the files. There is some API Gateway built-in functionality which you might be able to leverage, e.g. using an authorizer lambda for part of the functionality. – MyStackRunnethOver Jun 01 '20 at 21:37
  • Thank you @MyStackRunnethOver for the speedy reply. I will experiment with your suggestion using API Gateway and get back with my results. – JJJSchmidt Jun 01 '20 at 22:21