How to hide specific folder using AWS STS AssumeRole session policy? - amazon-s3

I have created STS AssumeRole session token with adding policy document as List only to specific folders, but how we can hide on showing remaining folders which doesn’t have access?
Example:
Let consider I have AWS s3 object paths s3://<bucketName>/folder1/{files…} & s3://<bucketName>/folder2/{files…}
I generated STS token having Action (i.e., S3:List*) and filter Condition policy ( i.e. "StringEquals" : “folder1/*” )
In my application using AWS SDK (Javascript) with above generated STS session token. If I try to List objects under Key (s3:///), response returning both folder1/ & folder2/.
How can I hide folder2/ based on current STS session policy?
(Note: Eventhough we have restrict List access to deep dive into folder2/. I don't my SDK to show folder2/ in frontend.

s3:List is a bucket-level operation, so it will list all the contents as long as the permissions allow it.
You can deny access to folder2/ by adding a condition like you said. However, that folder will still be visible if ListBucket is called in the above directory.

Related

Keycloak uma-grant type tickets for service accounts do not seem to work with policies

I am trying to use the Keycloak AuthzClient to register resources and related permissions in a resource server.
I have a resource server "resourceserver" with authz service enabled.
Using the AuthzClient, initialized with the json file containing the resource server's client id and secret, I'm able to obtain a pat.
...
authzClient.obtainAccessToken().getToken();
ResourceRepresentation resource = new ResourceRepresentation();
resource.setName("myresource");
resource.setUris(new HashSet<>(Collections.singletonList("urn:resourceserver:resourcetype1:myresource")));
resource.setOwnerManagedAccess(true);
resource.setType("urn:resourceserver:resourcetype1");
resource.addScope("read", "write");
resource = authzClient.protection(pat).resource().create(resource);
UmaPermissionRepresentation permissionRepresentation = new UmaPermissionRepresentation();
permissionRepresentation.setName("myresourcepermissions");
permissionRepresentation.setDescription("foo");
permissionRepresentation.addRole("somerole");
UmaPermissionRepresentation result = authzClient.protection(pat).policy(resource.getId()).create(permissionRepresentation)
After executing this code, I can see, in the keycloak admin UI, that the resource has been created, and the scopes, however the policy/permission don't seem to show up.
I believe it is probably intended, as this keycloak admin UI only shows policies of types client, role, js, etc., but not "uma" which is what UmaPermissionRepresentation creates.
I can however see that policy exists in Keycloak by querying authz/protection/uma-policy with my pat.
So there is something there. Now testing it. I created a regular user and assigned it the realm role somerole. Using this user and some arbitrary public client, I'm able to get an RPT.
First getting an access token using the password grant:
grant_type=password&username=joe&password=password&client_id=somepublicclient
Then exchanging that for an RPT:
grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&audience=resourceserver
The RPT comes back and if I view its contents, I can see the authorization block giving me access to the myresource resource.
However, when I try a similar flow with a service account (to which I also granted the somerole role)using the client credentials flow to obtain the initial access token:
grant_type=client_credentials&client_id=serviceaccount1&client_secret=77c1ffa8-0ea8-420c-ad45-e1a69a03838d
I am able to obtain an RPT, but that RPT does not contain myresource in the authorization/permission block, only the Default resource.
I have been trying to understand why that is. I have also tried using the .addClient("serviceaccount1") or even .addUser("service-account-serviceaccount1") in the UmaPermissionRepresentation, but still, the policy doesn't seem to kick in and my service account does not have access to the resource.
This is using Keycloak 4.8.0.Final.
Note: using the keycloak admin client, I am able to create policies/permissions that actually make this work; but in my environment this would causes other problems because of the roles I would need to assign to the admin client (like viewing all clients to retrieve an id etc.)
I have the same problem with KeyCloak 11.0.2.
Shared resources do not end up in the permission tickets of service accounts. Service accounts are explicitly excluded in the authorization token service.
Since sharing resources with service accounts is possible, this seems inconsistent.
However, you can work around this by explicitly setting the azp claim to something other than your client_id via a protocol mapper on your client.
.

Backblaze B2 download with "presigned URL"

Situation: I run a Django app in the web, where logged-in users can also download .pdf files (non-public, with specific restrictions, depending on user rights). The most convenient way to do so (e.g. in S3) is to use a time-restricted, pre-signed URL because they open immediately in the browser, plus the app server does not have to handle additional traffic.
Problem: Backblaze B2 oviously does not offer an explicit method for creating presigned URLs to download non-public files directly in the browser.
Generating the api URL and the authorization token, and fetching the file from the object store happens at the app server level and the process is not exposed to the "ordinary" user.
But in the end, the API operation "b2_download_file_by_name" just uses a GET request, which means I can add the authorization token to the request's URL using "?Authorization=123xyz........". This way I get a presigned URL that works perfectly fine in the browser to allow access to a specific non-public file for a limited time. (Please note: B2 downloads can be restricted to files with specific prefixes [like s3 pseudo-folders], but if the specified "prefix" is long enough, I can make the auth token specific for one file.)
Question: As I wrote above, usually the authorization token is not exposed to the user. Now, if I make the URL visible, does this imply a security risk? In other words, could a user that posesses one or many tokens, extract the general access key from the token, or is the token encrypted well enough to avoid this?
According to the documentation for the b2_download_file_by_name call you can use the download authorization in a URL in the way you describe.
An authorization token can be provided in the URL query string instead of being passed in the HTTP header. An account authorization token obtained from b2_authorize_account will allow access to all files in a private bucket. A download authorization token obtained from b2_get_download_authorization will allow access to files whose names begin with the filename prefix used to generate the download authorization token.
However it seems that the expiry time set in the b2_get_download_authorization call is being ignored so the resulting URL never expires which is not secure of course. I have a support ticket in with B2 about this so hoping for a solution.

Allow API users to run AWS Lambda using execution role from Cognito identity pool

I'm using AWS amplify to create an app, where users can upload images using either private or public file access levels, as described in the documentation. Besides this, I've implemented a lambda function which upon request through API gateway modifies an image and returns a link to the modified image.
What I want is that a given user should be able to call the API and modify only his own images, but not that of other users; i.e. allow the AWS lambda function to use the execution role from the cognito user. If I allow the lambda function to access all data in the S3 bucket then it works fine - but I don't want users to be able to access other users images.
I've been at it for a while now, trying different things to no avail.
Now I've integrated the API with the user pool as described here:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-enable-cognito-user-pool.html
And then I've tried to follow this guide:
https://aws.amazon.com/premiumsupport/knowledge-center/cognito-user-pool-group/
Which does not work since the "cognito:roles" is not present in the event variable of the lambda_handler (presumably because there are not user pool groups?).
What would the right way be to go about this in an AWS Amplify app?
Primarily, I've followed this guide:
https://aws.amazon.com/premiumsupport/knowledge-center/cognito-user-pool-group/
Use API Gateway request mapping and check permissions in Lambda itself:
Use API Gateway request mapping to pass context.identity.cognitoIdentityId to Lambda. Just it should be a Lambda integration with mapping (not a Proxy integration). Another limitation is that API request should be POST, for GET it's also possible if you map cognitoIdentityId to query string.
Lambda has access to all files in S3
Implement access control check in Lambda itself. Lambda can read all permissions of the file in S3. And then see if owner is Cognito user.

Setting different S3 read permissions based on uploader

I'm trying to arrive at a situation, where
one class of users can upload files that are subsequently not publicly available
another class of users can upload files that are publicly available.
I think I need to use two IAM users:
the first which has putObject permissions only and where I bake the secret key into javascript. (I use the AWS SDK putObject here, and bake in the first secret key)
the other where I keep the secret key on the server, and provide signatures for uploading to signed-in users of the right category. (I ended up using a POST command for this with multipart form-data, as I could not understand how to do it with the SDK other than baking in the second secret key, which would be bad as files can be uploaded and downloaded)
But I'm struggling to set up bucket permissions that support some files being publicly available while others are not at all.
Is there a way, or do I need to use separate buckets?
Update
Based on the first comment, I tried to add "acl": "public-read" to my policy and POST form data fields. The signatures are matching correctly, but I am now getting a forbidden response from AWS, which I don't get when this field is absent (but then the uploads are not publicly visible)

Amazon S3 authentiaction model

What is the proper way of delegating file access authentication from S3 to our authentiation service?
For example: web site's user(he have our session id in headers) sending request to S3 to get file by url. S3 sends request to our authentication service asking if user with such headers can access that file, and if our auth service allow getting that file it will be downloaded.
There are a lot of information about presigned requests but absolutely nothing about s3 quering with "hidden" authentication.
If a file has been made public on S3, then of course anyone can download it, using a direct link to the file.
If the file is not public, then there needs to be some type of authentication. There are really only two ways a file from S3 can be obtained if it is not public, one is via a pre-signed url, and the other is to be an Amazon user who has access to S3. Obviously this is how it works when you yourself want to access an object on S3, you must provide your access key and a signature in the header of the GET request. You can grant other users access to S3 via Amazon IAM, which is more like the 'hidden' authentication you mentioned. Via the IAM route, there are different ways of providing access including Federated Users. Visit this link to learn more:
http://docs.aws.amazon.com/AmazonS3/latest/dev/MakingAuthenticatedRequests.html
If you are simply trying to provide a authenticated user access to a file, the best and easiest way to do that would be to create a pre-signed url with an expiration time. The expiration time can be something short, like 10 minutes or even 1 minute, to prevent the user from passing the link to others.