This starter implements a full-stack baseline for your use case:
- ingest AWS VPC flow logs
- correlate
client->server (c2s)andserver->client (s2c)directions - enrich IPs with metadata (name, provider/team, tags, attributes)
- group IPs into CIDR-based VPC/container/external network groups
- visualize provider/consumer relationships as a bubble mesh graph
- generate firewall rule suggestions from observed traffic
- Project Layout
- Screenshots & Demo
- Backend Setup
- Frontend Setup
- Container (Docker)
- GitHub Container Registry (GHCR)
- Core API Endpoints
- Example Upload Request
- Notes
backend/Django + DRF APIfrontend/React (Vite) UI
- Demo video: Streamable walkthrough
Dashboard
|
Map View
|
Flow Logs
|
Assets
|
Firewall Simulator
|
|
cd backend
poetry install
poetry run python manage.py migrate
poetry run python manage.py runserverBackend runs on http://localhost:8000.
Seed realistic demo data (assets/groups/flows/correlations + firewall simulator snapshots):
./scripts/seed_demo_data.shEquivalent direct command:
cd backend && poetry run python manage.py seed_demo_data --reset --source demo-seed --seed 20260301 --days 14 --flow-pairs 2200Database behavior:
- default is SQLite (
backend/db.sqlite3) - set
DJANGO_DATABASE_URL(orDATABASE_URL) to use PostgreSQL, for example:postgresql://user:password@localhost:5432/aws_vpc_flow_logs - for local Poetry runs with PostgreSQL, install driver once:
cd backend && poetry add "psycopg[binary]"
Optional API login:
- leave unset for open access (current default behavior)
- set
WRITE_ACCOUNT=username:passwordfor read/write access - set
READ_ACCOUNT=username:passwordfor read-only access - when either variable is set, API endpoints require HTTP Basic auth
cd frontend
npm install
npm run devFrontend runs on http://localhost:5173 and proxies /api to the Django backend.
Build and run the full app (frontend + backend) as one container:
docker build -t aws-vpc-flow-logs-visualizer:local .
docker run --rm -p 8000:8000 aws-vpc-flow-logs-visualizer:localUse PostgreSQL in container runtime by passing a DB URL:
docker run --rm -p 8000:8000 \
-e DJANGO_DATABASE_URL='postgresql://user:password@host:5432/aws_vpc_flow_logs' \
aws-vpc-flow-logs-visualizer:localEnable optional auth in container runtime:
docker run --rm -p 8000:8000 \
-e WRITE_ACCOUNT='admin:admin' \
-e READ_ACCOUNT='user:user' \
aws-vpc-flow-logs-visualizer:localThen open:
http://localhost:8000/(React app)http://localhost:8000/api/docs/(Swagger UI)http://localhost:8000/api/redoc/(ReDoc)
You can also run with Docker Compose:
docker compose up --buildProduction-style Compose (pull app image from GHCR + run PostgreSQL):
export POSTGRES_PASSWORD='change-me'
docker compose -f docker-compose.prod.yml up -dOptional overrides:
APP_IMAGE(defaults toghcr.io/jbhoorasingh/aws-vpc-flow-logs-visualizer:latest)APP_PORT(defaults to8000)DJANGO_ALLOWED_HOSTSWRITE_ACCOUNT/READ_ACCOUNT(format:username:password)
This repo includes .github/workflows/container.yml, which builds and publishes:
ghcr.io/jbhoorasingh/aws-vpc-flow-logs-visualizer:lateston pushes tomainghcr.io/jbhoorasingh/aws-vpc-flow-logs-visualizer:v*when you push a version tagghcr.io/jbhoorasingh/aws-vpc-flow-logs-visualizer:sha-...for immutable deploys
Single-line deploy from GHCR:
docker run -d --name aws-vpc-flow-logs-visualizer --restart unless-stopped -p 8000:8000 ghcr.io/jbhoorasingh/aws-vpc-flow-logs-visualizer:latestGET /api/health/GET /api/search/?q=<term>(global search across flows/assets/groups)POST /api/uploads/flow-logs/- accepts multipart
file, repeatedfiles(bulk), or textlines - file supports plain text flow logs and gzip-compressed
.log.gz - optional:
source,auto_correlate=true|false - optional:
log_format(space-separated fields, defaults toversion account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status)
- accepts multipart
POST /api/correlation/rebuild/GET /api/flow-logs/- optional advanced expression filter with
advanced_filter, e.g.((addr.src == 10.108.1.1) or (addr.dst == 10.108.1.1)) and (protocol == icmp) and (port.dst == 80) - protocol names accepted in advanced filters:
icmp,ipip,tcp,udp(or numeric values) - supports asset metadata fields like
instance.owner=4442424324,instance.name=*aws*,instance.region=us-east-1,instance.az=us-east-1d, andinstance.tags.environment="prod"(asset.*is an alias)
- optional advanced expression filter with
GET /api/correlated-flows/GET/POST /api/ip-metadata/POST /api/metadata/import/GET/POST /api/network-groups/POST /api/maintenance/network-groups/import/GET /api/mesh/GET /api/firewall/recommendations/?min_bytes=0GET /api/schema/(OpenAPI schema)GET /api/docs/(Swagger UI)GET /api/redoc/(ReDoc)
Network groups support either a single cidr or a cidrs list:
{
"name": "prod-vpc",
"kind": "VPC",
"cidrs": ["10.0.0.0/16", "10.1.0.0/16"]
}curl -X POST http://localhost:8000/api/uploads/flow-logs/ \
-F "source=prod-vpc" \
-F "auto_correlate=true" \
-F "log_format=version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status" \
-F "file=@sample-flow.log"- Correlation uses server-port inference heuristics to pair c2s/s2c conversations.
- Firewall recommendations aggregate by CIDR group when available; otherwise by host CIDR.
- Service mesh view uses Cytoscape.js with interactive zoom/pan, layout switching, and node/edge inspection.
- SQLite is configured by default for fast local iteration.
This project is licensed under the custom non-commercial license in LICENSE.
Commercial use is reserved for the Licensor.