Storage & Data Security

Access Policies & Preventing Public Exposure

4 min read

Public storage exposure remains the #1 cause of cloud data breaches. Even with improved defaults since 2023, intentional and accidental misconfigurations continue to expose sensitive data.

The Public Exposure Problem

Current statistics:

  • 31% of S3 buckets are publicly accessible
  • 46% of S3 buckets could be misconfigured
  • Football Australia (2024): 127 storage containers exposed

The challenge isn't the default settings—it's developers creating exceptions for convenience that become permanent vulnerabilities.

AWS S3 Access Policy Patterns

Defense in Depth Approach

Account-level Block Public Access
       Bucket Policy (Deny public)
       IAM Policies (Least privilege)
       Access Points (Segmented access)

Account-Level Protection

Apply to the entire AWS account to prevent any S3 bucket from being public:

# Block public access at account level
aws s3control put-public-access-block \
    --account-id 123456789012 \
    --public-access-block-configuration \
    BlockPublicAcls=true,\
    IgnorePublicAcls=true,\
    BlockPublicPolicy=true,\
    RestrictPublicBuckets=true

Bucket Policy Templates

Deny external access (organization-only):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyExternalAccess",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
      "arn:aws:s3:::my-bucket",
      "arn:aws:s3:::my-bucket/*"
    ],
    "Condition": {
      "StringNotEquals": {
        "aws:PrincipalOrgID": "o-xxxxxxxxxx"
      }
    }
  }]
}

Restrict to specific VPC endpoint:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyNonVPCAccess",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
      "arn:aws:s3:::my-bucket",
      "arn:aws:s3:::my-bucket/*"
    ],
    "Condition": {
      "StringNotEquals": {
        "aws:SourceVpce": "vpce-1234567890abcdef0"
      }
    }
  }]
}

S3 Access Points

Modern approach for segmented access:

# Create access point for specific application
aws s3control create-access-point \
    --account-id 123456789012 \
    --name app-access-point \
    --bucket my-bucket \
    --vpc-configuration VpcId=vpc-12345678

# Access point policy
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::123456789012:role/ApplicationRole"
    },
    "Action": ["s3:GetObject", "s3:PutObject"],
    "Resource": "arn:aws:s3:us-east-1:123456789012:accesspoint/app-access-point/object/*"
  }]
}

Azure Storage Access Controls

Disable Shared Key Access

Eliminate storage account keys entirely:

# Disable shared key access
az storage account update \
    --name mystorageaccount \
    --resource-group myRG \
    --allow-shared-key-access false

Container Access Levels

Level Access Recommendation
Private No anonymous access Default, always use
Blob Anonymous read for blobs Rarely needed
Container Anonymous read for container + blobs Avoid
# Ensure container is private
az storage container set-permission \
    --name mycontainer \
    --account-name mystorageaccount \
    --public-access off

SAS Token Best Practices

When temporary access is needed:

# Generate scoped SAS token
az storage container generate-sas \
    --name mycontainer \
    --account-name mystorageaccount \
    --permissions r \
    --expiry $(date -u -d "1 hour" +"%Y-%m-%dT%H:%MZ") \
    --ip "10.0.0.0-10.0.0.255" \
    --https-only

SAS token security rules:

  • Short expiration (hours, not days)
  • Minimum required permissions
  • IP restrictions when possible
  • HTTPS only
  • Use stored access policies for revocation capability

GCP Cloud Storage Security

Public Access Prevention

Organization-wide enforcement:

# Enable public access prevention on bucket
gcloud storage buckets update gs://my-bucket \
    --public-access-prevention=enforced

# Organization policy constraint
gcloud resource-manager org-policies set-policy policy.yaml

policy.yaml:

constraint: constraints/storage.publicAccessPrevention
listPolicy:
  allValues: DENY

IAM Conditions

Time-limited or conditional access:

gcloud storage buckets add-iam-policy-binding gs://my-bucket \
    --member="user:developer@example.com" \
    --role="roles/storage.objectViewer" \
    --condition="expression=request.time < timestamp('2026-02-01T00:00:00Z'),title=temporary-access"

Detecting Public Exposure

AWS Access Analyzer

# Enable IAM Access Analyzer
aws accessanalyzer create-analyzer \
    --analyzer-name MyAnalyzer \
    --type ACCOUNT

# List public/cross-account findings
aws accessanalyzer list-findings \
    --analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/MyAnalyzer \
    --filter '{"resourceType": {"eq": ["AWS::S3::Bucket"]}}'

AWS Macie

Discover sensitive data in S3:

# Enable Macie
aws macie2 enable-macie

# Create sensitive data discovery job
aws macie2 create-classification-job \
    --job-type ONE_TIME \
    --s3-job-definition '{
        "bucketDefinitions": [{
            "accountId": "123456789012",
            "buckets": ["my-bucket"]
        }]
    }'

Prevention Checklist

Control AWS Azure GCP
Block public access ✓ Account + Bucket level ✓ Private containers ✓ Public access prevention
Organization policies ✓ SCPs ✓ Azure Policy ✓ Org constraints
Access analyzer ✓ IAM Access Analyzer ✓ Defender for Cloud ✓ Security Command Center
Data discovery ✓ Macie ✓ Purview ✓ DLP
Monitoring ✓ CloudTrail + Config ✓ Diagnostic logs ✓ Cloud Audit Logs

Next, we'll cover data backup, disaster recovery, and data lifecycle management. :::

Quiz

Module 3: Storage & Data Security

Take Quiz