Crossplane · 01 of 04 · Where it started

The SecretStore I planned, and the one I built

In my previous role I wanted to try Crossplane on one small, well-understood resource: a secret store. That proof of concept never happened. In Hangar the same idea became Airframe's first real cross-cluster API.

The SecretStore I planned, and the one I built Two panels. Left, drawn dashed because it was never built: a proof of concept in which a SecretStore claim is composed into an Azure Key Vault and an External Secrets SecretStore pointing at it, which syncs app secrets. Right, what Airframe runs today: a SecretStore XR with app, cluster and environment, composed by a go-templating pipeline into provider-infisical resources (a project and an identity in Infisical, the project never deleted with the XR) and a provider-kubernetes Object that wraps a ClusterSecretStore for External Secrets, which pulls values from Infisical. THE POC I PLANNED · NEVER BUILTWHAT AIRFRAME BUILT · LIVE SINCE 2026-08-17COMPOSESSYNCSSecretStore claimapp · envCompositionone template, two outputsAzure Key Vaultone per appESO SecretStorepoints at the vaultApp Secretspulled by ESOCOMPOSESPROJECT · IDENTITYSTOREPULLSSecretStore XRapp · cluster · envCompositiongo-templating pipelineprovider-infisicalmy own Upjet providerprovider-kubernetesObject wraps the storeInfisicalproject never deletedExternal SecretsClusterSecretStoreThe idea survived. The backend changed, and the first real API I shipped was the one I had wanted to prototype.LEGENDPlanned, never builtThe requestCompositionStateCreatesReads

Planned, never built

One claim, two outputs: an Azure Key Vault and an External Secrets SecretStore pointing at it. Small enough to learn on, useful enough to matter.

Built

  • First live on 2026-08-17 behind a small operator of my own.
  • Since September, provider-infisical (my own Upjet provider) does the provisioning, and the operator is retired.
  • A per-environment store narrows a secret to exactly one namespace.

What it taught me

A namespaced XR can't compose a cluster-scoped resource in Crossplane v2, so the ClusterSecretStore rides inside a provider-kubernetes Object. And a secret store must never be deleted just because its request was.

Hangar · Airframe · Crossplane