Ankos
CLI Reference

ankos scan

Run evidence collectors against your AWS, GCP, GitHub, Okta, Microsoft Entra ID, or Kubernetes environment. Outputs structured JSON evidence per collector plus a SHA-256 integrity manifest.

ankos scan is the primary command. It runs the registered evidence collectors against your environment — cloud, identity provider, source control, or Kubernetes cluster — using your local credentials, writes the results into an output directory, and computes a SHA-256 manifest so the evidence can be independently verified.

Synopsis

ankos scan [flags]

Quick start

# Scan AWS with default settings (us-east-1, all AWS collectors)
ankos scan

# Scan a specific GCP project
ankos scan --provider gcp --gcp-project my-project-id

# Scan a GitHub organization (read-only token)
ankos scan --provider github --github-org my-org

# Scan an identity provider
ankos scan --provider okta --okta-org-url https://acme.okta.com --okta-token <token>

# Scan a Kubernetes cluster (current kubeconfig context)
ankos scan --provider k8s

# Scan only specific collectors
ankos scan --collectors iam,vpc,s3,kms

# Scan all enabled AWS regions
ankos scan --all-regions

# Validate without making API calls
ankos scan --dry-run

Flags

Collector selection

FlagDefaultDescription
--collectors(all)Comma-separated collector names. See Collectors for the full list.
--providerawsEvidence source: aws, gcp, github, okta, entra, or k8s. Filters which collectors run.

AWS-specific

FlagDefaultDescription
--regionus-east-1AWS region(s) to scan, comma-separated.
--all-regionsfalseScan all enabled AWS regions in the account. Overrides --region.
--profile(none)AWS profile name from ~/.aws/credentials / ~/.aws/config.

GCP-specific

FlagDefaultDescription
--gcp-project(none)GCP project ID. Required when --provider gcp. Falls back to GOOGLE_CLOUD_PROJECT env var.

GitHub-specific

FlagDefaultDescription
--github-org(none)GitHub organization to scan. Required when --provider github. Falls back to GITHUB_ORG.
--github-token(none)Read-only GitHub token. Falls back to GITHUB_TOKEN / GH_TOKEN.

Okta-specific

FlagDefaultDescription
--okta-org-url(none)Okta org URL, e.g. https://acme.okta.com. Required when --provider okta. Falls back to OKTA_ORG_URL.
--okta-token(none)Read-only Okta API token. Falls back to OKTA_API_TOKEN.

Entra-specific

FlagDefaultDescription
--entra-tenant(none)Entra tenant ID. Required when --provider entra. Falls back to ENTRA_TENANT_ID.
--entra-client-id(none)Entra app (client) ID for client-credentials auth. Falls back to ENTRA_CLIENT_ID.
--entra-client-secret(none)Entra client secret. Falls back to ENTRA_CLIENT_SECRET.
--entra-token(none)Pre-acquired Microsoft Graph bearer token. Skips client-credentials when set. Falls back to ENTRA_ACCESS_TOKEN.

Kubernetes-specific

FlagDefaultDescription
--kubeconfig~/.kube/configPath to the kubeconfig for --provider k8s. Falls back to KUBECONFIG.
--kube-context(current-context)The kube-context to scan.

Output

FlagDefaultDescription
--output / -oankos-evidence-<timestamp>/Output directory for evidence files.
--formattextOutput format for terminal: text (human-readable progress) or json (machine-readable, suitable for piping).

Upload to Ankos cloud

FlagDefaultDescription
--uploadfalseAfter scanning, upload evidence to the Ankos ledger using the configured API key. Requires ankos auth set-key first. With -o pointing to an existing scan, uploads without re-scanning.
--upload-dry-runfalsePreview what would be uploaded without actually sending.
--seed-ledgerfalseAfter uploading, also seed your Ankos Ledger with the remediation plan as checklist items (Team and above). The same as running remediate --seed-ledger — just chained onto the upload. Enable it permanently with ankos config seed-on-upload on.

Multi-account (AWS)

FlagDefaultDescription
--all-accountsfalseScan all PCI-scoped accounts listed in the accounts file.
--accounts(none)Comma-separated account names from the accounts file to scan.
--accounts-file.ankosaccountsPath to the accounts configuration file.

Multi-account scanning uses STS AssumeRole against each account's configured role ARN. See ankos accounts --help for setup.

Alerting

FlagDefaultDescription
--webhook(none)Webhook URL to alert on a coverage gap (one or more collectors couldn't collect). A Slack incoming-webhook URL is posted as a Slack message; any other URL receives a generic JSON payload.
--notify(none)Alias for --webhook.

Validation + exit codes

FlagDefaultDescription
--dry-runfalsePrint which collectors would run and against which regions, without making any cloud API calls.
--fail-on(none)Exit non-zero on collector failures. any exits with code 2 if any collector fails; all exits only when every collector fails.

Examples

Single-region AWS scan, default collectors

ankos scan

Output: ankos-evidence-20260526-153045/ containing one JSON file per collector, an aggregate evidence.json, and a manifest.json.

Multi-region scan

ankos scan --region us-east-1,eu-west-1 --collectors iam,cloudtrail,kms

Each collector runs in each region. The output filenames include the region for disambiguation (e.g. iam-us-east-1.json).

GCP scan with a subset of collectors

ankos scan --provider gcp \
           --gcp-project acme-prod \
           --collectors gcp-iam,gcp-kms,gcp-gcs

GitHub organization scan

ankos scan --provider github \
           --github-org acme-inc \
           --github-token "$GITHUB_TOKEN"

Pulls org 2FA enforcement, branch protection, Actions policy, scanning alerts, and the audit log. A read-only token (org read:org + repo read) is enough.

Identity-provider scan (Okta / Entra)

# Okta
ankos scan --provider okta \
           --okta-org-url https://acme.okta.com \
           --okta-token "$OKTA_API_TOKEN"

# Microsoft Entra ID (app client-credentials)
ankos scan --provider entra \
           --entra-tenant "$ENTRA_TENANT_ID" \
           --entra-client-id "$ENTRA_CLIENT_ID" \
           --entra-client-secret "$ENTRA_CLIENT_SECRET"

Kubernetes cluster scan

# Current kubeconfig context
ankos scan --provider k8s

# A specific context, just RBAC + network posture
ankos scan --provider k8s \
           --kube-context staging \
           --collectors k8s-rbac,k8s-network

Reads in-cluster posture (RBAC, NetworkPolicies, Secrets metadata, workload security) through the cluster API, read-only.

Scan + upload in one command

ankos auth set-key --key <your-api-key>    # one-time setup
ankos scan --upload

The scan runs locally first, then the evidence is uploaded to your Ankos ledger and attached to the matching entries in your active cycle.

Seed the ledger in the same step (Team)

ankos scan --upload --seed-ledger

On the Team plan and above, add --seed-ledger to also push the remediation plan onto the matching ledger entries as checklist items — no separate remediate --seed-ledger run. The plan is built locally, so it respects your .ankosscope and .ankosignore, and it seeds every actionable finding (use remediate --severity … --seed-ledger if you want to seed only a subset).

Prefer it always on? Flip it once and plain scan --upload will do it:

ankos config seed-on-upload on

Seeding never blocks the upload — your evidence is already safe; if seeding fails (e.g. you're not on a paid plan) you'll see a warning, not an error.

Upload an existing scan without re-running

ankos scan --upload -o ./ankos-evidence-20260526-153045/

If -o points to a directory that already contains a manifest.json, the CLI skips the scan and uploads what's already there.

CI-friendly mode

ankos scan --format json --fail-on any --output ./out

--format json emits structured progress to stdout so other tools can parse it. --fail-on any makes the command exit non-zero if anything failed — useful for build pipelines.

Output

Every scan produces a directory like this:

ankos-evidence-20260526-153045/
├── manifest.json              # SHA-256 hashes + scan metadata
├── evidence.json              # Full package as a single JSON document
├── iam.json                   # Per-collector evidence (one per collector)
├── vpc.json
├── kms.json
├── ... (one per successful collector)

See Scan output for the JSON shapes.

Authentication

The CLI uses your existing local credentials — the same ones the AWS CLI or gcloud reads, or a read-only token you pass per provider. It does not prompt for or store credentials.

  • AWS: standard provider chain (env vars → ~/.aws/credentials → IAM role on EC2/ECS/Lambda → SSO). Use --profile to pin to a named profile.
  • GCP: Application Default Credentials (ADC). Run gcloud auth application-default login or set GOOGLE_APPLICATION_CREDENTIALS to a service-account JSON path. The CLI uses read-only scopes where the service offers them.
  • GitHub: a read-only personal-access or app token via --github-token (or GITHUB_TOKEN / GH_TOKEN), plus the org via --github-org.
  • Okta: a read-only API token via --okta-token (or OKTA_API_TOKEN) and your org URL via --okta-org-url.
  • Entra: an app registration's client-credentials (--entra-tenant / --entra-client-id / --entra-client-secret), or a pre-acquired Microsoft Graph bearer token via --entra-token.
  • Kubernetes: your kubeconfig context (--kube-context / --kubeconfig); the CLI only issues read (list/get) calls.

Permissions required

All collectors are read-only. For AWS, the broadest scope is SecurityAudit plus ViewOnlyAccess. For GCP, project-level Viewer plus the relevant service-specific viewer roles is sufficient. For GitHub, a token with org read (read:org) and repository read access. For Okta, a read-only API token; for Entra, the Graph application permissions to read users, MFA/authentication methods, conditional-access policies, and app assignments. For Kubernetes, a context bound to a role that can get/list RBAC, NetworkPolicies, Secrets (metadata), and workloads.

If a collector hits a permission error on a specific call, it reports the failure and continues — other collectors still produce evidence. Use --dry-run ahead of time to validate which collectors are wired up.

Exit codes

CodeMeaning
0Scan completed; either all collectors ran cleanly or --fail-on was unset
1Setup error — invalid flags, missing credentials, can't reach a cloud API at all
2Collectors failed and the --fail-on threshold was met (any = any collector failed; all = every collector failed)