Skip to main content
emnode / learn
Compliance

Block public access to AWS resources

One capability across S3, EC2, RDS, snapshots, queues and topics: make sure nothing is reachable from, or shareable with, the public internet unless you genuinely intend it.

14 min·10 sections·AWS

Last reviewed

Blocking public access: the basics

What does "public" actually mean across AWS services?

"Public" in AWS is not one setting. It is a property that shows up in a dozen different shapes: an S3 bucket with a public policy or ACL, an EC2 instance with a public IPv4 address, an RDS instance marked publicly accessible, a snapshot shared with all accounts, an SNS topic or SQS queue whose resource policy allows a wildcard principal, an SSM document shared publicly, an EMR or MSK cluster on a public subnet. Each service expresses public reachability in its own way, but the risk is identical: data or control planes that anyone on the internet can reach.

AWS Security Hub turns each of these into its own control, which is why a single estate can fail twenty or more public-access checks at once. S3.1, S3.2, S3.8 and S3.19 cover buckets and access points; EC2.9 and EC2.15 cover public IPs; RDS.2 covers publicly accessible databases; SNS.4 and SQS.3 cover open resource policies; SSM.4 covers shared documents. They look like separate problems on the report, but they are one capability: close the doors you did not mean to leave open.

The good news is that most public exposure is drift, not intent. A subnet that auto-assigns public IPs, a snapshot copied with the wrong sharing flag, a bucket policy pasted with a wildcard principal. The job is to find every resource that is reachable from the public internet, decide which handful are public on purpose, route those through a controlled front door such as CloudFront or a load balancer, and then shut the rest.

In this lesson you will learn how AWS expresses public reachability across storage, compute, databases, snapshots and messaging, how to find every publicly exposed resource in an account, and how to close them down without breaking the few that are public on purpose. The Controls this lesson covers section lists every Security Hub control in this capability, each linking to a deep page with the exact check and a copy-and-paste fix.

Fun fact

The decade of leaked buckets

Between 2017 and 2020, before account-level Block Public Access existed and before AWS started enabling it by default, publicly exposed S3 buckets were the dominant source of cloud data leaks: Dow Jones, Verizon, Accenture, the US Department of Defense and Capital One among them. The pattern was always the same, a resource that could be made public was made public by accident. AWS has since shipped account-level and VPC-level public-access blocks, but every resource created before those defaults still needs to be checked and shut explicitly.

Finding public exposure across an estate

Priya is the security lead at a scale-up preparing for its first SOC 2 audit. Security Hub shows public-access failures spread across S3, EC2, RDS and SNS in three accounts that pre-date the team's current guardrails.

Rather than work the findings one by one, she starts by listing what is actually reachable from the internet, so she can separate genuine public services from drift before changing anything.

Start with the resources that expose data directly. Publicly accessible RDS instances are a common and high-impact finding.

$ aws rds describe-db-instances --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Engine]' --output table
-------------------------------------------
| legacy-reporting | postgres |
| analytics-staging | mysql |
-------------------------------------------
# Two databases reachable from the internet. Neither needs to be.

Public databases are the highest-value target in this group. Fix these first.

How AWS decides a resource is publicdeep dive

Most public-access controls resolve to one of three mechanisms. The first is a network property: a public IPv4 address or a resource placed on a subnet that routes to an internet gateway, which is how EC2.9, EC2.15, RDS.2 and the EMR and MSK public-subnet checks work. The second is a resource policy with a wildcard principal, which is how SNS.4, SQS.3 and the public snapshot and SSM document checks work. The third is the S3 access model, where bucket and account Block Public Access settings sit in front of policies and ACLs.

Security Hub evaluates these through AWS Config, typically on a several-hour cycle, so a fix does not flip the finding to PASSED instantly. The control plane change itself is immediate, but the report catches up on the next evaluation. This matters when you are gathering audit evidence against a deadline.

The strongest controls are the account-wide and VPC-wide blocks: S3 account-level Block Public Access and VPC Block Public Access act as a backstop that no individual resource can override. Turning those on is the difference between checking that nothing is public today and guaranteeing that nothing can be made public tomorrow.

What is the impact of leaving resources public?

The direct impact is data exposure. A public database, bucket or queue is reachable by anyone who finds it, and internet-facing resources are found quickly by automated scanners. The overwhelming majority of public-exposure incidents were accidents, a resource that could be public was made public by a policy or flag nobody intended to set.

The second-order impact is blast radius. Every public IP and open endpoint is attack surface that has to be defended continuously. Closing public access shrinks that surface to the handful of front doors you actually operate, which are the ones you can monitor, rate-limit and put a WAF in front of.

On the compliance side, every modern framework, SOC 2, ISO 27001, HIPAA, PCI DSS and FedRAMP, expects evidence that data stores are not publicly accessible by default. A passing set of public-access controls across every account is the cheapest and most defensible artefact you can hand an auditor.

How do you close public access safely?

Work the capability as one loop rather than chasing individual findings. The order matters: find the legitimate exceptions before you start shutting things, so you do not take a live service offline.

1. Inventory everything reachable from the internet

Across services, list the resources that are public: buckets and access points, EC2 instances and subnets that assign public IPs, publicly accessible databases, shared snapshots, and SNS topics, SQS queues and SSM documents with wildcard policies. Treat this inventory as the source of truth, not the Security Hub finding count, because one resource can trigger several controls.

2. Separate genuine public services from drift

Most public exposure is unintended. For each resource, decide whether it is public on purpose. Genuine public content (a static site, a public download bucket) belongs behind CloudFront with Origin Access Control or behind a load balancer, never directly exposed. Everything else is drift and can be closed.

3. Close the doors, highest impact first

Remove public IPs, set databases to not publicly accessible, tighten resource policies to remove wildcard principals, and un-share snapshots. Prioritise resources that hold data over those that do not. Each change is a single API call per resource and takes effect immediately.

4. Ratchet it shut with account and VPC blocks

Enable account-level S3 Block Public Access and VPC Block Public Access so no individual resource can be made public again, and disable public IP auto-assignment on subnets. Back this with AWS Config rules and Service Control Policies so the blocks cannot be quietly undone.

# Close the highest-impact public exposure first: databases.
for db in $(aws rds describe-db-instances \
    --query 'DBInstances[?PubliclyAccessible==`true`].DBInstanceIdentifier' --output text); do
  aws rds modify-db-instance --db-instance-identifier "$db" \
    --no-publicly-accessible --apply-immediately
  echo "$db: public access removed"
done

# Ratchet S3 shut at the account level so no bucket can be made public again.
aws s3control put-public-access-block --account-id 123456789012 \
  --public-access-block-configuration \
    'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'

Quick quiz

Question 1 of 5

Security Hub shows public-access failures across S3, EC2, RDS and SNS. What is the most efficient way to think about them?

You can now treat public access as one capability rather than a scatter of findings: inventory what is reachable from the internet, separate the genuine public services and route them through a controlled front door, close the rest highest-impact first, and ratchet the estate shut with account-level and VPC-level blocks. The Controls this lesson covers section below links every control in this group to its deep page and fix.

Back to the library

Controls this lesson covers

One capability, many AWS Security Hub controls. This lesson is the shared playbook; each control below keeps its own deep page with the exact check, severity and a copy-and-paste fix.