Ankos
CLI Reference

ankos drift

Detect PCI posture drift by comparing the current state against a previously collected evidence baseline. Works across every provider, CI/CD-friendly, with severity-based exit codes.

ankos drift compares the current state of your environment against a baseline directory produced by an earlier ankos scan and reports what changed — new resources, removed resources, security posture degradations, and improvements.

The intended use is scheduled execution: run it nightly or weekly in CI, fail the build when something drifts in a critical direction, and catch PCI regressions between assessments instead of at them.

Works for every provider. drift infers the provider from the baseline you point it at — an AWS baseline re-scans AWS (honoring --profile / --region), and GCP, GitHub, Okta, Entra, and Kubernetes baselines re-scan their provider using the same scope and your environment-based credentials (GOOGLE_*, GITHUB_TOKEN, OKTA_*, ENTRA_*, KUBECONFIG). No extra flags — just pass the baseline directory from any ankos scan.

Synopsis

ankos drift <baseline-dir> [flags]

Quick start

# Last week's scan is the baseline; compare current state against it
ankos drift ./ankos-evidence-baseline

# Save the drift report to a file
ankos drift ./ankos-evidence-baseline -o ./drift-report.json --format json

# CI gate: fail the build if any critical-severity drift appeared
ankos drift ./ankos-evidence-baseline --fail-on critical

# Update the baseline in place after the comparison (start of new week)
ankos drift ./ankos-evidence-baseline --baseline-update

# Post a Slack/webhook alert when posture regresses
ankos drift ./ankos-evidence-baseline --webhook "$SLACK_WEBHOOK_URL" --fail-on any

Point drift at a baseline from any provider — an AWS, GCP, GitHub, Okta, Entra, or Kubernetes scan — and it re-scans that provider automatically:

# A GCP baseline re-scans GCP; a GitHub baseline re-scans GitHub, etc.
ankos drift ./gcp-evidence-baseline
ankos drift ./github-evidence-baseline

Flags

FlagDefaultDescription
--region(from baseline)Region to check (AWS baselines). Defaults to the region recorded in the baseline.
--profile(none)AWS profile to use (AWS baselines).
--collectors(from baseline)Subset of collectors to compare. Default uses everything in the baseline.
--formattextOutput format: text or json.
--output / -o(stdout)Save drift report to file.
--fail-on(none)Exit non-zero on drift: any, critical, or high.
--baseline-updatefalseOverwrite the baseline with the current state after comparing. Use to "roll forward" the baseline at the start of each comparison window.
--webhook(none)Webhook URL to alert on a posture regression. A Slack incoming-webhook URL is posted as a Slack message; any other URL receives a generic JSON payload.
--notify(none)Alias for --webhook.
--uploadfalseUpload the live scan's evidence to the Ankos Ledger, so a scheduled drift run doubles as continuous evidence collection.

CI exit codes

Pair --fail-on with your build's failure threshold:

SettingExits non-zero when…
--fail-on anyAny drift detected (degradation / improvement / change)
--fail-on criticalAt least one critical-severity drift
--fail-on highAt least one high-severity or above

Typical pattern: weekly cron in CI with --fail-on critical, so the build only breaks on serious regressions. High-severity changes get filed as work; low-severity churn (new tags, capacity changes) stays informational.

Baseline lifecycle

The baseline is just an evidence directory from ankos scan. Common patterns:

  1. Weekly window. Scan on Sunday → that's the baseline for the week. Daily drift checks reference it. The next Sunday's scan replaces the baseline.
  2. Quarterly window. Use last quarter's evidence package as the baseline; daily drift checks surface anything that drifted since the last QSA review.
  3. Rolling. Run ankos drift ./baseline --baseline-update daily; the baseline always represents "yesterday."

For options 1 and 2, store the baseline in S3 or your CI artifact storage and pull it before each drift run. For option 3, the baseline is local to the runner.

Output

In text format, drift opens with a Direction line (↓ Degrading, ↑ Improving, or → Stable) summarizing the overall posture move, then groups changes into three sections:

  • Degradations — PCI posture worsened (encryption disabled, public access enabled, MFA removed, a new public bucket, etc.)
  • Improvements — PCI posture improved since the baseline
  • Changes — informational infrastructure changes that don't move posture in either direction

In JSON format, the same data is structured per-collector (with a posture_direction summary field) for easy machine processing.

What drift catches

A non-exhaustive list of common drift events you'll see flagged:

  • A new public S3 bucket appears
  • CloudTrail logging is disabled in a region
  • An IAM user is granted administrative permissions
  • An EC2 security group adds 0.0.0.0/0 ingress on a CDE port
  • KMS key rotation is disabled
  • A WAF rule is deleted
  • A new EKS cluster appears that wasn't covered by the baseline

Limitations

  • Read-only. Like all Ankos commands, drift never modifies your environment. It re-scans read-only, reports, and your team remediates.
  • Single baseline at a time. Multi-baseline comparison (3-way diff) isn't supported; combine ankos report --diff if you need that shape.

Alerting on regressions

Pass --webhook (alias --notify) to post an alert whenever posture regresses — a new degradation or lost coverage. A Slack incoming-webhook URL (hooks.slack.com/...) is rendered as a Slack message; any other URL receives the same alert as a generic JSON payload, so it works with a custom endpoint or a relay. Nothing is sent unless a webhook is configured, and a delivery failure never changes the exit code — CI gating still works.

# Nightly cron: fail CI on regression AND post to Slack
ankos drift ./ankos-evidence-baseline \
  --webhook "$SLACK_WEBHOOK_URL" \
  --fail-on any

# Refresh the Ledger with the live scan's evidence in the same run
ankos drift ./ankos-evidence-baseline \
  --upload \
  --webhook "$SLACK_WEBHOOK_URL" \
  --fail-on any

The alert states evidence-readiness signal ("N items need attention"), never a pass/fail verdict — the determination stays with your QSA. For a long-running local daemon instead of a CI scheduler, see ankos watch.