Schedule icon
List icon
Return icon
Switch icon
Log icon
SlackIncomingWebhook icon

Aikido Domain Scan Staleness Compliance Gate

Audit Aikido domain scan coverage and alert Slack when a monitored domain has never been scanned or has gone stale.

Categories
Infrastructure

A domain sitting in Aikido's surface monitoring with a scan from six months ago, or one that was added and never scanned at all, looks identical to a freshly-scanned domain in a dashboard list until someone checks the timestamp. This blueprint lists every domain Aikido tracks on a schedule, checks each one's last-scanned time, and pages Slack the moment coverage degrades instead of waiting for someone to notice during a security review.

How it works

  1. list_monitored_domains (io.kestra.plugin.aikido.domains.List) lists every domain connected to Aikido's surface/DAST monitoring, including each domain's lastScannedAt Unix timestamp (-1 if never scanned). allowFailure: true means a connection or authentication failure still lets the flow continue instead of aborting.
  2. classify_scan_coverage (io.kestra.plugin.core.debug.Return) checks whether outputs.list_monitored_domains.rows is defined; if not, UNREACHABLE. Otherwise it runs a jq filter counting domains with lastScannedAt == -1 (never scanned) for CRITICAL, then a second filter counting domains scanned longer ago than staleness_threshold_days for AT_RISK, falling back to HEALTHY.
  3. route_by_coverage (io.kestra.plugin.core.flow.Switch) branches on that string: HEALTHY logs a quiet confirmation, AT_RISK pages Slack naming the stale domains, CRITICAL pages Slack naming the never-scanned domains, UNREACHABLE pages Slack separately, and defaults logs the raw outcome.
  4. log_audit_status records a status line on every run regardless of branch, so the execution history is a continuous scan-coverage trend.
  5. The errors block pages Slack separately if the flow itself fails outright.
  6. The domain_scan_coverage_schedule trigger polls once a day with explicit input overrides, shipped disabled: true until you add real Aikido credentials.

What you get

  • A scheduled, API-native scan-coverage audit with zero custom client code.
  • A four-way status output (HEALTHY / AT_RISK / CRITICAL / UNREACHABLE) you can chart or gate other flows on.
  • A Slack page naming the exact domains that are stale or have never been scanned, not just a generic warning.
  • A separate failure channel for the audit flow itself, plus a standing audit log line per run.

Who it's for

  • Application security and platform teams who want a recurring check that every domain in Aikido's attack-surface inventory is actually being rescanned, not just listed.
  • Teams onboarding new domains into Aikido who want an automatic signal if a newly added domain's first scan never happens.

Why orchestrate this with Kestra

Aikido's own dashboard shows scan coverage when someone opens it; this flow watches it continuously. Every check is recorded in the execution history, the coverage classification becomes a typed output other flows can depend on, and the Switch branch is one edit away from real remediation (triggering io.kestra.plugin.aikido.domains.Scan on the stale domains, opening a ticket) instead of a one-off dashboard glance.

Prerequisites

  • An Aikido account with at least one domain connected to surface/DAST monitoring, and an API client ID/secret with the domains:read scope. Aikido's free-tier availability was not independently confirmed while building this blueprint; check Aikido's current plans before relying on it for scan volume.
  • A Slack incoming webhook for the at-risk, critical, and unreachable alerts.
  • There is no self-hostable Docker image for the Aikido API, so test this blueprint directly against a real Aikido account with at least one monitored domain.

Secrets

  • AIKIDO_CLIENT_ID: Aikido API client ID.
  • AIKIDO_CLIENT_SECRET: Aikido API client secret.
  • SLACK_WEBHOOK_URL: Slack incoming webhook used for the at-risk alert, the critical alert, the unreachable alert, and the flow-failure alert.
  • OSS note: if your Kestra instance reads secrets from environment variables instead of a secrets backend, set SECRET_AIKIDO_CLIENT_ID, SECRET_AIKIDO_CLIENT_SECRET, and SECRET_SLACK_WEBHOOK_URL as base64, for example echo -n "<your-client-id>" | base64.

Quick start

  1. Add the AIKIDO_CLIENT_ID, AIKIDO_CLIENT_SECRET, and SLACK_WEBHOOK_URL secrets.
  2. Set staleness_threshold_days to the scan cadence your team expects.
  3. Run the flow once and confirm status reflects your account's real scan coverage.
  4. Enable domain_scan_coverage_schedule.

How to extend

  • Chain a follow-up io.kestra.plugin.aikido.domains.Scan task inside the AT_RISK/CRITICAL cases to trigger a rescan automatically instead of only alerting.
  • Apply the same pattern to io.kestra.plugin.aikido.repositories.List and io.kestra.plugin.aikido.containers.List, which expose comparable scan-coverage fields for code repositories and container images.
  • Store each domain's lastScannedAt in a KV store and alert only when a previously-fresh domain newly crosses the staleness threshold, instead of on every run.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.