Allowlist
Progress checklist
Overview
Section titled “Overview”demo.sh allowlist rewrites each bucket policy from .lab-state.json.
Same shape on primary and replica; only the gateway ID changes.
Who can hit the S3 replica (…-akl):
- Auckland S3 gateway VPCE (
aws:SourceVpce=vpce-03e2d0531f4aa10bc):GetObject/ListBucketfor the Akl probe - SSO admin role: bypass
s3:*(publish / ops from your laptop) - CRR role: bypass
s3:*(replication writer)
Everyone else (internet, unsigned, wrong Region gateway) is denied. The Sydney gateway is not on the replica allowlist.
Policy SIDs:
- DenyNonVpce: deny
s3:*unlessaws:SourceVpcematches that bucket’s gateway (SSO admin and CRR exempt) - AllowVpceRead: allow
GetObject/ListBucketvia that VPCE - AllowBypassPrincipals: full
s3:*for SSO admin + CRR - AllowSSLRequestsOnly: deny non-TLS
If a Region has no consumer yet, that bucket only gets the bypass + TLS
statements (no VPCE lock). Run up-consumer in both Regions first, then
allowlist once.
-
Apply policies from state (needs Syd and Akl
s3_vpce_idvalues):Terminal window export AWS_PROFILE=sandbox./scripts/demo.sh allowlistLab run (both consumers present):
allowlist applied (syd=["vpce-0e5bfd92d3a7c0f29"] akl=["vpce-03e2d0531f4aa10bc"])
Verify
Section titled “Verify”Set once for the checks below:
PRIMARY="$(jq -r .primary_bucket .lab-state.json)"REPLICA="$(jq -r .replica_bucket .lab-state.json)"KEY=demo/allowlist-verify.txtINSTANCE="$(jq -r .consumers.syd.instance_id .lab-state.json)"-
Put a tiny object as admin (bypass) so curl / probe have a target:
Terminal window echo "allowlist verify" | aws s3 cp - "s3://${PRIMARY}/${KEY}" --region ap-southeast-2upload: - to s3://ps3a-artifacts-**ACCOUNT**-syd/demo/allowlist-verify.txt -
Primary policy SIDs (Sydney; VPCE lock present):
Terminal window aws s3api get-bucket-policy --bucket "$PRIMARY" --region ap-southeast-2 \--query Policy --output text | jq '.Statement[] | {Sid, Effect}'{ "Sid": "AllowBypassPrincipals", "Effect": "Allow" }{ "Sid": "AllowSSLRequestsOnly", "Effect": "Deny" }{ "Sid": "DenyNonVpce", "Effect": "Deny" }{ "Sid": "AllowVpceRead", "Effect": "Allow" } -
Primary
aws:SourceVpceon the deny/allow statements:Terminal window aws s3api get-bucket-policy --bucket "$PRIMARY" --region ap-southeast-2 \--query Policy --output text \| jq -r '.Statement[] | select(.Sid=="DenyNonVpce")| .Condition.StringNotEquals["aws:SourceVpce"][]'vpce-0e5bfd92d3a7c0f29 -
Replica policy SIDs (Auckland VPCE lock present):
Terminal window aws s3api get-bucket-policy --bucket "$REPLICA" --region ap-southeast-6 \--query Policy --output text | jq '.Statement[] | {Sid, Effect}'{ "Sid": "AllowBypassPrincipals", "Effect": "Allow" }{ "Sid": "AllowSSLRequestsOnly", "Effect": "Deny" }{ "Sid": "DenyNonVpce", "Effect": "Deny" }{ "Sid": "AllowVpceRead", "Effect": "Allow" } -
Replica
aws:SourceVpce:Terminal window aws s3api get-bucket-policy --bucket "$REPLICA" --region ap-southeast-6 \--query Policy --output text \| jq -r '.Statement[] | select(.Sid=="DenyNonVpce")| .Condition.StringNotEquals["aws:SourceVpce"][]'vpce-03e2d0531f4aa10bc -
Anonymous curl (must fail):
Terminal window curl -sS -o /tmp/allowlist-curl.body -w 'http_code=%{http_code}\n' \"https://${PRIMARY}.s3.ap-southeast-2.amazonaws.com/${KEY}"head -c 200 /tmp/allowlist-curl.body; echohttp_code=403<?xml version="1.0" encoding="UTF-8"?><Error><Code>AccessDenied</Code><Message>Access Denied</Message>...</Error> -
Unsigned CLI head (must fail):
Terminal window aws s3api head-object --bucket "$PRIMARY" --key "$KEY" \--region ap-southeast-2 --no-sign-requestaws: [ERROR]: An error occurred (403) when calling the HeadObject operation: Forbidden -
Admin signed head (bypass ARN; must succeed):
Terminal window aws s3api head-object --bucket "$PRIMARY" --key "$KEY" \--region ap-southeast-2 --query ContentLength --output text17 -
Probe EC2 via Syd gateway + SSM (must succeed):
Terminal window CMD_ID=$(aws ssm send-command \--instance-ids "$INSTANCE" \--document-name AWS-RunShellScript \--parameters "commands=[\"aws s3api head-object --bucket $PRIMARY --key $KEY --region ap-southeast-2 --query ContentLength --output text\"]" \--region ap-southeast-2 \--query 'Command.CommandId' --output text)aws ssm get-command-invocation --command-id "$CMD_ID" --instance-id "$INSTANCE" \--region ap-southeast-2 \--query '{Status:Status,StdOut:StandardOutputContent}' --output json{"Status": "Success","StdOut": "34\n"}