Signed cookie does not let me set specific resources in the policy - amazon-s3

In S3, we create one bucket that contains multiple organizations. For the example above, we have the following device folder objects created. Again, User A should only access device1, device2 , but not device3.
https://s3.host/bucket/org1/devices/device1
https://s3.host/bucket/org1/devices/device2
https://s3.host/bucket/org1/devices/device3
We are using signed cookies to allow our browser application to access the S3 objects (per your documentation here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)
The signed cookie however does not let me set specific resources in the policy and instead I would need a wild card policy. This creates a problem because the signed cookie allows access to device3.
s3://duclo.domain/bucket/org1/* <-- DOESN'T MEET
I am unable to set it to the following:
{ "Statement": [ { "Resource": " https://s3.host/bucket/org1/devices/device1", "Condition": { "IpAddress": { "AWS:SourceIp": "1.2.3.4" } } }, { "Resource": " https://s3.host/bucket/org1/devices/device2", "Condition": { "IpAddress": { "AWS:SourceIp": "1.2.3.4" } } } ] }
Instead, I can only do this below which again breaks the requirement.
{ "Statement": [ { "Resource": " https://s3.host/bucket/org1/devices/*", "Condition": { "IpAddress": { "AWS:SourceIp": "1.2.3.4" } } } ] }
I need it to allow multiple resources, or another solution perhaps?Any suggestions on how to accomplish this?

Related

unable to assume role with gitlab oidc and AWS

I have configured the IAM Role with the below definition. I am getting the AccessDenied error when I configure the condition below. Where am I going wrong?
Access Denied
"Condition": {
"StringEquals": {
"gitlab.com:sub": "https://gitlab.com/pradeepkumarl/configure-openid-connect-in-aws::ref_type:branch:ref:main"
}
}
Total policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/gitlab.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"gitlab.com:sub": "https://gitlab.com/pradeepkumarl/configure-openid-connect-in-aws::ref_type:branch:ref:main"
}
}
}
]
}
There is a mistake in your sub field under condition. It should be of the form project_path::ref_type:branch:ref:. You don't need to include the Gitlab url.
Also keep in mind that you may need to change the condition from "StringEquals" to "StringLike" to accommodate wildcards, as mentioned in the troubleshooting section of the documentation: https://docs.gitlab.com/ee/ci/cloud_services/aws/index.html

AWS Cognito IAM policy - How to limit access to S3 folder (.NET SDK ListObjectsV2)

I am trying to limit access for a Cognito user to specific folders in a bucket. The final target is to reach what is described here but I've simplified it for debugging.
The structure is as follows
MYBUCKET/111/content_111_1.txt
MYBUCKET/111/content_111_2.txt
MYBUCKET/222/content_222_1.txt
MYBUCKET/333/
I am performing a simple "list" call via the SDK.
using (AmazonS3Client s3Client = new AmazonS3Client(cognitoAWSCredentials))
{
ListObjectsV2Request listRequest = new()
{
BucketName = "MYBUCKET"
};
ListObjectsV2Response listResponse = await s3Client.ListObjectsV2Async(listRequest);
}
I am authenticating via Cognito so I am updating Cognito's IAM policy linked to the authenticated role.
The following policy returns an S3 exception "Access Denied":
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::MYBUCKET",
"Condition": {
"StringLike": {
"s3:prefix": [
"111",
"111/*"
]
}
}
}
]
}
The following policy returns all results (as expected).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::MYBUCKET"
}
]
}
This is supposed to be super straightforward (see here ). There are other similar questions (such as this and others) but with no final answer.
How should I write the IAM policy so that authenticated users can only access the contents of the folder "111"?
Best regards,
Andrej
I hope I now understand what I got wrong."s3:prefix" is not some form of "filter that will only return the objects that match the prefix"; it is "a parameter that forces the caller to provide specific prefix information when executing the operation".
The following is taken from the S3 documentation :
To answer my own question, starting from the IAM policy above
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::MYBUCKET",
"Condition": {
"StringLike": {
"s3:prefix": [
"111",
"111/*"
]
}
}
}
]
}
If I call the SDK with the code below, I will indeed get an "Access Denied" because I have not specified a prefix that matches the IAM policy.
using (AmazonS3Client s3Client = new AmazonS3Client(cognitoAWSCredentials))
{
ListObjectsV2Request listRequest = new()
{
BucketName = "MYBUCKET"
};
ListObjectsV2Response listResponse = await s3Client.ListObjectsV2Async(listRequest);
}
But if I do specify the prefix in my SDK call, S3 will return the expected results i.e., only the ones "starting with 111".
using (AmazonS3Client s3Client = new AmazonS3Client(cognitoAWSCredentials))
{
ListObjectsV2Request listRequest = new()
{
BucketName = "MYBUCKET",
Prefix = "111"
};
ListObjectsV2Response listResponse = await s3Client.ListObjectsV2Async(listRequest);
}
In other words, my problem was not in the way I had written the IAM policy but in the way I was expecting the "s3:prefix" to work.

Is it possible to create a trust that allow federated users from cognito to assume role according to a custom attribute?

Is it possible to create a trust that allow federated users from cognito to assume role according to a custom attribute?
For example with a tenant attribute:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:12345678-corner-cafe-123456790ab"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "unauthenticated"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:custom:tenant": "tenant-name"
}
}
}
]
}
I'm using get_credentials_for_identity api with cognito token to assume this role.
Yes, this is definitely possible with attributes for access control. This will only work for an authenticated user (you need an ID token to map claims to principal tags).
Your trust policy needs to looks like this:
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRoleWithWebIdentity",
"sts:TagSession"
],
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:12345678-corner-cafe-123456790ab"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
},
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
}
}
]
}
The difference is the sts:TagSession action and the fact that amr must be authenticated.
Policy for assumed role will look something like this:
{
"PolicyDocument": {
"Statement": [
{
"Action": "s3:GetObject",
"Effect": "Allow",
"Resource": "arn:aws:s3:::your-bucket-name/cognito/attributes/by_family_name/${aws:PrincipalTag/family_name}/*"
},
{
"Action": "s3:GetObject",
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/given_name": "${aws:PrincipalTag/given_name}"
}
},
"Effect": "Allow",
"Resource": "arn:aws:s3:::your-bucket-name/cognito/attributes/by_tag/*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "attributes-policy"
}
You need to configure your Cognito (or any other) provider in Identity Pool to do the mapping between claims from the token to tags. You can do it in console under Attributes for access control. Or with CLI like this:
aws cognito-identity set-principal-tag-attribute-map --cli-input-json file://set-principal-tag-attribute-map.json
Where set-principal-tag-attribute-map.json would look something like this (for Cognito as IDP):
{
"IdentityPoolId": "here-is-your-identity-pool-id",
"IdentityProviderName": "cognito-idp.<region>.amazonaws.com/<user_pool_id>",
"UseDefaults": false,
"PrincipalTags": {
"given_name": "given_name",
"family_name": "family_name"
}
}
You can find more details in documentation here: https://docs.aws.amazon.com/cognito/latest/developerguide/attributes-for-access-control.html

How to access AWS S3 bucket logging in with Google and Cognito User/Identity Pool

I'm using the AWS Cognito Enhanced (Simplified) Flow to get the Cognito Identity Credentials providing the idToken received after logging in with Google sign-in api:
export function getAWSCredentialWithGoogle(authResult) {
if (authResult['idToken'] != null) {
AWS.config.region = 'eu-central-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'eu-central-1:xxxxxxxxxxxxxxxxxxxxxxxx',
Logins: {
'accounts.google.com': authResult['idToken']
}
})
return AWS.config.credentials.getPromise()
.then(
function(){
return getAWSCredentials(AWS.config.credentials);
},
function(err) {
}
)
} else {
console.log('no auth code found!');
}
}
I get the:
accessKeyId:"ASIAXXXXXX",
secretAccessKey:"ta4eqkCcxxxxxxxxxxxxxxxxxxx",
sessionToken:"xxxxxxxxx...etc..."
Then I try to upload a picture to an S3 bucket passing the above received accessKeyId and secretAccessKey.
But I receive this error result:
InvalidAccessKeyIdThe AWS Access Key Id you provided does not exist in our records.ASIAXXXXXXXXXXXXXXXX
This is how I set up the AWS S3 (managed) policy (the resource policy for the bucket is the default one) to access progammaticaly the bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::xxxxxxxxxx",
"arn:aws:s3:::xxxxxxxxxx/users"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"${cognito-identity.amazonaws.com:sub}/*"
]
}
}
},
{
"Action": [
"s3:PutObject",
"s3:GetObjectAcl",
"s3:GetObject",
"s3:PutObjectVersionAcl",
"s3:DeleteObject",
"s3:PutObjectAcl",
"s3:GetObjectVersion"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::xxxxxxxxx/users/${cognito-identity.amazonaws.com:sub}",
"arn:aws:s3:::xxxxxxxxx/users/${cognito-identity.amazonaws.com:sub}/*"
]
}
]
}
this policy has been attached to an IAM role with the following trust relationship:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "eu-central-1xxxxxxxxxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
I've properly configured the Federated Identity Pool to use this role, and added Google as an OpenID Connect provider.
I also configured my Cognito Identity Pool to accept users federated with my Cognito User Pool by supplying the User Pool ID and the App Client ID.
I would like to to give to any Google sign-in authenticated user, access to the S3 bucket and have read/write permission to his own directory.

Access Denied to S3 Objects Uploaded via SDK

I am trying to create an IAM user that is permitted to:
Upload Objects
Get Objects
List Bucket Objects
The policy seems to be working. However, I cannot view the images that were uploaded via the S3 SDK. When referencing one of the image files in an HTML <img /> tag, I get a 403 Forbidden error. On the other hand, I am able to successfully view images that were uploaded via the AWS Console with the defaults, without setting any additional policies, etc. Is there an attribute I'm not setting when uploading the image to S3 using the SDK?
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my_bucket"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "MyIpV4Address"
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl"
],
"Resource": [
"arn:aws:s3:::my_bucket/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "MyIpV4Address"
}
}
}
]}
The JavaScript code I am using to upload the files.
handleFileUpload(acceptedFiles, rejectedFiles) {
return Promise.map(acceptedFiles.map(file => {
const object = {
Key: `some-image-key.jpg`,
Body: file,
ContentType: file.type,
StorageClass: 'STANDARD_IA'
}
return this.s3.putObject(object).promise(response => {
console.log(response);
});
}));
Try uploading with an additional: .withCannedAcl(BucketOwnerFullControl)
This specifies the owner of the bucket, but not necessarily the same as the owner of the object, is granted Permission.FullControl.
See:
withCannedAcl()
CannedAccessControlList