<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Flux – integrations</title><link>https://fluxcd.io/tags/integrations/</link><description>Recent content in integrations on Flux</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 27 Jul 2026 11:00:00 +0000</lastBuildDate><atom:link href="https://fluxcd.io/tags/integrations/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: Flux and OpenBao: Secrets and Signatures</title><link>https://fluxcd.io/blog/2026/07/flux-openbao-secrets-signatures/</link><pubDate>Mon, 27 Jul 2026 11:00:00 +0000</pubDate><guid>https://fluxcd.io/blog/2026/07/flux-openbao-secrets-signatures/</guid><description>
&lt;img src="https://fluxcd.io/blog/2026/07/flux-openbao-secrets-signatures/featured-image_hu0d1ac7688a28dacaacf6d784d011bba4_505147_640x0_resize_box_3.png" width="640" height="320"/>
&lt;p>GitOps helps us declare our desired workloads, but how do we deal with and manage secrets? Additionally, as our fleet grows, we also blend artifacts and configuration from many
different sources. How do we trust what we are running?&lt;/p>
&lt;p>
&lt;a href="https://openbao.org/" target="_blank">OpenBao&lt;/a> is an open source secrets and encryption
platform under the
&lt;a href="https://openssf.org/" target="_blank">OpenSSF&lt;/a>. In this post we&amp;rsquo;ll integrate OpenBao with Flux in two ways:&lt;/p>
&lt;ul>
&lt;li>kustomize-controller will decrypt SOPS-encrypted Secrets through OpenBao using &lt;strong>workload identity&lt;/strong>, with no
static &lt;code>BAO_TOKEN&lt;/code> or &lt;code>VAULT_TOKEN&lt;/code> to bootstrap&lt;/li>
&lt;li>Cosign will sign OCI artifacts with a key held within OpenBao,
producing signatures Flux can verify without any service
outside your infrastructure&lt;/li>
&lt;/ul>
&lt;p>For both integrations, we&amp;rsquo;ll use two OpenBao features. The
&lt;a href="https://openbao.org/docs/secrets/transit/" target="_blank">Transit secrets engine&lt;/a> performs
encrypt, decrypt, and sign operations without ever releasing the key
material, acting as a
&lt;a href="https://csrc.nist.gov/glossary/term/key_management_system" target="_blank">Key Management System (KMS)&lt;/a>,
and the Kubernetes and JWT auth methods let a workload trade its
Kubernetes-issued ServiceAccount token for a short-lived OpenBao token, so
no long-lived credential has to exist on either the OpenBao or Kubernetes side.&lt;/p>
&lt;p>&lt;img src="featured-image.png" alt="">&lt;/p>
&lt;h2 id="configuring-sops-gitops-secrets-without-a-static-token">Configuring SOPS: GitOps secrets without a static token&lt;/h2>
&lt;p>Keeping encrypted secrets in Git solves most of the secret-distribution
problem: the ciphertext goes through the same pull requests and the same
reconciliation as the rest of your configuration.
&lt;a href="https://getsops.io/" target="_blank">SOPS&lt;/a>,
a CNCF project, is the standard tool for this. It encrypts the values of a
file with a data key, then asks a KMS to protect that data key; only the
small data key ever travels to the KMS. OpenBao is one of many supported
backends that SOPS can use, and many teams rely on Flux&amp;rsquo;s support for decrypting secrets with SOPS.&lt;/p>
&lt;p>Bootstrapping secrets management is tricky though. The SOPS encryption key lives in OpenBao&amp;rsquo;s
Transit engine, so Flux used to need a static &lt;code>BAO_TOKEN&lt;/code> added in the cluster in order to
request decryption. Teams installing Flux would need to provision this bootstrap secret before using GitOps to manage secrets. Starting with Flux v2.9, that token is optional:
kustomize-controller can now directly authenticate to OpenBao with Kubernetes ServiceAccount tokens.&lt;/p>
&lt;h3 id="step-1-configure-openbao-for-sops-decryption">Step 1: Configure OpenBao for SOPS decryption&lt;/h3>
&lt;p>For our use-case, OpenBao needs a Transit key, a decrypt-only policy, and an auth role bound
to the kube ServiceAccount Flux will use. Both the &amp;ldquo;Kubernetes&amp;rdquo; and &amp;ldquo;JWT&amp;rdquo; auth
methods within OpenBao work for this; with Kubernetes auth and the &lt;code>flux-system/kustomize-controller&lt;/code>
ServiceAccount, the setup is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>bao secrets &lt;span style="color:#007020">enable&lt;/span> transit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bao write transit/keys/sops &lt;span style="color:#bb60d5">key_type&lt;/span>&lt;span style="color:#666">=&lt;/span>aes256-gcm96
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bao policy write flux_sops_decrypt - &lt;span style="color:#4070a0">&amp;lt;&amp;lt;EOF
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0">path &amp;#34;transit/decrypt/sops&amp;#34; {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0"> capabilities = [&amp;#34;update&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0">}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bao auth &lt;span style="color:#007020">enable&lt;/span> kubernetes
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bao write auth/kubernetes/config &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">kubernetes_host&lt;/span>&lt;span style="color:#666">=&lt;/span>https://kubernetes.example.com:6443 &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">kubernetes_ca_cert&lt;/span>&lt;span style="color:#666">=&lt;/span>@ca.crt &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">token_reviewer_jwt&lt;/span>&lt;span style="color:#666">=&lt;/span>@reviewer.jwt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bao write auth/kubernetes/role/flux-system_kustomize-controller &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">bound_service_account_names&lt;/span>&lt;span style="color:#666">=&lt;/span>kustomize-controller &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">bound_service_account_namespaces&lt;/span>&lt;span style="color:#666">=&lt;/span>flux-system &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">audience&lt;/span>&lt;span style="color:#666">=&lt;/span>https://openbao.example.com:8200 &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">token_policies&lt;/span>&lt;span style="color:#666">=&lt;/span>flux_sops_decrypt &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> &lt;span style="color:#bb60d5">ttl&lt;/span>&lt;span style="color:#666">=&lt;/span>20m
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The role name here follows Flux&amp;rsquo;s &lt;code>{namespace}_{name}&lt;/code> convention, and the
&lt;code>audience&lt;/code> needs to match the OpenBao address that will show up in the SOPS
metadata below. Note that &lt;code>flux_sops_decrypt&lt;/code> only grants decryption; the
developer or CI identity encrypting in Step 2 needs &lt;code>update&lt;/code> on
&lt;code>transit/encrypt/sops&lt;/code> instead. The
&lt;a href="https://openbao.org/api-docs/auth/kubernetes/" target="_blank">Kubernetes auth&lt;/a> and
&lt;a href="https://openbao.org/api-docs/auth/jwt/" target="_blank">JWT/OIDC auth&lt;/a> API docs cover the
OpenBao server-side options.&lt;/p>
&lt;h3 id="step-2-encrypt-a-secret-with-openbao">Step 2: Encrypt a Secret with OpenBao&lt;/h3>
&lt;p>After authenticating to OpenBao, a developer or CI job encrypts a regular
Kubernetes Secret with the Transit key:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>sops encrypt &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> --hc-vault-transit https://openbao.example.com:8200/v1/transit/keys/sops &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> --encrypted-regex &lt;span style="color:#4070a0">&amp;#39;^(data|stringData)$&amp;#39;&lt;/span> &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> secret.yaml &amp;gt; secret.enc.yaml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#60a0b0;font-style:italic"># These flag options can be defaulted in the repo with `.sops.yaml`&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SOPS calls &lt;code>transit/encrypt/sops&lt;/code> on the user&amp;rsquo;s behalf and writes out a
file that is encrypted and safe to commit to Git:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#062873;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Secret&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>database&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apps&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">type&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>Opaque&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">stringData&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">username&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">password&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">sops&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">hc_vault&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- &lt;span style="color:#062873;font-weight:bold">vault_address&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>https://openbao.example.com:8200&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">engine_path&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>transit&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">key_name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>sops&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">created_at&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#4070a0">&amp;#34;2026-07-14T12:00:00Z&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">enc&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>vault:v1:...&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">encrypted_regex&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>^(data|stringData)$&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">mac&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The plaintext values are replaced with ciphertext, and the &lt;code>sops.hc_vault&lt;/code>
metadata records which OpenBao instance and key can decrypt them.&lt;/p>
&lt;h3 id="step-3-configure-kustomize-controller-to-use-workload-identity-for-openbao">Step 3: Configure kustomize-controller to use workload identity for OpenBao&lt;/h3>
&lt;p>When Flux reconciles a file like this, kustomize-controller must ask
OpenBao to decrypt it. Instead of a static token, the controller gets an allowlist
of OpenBao instances and their JWT-backed login endpoints from a ConfigMap in the
&lt;code>flux-system&lt;/code> namespace, set by the &lt;code>--sops-vault-configmap&lt;/code> controller flag:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#60a0b0;font-style:italic"># data fields for a ConfigMap in the flux-system namespace&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">data&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">config.yaml&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>|&lt;span style="color:#4070a0;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-style:italic"> instances:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-style:italic"> - address: https://openbao.example.com:8200
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-style:italic"> loginPath: auth/kubernetes/login&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>During decryption, the OpenBao address in the SOPS metadata matches an
entry from this list. kustomize-controller requests a ServiceAccount token
with that address as its audience and presents it at the login path, where
OpenBao matches it against the role from Step 1 and returns a short-lived
token. Flux uses that token to call the Transit engine and decrypt the
Secret. No static credential is needed anywhere for this decryption operation! We&amp;rsquo;re leveraging Kubernetes&amp;rsquo; native workload identity.&lt;/p>
&lt;h3 id="step-4-use-a-dedicated-serviceaccount-for-decryption">Step 4: Use a dedicated ServiceAccount for decryption&lt;/h3>
&lt;p>By default the exchange above uses kustomize-controller&amp;rsquo;s own
ServiceAccount. A Flux Kustomization can select a dedicated one instead:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#062873;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">decryption&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">provider&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>sops&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">serviceAccountName&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>sops&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This requires the &lt;code>ObjectLevelWorkloadIdentity&lt;/code> feature gate to be enabled
in kustomize-controller. For a Kustomization in the &lt;code>apps&lt;/code> namespace, the
&lt;code>sops&lt;/code> ServiceAccount needs a matching &lt;code>apps_sops&lt;/code> role in OpenBao,
configured with the same audience and policy as in Step 1. For more
details, see the
&lt;a href="https://fluxcd.io/flux/components/kustomize/kustomizations/#openbaovault-kubernetes-auth">Kustomization decryption documentation&lt;/a>.&lt;/p>
&lt;h2 id="cosign-sovereign-software-signatures">Cosign: Sovereign Software Signatures&lt;/h2>
&lt;p>We can use this KMS setup for more than application Secrets.&lt;/p>
&lt;p>Flux can verify the
&lt;a href="https://docs.sigstore.dev/" target="_blank">Cosign&lt;/a> signature of an
OCI artifact before reconciling desired state from it. With a static public key, that
verification can be entirely local to the cluster: Flux checks the signature against the key
and forms no opinion about how or where the artifact was signed. It never
contacts Fulcio, Rekor, or any other service outside the cluster and its container registry.&lt;/p>
&lt;p>This makes a fully self-hosted signing chain possible: OpenBao holds the
signing key, Cosign signs the artifact, the registry stores the signature,
and Flux verifies it. No public cloud KMS ever holds your key, and no
public transparency log records your signing events. This is really attractive in regulated environments that prioritize data-sovereignty.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>OpenBao Transit engine → Cosign → GHCR (artifact + signature) → Flux
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>holds the signing key signs stores signature verifies
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Flux also supports keyless verification: omit &lt;code>.verify.secretRef&lt;/code> and Flux
matches OIDC identities against Fulcio certificates and the Rekor
transparency log. Keyless signing gives you short-lived signing identities and a
public audit record, at the cost of depending on public Sigstore
infrastructure. Flux lets you choose this behavior per source; we use a static
key in this post to show that key custody and rotation can stay fully under your responsibility.&lt;/p>
&lt;p>For a fully reproducible setup, see the
&lt;a href="https://github.com/controlplaneio-openbao/openbao-flux-demo" target="_blank">openbao-flux-demo&lt;/a> on GitHub.&lt;br>
We&amp;rsquo;ll detail the steps quickly below.&lt;/p>
&lt;h3 id="step-1-generate-the-signing-key-in-openbao">Step 1: Generate the signing key in OpenBao&lt;/h3>
&lt;p>OpenBao&amp;rsquo;s Transit secrets engine is a cryptography-as-a-service backend: it holds key material and performs sign and verify operations on request. Cosign supports this natively. Let&amp;rsquo;s use Cosign to generate the keypair through our &lt;code>openbao://&lt;/code> KMS URI:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>cosign generate-key-pair --kms openbao://control-plane-demo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The private key is created inside OpenBao and never written to disk. Only
&lt;code>cosign.pub&lt;/code> lands on the local filesystem; we&amp;rsquo;ll configure Flux to use this public key.&lt;/p>
&lt;p>The demo runs OpenBao in development mode with a root token to keep setup
short. In production, you&amp;rsquo;ll want to sign with a token scoped to just this key like so:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-hcl" data-lang="hcl">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#007020;font-weight:bold">path&lt;/span> &lt;span style="color:#4070a0">&amp;#34;transit/keys/control-plane-demo&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> capabilities &lt;span style="color:#666">=&lt;/span> [&lt;span style="color:#4070a0">&amp;#34;read&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#007020;font-weight:bold">path&lt;/span> &lt;span style="color:#4070a0">&amp;#34;transit/sign/control-plane-demo&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> capabilities &lt;span style="color:#666">=&lt;/span> [&lt;span style="color:#4070a0">&amp;#34;update&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="step-2-push-and-sign-the-artifact-by-digest">Step 2: Push and sign the artifact by digest&lt;/h3>
&lt;p>Package the manifests as an OCI artifact and push them with the Flux CLI:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>flux push artifact oci://ghcr.io/controlplaneio-openbao/openbao-flux-demo-workload:latest &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> --path&lt;span style="color:#666">=&lt;/span>./workload &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> --source&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#4070a0">&amp;#34;https://github.com/controlplaneio-openbao/openbao-flux-demo&amp;#34;&lt;/span> &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> --revision&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#4070a0">&amp;#34;main@sha1:&lt;/span>&lt;span style="color:#007020;font-weight:bold">$(&lt;/span>git rev-parse HEAD&lt;span style="color:#007020;font-weight:bold">)&lt;/span>&lt;span style="color:#4070a0">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then sign the pushed artifact by its digest. Passing &lt;code>--tlog-upload=false&lt;/code>
keeps the signature off the public Rekor log, so the signing event itself
never becomes a public record:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>cosign sign --key openbao://control-plane-demo --tlog-upload&lt;span style="color:#666">=&lt;/span>&lt;span style="color:#007020">false&lt;/span> &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> ghcr.io/controlplaneio-openbao/openbao-flux-demo-workload@sha256:...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>OpenBao performs the signing operation and the signature is stored in the
registry alongside the artifact. One thing to watch out for: Cosign
authenticates to the registry on its own and does not share credentials
with &lt;code>flux push artifact --creds&lt;/code>, so it needs a separate &lt;code>cosign login&lt;/code>.&lt;/p>
&lt;h3 id="step-3-configure-flux-to-verify-the-artifact">Step 3: Configure Flux to verify the artifact&lt;/h3>
&lt;p>Flux only needs the public key. Create a Secret holding it and reference
that Secret from the &lt;code>OCIRepository&lt;/code>&amp;rsquo;s &lt;code>.spec.verify&lt;/code>. The demo creates the
Secret directly; in production you would commit the public key to Git (it
is not sensitive, but you can optionally encrypt it), then let Flux manage the Secret alongside your other manifests:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>kubectl -n flux-system create secret generic cosign-public-key &lt;span style="color:#4070a0;font-weight:bold">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4070a0;font-weight:bold">&lt;/span> --from-file&lt;span style="color:#666">=&lt;/span>cosign.pub&lt;span style="color:#666">=&lt;/span>cosign.pub
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#062873;font-weight:bold">apiVersion&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>source.toolkit.fluxcd.io/v1&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">kind&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>OCIRepository&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">metadata&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>demo-workload&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">namespace&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>flux-system&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>&lt;span style="color:#062873;font-weight:bold">spec&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">interval&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>5m&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">url&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>oci://ghcr.io/controlplaneio-openbao/openbao-flux-demo-workload&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">ref&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">tag&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>latest&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">verify&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">provider&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>cosign&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">secretRef&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#062873;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>cosign-public-key&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When the signature checks out, Flux records it on the source and only then
applies the manifests:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>SourceVerified=True (Succeeded): verified signature of revision latest@sha256:…
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The whole sign &amp;amp; verify flow here only depends on our private infrastructure.
No external services on the internet are needed, the signing key comes from our OpenBao instance, and the signature on the artifact proves that the desired state configuration was signed within our network.&lt;/p>
&lt;h2 id="get-involved">Get Involved&lt;/h2>
&lt;p>We&amp;rsquo;re really keen on helping folks adopt workload identity. In this demo Flux
authenticates to OpenBao with short-lived ServiceAccount tokens instead of
a bootstrap secret, and clusters only reconcile artifacts signed by secure and self-hosted key infrastructure.&lt;/p>
&lt;p>If you run OpenBao and Flux together, we&amp;rsquo;d like to hear how it goes. Talk
to us in the #flux channel on
&lt;a href="https://slack.cncf.io/" target="_blank">CNCF Slack&lt;/a>, or
bring your use-case to one of the meetings on our
&lt;a href="https://fluxcd.io/community/" target="_blank">community page&lt;/a>.&lt;/p>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>
&lt;a href="https://fluxcd.io/flux/components/kustomize/kustomizations/#openbaovault-kubernetes-auth" target="_blank">Flux Kustomization decryption with OpenBao via workload identity&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://fluxcd.io/flux/components/source/ocirepositories/#public-keys-verification" target="_blank">Flux OCIRepository verification with public keys&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://openbao.org/api-docs/secret/transit/" target="_blank">OpenBao Transit engine&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://docs.sigstore.dev/cosign/key_management/overview/" target="_blank">Cosign key management and KMS providers&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://openbao.org/api-docs/auth/kubernetes/" target="_blank">OpenBao Kubernetes auth method API docs&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://openbao.org/api-docs/auth/jwt/" target="_blank">OpenBao JWT/OIDC auth method API docs&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>