Skip to content

Docker

The image is vpcatlas/vpcatlas on Docker Hub. It carries the whole tool: the command line and the dashboard.

Tags and platforms

Each release tag v<major>.<minor>.<patch> publishes the image for linux/amd64 and linux/arm64 under:

Tag Meaning
<major>.<minor>.<patch> (for example 0.1.0) That exact release. Pin this in production.
<major>.<minor> The latest patch of that minor version.
latest The latest release.

The Lambda image is a separate repository, vpcatlas/vpcatlas-lambda; see lambda.md.

Entrypoint and default command

The entrypoint is the vpcatlas command and the default command is serve --host 0.0.0.0 --port 8080. So with no arguments the container runs the dashboard, and any other command of the CLI is the argument list:

docker run --rm -p 8080:8080 vpcatlas/vpcatlas:0.1.0            # the dashboard
docker run --rm vpcatlas/vpcatlas:0.1.0 --version
docker run --rm vpcatlas/vpcatlas:0.1.0 serve --help

The image runs as the unprivileged user atlas (uid and gid 10001, home /home/atlas), exposes port 8080, and runs one worker: the snapshot lives in the memory of the process. To scale out, share state with VPCATLAS_SNAPSHOT_URI instead of adding workers (see the dashboard).

Environment set by the image:

Variable Value Why
VPCATLAS_REFRESH_SECONDS 0 One scan at start, then manual refreshes only. Set it (for example 900) to rescan periodically.
PORT 8080 Read by the health check only, to find the port. The server listens on --port.
AWS_STS_REGIONAL_ENDPOINTS regional Session tokens from the global STS endpoint are not valid in opt-in Regions.
PYTHONUNBUFFERED 1 Logs appear immediately.

The image has a HEALTHCHECK that runs python -m vpcatlas.dashboard.healthcheck every 30 seconds (it requests /healthz on the loopback address).

Run the dashboard

docker run --rm -p 8080:8080 \
  -e VPCATLAS_REFRESH_SECONDS=900 \
  -e VPCATLAS_REGIONS=eu-west-1,eu-central-1 \
  -e AWS_PROFILE=audit \
  -v "$HOME/.aws:/home/atlas/.aws:ro" \
  vpcatlas/vpcatlas:0.1.0

Open http://127.0.0.1:8080. -p 8080:8080 publishes the port on every interface of the host; use -p 127.0.0.1:8080:8080 unless you mean to expose it, and read authentication first. The settings are the VPCATLAS_* variables described in the dashboard page.

Credentials in the container

The container resolves credentials with the standard AWS chain. Pick the way that fits where it runs:

  • On AWS (ECS, EKS, EC2). Use the task role, the pod role (IAM roles for service accounts) or the instance role. Nothing is mounted or passed. This is the preferred way; see ecs.md and kubernetes.md.
  • Environment variables. Pass AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and, for temporary credentials, AWS_SESSION_TOKEN with -e NAME (no value, so the secret is copied from your shell and never appears on the command line or in the image):
docker run --rm -p 127.0.0.1:8080:8080 \
  -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e AWS_REGION \
  vpcatlas/vpcatlas:0.1.0

Short-lived credentials from an SSO profile can be exported for this: eval "$(aws configure export-credentials --profile my-audit --format env)". - Shared credentials and config files. Mount ~/.aws read-only at /home/atlas/.aws and name the profile with AWS_PROFILE or VPCATLAS_PROFILE. A credential_process profile needs its helper binary, which the image does not contain. An SSO profile works from the token cache in the mount until that token expires (the mount is read-only, so a refreshed token is not written back); for a long run, export short-lived credentials instead. On Linux the mounted files must be readable by uid 10001, or run the container with --user "$(id -u):$(id -g)" and -e HOME=/home/atlas. - Another account through a role. Set VPCATLAS_ROLE_ARN (comma separated for several) and, if the trust policy has one, VPCATLAS_EXTERNAL_ID. The identity from the sources above assumes the role. See iam.md.

Secret keys are not command-line options anywhere in vpcatlas; do not write them in the docker run line as -e AWS_SECRET_ACCESS_KEY=... either, because they end up in the shell history and in docker inspect.

Run other CLI commands

Use the same image with a different command, and a volume for the output:

docker run --rm \
  -v "$HOME/.aws:/home/atlas/.aws:ro" \
  -v "$PWD/out:/data" \
  vpcatlas/vpcatlas:0.1.0 \
  discover --profile audit --regions eu-west-1 --output-dir /data

The mounted output directory must be writable by uid 10001 (on Linux, chown 10001:10001 out or pass --user). vpcatlas iam-policy prints the auditor policy, so you can create the role without cloning the repository:

docker run --rm vpcatlas/vpcatlas:0.1.0 iam-policy > auditor-policy.json

Volumes

Mount Use
/home/atlas/.aws (read-only) Shared credentials and config files. Optional.
/data (or any path you choose) Output of discover, inventory and diagram.
A directory for VPCATLAS_SNAPSHOT_URI=file:///... Snapshots and history, if you do not use S3. Must be writable by uid 10001.
/tmp as a tmpfs Needed when the root file system is read-only, as in the shipped Compose, ECS and Kubernetes manifests.

Resource needs

The dashboard is light while idle and busy during a scan, which makes parallel API calls and builds the diagrams in memory. The shipped manifests give a feel for the sizes:

  • Kubernetes: request 100m CPU and 256Mi, limit 1 CPU and 1Gi.
  • ECS Fargate: 512 CPU units and 1024 MiB, which is enough for a typical account. If a scan of a very large estate is killed (exit code 137), raise memory to 2048 and CPU to 1024.
  • Lambda: 2048 MB and a 15-minute timeout; see lambda.md.

Scanning fewer Regions (VPCATLAS_REGIONS) or lowering VPCATLAS_CONCURRENCY reduces both time and peak memory. The scan makes read-only calls to the AWS APIs, so the container needs outbound HTTPS (443) to them, and to viewer.diagrams.net only in the browsers that open the dashboard, not in the container.

Build it yourself

From the repository root:

make docker-build        # docker build -f deploy/Dockerfile -t <image>:<version> .

deploy/Dockerfile is a multi-stage build on python:3.12-slim: the package is installed into a virtual environment, and only that environment is copied into the runtime stage. Next: compose.md runs it locally with a hardened configuration.