I recently saw a Twitter thread on AWS’s notorious public S3 bucket permissions issue. Some of the replies, especially from AWS folks defending AWS on the issue, got me thinking about whether there are additional improvements that can be made.
While it’s true that AWS has done a lot in the past year to improve S3 bucket security, for some reason we’re still seeing breaches occur with a regular cadence. Something more is needed.
So I fired up my AWS console and started taking some notes. I don’t expect AWS to implement all of these suggestions (I don’t claim to be an expert on the S3 product and am certain to be missing some nuances), but maybe they can reach the right teams who can use them as a starting point for discussion.
1. Decouple public access from buckets entirely.
If you physically cannot make a bucket public, the problem disappears. Let’s start off by making it impossible to make a bucket public by itself. I recognize that there are edge cases where public buckets are needed, and so I propose a new AWS service, “AWS Bucket Exposing Endpoints” (the name is a work-in-progress) that creates a separate, public endpoint for an existing S3 bucket (yes, sort of like CloudFront, but without all the extra CDN components). This service lives in a different namespace, has different permissions, and a different page in the UI.
2. Merge ACLs and bucket policies
Mistakes are made when developers are confused, and there is little in the AWS ecosystem that is more confusing than trying to understand the inner-workings of S3 bucket policies and ACLs. If I could vote, I would get rid of ACLs; they seem to be a relic of years ago when the entire bucket permission system worked in a different way.
3. Make public bucket access a CLI-only setting
If my first proposal can’t be done, my fallback suggestion is to remove the public access setting from the UI entirely. It’s a bit drastic, but not without precedent; Lambda’s invocation permissions were hidden behind a CLI-only option for years.
4. Move the decision to account owners
Settings this important shouldn’t be left to any developer with “S3:*” permissions. For all new accounts, create a global setting called “Prevent S3 buckets from being public” and set it to “true.” Require the root user to disable it (and before allowing them to disable it, require them to add an MFA device for good measure). So it’s said, AWS Organizations have the ability to define settings like these, but not everyone uses Organizations, or goes through the configuration pain to opt-in.
5. Require a two-person developer opt-in
Much like the rules of nuclear engagement, S3 bucket permissions are serious work! If an account has more than one developer and that developer attempts to make a bucket public (especially one with data already in it), an email should be sent to account admins to confirm the change (similar to ACM certificate validation emails).
6. Enforce a waiting period
A developer shouldn’t be allowed to log into the AWS console and make a choice they might come to regret. For existing buckets with data, a 24-hour waiting period should be enforced before the “public” setting is enabled. If the developer doesn’t re-confirm the option, it doesn’t go into effect.
7. Disable public buckets that have never received public traffic
All of the previous suggestions refer to new buckets or new accounts. But what about existing buckets that have been public for years? If AWS has access logs for the bucket, and the bucket has never been accessed from a public IP address, I would suggest it should be reverted to private with an email to the account owner. This of course requires long-term access log retention, so may be a stretch, but would go a long way to preventing future breaches.
To summarize, while I think AWS does a fantastic job of creating good services that have excellent security options, the answer to “developers are mistakenly configuring buckets insecurely” shouldn’t be “they just aren’t reading the options,” but rather “what more can we do to make it nearly impossible to do the wrong thing?”