CD-RUM CD-RUM - 1 year ago 87
Java Question

S3: using a token in a header as a dumbed-down auth token

I want to grant read access to an S3 bucket if the request has a token attached to it. My AWS policy looks like this:

"Version": "2012-10-17",
"Statement": [
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::some_bucket/*",
"Condition": {
"StringEquals": {
"aws:principaltype": "authorized_user"

And I'm trying to write links to it like so (it's in Java):

fileInfo.add('' + file + '?aws:principaltype=authorized_user');

But I'm just getting a standard access denied message:


What am I doing wrong? Or is there a better way to achieve a pseudo-public access setup?

Answer Source

You can't just make up condition keys.

They are not equivalent to headers -- the fact that some of them happen to correspond to headers is for convenience rather than necessity.

When I see questions like this, I become suspicious that the motivation is primarily one of wanting to avoid learning how to just do things the customary way, for whatever reason. If you're in an environment where it's easy enough to inject a request header, then why not just generate an Authorization header with a matching signsture?

There is no capability like you envision, in S3.

If you were to configure CloudFront in front of the bucket, with an origin access identity, it would be possible to generate a pre-signed URL with a wildcard, so one pre-signed URL could represent any or all of a bucket, e.g. allow*.jpg which would allow access to JPEG file with an S3 object key prefix of cats/. CloudFront validates the wildcard signed URL, then fetches the object from S3 using its origin access identity. (S3 signed URLs do not support wildcards; CloudFront signed URLs do).

This seems like a straightforward solution.

Alternately, if your application has a web server, send the request to that server, and if the desired "token" matches, then sign a URL and return a 302 redirect, sending the browser to get the object from S3. I have a couple of systems that do this, one of which looks up the user's session cookie contents and compares it with object metadata, allowing the signed redirect to be generated if there's a match (it can allow users to access objects based on their user id, user class id, or permission set id in session matching what was stored with the object; if access is denied, it returns 403; if the object doesn't exist, it lies and still returns 403 so that the bucket can't be scanned, for security reasons). This -- with or without the session validation, but simply the presence of a token -- could also be implemented with a lambda function behind API gateway... which even supports tokens natively ("API keys.")