Webhook icon
Schedule icon
SkopeoCLI icon
Script icon
Switch icon
If icon
Write icon
Log icon
SlackIncomingWebhook icon
Fail icon

Skopeo Container Image Promotion and Supply Chain Provenance Gate

Verify container image OCI manifests, enforce Git provenance labels and tag immutability, and promote images across registries with Skopeo digest pinning.

Categories
Infrastructure

Automates container image release gating, supply chain provenance verification, and cross-registry promotion using Skopeo. When deploying microservices to production Kubernetes clusters, promoting images directly by mutable tags (e.g. :v1.2.0) creates severe security and reliability risks: build tags can be maliciously or accidentally overwritten (tag hijacking), untrusted images lacking Git commit traceability slip into production, and full Docker daemons must traditionally be provisioned just to move container layers. This blueprint leverages Skopeo to inspect remote OCI image manifests without downloading gigabytes of layer data, verifies Git SHA provenance labels and cryptographic digest immutability, and performs daemonless, digest-pinned image promotion with full audit receipts. Unlike a mirror or sync workflow that overwrites the destination whenever it drifts from the source, this gate treats an existing, mismatched destination tag as a security incident to block and investigate, never to silently overwrite.

How it works

  1. An event-driven io.kestra.plugin.core.trigger.Webhook trigger receives image publication notifications from upstream CI build pipelines (e.g. GitHub Actions, GitLab CI), with a disabled Schedule trigger available for batch release sweeps.
  2. inspect_staging_manifest (io.kestra.plugin.skopeo.cli.SkopeoCLI) runs skopeo inspect against the source staging registry, extracting raw manifest metadata, architecture specifications, layer counts, and OCI annotations without pulling heavy image tarballs.
  3. inspect_production_target (io.kestra.plugin.skopeo.cli.SkopeoCLI) queries the destination production registry to inspect whether the target tag already exists and reads its cryptographic digest.
  4. evaluate_promotion_policies (io.kestra.plugin.scripts.python.Script) validates compliance rules:
    • Tag Immutability & Anti-Hijack: Verifies that if the destination tag already exists, its digest matches the staging digest exactly. Any mismatch triggers an immediate REJECTED_TAG_HIJACK verdict.
    • Supply Chain Provenance: Checks for standard OCI metadata labels (org.opencontainers.image.revision or vcs-ref) to verify Git commit traceability.
    • Layer Integrity: Confirms the manifest contains valid filesystem layers and supported architecture metadata.
  5. route_promotion_decision (io.kestra.plugin.core.flow.Switch) routes downstream execution:
    • APPROVED_PROMOTION: Copies the image directly between registries using daemonless skopeo copy when dry_run is false, and persists an immutable promotion receipt to internal storage.
    • REJECTED_TAG_HIJACK: Writes a security incident dossier, logs an alert, and dispatches an emergency notification to the SecOps Slack channel.
    • REJECTED_MISSING_PROVENANCE: Records an unprovenanced build hold manifest for developer remediation.
  6. enforce_promotion_gate (io.kestra.plugin.core.flow.If) halts pipeline execution via io.kestra.plugin.core.execution.Fail if enforce_gate is enabled and any policy failed.

What you get

  • Daemonless cross-registry container image promotion without granting privileged Docker socket access to workflow runners.
  • Zero-download remote manifest inspection that verifies layer structures and labels in milliseconds.
  • Strict tag immutability protection preventing production containers from being silently overwritten.
  • Automated enforcement of OCI provenance standards linking production images to verifiable Git commits.
  • Cryptographic promotion receipts persisted to internal storage (kestra://...) for compliance auditing.

Who it's for

  • Platform Engineers and DevSecOps teams establishing secure container promotion gates between staging and production clusters.
  • Kubernetes SREs enforcing image immutability and preventing supply-chain poisoning.
  • CI/CD Engineers looking to replace heavy, privileged Docker-in-Docker promotion scripts with lightweight daemonless tooling.

Why orchestrate this with Kestra

  • Combines container inspection, policy evaluation, and atomic cross-registry copying in a single declarative YAML workflow.
  • Isolates credentials and registry secrets using Kestra's encrypted secret engine instead of writing credentials to persistent build agent disks.
  • Provides native flow control, conditional Slack alerting, and full execution audit trails across every release.

Prerequisites

  • A container runtime (Docker or Kubernetes) available to the Kestra worker for executing the containerized Skopeo task.
  • Network connectivity to source and destination container registries.

Secrets

  • CONTAINER_PROMOTION_WEBHOOK_KEY: Secret authentication key for securing the incoming CI/CD Webhook trigger.
  • SLACK_WEBHOOK_URL: Optional Slack incoming webhook URL for dispatching security breach alerts (required only if notify_slack is enabled).
  • STAGING_REGISTRY_USERNAME / STAGING_REGISTRY_PASSWORD: Credentials for the source registry. Leave both set to an empty string for public, anonymously-readable registries.
  • PRODUCTION_REGISTRY_USERNAME / PRODUCTION_REGISTRY_PASSWORD: Credentials for the destination registry. Leave both set to an empty string for public, anonymously-writable registries (e.g. a local test registry).

Quick start

  1. Import this blueprint into your Kestra instance.
  2. Set the four registry secrets to empty strings for a zero-credential first run against public images, then click Execute using default inputs (alpine:3.20.0 with dry_run: true) to observe policy evaluation and manifest inspection.
  3. Test tag immutability by setting destination_image to a different public image tag (e.g. alpine:3.19.0) to observe automated REJECTED_TAG_HIJACK detection and quarantine gating.
  4. Configure your real STAGING_REGISTRY_USERNAME/PASSWORD and PRODUCTION_REGISTRY_USERNAME/PASSWORD secrets, then activate the on_staging_image_push webhook to connect your CI build pipeline.

How to extend

  • Add container vulnerability scanning (e.g. chaining io.kestra.plugin.trivy.TrivyCLI) before the promotion step to enforce zero-critical-CVE gates.
  • Wire Cosign signature verification (skopeo standalone-verify) to enforce cryptographic signature validation prior to registry copy.
  • Trigger downstream GitOps manifest synchronization (e.g. updating Helm or ArgoCD values files with the newly promoted digest).

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.