0
votes

I'm writing an IAM policy for my Kubernetes workers. I want them to have read/write access to a certain S3 bucket, no access to other S3 buckets in my account, but read access to any bucket that is publicly readable (such as the s3://1000genomes/ bucket, and other buckets where Amazon or other people have put up public data).

(Whether access is granted or denied to public buckets in my account doesn't matter. If I need to grant access to one I can do that explicitly. But I can't go granting access to every public bucket in the world explicitly.)

I can write a stanza that looks like this to give read access to all buckets in the world:

    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::*",
        "arn:aws:s3:::*/*"
      ]
    }

I can also write one that grants access to the particular named bucket on my account that I want to allow access to, filling the name in for *.

But how do I write a policy that denies access to buckets on my account that aren't the named bucket? Or if I take a different approach, how do I write a grant for all buckets not on my account? Is there something I can put between those extra colons that will do this? I've tried using Resource and NotResource together, but AWS rejects that.

For reference, my policy looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::vg-k8s",
                "arn:aws:s3:::vg-k8s/*",
            ]
        }
    ]
}

With that policy in place on my nodes' group, I have no access to s3://1000genomes from the nodes. To get access to that bucket specifically, I can change it to:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::vg-k8s",
                "arn:aws:s3:::vg-k8s/*",
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::1000genomes",
                "arn:aws:s3:::1000genomes/*"
            ]
        }
    ]
}

But I need a way to do this so I cover all public buckets, not just those I list, but so I don't cover non-public buckets in my account.

1
Write a policy that has an ALLOW for all buckets, and then an explicit DENY on your buckets.hephalump
@hephalump How can I DENY all my buckets except the ones I want to ALLOW, though? I can DENY all my buckets, but then the deny will win and I won't be able to access any of my buckets.interfect

1 Answers

0
votes

How do I write a policy that denies access to buckets on my account that aren't the named bucket?

You don't. IAM policies are deny by default.

How do I give read access to any bucket that is publicly readable?

You don't. No additional permission or policy is required to access public buckets.

You will potentially run into an issue, however, with public bucket access and should make your requests to public buckets unsigned.

To interact with the public bucket from the awscli, use:

aws s3 ls s3://1000genomes/ --no-sign-request

To do the same from boto3, use:

import boto3
from botocore import UNSIGNED
from botocore.config import Config
s3 = boto3.client('s3', config=Config(signature_version=UNSIGNED))