S3 Private Bucket - amazon-web-services

I'm trying to create a private S3 bucket with limited access. I only want myself as a user and an EC2 role to have access to the bucket. The purpose of the bucket is to store encrypted SSH keys that will be copied onto machines in an autoscaling group. Right now, when I run aws sync against the bucket, here is the output:
cogility#ip-10-10-200-113:~$ aws s3 sync s3://sshfolder.companycloud.com/cogility /home/cogility/.ssh
download failed: s3://sshfolder.companycloud.com/cogility/id_rsa to ../cogility/.ssh/id_rsa An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
download failed: s3://sshfolder.companycloud.com/cogility/id_rsa.pub to ../cogility/.ssh/id_rsa.pub An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
I create the EC2 instances with an EC2 role with the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"kms:List*",
"kms:Get*",
"kms:Describe*"
],
"Resource": "arn:aws:kms:us-west-2:0000000000:key/kms-id-01234567890"
},
{
"Sid": "",
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com/*",
"arn:aws:s3:::sshfolder.companycloud.com"
]
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:*",
"ec2:*",
"cloudwatch:*",
"autoscaling:*"
],
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"lambda:List*",
"lambda:Invoke*",
"lambda:Get*"
],
"Resource": "*"
}
]
}
And here is the bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com",
"arn:aws:s3:::sshfolder.companycloud.com/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAXXXXXXXXXXXXXXXXX", <-- autoscaling-ec2-role user id
"AROAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX"
],
"aws:sourceVpce": "vpce-abc82480d"
},
"ArnNotLike": {
"aws:SourceArn": "arn:aws:sts::000000000000:assumed-role/autoscaling-ec2-role/"
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::000000000000:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com",
"arn:aws:s3:::sshfolder.companycloud.com/*"
]
}
]
}
Any idea why I'm not able to access the S3 bucket from my EC2 instance?

Amazon S3 buckets are private by default. Therefore, one approach would be:
Do not use a Bucket Policy
Add permissions to your IAM User and the IAM Role to access the bucket
Alternatively:
Use a Bucket Policy to grant access to the IAM User and IAM Role
Both would be sufficient to meet your needs.
However, if you are further paranoid that somebody might accidentally grant access to the bucket (eg with s3:* and a principal of *), then your approach of explicitly Denying access to anyone other than that User & Role is a good approach.

deny trumps allow in your bucket policy. You need to use not principal to achieve this.
"Statement": [
{
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::000000000000:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sshfolder.companycloud.com",
"arn:aws:s3:::sshfolder.companycloud.com/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AROAXXXXXXXXXXXXXXXXX", <-- autoscaling-ec2-role user id
"AROAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX",
"AIDAXXXXXXXXXXXXXXXXX"
],
"aws:sourceVpce": "vpce-abc82480d"
},
"ArnNotLike": {
"aws:SourceArn": "arn:aws:sts::000000000000:assumed-role/autoscaling-ec2-role/"
}
}
}
]
It just inverts the principal element. You can similarly use NotAction and NotResource as appropriate. You could do away with your conditionals altogether and just use NotPrincipal for all of them, it's generally better practice than conditionals.
Here is a resource on it: https://aws.amazon.com/blogs/security/how-to-create-a-policy-that-whitelists-access-to-sensitive-amazon-s3-buckets/

Related

Issue with enabling AWS cross-acount reads + writes while having bucket owner retain ownership over all objects

I need AWS accounts A, B to have read + write access to bucket Q in account C. However, account C should have full ownership over all objects in bucket Q. In line with these docs, I added the following permissions policy.
{
"Version": "2012-10-17",
"Statement": [
// WRITE PERMISSIONS
{
"Effect": "Allow",
"Principal": {
"AWS": [
// Account A
"arn:aws:iam::<Account A ID>:root",
// Account B
"arn:aws:iam::<Account B ID>:root"
]
},
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
// Bucket Q
"Resource": "arn:aws:s3:::<Bucket Q name>/*",
// Basically, all writes must supply bucket-owner-full-control as the ACL or they will be rejected
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
},
// READ PERMISSION for account A
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<Account A ID>:root"
},
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::<Bucket Q name>",
"arn:aws:s3:::<Bucket Q name>/*"
]
},
// READ PERMISSION for account B
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<Account B ID>:root"
},
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::<Bucket Q name>",
"arn:aws:s3:::<Bucket Q name>/*"
]
}
]
}
However, writes (e.g. s3.meta.client.put_object(Bucket=bucket, Key=key, Body=data, ACL='bucket-owner-full-control')) fail with ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied. What am I missing? If it matters at all, writes are being issued from a SageMaker notebook in account B.
Solution:
Attach a resource policy to the IAM role that the SageMaker notebook uses. This policy should give the role s3:putObject and s3:putObjectAcl permissions (i.e. the same permissions the bucket policy lists). You can find the role that the SageMaker notebook uses by viewing your notebook instance in the SageMaker UI.
Attach an identity policy to the IAM role that the SageMaker notebook uses. This policy should allow the account root to assume the role.
In my case, the resource policy was:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::<Bucket Q name>/*"
]
}
]
}
and the identity policy was
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<Account B ID>:root"
},
"Action": "sts:AssumeRole"
}

AWS S3 GetObject error on cross account access

I am the owner of AWS AccountC and need List and Get Permissions to BucketName owned by another person/team.
The bucket policy created is attached below. Policy for AccountA and AccountB were already existing and I added the policy for AccountC as given below
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessA",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AccountA:root",
"arn:aws:iam::AccountA:user/ABC-Prod"
]
},
"Action": [
"s3:GetObject",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::BucketName/*",
"arn:aws:s3:::BucketName"
]
},
{
"Sid": "AccessB",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AccountB:user/service-user",
"arn:aws:iam::AccountB:role/BatchUserRole"
]
},
"Action": "*",
"Resource": [
"arn:aws:s3:::BucketName/*",
"arn:aws:s3:::BucketName"
]
},
{
"Sid": "AccessC",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AccountC:root"
},
"Action": "s3:List*",
"Resource": "arn:aws:s3:::BucketName"
},
{
"Sid": "AccessD",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AccountC:root"
},
"Action": "s3:Get*",
"Resource": "arn:aws:s3:::BucketName/*"
}
]
}
I am able to list contents of BucketName using
aws s3 ls BucketName.
However, when I try
aws s3 cp --recursive BucketName/folderName/ ., it gives me an Access Denied error
An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
Block public access is enabled on the bucket, however I believe it should not affect since the Bucket policy is added
Tried multiple way to write the policy but the error persists. Can someone please help me understand what I might be missing here? Would be really grateful

Restrict all access to a s3 bucket and allow 1 IAM user

As a plan to deprecate s3 objects, I am revoking all access apart from mine. I tried 2 ways but I see I am not able to see the bucket policy.
Error message from console:
You don’t have permission to get bucket policy
You or your AWS administrator must update your IAM permissions to allow s3:GetBucketPolicy. After you obtain the necessary permission, refresh the page. Learn more about Identity and access management in Amazon S3
First:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::ck",
"arn:aws:s3:::k/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AIDA"
]
}
}
}
]
}
Second:
{
"Id": "bucketPolicy",
"Statement": [
{
"Action": "s3:*",
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::0220:user/an"
]
},
"Resource": [
"arn:aws:s3:::tes",
"arn:aws:s3:::tes/*"
]
}
],
"Version": "2012-10-17"
}

S3 bucket policy to deny all except a particular AWS service role and IAM role

Can you write an s3 bucket policy that will deny access to all principals except a particular IAM role and AWS service role (e.g. billingreports.amazonaws.com).
I have tried using 'Deny' with 'NotPrincipal', but none of the below examples work as I don't think the ability to have multiple types of principals is supported by AWS?
This allows you to save the policy but locks out the bucket (warning: only root user can then update policy to unlock)
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::<account_id>:root",
"arn:aws:iam::<account_id>:role/specialBillingRole"
],
"Service": "billingreports.amazonaws.com"
}
Therefore I am trying to use conditions but can't find the right combinations that will work. Here is an example policy.
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "billingreports.amazonaws.com"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket/*",
"arn:aws:s3:::my-bucket"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::<account_id>:role/specialBillingRole",
"billingreports.amazonaws.com",
"<account_id>"
]
}
}
}
]
}
UPDATED the question as per some comment suggestions.
2nd UPDATE Also tried the below, which still gives access to all roles/users in the account (can't use wildcards in the Principal).
{
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::<account_id>:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket/*",
"arn:aws:s3:::my-bucket"
],
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": [
"arn:aws:iam::<account_id>:role/specialBillingRole",
"<account_id>"
]
}
}
}
You can certainly create a bucket policy that grants access only to a service role and an IAM role, but to be clear, a service role will still begin with "arn:aws:iam:::role...".
Are you instead trying to create a bucket policy that grants access both to a particular service and a service role? I'm asking because if you have a role created with billingreports.amazonaws.com as its trusted entity, and if that role is what's intended to access the bucket, then you do not need to list the service separately in your bucket policy (if the scenario is as I imagine).
Please do note, also, that you can indeed use wildcards with the principal, combined with a condition - I do so all the time (see my example policy below). When I want to restrict bucket access to a specific role, I simply include an Allow statement with a Principal of just the role I want to allow, and then a Deny statement with a Principal of "AWS": "*", followed by a condition, like so:
{
"Version": "2008-10-17",
"Id": "PolicyScopedToSecurity",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[accountID]:role/[roleName]",
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::[bucketName]",
"arn:aws:s3:::[bucketName]/*"
]
},
{
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::[bucketName]",
"arn:aws:s3:::[bucketName]/*"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::[accountID]:role/[roleName]",
"[accountID]"
]
}
}
}
]
}
If you truly need the service itself to access the bucket, the solution will be slightly different. My response assumes the service role needs access.

Can you use tags to give access to S3 Buckets?

I just tried adding tags to some buckets and then I created an inline IAM role policy that'd give that role access to the S3 buckets however that didn't work. I tried both iam:ResourceTag/tagName and s3:ResourceTag/tagName as conditionals but neither worked.
As everything looked just fine I started thinking that AWS might not have implemented this yet for S3. Is that the case? I tried reviewing documentation and indeed I didn't find anything about this use of tags working with S3.
For example the role HumanResources should have to all buckets tagged with HR, Recruitment etc. but no other buckets.
In looking at Actions, Resources, and Condition Keys for Amazon S3 - AWS Identity and Access Management, there does not appear to be the ability to specify a Bucket Tag in an IAM Policy.
One alternative is to use a wildcard in a bucket name. For example, you could grant permission to access:
acme-hr-1
You could grant permissions based on a bucket name of acme-hr-*.
Yes you can but you will need do on each S3 Resource Policy.
Here is an S3 Policy to grant access to the bucket for only IAM users and roles with a Tag department set to "hr".
To ensure HR employee only have access to these buckets you will need to remove all S3 access from their IAM user/role access polices.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyObjectOthers",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:DeleteObject*",
"s3:PutObject*",
"s3:GetObject*",
"s3:RestoreObject*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME/*"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
},
{
"Sid": "DenyListOthers",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:ListBucket*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME"
],
"Condition": {
"StringNotLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
},
{
"Sid": "AllowObject",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWS_ACCOUNT_NUMBER:root"
},
"Action": [
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:DeleteObject*",
"s3:PutObject*",
"s3:GetObject*",
"s3:RestoreObject*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME/*"
],
"Condition": {
"StringLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
},
{
"Sid": "AllowList",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWS_ACCOUNT_NUMBER:root"
},
"Action": [
"s3:ListBucket*"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME"
],
"Condition": {
"StringLike": {
"aws:PrincipalTag/department": [
"hr"
]
}
}
}
]
}
Previous Wrong Answer
From: IAM Policy Elements: Variables and Tags - AWS Identity and Access Management
"Resource": ["arn:aws:s3:::bucket/${aws:PrincipalTag/department}"]
Also make sure to include the version at 2012-10-17.