Declare allowed and denied AWS connectivity in YAML and verify it with AWS Reachability Analyzer.
Project description
aws-network-preflight
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.
Why this exists
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
Installation
Python 3.11+ is required.
Recommended install
Install from PyPI:
pipx install aws-network-preflight
That gives you a globally available CLI in an isolated environment.
Install from source
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-preflight
This 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.
Quick start
Create a starter config:
anp init
Edit preflight.yaml with your real AWS profile, region, accounts, and selectors.
Validate the config:
anp validate -f preflight.yaml
Resolve the configured targets without running analysis:
anp list-targets -f preflight.yaml
Run the assertions:
anp run -f preflight.yaml
Inspect one assertion in detail:
anp explain -f preflight.yaml --id client-to-server-443-allow
For CI-friendly output, run and explain also support --format json.
Minimal example config
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: 80
role_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.
Cross-account example
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: 5432
Recommended IAM permissions
At a minimum, the CLI usually needs enough access to discover the selected resources, run Reachability Analyzer, and identify the effective AWS account for each configured session.
- Discovery:
ec2:DescribeInstances,ec2:DescribeNetworkInterfaces - Reachability Analyzer execution:
ec2:CreateNetworkInsightsPath,ec2:DeleteNetworkInsightsPath,ec2:StartNetworkInsightsAnalysis,ec2:DescribeNetworkInsightsAnalyses,ec2:DeleteNetworkInsightsAnalysis - Identity and account resolution:
sts:GetCallerIdentity - Cross-account usage with
role_arn:sts:AssumeRole
The exact policy can vary by account structure and whether you use same-account credentials or cross-account role assumption.
Example commands and output
Common 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 json
Text 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"
}
]
}
Troubleshooting
Unable to locate credentials: the AWS credential chain did not find usable credentials. Check your environment, local AWS config, or the profile referenced indefaults.auth.profile.AccessDeniedorUnauthorizedOperation: the active credentials can reach AWS but do not have one or more required EC2 or STS permissions. Check discovery permissions, Reachability Analyzer permissions, andsts:AssumeRolewhenrole_arnis configured.- Tag selector matches no resources: the selected account, region, or tag values do not resolve to a supported v1 target. Check
defaults.region, the endpointaccount, and the exact tag key and value on the EC2 instance or ENI. - Tag selector matches multiple resources: the selector is not unique within the configured account and region. Tighten the tag set until it resolves to exactly one EC2 instance or ENI.
- Reachability Analyzer finished with
failedor another unexpected status: AWS did not produce a normal successful analysis result. Check the detailed error output first, then confirm the source and destination resolved to the intended ENIs and that the execution account has the required Reachability Analyzer permissions.
Exit codes
0: all assertions passed1: one or more assertions failed2: config or validation error3: runtime, AWS API, or authentication error
Demo
A short terminal demo showing config validation, target resolution, real Reachability Analyzer execution, and assertion inspection will be added here.
Design choices
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.
Limitations
- 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
Development
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
pytest
Contributing
Issues, 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
License
This project is licensed under the Apache License 2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aws_network_preflight-0.1.0.tar.gz.
File metadata
- Download URL: aws_network_preflight-0.1.0.tar.gz
- Upload date:
- Size: 42.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45b7fa768bdd6e9bbbb74868d1beb32c59ce12e4a1c2419847f96f5661ec4ce7
|
|
| MD5 |
ac11751ff552f47e3720174d2e03ef2e
|
|
| BLAKE2b-256 |
afa69a4bcd6f26fbe817c0dc2de9e8c62ea4bd04e44b2123fb21a27771a5cc14
|
Provenance
The following attestation bundles were made for aws_network_preflight-0.1.0.tar.gz:
Publisher:
release.yml on gcasanova/aws-network-preflight
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aws_network_preflight-0.1.0.tar.gz -
Subject digest:
45b7fa768bdd6e9bbbb74868d1beb32c59ce12e4a1c2419847f96f5661ec4ce7 - Sigstore transparency entry: 1245126433
- Sigstore integration time:
-
Permalink:
gcasanova/aws-network-preflight@4608bf9b27ab574d75c449d9be5bde59bc448a4b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gcasanova
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4608bf9b27ab574d75c449d9be5bde59bc448a4b -
Trigger Event:
push
-
Statement type:
File details
Details for the file aws_network_preflight-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aws_network_preflight-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99198f978dbbacda0c0245eb635866b256753a731e7f67deccec5597c64ca7aa
|
|
| MD5 |
358089a47ba075405f3d3d2ff797cc17
|
|
| BLAKE2b-256 |
ce31212e72db2d7e31258da79831dec40b436613773152385c99a894a1ccb8b1
|
Provenance
The following attestation bundles were made for aws_network_preflight-0.1.0-py3-none-any.whl:
Publisher:
release.yml on gcasanova/aws-network-preflight
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aws_network_preflight-0.1.0-py3-none-any.whl -
Subject digest:
99198f978dbbacda0c0245eb635866b256753a731e7f67deccec5597c64ca7aa - Sigstore transparency entry: 1245126439
- Sigstore integration time:
-
Permalink:
gcasanova/aws-network-preflight@4608bf9b27ab574d75c449d9be5bde59bc448a4b -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gcasanova
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4608bf9b27ab574d75c449d9be5bde59bc448a4b -
Trigger Event:
push
-
Statement type: