AWS Builder Center

Penetration testing a private application with AWS Security Agent — Part 3: zero internet, from the first second

Series: Penetration testing private applications with AWS Security Agent (now part of AWS Continuum) — Part 3 of 3

Co-authored with   Sakthivel Chellapparimanam 



The strictest posture

 Part 1  tested a private target with internet egress in place.  Part 2  removed that egress after deployment, migrating to AWS PrivateLink. This post builds the same application in a VPC that has no internet egress at any point — no Internet Gateway and no NAT Gateway are ever created. This is the posture for regulated and air-gapped environments, and it is the furthest extension of the official   aws-samples/sample-security-agent-demo  , which keeps the ALB public and the egress open.
Everything the agent and the application need must be reachable from inside the VPC, over endpoints.
The Terraform for this series is in the companion repository (  srcsakthivel/security-agent-private-demo  ); this posture is under  paths/3-true-private/ .
The Agent Space is created for a VPC that has never had internet access:
Create Agent Space for the true-private posture, described as a VPC without internet access




Architecture: private subnets only

The VPC has only private subnets. Their route tables have no default route. The only paths off a subnet are the VPC interface and gateway endpoints, and the local route to the target application.
The VPC resource map makes the posture explicit — two private subnets, their route tables, and a single network connection, which is the S3 gateway endpoint. There is no Internet Gateway and no NAT Gateway.
VPC resource map showing two private subnets, three route tables, and one network connection — the S

The Security Agent and SSM interface endpoints are the agent's only path to AWS, and they are created up front rather than added later:
  • Security Agent:  securityagent ,  bedrock-runtime ,  logs 
  • Instance management (SSM):  ssm ,  ssmmessages ,  ec2messages 
  • S3 gateway endpoint: for the instance's package and dependency installs (below)
The same all-or-nothing rule from Part 2 applies: a partial Security Agent endpoint set causes the agent to authenticate and then stall at reasoning or logging, and missing SSM endpoints remove Session Manager access. (See Part 2 for the full operational detail; it is identical here.)



The dependency problem no one expects

With no internet egress, the agent is not the only thing that cannot reach the internet — the application instance cannot reach PyPI either. A standard  pip install flask pymysql  has nowhere to go. Two specific obstacles have to be solved for the instance to boot successfully.

1. Vendor the Python wheels into S3

Download the dependency wheels on an internet-connected machine, store them in a private S3 bucket, and have the instance install them with  pip --no-index  over the S3 gateway endpoint. The wheels must be built for the instance, not the machine that downloads them — Amazon Linux 2023 runs Python 3.9 on  manylinux  x86_64, which is often not the architecture of the machine running the download:
Bash
cd paths/3-true-private
cp terraform.tfvars.example terraform.tfvars # set db_password

# on an internet-connected machine (the VPC never gets internet)
terraform init
./vendor-wheels.sh # downloads py3.9 / manylinux x86_64 wheels into ./wheels
terraform apply # uploads ./wheels/* to the private S3 bucket, boots the instance
The  vendor-wheels.sh  script pins  --platform manylinux2014_x86_64 --python-version 3.9 --only-binary=:all:  so  pip download  fetches the target's wheels rather than the host's, and it explicitly requests the environment-marker dependencies ( importlib-metadata ,  zipp ) that a newer host interpreter would otherwise skip. The Terraform fails fast with a clear message if the wheels were never vendored, rather than booting an instance that would then fail its offline install.

2. Force IPv4 for Amazon Linux 2023 package installs

This is the non-obvious trap. On first boot the instance still needs  dnf install python3-pip  from the AL2023 repositories, which are served from regional Amazon S3 and reachable over the S3 gateway endpoint. But AL2023's  dnf  resolves the dual-stack S3 hostname to IPv6-only addresses. The instance has no IPv6 route, and the S3 gateway endpoint's managed prefix list covers only IPv4 S3 ranges, so  dnf  hangs on IPv6 and times out — stalling the entire first boot.
The fix is to force  dnf  (and libcurl) to IPv4 before the first  dnf  call:
Bash
echo "ip_resolve=4" >> /etc/dnf/dnf.conf
With that one line, the same hostname resolves to an IPv4 S3 address the gateway endpoint routes, and the install completes. This single line is the difference between a working and a hanging first boot in a zero-internet AL2023 VPC.
You do not need to add either fix yourself: both the  ip_resolve=4  line and the offline  pip install --no-index --find-links /opt/wheels  step are already in the shared boot script,   modules/pentest-target/user_data.sh.tftpl  , and run only in this posture's offline install mode.



Configure and run

Enable penetration testing in the Agent Space exactly as in Part 1: add  app.internal.pentest-demo.local  with Private VPC verification, accept the expected Unreachable status, then in Configure resources and access select this posture's private VPC, both private subnets, the agent security group, and the service role from  terraform output .
Setup Pentest configurations for the true-private Agent Space: the private VPC, both private subnets

Before starting the run, use the same readiness check as Part 2: the SSM agent reports  Online , the ALB target is  healthy , and every endpoint is  available . In this posture, a failed check usually points to the first boot — if the target is unhealthy, open a Session Manager session and check  /var/log/cloud-init-output.log  for a stalled  dnf  or a failed offline  pip install .
The run starts and moves to In progress, with no internet path anywhere in the VPC:
Pentest started: run in progress for the true-private Agent Space

As in the earlier posts, specific findings are a property of the demo application and are not reproduced here. The result that matters is the one this series set out to demonstrate: Security Agent performed a validated, exploit-backed penetration test of a private application in a VPC with zero internet egress at any point, reaching its control plane, inference, and logging exclusively over PrivateLink.



Cross-region inference

As in Part 2: Cross-region inference does not change the endpoint set. Requests go to bedrock-runtime in the source Region, and Bedrock routes them to destination Regions over its own network, so the single bedrock-runtime endpoint above is sufficient. What can break is authorization: if your organization restricts Regions with SCPs, or you attach a custom endpoint policy, make sure neither denies the destination Regions or model ARNs that the inference profile routes to.



Cleanup and cost

Interface endpoints (hourly per endpoint per Availability Zone, plus data processing) dominate the cost. The vendored-wheels S3 bucket is configured for  force_destroy  so it empties itself on teardown. Destroy the environment when the exercise is complete:
Bash
terraform destroy



Series recap: pick your posture

Posture
Internet egress
Verification
Extra setup
 Part 1 
— Public internet
Yes (NAT), throughout
DNS-TXT / HTTP-route or Private VPC
none
 Part 2 
— Deploy, then private
Yes at first apply → removed
Private VPC after the flip
two applies
Part 3 — True private
None, ever
Private VPC
vendor wheels first
Across all three, the target is never publicly exposed, and the finding that holds regardless of posture is the one that answers the opening objection: a private application with no public domain can be penetration tested, because AWS Security Agent tests from inside the VPC and proves control rather than public ownership.
Learn more:
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article