‹ Blogs

Sovereign Signing: A Self-Hosted Supply Chain with OpenBao, Cosign, and Flux CD

Featured Image
Published on August 04, 2026
Author Fabian Kammel

The Ground Is Moving Under Secrets Management

If you run a regulated platform, the last three years have shifted the assumptions under your secrets management strategy. In August 2023, HashiCorp relicensed Vault from the open source MPL 2.0 to the Business Source License (BSL 1.1). The source is still readable, but it now carries commercial-use restrictions that make it source-available, not open source. In February 2025, IBM completed its acquisition of HashiCorp. And on 1 July 2026, HCP Vault Secrets reaches end of life, prompting its remaining users to move to higher, pricier tiers.

None of these changes is a red line on its own. Combined, however, they create a natural inflexion point for infrastructure teams. For the highly regulated organisations we work with, such as the public sector or enterprises with genuine data-sovereignty obligations, the resulting conversations rarely stop at picking a new secrets manager. They force us to address the fundamental question: how much of my trust chain am I willing to rent from infrastructure I don’t control?

This post answers a specific slice of that question. We’ll build a software supply chain signing pipeline for GitOps delivery where every link in the chain is self-hosted and vendor-neutral: OpenBao holds the signing key, Cosign signs the OCI artifacts, and Flux CD verifies them before anything lands in the cluster. No public cloud KMS. No public Sigstore transparency log.

The full, reproducible reference lives at github.com/controlplaneio-openbao/openbao-flux-demo.

Defining “Sovereign”

The term “sovereign” is often used loosely, so we need to define it clearly for our context. The standard approach to signing (container) artifacts today relies heavily on two components outside of your control:

  • A public cloud KMS (AWS KMS, GCP KMS, Azure Key Vault) to hold the signing key is convenient. It also means that the key’s custody and jurisdiction are outside of your control.
  • The public Sigstore stack (Fulcio for short-lived certificates, Rekor for the transparency log), when you sign keylessly. This removes the burden of managing the lifecycle of the signing key, but it makes your signing flow depend on public, shared infrastructure that must be reachable and trustworthy. In addition, leaking information about private signing events to a public ledger does not necessarily align with security requirements.

In most industries, these trade-offs are reasonable and make-or-buy decisions are primarily driven by market pressure. However, in heavily regulated environments, relying on public infrastructure introduces third-party dependencies that auditors will flag. To meet sovereignty requirements, we define a hard boundary: the signing key remains strictly within self-hosted infrastructure, and neither signing nor verification relies on external services.

The Chain

flowchart TD
    A["OpenBao's transit engine
holds private signing key"] -->|signs digest on request| B["Cosign"] B -->|attaches signature to artifact| C["GHCR
OCI registry"] C -->|pulls + verifies| D["Flux CD
with static public key"]

OpenBao is the Linux Foundation’s open source fork of HashiCorp’s Vault, created in direct response to the BSL relicensing. Its transit secrets engine is a “cryptography as a service” backend: it holds key material and performs cryptographic operations on request, so the private key is generated inside OpenBao and never leaves.

Cosign orchestrates signing the OCI artifact and storing the signature. Crucially, it has first-class, native support for OpenBao through the openbao:// KMS URI scheme. Cosign asks OpenBao to sign the artifact’s digest, OpenBao does the cryptography, and the signature is stored in the registry right next to the artifact.

Flux CD verifies the signature during reconciliation before applying anything. Flux’s verification is signing-backend-agnostic. It uses a configured public key to check the artifact’s signature. It has no awareness of OpenBao, Vault, or any KMS, and when you use a static key, it never reaches out to Fulcio or Rekor.

The Deliberate Trade-off: Static Keys, Not Keyless

Regular readers will notice this diverges from our own Flux D2 Reference Architecture, which defaults to keyless signing via GitHub Actions OIDC. That is not an inconsistency, but the whole point on which the sovereignty claim rests!

Keyless signing is excellent. It removes the operational burden of key custody entirely: identities are short-lived, and the transparency log gives you a tamper-evident, auditable record for free. When operational convenience is the priority and reliance on the public Sigstore instance is acceptable, keyless is the right default, and it is ours.

But keyless depends on public Sigstore infrastructure. For a pipeline whose entire reason for existence is to avoid dependence on external infrastructure, that dependency disqualifies it. Therefore, we make the opposite call on purpose: a static key, held in OpenBao, with full self-custody. Still, this comes at a cost: you are now responsible for key custody and rotation. On the other hand, the benefit is a materially stronger sovereignty claim, and the trust chain is yours end-to-end.

The lesson here should not be that “static keys are good, keyless is bad.” It’s that the two approaches encode different threat models, and you should choose the one that best fits your organisation’s requirements.

Building It (the Short Version)

The repository automates the whole demo using make targets. Once you’ve cloned the repository and run make prereqs, you can step through each step of the demo using the sequence laid out in the project’s README. In the following, we will step through the key insights and point out any sharp edges.

The key is generated inside OpenBao. With the transit engine enabled, Cosign creates the key in the vault and only ever writes out the public half:

cosign generate-key-pair --kms openbao://control-plane-demo

The signing occurs via digest, with the transparency log disabled. Here, we sign the immutable digest rather than a mutable tag, and pass --tlog-upload=false so nothing is written to the public Rekor log:

cosign sign --key openbao://control-plane-demo --tlog-upload=false \
  ghcr.io/controlplaneio-openbao/openbao-flux-demo-workload@sha256:a8c47e...

Next, Flux verifies the artifact with the public key. The OCIRepository references a secret that contains the cosign.pub; that’s the entire verification configuration:

apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
  name: demo-workload
  namespace: flux-system
spec:
  interval: 5m
  url: oci://ghcr.io/controlplaneio-openbao/openbao-flux-demo-workload
  ref:
    tag: latest
  verify:
    provider: cosign
    secretRef:
      name: cosign-public-key

On successful verification, Flux records the event and refuses to apply anything until it has:

SourceVerified=True (Succeeded): verified signature of revision latest@sha256:…

We install Flux with the Flux Operator via a declarative FluxInstance, rather than the classic flux bootstrap CLI, just as we do in our D2 Reference Architecture.

Mind the (demo environment) gap

Note that this is a demo environment and some trade-offs have been made for educational purposes:

  • OpenBao dev mode is not production. The demo runs bao server -dev with a well-known root token and an in-memory store. This configuration is intended for a throwaway playground, and nothing else. The repo includes a worked example of a least-privilege policy scoped to a single transit key (read the public key and sign) because in production, you never sign with a root token.
  • GHCR packages default to private and unlinked, even when the repository is public. Until you set the package to public in the GitHub UI, Flux cannot pull it anonymously, and verification never starts. When you have to change the configuration, the demo will call this out.
  • GitHub Packages still requires a classic PAT. Fine-grained tokens currently have no Packages permission at all, so a classic token with write:packages is unavoidable today. Use a short-lived token and revoke it afterwards.
  • flux push artifact --creds and Cosign’s registry auth are separate credential paths. Cosign needs its own cosign login.

It is worth noting that we chose GitHub and GHCR to make it easier to share code with our readers. In a regulated enterprise environment, you may find different tools for SCM and OCI registry, but the approach will work the same.

A Word on Licensing

The licenses used by these projects match what enterprises expect today. In addition, most projects are governed by the Linux Foundation:

  • OpenBao: MPL 2.0, Linux Foundation-governed.
  • Flux CD: Apache 2.0, Linux Foundation-governed.
  • Flux Operator: AGPL 3.0
  • Cosign: Apache 2.0, Linux Foundation-governed.

Prove That It Blocks

A control you never watch fail is a control you don’t trust. The repository includes a tamper test that pushes an unsigned artifact to a separate tag, points a throwaway OCIRepository at it, and confirms that Flux refuses to deploy it: SourceVerified=False. The manifests never reach the cluster. Watching the pipeline correctly reject an unsigned artifact closes the loop and builds trust in the system.

The Path to Production

Note that the code is just a demo, and not a complete production blueprint. To focus on the trust chain as the primary educational piece, we deliberately scoped out several enterprise requirements. To make this production-ready, several factors need to be considered: HA/DR for OpenBao, proper seal management, and configured audit devices. Key rotation must be automated, and the public key must be delivered declaratively (e.g., via SOPS or Sealed Secrets) rather than applied imperatively.

And there’s one more step toward full sovereignty we didn’t take here: a self-hosted Rekor transparency log. Static-key signing gives you self-custody of the key; a self-hosted transparency log would provide a tamper-evident, auditable signing history without relying on the public Sigstore instance.

Talk to the People Who Maintain These Projects

If you’re navigating the secrets-management decision the Vault relicensing has forced, or hardening a GitOps delivery pipeline against supply chain attacks, that’s exactly the work we do. Explore Enterprise for Flux CD and Enterprise for OpenBao, or get in touch to talk through what a sovereign, self-hosted supply chain looks like for your environment.

Related blogs