New to Kestra?
Use blueprints to kickstart your first workflows.
Admit container images only when proven in Kestra: Trivy SBOM, cosign sign and attest, verify gate, then promote or block the release with an issue.
Diagram unavailable
We could not build the topology for this blueprint. The flow itself is valid, use the YAML on the left to run it.
Signing an image proves who built it; verifying the signature before production pulls it proves someone actually checked. Most pipelines do the first half and skip the second - the registry accepts whatever CI pushes, and the first time anyone verifies a signature is during an incident. This blueprint is the missing admission control: every pushed image gets an SBOM, an attached attestation, a cryptographic verification against your public key, and only then a promotion to the production reference. Anything that fails either half stops the release with a ticket instead of a red build nobody reads.
image_push (io.kestra.plugin.core.trigger.Webhook) receives the pushed image reference from CI or a registry event relay; trigger.body.image overrides the image input.prepare_evidence (io.kestra.plugin.core.flow.WorkingDirectory) gives the evidence tasks one shared directory. Inside it, sbom (io.kestra.plugin.trivy.cli.TrivyCLI) generates a CycloneDX SBOM (sbom.json) - the predicate the attestation will cover.sign_attest (io.kestra.plugin.scripts.shell.Commands on the bitnami/cosign Docker runner, key material from env) signs the image and attaches the SBOM as a cyclonedx attestation.verify runs cosign verify and cosign verify-attestation against COSIGN_PUBLIC_KEY - deliberately writing marker files on failure instead of aborting, so the gate decides the outcome, not the shell exit code.verdict (io.kestra.plugin.scripts.python.Script) reads the JSON outputs and marker files into signature_ok, attestation_ok, and gate_pass.integrity_gate (io.kestra.plugin.core.flow.If): on pass, promote runs cosign copy so the production reference carries signatures and attestations with it, and Slack announces the admission; on failure, open_block_issue (io.kestra.plugin.github.issues.Create) files a labeled release-blocked ticket with both check results, Slack alerts, and core.execution.Fail stops any deploy pipeline waiting on this gate.errors handler alerts Slack when the gate itself breaks (registry outage, key material missing), so a broken gate reads as blocked, never as approved.cosign copy, so provenance travels to the production reference.image, promoted_to, and gate_pass outputs for deploy pipelines to wait on.Verification stapled into CI scripts fails open: the job is skipped, the key is missing, and nothing stops the deploy. Kestra makes the gate a first-class execution with a failure handler that alerts, outputs that downstream pipelines can wait on, webhook entry from any registry event, and an audit trail where every admission or block is a recorded decision with its numbers.
COSIGN_PRIVATE_KEY: PEM-encoded cosign private key (used via env://COSIGN_KEY).COSIGN_PASSWORD: password protecting the private key.COSIGN_PUBLIC_KEY: PEM-encoded cosign public key for verification.SLACK_WEBHOOK_URL: Slack incoming webhook for admission and failure messages.GITHUB_TOKEN: token with issue-write access to the repository input.key with a strong random value.image to a pushed reference and promote_to to your production tag.sbom, sign_attest, verify, and the verdict numbers.gate_pass=false, the GitHub issue, and the failed execution.image_push webhook to CI and gate deploys on this flow finishing green.trivy image --exit-code 1 --severity HIGH,CRITICAL before sign_attest so vulnerability and provenance share one gate.cosign verify command and requiring both in verdict.image and gate_pass to a registry table with a jdbc task for audit dashboards.--key env://... for --certificate-identity / --certificate-oidc-issuer to verify Fulcio-issued signatures.