Cross account S3 access with CannedACL - amazon-web-services

We have a usecase where we put objects in an S3 bucket which is in different account than ours. We do that using IAM user. This is working fine.
We’ve now replaced IAM user based access with IAM role based access. Hence instead of IAM user I have created an IAM role and I have put identical permissions (same as IAM user) for IAM role at all places(on IAM role, on S3 bucket).
But it’s giving 403 error when I try to put an object in that bucket. What could be the reason (Shall I whitelist the sts arn on bucket ? Do we need to change bucket ACLs in anyway ?)
The S3 bucket has following policy attached
IAM role in account A is : arn:aws:iam::AAAAAA:role/my-role
Bucket in account B is : arn:aws:s3:::bucket
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Allow Development Write Access",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AAAAAA:role/my-role"
]
},
"Action": "s3:Put*",
"Resource": [
"arn:aws:s3:::bucket/*",
"arn:aws:s3:::bucket"
],
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
},
{
"Sid": "Allow Development Read Access",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AAAAAA:role/my-role"
]
},
"Action": [
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::bucket/*",
"arn:aws:s3:::bucket"
]
}
]
}
I'm accessing it with the following piece of code:
s3Client.putObject(new PutObjectRequest(bucketName, key, file)
.withCannedAcl(CannedAccessControlList.BucketOwnerFullControl));
What could I be missing here?

This is fixed now. There was server side encryption enabled for that S3 bucket and my IAM role didn't have permission to KMS key used for encryption. Once this role given permission to KMS key it worked.
I didn't have to use that KMS key while making a putObject request, not sure why it required permission to KMS key then.
Also I could list the buckets (before the KMS key permission given) but couldn't put object (strange!)

Related

IAM Role policy for cross account access to S3 bucket in a specific AWS account

Allow access from IAM Role in AccountA to given S3 buckets only if they are present in AWS AccountB (using Account Number).
Here is my Role policy in AccountA which currently has following permission. How can I update it to only access S3 bucket in AccountB.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*",
"s3:Put*"
],
"Resource": [
"arn:aws:s3:::kul-my-bucket/my-dir/*"
]
},
{
"Sid": "ListBucket",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::kul-my-bucket"
]
}
]
}
Wondering if it is possible or should I try it differently?
Is anything similar to this possible for my case by providing the condition in the policy:
"Condition": {
"StringLike": {
"aws:accountId": [
"111111111111"
]
}
}
I need this because on the S3 bucket in AccountB it allows root access to AccountA. Hence I want to put restriction on Role policy in AccountA.
I do not think it is possible to grant/deny access to an Amazon S3 bucket based on an AWS Account number. This is because Amazon S3 ARNs exclude the Account ID and instead use the unique bucket name.
You would need to grant Allow access specifically to each bucket by name.
I have seen this situation before where the requirement was to grant S3 permission to access buckets only in other accounts, but not the account owning the IAM User themselves. We could not determine a way to do this without also granting permission to access the "same account" S3 buckets.

KMS Not found Exception in AWS Cross Account S3 PutObject encrypted by AWS Managed Key

I am trying to put a dummy file from Glue which is in Account B to S3 bucket in account A. S3 bucket(test-bucket) is having AWS-KMS encryption with aws/s3 Managed Key enabled.
I added below permissions in Account A- S3 bucket (test-bucket):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Deny PutObject if NOT using correct KMS Encryption Key",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::test-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "",
"s3:x-amz-server-side-encryption-aws-kms-key-id": "<ARN_KMS_ACCOUNT_A>"
}
}
},
{
"Sid": "Allow Glue Role in Application account to put objects in the S3 bucket",
"Effect": "Allow",
"Principal": {
"AWS": "<IAM_Glue_Role_ARN>"
},
"Action": [
"s3:AbortMultipartUpload",
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::test-bucket",
"arn:aws:s3:::test-bucket/*"
]
},
{
"Sid": "Only allow writes to my bucket with bucket owner full control",
"Effect": "Allow",
"Principal": {
"AWS": "<IAM_Glue_Role_ARN>"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::test-bucket/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
Added below policy to IAM Glue role in Account B
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:Get*",
"s3:List*",
"s3:Put*"
],
"Resource": "arn:aws:s3:::test-bucket*",
"Effect": "Allow"
},
{
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey"
],
"Resource": "<ARN_KMS_ACCOUNT_A>",
"Effect": "Allow"
}
]
}
This is my Glue Code:
s3.put_object(
Bucket='output',
Key='_SUCCESS',
ServerSideEncryption='aws:kms',
SSEKMSKeyId='<ARN_KMS_ACCOUNT_A>'
)
Getting below error while running this code from Account B Glue:
ClientError: An error occurred (KMS.NotFoundException) when calling the PutObject operation: Invalid arn ap-southeast-2
Any thoughts on this.?
The AWS managed CMK aws/s3 can only be used in the same account i.e. where the key exists (in your case, its Account A). You can either try to use the aws/s3 CMK from Account B OR create a customer managed CMK in Account A and share it with Account B following the steps here.
There's a couple of things:
For the policy on the bucket, Deny permissions should be always at the end after all the Allow permissions. And remove the condition on the Deny permissions. You want to block all traffic that's not authorized.
Use a managed KMS key. And on that key, grant kms:decrypt to the glue role on the key's policy.
As documented here you must use the full ARN of the encryption key so cross-account succeeds. Using an alias or key ID does not work.
Be aware of the following when using encryption for cross-account operations:
The AWS managed key (aws/s3) is used when a AWS KMS key Amazon Resource Name (ARN) or alias is not provided at request time, nor via the bucket's default encryption configuration.
If you're uploading or accessing S3 objects using AWS Identity and Access Management (IAM) principals that are in the same AWS account as your KMS key, you can use the AWS managed key (aws/s3).
Use a customer managed key if you want to grant cross-account access to your S3 objects. You can configure the policy of a customer managed key to allow access from another account.
If specifying your own KMS key, you should use a fully qualified KMS key key ARN. When using a KMS key alias, be aware that AWS KMS will resolve the key within the requester’s account. This can result in data encrypted with a KMS key that belongs to the requester, and not the bucket administrator.
You must specify a key that you (the requester) have been granted Encrypt permission to. For more information, see Allows key users to use a KMS key for cryptographic operations in the AWS Key Management Service Developer Guide.
The S3 bucket should look something like this

AWS: Could not able to give s3 access via s3 bucket policy

I am the root user of my account and i created one new user and trying to give access to s3 via s3 bucket policy:
Here is my policy details :-
{  "Id": "Policy1542998309644",  "Version": "2012-10-17",  "Statement": [    {      "Sid": "Stmt1542998308012",      "Action": [        "s3:ListBucket"      ],      "Effect": "Allow",      "Resource": "arn:aws:s3:::aws-bucket-demo-1",      "Principal": {        "AWS": [          "arn:aws:iam::213171387512:user/Dave"        ]      }    }  ]}
in IAM i have not given any access to the new user. I want to provide him access to s3 via s3 bucket policy. Actually i would like to achieve this : https://aws.amazon.com/premiumsupport/knowledge-center/s3-console-access-certain-bucket/ But not from IAM , I want to use only s3 bucket policy.
Based on the following AWS blog post (the blog shows IAM policy, but it can be adapted to a bucket policy):
How can I grant a user Amazon S3 console access to only a certain bucket?
you can make the following bucket policy:
{
"Id": "Policy1589632516440",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1589632482887",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::aws-bucket-demo-1",
"Principal": {
"AWS": [
"arn:aws:iam::213171387512:user/Dave"
]
}
},
{
"Sid": "Stmt1589632515136",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::aws-bucket-demo-1/*",
"Principal": {
"AWS": [
"arn:aws:iam::213171387512:user/Dave"
]
}
}
]
}
This will require user to url directly to the bucket:
https://s3.console.aws.amazon.com/s3/buckets/aws-bucket-demo-1/
The reason is that the user does not have permissions to list all buckets available. Thus he/she has to go directly to the one you specify.
Obviously the IAM user needs to have AWS Management Console access enabled when you create him/her in the IAM service. With Programmatic access only, IAM users can't use console and no bucket policy can change that.
You will need to use ListBuckets.
It seems like you want this user to only be able to see your bucket but not access anything in it.

S3 deny access to administrators

For one AWS S3 bucket, I would like to deny access to everyone except for one specific IAM role. I created a role-based policy to allow access and that works. But other IAM users are also able to access objects and I want to prevent this. I tried adding a bucket policy like this, which denies everyone except this principal and then allows this principal. But this policy blocks access to everyone including that role.
The other IAM users I am trying to block are attached to the built-in AdminstratorAccess policy.
{
"Version": "2012-10-17",
"Id": "PolicySecretBucket",
"Statement": [
{
"Sid": "StmtDenyAll",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::********:role/service-role/my-role"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "StmtAllowLambdaBot",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::********:role/service-role/my-role"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
this is how I would do it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::MyExampleBucket",
"arn:aws:s3:::MyExampleBucket/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAEXAMPLEID:*",
"ACCOUNT NUMBER"
]
}
}
}
]
}
this is how it works.
the user's will have an IAM policy which allows s3.* actions
we will deny all the s3 actions for the bucket MyExampleBucket for any user id but the user id of the role (and the user id of the root account in case if the role is deleted) using the bucket policy
to get the user id of the role:
aws iam get-role --role-name ROLE-NAME
And finally, why yours does not work: https://serverfault.com/a/988136
reference:
https://aws.amazon.com/blogs/security/how-to-restrict-amazon-s3-bucket-access-to-a-specific-iam-role/
Denying access to a specific bucket is actually quite difficult.
For example, an Administrator might have permissions to assume the Role, so they can still access the bucket.
You would also need to review all policies to ensure that only authorized people can use iam:PassRole to assume the role via an Amazon EC2 instance.
An safer approach would be to put the bucket in a separate AWS Account. Then, only give cross-account access to specific users (not a Role). This way, the default is that Admins have zero access and you then grant access to the desired people. There are less ways to "get around" this type of access.

Cross-Account IAM Access Denied with GUI Client, but permitted via CLI

I am stuck with provisioning end-user access into a cross account shared bucket, and need help figuring out if there are specific policy requirements for using clients to access the bucket, vs straight CLI.
IAM User Accounts are managed in our "Core" AWS Account.
S3 Bucket is provisioned in our "Dev" AWS Account.
S3 Bucket in Dev account is encrypted with KMS key in Dev Account.
We have configured our Bucket Policy to permit the user access.
We have configured user policies to permit access to the S3 bucket.
We have configured user policies to permit use of the KMS key.
When using the CLI our user account can succesfully access and use the S3 bucket. When attempting to connect with a GUI Client (Win-SCP, CyberDuck, MAC ForkLift) we receive permission denied errors.
BUCKET POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListObjectsInBucket",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::[DEVACCOUNT#]:role/EC2-ROLE-FOR-APP-ACCESS",
"arn:aws:iam::[COREACCOUNT#]:user/end.user"
]
},
"Action": "s3:List*",
"Resource": [
"arn:aws:s3:::dev-mybucket",
"arn:aws:s3:::dev-mybucket/*"
]
},
{
"Sid": "AllObjectActions",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::[DEVACCOUNT#]:role/EC2-ROLE-FOR-APP-ACCESS",
"arn:aws:iam::[COREACCOUNT#]:user/end.user"
]
},
"Action": [
"s3:GetObject",
"s3:Put*"
],
"Resource": "arn:aws:s3:::dev-mybucket/*"
}
]
}
User Policy - access KMS
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowUseOfDevAPPSKey",
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:Describe*"
],
"Resource": [
"arn:aws:kms:ca-central-1:[DEVACCOUNT#]:key/[redacted-key-number]"
]
},
{
"Sid": "AllowAttachmentOfPersistentResources",
"Effect": "Allow",
"Action": [
"kms:CreateGrant",
"kms:List*",
"kms:RevokeGrant"
],
"Resource": [
"arn:aws:kms:ca-central-1:[DEVACCOUNT#]:key/[redacted-key-number]"
],
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": true
}
}
}
]
}
User policy - Access S3 Bucket
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessToMyBucket",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::dev-mybucket/",
"arn:aws:s3:::dev-mybucket/*"
]
}
]
}
From aws s3 commands we can 'ls' content and 'cp' content from local to remote and from remote to local.
When configuring access with the GUI Clients we always receive somewhat generic 'permission denied' or 'access denied' type errors.
The GUI client is probably making a call that is not List*, Put* or GetObject.
For example, it might be calling GetObjectVersion, GetObjectAcl or GetBucketAcl.
Try adding Get* permissions in addition to List*.
You might also be able to look at the events in your AWS CloudTrail trail to see what specific API calls were denied.
For details, see: Specifying Permissions in a Policy - Amazon Simple Storage Service
Access to an S3 bucket via a GUI such as the AWS web console or SFTP clients with s3 functionality(FileZilla, Cyberduck, ForkLift, etc.) requires the s3:ListAllMyBuckets action in a policy attached to that IAM user. This is very unfortunate as the user will now have access to see ALL your bucket names in that account even if they just have read, write, and or List access to just one bucket in that account.
https://docs.aws.amazon.com/AmazonS3/latest/API/API_Operations.html
https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html
One other option is to go to the bucket URL directly. The user/role will require access via that bucket's Bucket policy.
https://s3.console.aws.amazon.com/s3/buckets/dev-mybucket