Many cases have been reported where data has leaked to public from AWS S3 buckets. While some of those might be done on purpose, I would guess in most cases it was accident that happend either because bucket configuration was copied from existing bucket or data was stored into existing bucket without checking what permissions it has.

To fix the problem before anything gets leaked, AWS and others have provided bunch of tools for reporting public S3 buckets. These will help you to fix the problem, assuming you can deny public access without breaking things at the same time.

One typical excuse for public access on S3 bucket is when you need to share non-confidential data with multiple accounts you own. This could be e.g. Cloudformation templates, Ansible playbooks or build artefacts from your CI pipeline. You could list the accounts you own in bucket policy but as the number of AWS accounts grows it gets difficult to maintain the list, until one day you’ll give up - this doesn’t really contain any secrets so why don’t I just allow public read access and be done with it.

Now you can forget that excuse as AWS announced “aws:PrincicalOrgID” condition key to be used in IAM polices. If you have S3 bucket policies where you explicitly list accounts that have access to bucket (and maintain that list for each bucket)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListGet",
            "Effect": "Allow",
            "Principal": {
            		"AWS": [
            			"arn:aws:iam::111111111111:root",
            			"arn:aws:iam::222222222222:root",
            			"arn:aws:iam::333333333333:root",
            			...
            			"arn:aws:iam::999999999999:root"
            		]
            },
            "Action": [
                "s3:GetObject",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket",
                "arn:aws:s3:::my-bucket/*"
            ]
      ]
}

You can now replace above with simple and static policy that grants access for any account in your AWS Organization. When you add new accounts to your org-tree, access is automatically granted.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListGet",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket",
                "arn:aws:s3:::my-bucket/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalOrgID": "o-xxxxxxxxxx"
                }
            }
        }
    ]
}

Similar condition can also be applied to any other IAM based policies, e.g. SQS policies, when you need to enable cross-account access for your AWS resources.