Declare allowed and denied AWS connectivity in YAML and verify it with AWS Reachability Analyzer.
aws-network-preflight is a Python CLI for platform, SRE, and networking teams that want to describe expected AWS connectivity in version-controlled YAML and verify it with AWS Reachability Analyzer. It helps catch drift in security groups, routes, and attachments before that drift turns into a broken deployment or an incident.
The scope is intentionally narrow. v1 focuses on single-region AWS connectivity validation for EC2 instances and ENIs.
AWS connectivity changes over time. Security groups get edited, routes move, NACLs tighten, new attachments appear, and paths that used to work quietly stop working.
This project exists to make expected connectivity explicit and testable:
- declare intent in YAML
- verify it locally or in CI
- use AWS-native analysis instead of hand-built network heuristics
Python 3.11+ is required.
Install from PyPI:
pipx install aws-network-preflightThat gives you a globally available CLI in an isolated environment.
Install from source for local development:
git clone https://github.com/gcasanova/aws-network-preflight.git
python3 -m venv ~/venvs/anp
source ~/venvs/anp/bin/activate
pip install -e ./aws-network-preflightThis keeps the virtual environment outside the repository instead of creating a local .venv inside the source tree.
anp is the short alias for aws-network-preflight.
The CLI uses the AWS credential chain and supports profile-based authentication. For multi-account setups, logical accounts can also define per-account role_arn values to assume.
You will need AWS credentials and permissions that can read the referenced resources and run Reachability Analyzer in the configured accounts.
Create a starter config:
anp initEdit preflight.yaml with your real AWS profile, region, accounts, and selectors.
Validate the config:
anp validate -f preflight.yamlResolve the configured targets without running analysis:
anp list-targets -f preflight.yamlRun the assertions:
anp run -f preflight.yamlInspect one assertion in detail:
anp explain -f preflight.yaml --id client-to-server-443-allowFor CI-friendly output, run and explain also support --format json.
This is the simplest same-account profile-based shape:
version: 1
defaults:
region: us-east-1
auth:
mode: profile
profile: default
accounts:
lab:
regions: [us-east-1]
assertions:
- id: client-to-server-443-allow
type: allow
source:
account: lab
selector:
tags:
Name: client
destination:
account: lab
selector:
tags:
Name: server
protocol: tcp
port: 443
- id: client-to-server-80-deny
type: deny
source:
account: lab
selector:
tags:
Name: client
destination:
account: lab
selector:
tags:
Name: server
protocol: tcp
port: 80role_arn is optional for simple same-account profile-based usage. For multi-account configurations, each logical account can also define a role_arn to assume.
For multi-account setups, logical accounts can carry their own role assumptions:
version: 1
defaults:
region: us-east-1
auth:
mode: profile
profile: default
accounts:
shared:
role_arn: arn:aws:iam::111111111111:role/PreflightReadRole
regions: [us-east-1]
app:
role_arn: arn:aws:iam::222222222222:role/PreflightReadRole
regions: [us-east-1]
assertions:
- id: dev-to-shared-dns-allow
type: allow
source:
account: app
selector:
tags:
Name: app-dev-ec2
destination:
account: shared
selector:
tags:
Name: shared-dns-endpoint
protocol: tcp
port: 53
- id: dev-to-prod-db-deny
type: deny
source:
account: app
selector:
tags:
Name: app-dev-ec2
destination:
account: app
selector:
tags:
Name: app-prod-db
protocol: tcp
port: 5432Common tasks:
# run all configured assertions
anp run -f preflight.yaml
# inspect one assertion in detail
anp explain -f preflight.yaml --id client-to-server-443-allow
# emit machine-readable output for CI
anp run -f preflight.yaml --format jsonText output from run:
Assertion Results
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Assertion ID ┃ Expected ┃ Actual ┃ Status ┃ Analysis ID ┃ Detail ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ client-to-server-443-allow │ reachable │ reachable │ passed │ nia-0abc123def456789 │ Expected reachable and Reachability Analyzer reported │
│ │ │ │ │ │ reachable. │
│ client-to-server-80-deny │ not reachable │ reachable │ failed │ nia-0123abc456def789 │ Expected not reachable but Reachability Analyzer reported │
│ │ │ │ │ │ reachable. │
└──────────────────────────┴───────────────┴───────────────┴────────┴───────────────────────┴──────────────────────────────────────────────────────────────┘
Passed: 1 Failed: 1 Errors: 0
JSON output from run --format json:
{
"error_count": 0,
"failed_count": 1,
"passed_count": 1,
"results": [
{
"actual_outcome": "reachable",
"assertion_id": "client-to-server-443-allow",
"expected_outcome": "reachable",
"status": "passed"
},
{
"actual_outcome": "reachable",
"assertion_id": "client-to-server-80-deny",
"expected_outcome": "not_reachable",
"status": "failed"
}
]
}0: all assertions passed1: one or more assertions failed2: config or validation error3: runtime, AWS API, or authentication error
A short terminal demo showing config validation, target resolution, real Reachability Analyzer execution, and assertion inspection will be added here.
The scope is intentionally narrow because the goal is a reliable v1, not a vague networking framework.
- AWS-first because the tool is built around AWS-native analysis and AWS account boundaries, not generic abstractions.
- Single-region-only in v1 because discovery and execution are easier to reason about when every assertion runs in one explicit effective region from
defaults.region. - Reachability Analyzer only in v1 because one trustworthy engine is more useful than several partially supported analysis modes.
- ENI as the canonical execution target because it is the most precise AWS networking anchor for path analysis.
- EC2 instance as a convenience input because it keeps the CLI practical while still normalizing execution to one concrete ENI.
- Narrow target-family support because public v1 credibility comes from being explicit about what the tool does support, not by implying it solves all of AWS networking.
- v1 is single-region-only
- v1 uses AWS Reachability Analyzer only
- supported target families are limited to EC2 instances and ENIs
- selectors must resolve to exactly one supported resource
- tag ambiguity is a hard failure
- only the standard commercial AWS partition (
aws) is supported - no Network Access Analyzer, active probes, internet exposure checks, or service-specific logic for TGW, Cloud WAN, PrivateLink, or VPC Lattice
Install development dependencies and run the local checks:
git clone https://github.com/gcasanova/aws-network-preflight.git
python3 -m venv ~/venvs/anp-dev
source ~/venvs/anp-dev/bin/activate
pip install -e "./aws-network-preflight[dev]"
cd aws-network-preflight
ruff check .
ruff format --check .
mypy preflight
pytestIssues, feedback, and contributions are welcome.
A good first contribution is usually one of these:
- improve documentation and examples
- tighten validation and error messages
- add focused test coverage for supported v1 behavior
- improve local UX without broadening the scope carelessly
This project is licensed under the Apache License 2.0. See LICENSE.