Request icon
If icon
Log icon
AIAgent icon
OpenAI icon
SlackIncomingWebhook icon
Pause icon
Loop icon
AnsibleCLI icon
Scan icon
ListOpen icon

Patch an Actively Exploited CVE Across the Fleet with Ansible, Gated by Human Approval and Verified by Aikido

Detect an actively exploited CVE in Aikido, draft an AI patch plan, pause for human approval, roll Ansible patch waves across the fleet, then rescan to prove the issue closed.

Categories
AIInfrastructure

An actively exploited CVE is the one case where waiting for the next patch window is the wrong answer, and also the case where a careless rollout does more damage than the vulnerability. This blueprint threads that needle. It starts from an Aikido finding, refuses to act unless Aikido marks the vulnerability as actively exploited, drafts a structured patch plan with an AI agent, and then stops dead until a human approves it. Only then does it roll Ansible across the fleet one wave at a time, canary first, and finish by asking Aikido to rescan so that the fix is confirmed by the scanner rather than asserted by the engineer.

How it works

  1. The authenticate task (io.kestra.plugin.core.http.Request) performs the OAuth2 client-credentials exchange against the Aikido token endpoint.
  2. The vulnerability task reads /api/public/v1/issues/{id} for the affected package, the installed version, the patched version, and Aikido's exploitability verdict.
  3. The exploit_gate task (io.kestra.plugin.core.flow.If) is the safety catch. Anything other than actively_exploited routes to not_urgent and the flow ends without touching production.
  4. The build_patch_plan task (io.kestra.plugin.ai.agent.AIAgent) converts the finding into JSON with risk, blast_radius, recommended_action, rollback, and requires_restart, using responseFormat: JSON so the output is parseable rather than prose.
  5. The request_approval task posts that plan to Slack with the execution id, and approve_rollout (io.kestra.plugin.core.flow.Pause) holds the run for up to two hours. Its onResume inputs capture both the approval boolean and the change ticket number, so the audit trail records who authorized the rollout and under which change record. behavior: FAIL means an ignored approval request fails loudly instead of quietly patching production.
  6. The patch_waves task (io.kestra.plugin.core.flow.Loop) with concurrencyLimit: 1 walks the waves strictly in order. Each iteration renders an inventory and a playbook through inputFiles and runs ansible-playbook inside a container, so the canary wave must finish before the half wave begins.
  7. The rescan_repository task (io.kestra.plugin.aikido.repositories.Scan) triggers a fresh Aikido scan with waitForCompletion: true, and verify_closed re-lists open critical and high issues so the closing Slack message reports a measured result.

What you get

  • A hard gate that refuses to run an emergency rollout on anything Aikido has not marked actively exploited.
  • An AI-drafted patch plan reviewed by a human before a single host is touched, not after.
  • Ordered patch waves with a canary, so a bad patch stops at one host instead of twelve.
  • The approver and the change ticket captured as execution data through onResume.
  • Scanner-verified remediation: the flow asks Aikido to prove the issue is gone.

Who it's for

  • Security and platform teams who own emergency patching but have to answer to change management.
  • SRE teams that need a canary-first rollout rather than a fleet-wide ansible-playbook run.
  • Anyone who has had to reconstruct, weeks later, who approved an out-of-band production change.

Why orchestrate this with Kestra

Each piece of this exists already: Aikido knows what is exploited, Ansible can patch hosts, Slack can carry an approval. What is missing is the connective tissue that survives a real incident. Kestra provides the pause-and-resume primitive that turns an approval into flow state, the ordered Loop that makes waves a property of the workflow rather than a convention, typed onResume inputs that become part of the audit record, and an errors block that announces a half-patched fleet instead of leaving it silent. A bash script wrapping the same three tools cannot pause for two hours, cannot record who resumed it, and cannot show you months later exactly which hosts were in the canary wave.

Prerequisites

  • An Aikido workspace with API credentials carrying the issues:read and repositories:write scopes.
  • An OpenAI API key for the patch plan agent, or swap in any other provider supported by the Kestra AI plugin.
  • Ansible reachable from the Kestra worker. This blueprint uses containerImage so no Ansible install is needed on the host, but your inventory must be able to reach the target hosts.
  • A Slack incoming webhook for the approval request and the outcome report.

Secrets

  • AIKIDO_CLIENT_ID, AIKIDO_CLIENT_SECRET: OAuth2 credentials for the Aikido public API.
  • OPENAI_API_KEY: key used by the patch plan agent.
  • SLACK_WEBHOOK: incoming webhook for the approval request and the result.

Quick start

  1. Add the secrets above to your Kestra namespace.
  2. Replace the fleet input with your real wave definitions. Keep the first wave small.
  3. Replace the inline patch.yml with your real playbook. The shipped one logs the target version and runs a health check so you can dry run the whole flow safely.
  4. Point vars.api_base and vars.token_url at your Aikido region if you are not on the EU instance.
  5. Execute manually with the default issue id, approve the pause from the Kestra UI, and watch the waves run in order.

How to extend

  • Replace the Slack approval with io.kestra.plugin.ee.flow.HumanTask to route the decision to a named approver group with an expiry.
  • Add a real health probe between waves using io.kestra.plugin.core.http.Request against your load balancer, and fail the loop when error rates rise.
  • Gate the rollout on reachability as well as exploitability by calling the reachability endpoint, as shown in the Aikido reachability triage blueprint.
  • Open and close a ServiceNow change record automatically with io.kestra.plugin.servicenow.Post so the change ticket is created by the flow rather than typed in by hand.
  • Snooze the issue in Aikido with io.kestra.plugin.aikido.issues.Snooze when the rescan confirms closure but the issue lingers pending a registry refresh.
  • Trigger the flow directly from Aikido with io.kestra.plugin.aikido.issues.Trigger at a high severityThreshold so exploited findings start the approval clock automatically.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.