Apron · Review and roadmap · kubara

Apron's next shape: self-contained, built on kubara

Apron deploys Hangar onto a Kubernetes cluster: it onboards a cluster you already have, or creates a local one first. When this was written it did that by copying a template repo and rewriting it with one script. kubara, an open-source GitOps platform framework from STACKIT, does the same job with a CLI, versioned catalogs and generated Helm values. This review compares the two and records the decision taken on October 16: Apron keeps its services in one kubara catalog, uses kubara as its only renderer, and lets DIY users install kubara's plain output without kubara.

Review October 16, 2026Decision October 16, 2026Status decided; v0.5 (the apron CLI and the lab rebuild) built Oct 16 and 17, 2026; the kubara port not startedRead jfillman/apron · jfillman/hangar · kubara-io/kubara · kubara-io/catalogs

Since then. v0.5 is built: the apron CLI (init, render, up, fleet, identity, verify, resume, down) replaced the script on October 16, 2026, with templates harvested from the live clusters, profiles independent of runtimes and Traefik on every cluster, and both lab clusters were rebuilt with it the next day. Tower now deploys as an Airframe app. The kubara port (v1) has not started. This page is the review and decision as written.

Verdict · adopt kubara, build on it, give back

kubara and Apron solve the same problem. Adopt kubara, and move Apron's best ideas into it.

  • Same layer, same shape. Both take one config file and produce the Argo CD state that installs a cluster's baseline. kubara regenerates on every change and versions its add-ons as OCI catalogs. Apron copies a repo once and rewrites it with sed, so it can't upgrade a fleet.
  • Apron becomes a thin kubara catalog. It keeps only what is Hangar's: the service catalog, platform CI/CD, Autopilot, Backstage, the second Argo CD. cert-manager, External Secrets, Kyverno, Prometheus, Loki and Crossplane come from kubara's general catalog today.
  • Generic pieces go upstream, not into Apron. Argo Rollouts, Sloth, Thanos, Tempo and an Infisical secret store are useful to every kubara user. Contribute them to kubara's general catalog, and ship them from Apron only until they land.
  • The script stays, as apron check, and points the way for kubara. kubara validates each service's settings on its own, but can't say "an upper cluster can't run the CI/CD control plane". apron check enforces those rules now; proposing catalog-level rules to kubara is how it becomes unnecessary.
  • One catalog, one renderer, DIY from the output. Apron's services are a kubara catalog (kubara's word for what you might call a profile), rendered only by kubara. What kubara writes to Git is plain Helm charts, values and Argo CD ApplicationSets, so a DIY user installs that with Helm and Argo CD and never runs kubara.
  • Apron stays self-contained, and you name the cluster. One script, apron up dev --name dev or apron up prod --name prod, onboards Hangar onto an existing cluster, or creates a local one on kiac or kind first, then generates, bootstraps and verifies it. kubara is a pinned tool the script drives, like kind or Helm; the apron catalog ships inside the repo, and nothing else in Hangar has to exist first.
  • Every Hangar cluster is its own kubara hub. kubara's default is one hub that holds every spoke's kubeconfig. That's the setup ADR-0005 rejected, and kubara supports the alternative natively.

What kubara is

kubara is a single Go binary, Apache-2.0, that started inside STACKIT and was open-sourced in 2026. You describe clusters and the services each one runs in config.yaml. kubara generate merges that with one or more catalogs and writes reviewable files to Git: reusable charts under platform-components/, per-cluster values under platform-configs/<cluster>/. kubara bootstrap installs Argo CD and a few CRDs once. From then on Argo CD reconciles, and kubara isn't running.

A catalog is to a platform what a Helm chart is to an app. It holds a Catalog.yaml with a plain semver version, one ServiceDefinition per service, the charts, and Go templates (.tplt, with Sprig) for each cluster's values. Catalogs are published as OCI artifacts and listed per cluster, in order. kubara ships two: bootstrap (Argo CD, CRDs) and general (17 services, from cert-manager to Velero).

On each cluster, the bootstrap catalog's Argo CD chart creates one ApplicationSet per service. Each selects clusters labelled <service>: enabled and layers values in a fixed order: chart defaults, then values.generated.yaml, then additional-values.yaml, then any values-*.yaml you add. Generated files are never hand-edited; your changes live in the last two.

INPUTS config.yamlclusters, services bootstrap catalogargo-cd, crds general catalog17 services apron catalogHangar services OCI, pinned per cluster, merged in listed order apron checkzone/role rulessecrets, fleet record kubara generate.tplt → valuesschema per cluster GIT · REVIEWED platform-components/helm/<service>/ chartsregenerated platform-configs/<cluster>/helm/<svc>/values.generated.yamlvalues-*.yaml (yours) Argo CD on each clusterone ApplicationSetper enabled service kubara runs at generate time only. Re-running it after a catalog bump is the fleet upgrade: the diff is the PR.
Figure 1The proposed flow. kubara's pieces are grey; Apron's are blue. Apron becomes one catalog plus a check that runs before generation.

Apron and kubara, side by side

The two tools started from the same pain: hand-maintained cluster repos that drift apart. kubara solved generation and upgrades. Apron solved fleet safety rules and Hangar's specific stack.

ConcernApron todaykubaraBetter
Inputcluster.yaml, deleted after one runconfig.yaml, committed, all clusters in one filekubara
RenderingLiteral sed over a copy of a live cluster; macOS onlyGo templates with Sprig, reading the cluster, its services and the catalogkubara
Re-runnableNo; run once on a fresh cloneYes; generated files are rewritten, yours are left alonekubara
VersioningNone; each cluster repo is a forkOCI catalogs, immutable semver, pinned per clusterkubara
Per-service validationField presence in the scriptconfigSchema per service; kubara schema for editorskubara
Cross-cluster rulesZone and role invariants, refused before writingOnly hub vs spoke per serviceApron
TopologyEvery cluster runs and pulls with its own Argo CDDefault: hub holds spoke kubeconfigs. A hub with no spokes works toocompatible
SecretsInfisical via ESO; fresh passwords per clusterESO with a backend you choose; OpenBao locally, Bitwarden in examplescompatible
Stack opinionsTraefik, Thanos, Tempo, Rollouts, Sloth, Crossplane, TektonTraefik, oauth2-proxy, Homer, Velero, Longhorn, MetalLBoverlap on Traefik
ProvisioningNone (kind config only)Optional Terraform for STACKIT and T Cloud; --local kind for evaluationneither for Hangar
MaturityBuilt for two live clustersYoung: config schema v1alpha5, releases every two weeks, migrations in the CLIpin it

What the Apron code shows today

These are the reasons to move, and which ones kubara fixes on its own.

highAP-1

Every cluster repo is a fork, so upgrades go back to hand diffs

kubara fixes

The script deletes cluster.yaml and isn't safe to re-run. Each cluster keeps its own copy of 38 Applications and about 62,000 lines of vendored installs. Bumping cert-manager across the fleet is N pull requests on N diverging copies, the drift Apron was built to stop. It only stops it on day 0.

mediumAP-2

The substitution only runs on macOS

kubara fixes

substitute() calls sed -i '' "s|…|…|g", which is BSD syntax. GNU sed reads '' as the script, so the run fails on Linux and in CI. Templating replaces sed entirely.

mediumAP-3

Install order is a folder-name convention

still open

The 00- to 60- prefixes read as an order, but every Application starts at once; one manifest in the repo has a sync wave. kubara has the same property: one ApplicationSet per service, all in parallel, with a retry limit of 5 and a 5-minute maximum backoff. Crossplane packages before the XRs that need them is the case to test.

lowAP-4

The template is a curated copy of a live cluster

kubara fixes

Substitution targets are real names from the old dev cluster and the prod cluster, which is why the script must skip hack/ and order rules longest-first. Templates with parameters remove this class of bug.

lowAP-5

Housekeeping

Two .DS_Store files are committed. AI triage has no components.aiTriage toggle yet, as the README notes.

Apron as a kubara catalog

Each of today's components.* toggles becomes a ServiceDefinition. Where kubara's general catalog already ships the same service, Hangar uses kubara's and supplies its own values in values-hangar.yaml. Where it doesn't, the apron catalog ships the chart. Name collisions fail by default in kubara, so Apron never redefines a general service by accident.

BOOTSTRAP · kubara installed by kubara bootstrap argo-cd bootstrap-crds GENERAL · kubara used with Hangar values cert-manager external-secrets kyverno crossplane kube-prom-stack loki metrics-server traefik on; homer,velero… off APRON · Hangar ships the chart ghcr.io/jfillman/catalogs/apron infisical gateway routes argo-rollouts sloth thanos · tempo service-catalog argocd-apps cluster-registry platform-cicd autopilot backstage + otel, minio, …
Figure 2Where each service comes from at first. Infisical, Rollouts, Sloth, Thanos and Tempo in the Apron band are generic and should move up into kubara's general catalog. Amber services are role-gated: apron check refuses them on any cluster without the control-plane role.
apron catalog repo
apron/
  Catalog.yaml          # spec.version: 1.0.0
  services/
    hangar.yaml         # zone + roles live here
    infisical.yaml
    argocd-apps.yaml    # second Argo CD
    platform-cicd.yaml
    autopilot.yaml
    …
  platform-components/helm/
    argocd-apps/ platform-cicd/ …
                        # today's Applications,
                        # as charts
  platform-configs/helm/
    argocd-apps/values.generated.yaml.tplt
    …
  hack/
    apron-check         # was customize-cluster.sh
    cluster-identity.sh # unchanged
kubara config.yaml, one Hangar cluster
version: v1alpha5
clusters:
  - name: kind-staging
    stage: upper
    type: hub             # its own Argo CD
    dnsName: staging.hangar.example
    ingressClassName: traefik
    argocd:
      selfManaged: enabled
      repo: { … }
    catalogs:
      - oci://ghcr.io/kubara-io/catalogs/general:2026.42.1
      - oci://ghcr.io/jfillman/catalogs/apron:1.0.0
    services:
      hangar:
        status: enabled
        config: { zone: upper, roles: [workloads] }
      traefik:       { status: enabled }   # Hangar's gateway too
      platform-cicd: { status: disabled }

Where zone and roles live. kubara's cluster record has a free-form stage and a type of hub or spoke, nothing richer. An always-on hangar service carries zone and roles in its configSchema, so kubara types and checks them, and every template can read them through .cluster.services.hangar.config.

# services/platform-cicd.yaml
apiVersion: kubara.io/v1alpha1
kind: ServiceDefinition
metadata:
  name: platform-cicd
  annotations: { kubara.io/category: delivery }
spec:
  chartPath: platform-cicd
  status: disabled          # opt-in, control-plane only
  clusterTypes: [hub]
  configSchema:
    type: object
    properties:
      cicdReady: { type: boolean, default: false }

What apron check keeps doing. Everything kubara can't express. It reads config.yaml, refuses the same combinations the script refuses today (an upper zone with platform-cicd, provider-github, autopilot or a full service catalog; a control-plane cluster outside the lower zone; Autopilot without the full catalog), generates the Infisical and Rekor passwords, renders cluster identity, and prints the clusters.yaml record. It runs before kubara generate locally and as a required CI check. What it drops: copying, directory deletion, and the whole sed table.

How it goes upstream. Rules that span services are a gap any multi-cluster kubara user hits. Propose a small addition to kubara: rules in Catalog.yaml, checked during generate and schema, for example "service platform-cicd requires hangar.config.zone == lower". Open it as an ADR in kubara's own format, with apron check as the working reference. Once it lands, Apron's rules move into its catalog and the check script retires.

Decision: how Apron installs

Decided · October 16, 2026
  • Catalog format: kubara's, Catalog.yaml plus one ServiceDefinition per service. An open format already in use, not a Hangar invention.
  • Renderer: kubara only, pinned in apron.lock and installed by the apron script like kind or Helm.
  • DIY: supported through kubara's output. The rendered charts, values and ApplicationSets are committed to Git; anyone can install them with Helm and Argo CD alone.
  • Profile and runtime are independent: a profile (dev or prod) says what the cluster runs; the runtime (kiac, kind, or an existing cluster) says where. v1 supports existing clusters, kiac and kind, and any profile runs on any runtime.
  • One name per cluster, chosen by you: the name passed to apron up --name is the kubectl context, the fleet registry entry, the Infisical project stem, the issuer path and the hostname stem. It is recorded once, in the cluster's config; no tool, chart, template or script contains a cluster name.
  • Gateway: Traefik on every runtime, installed by Apron. Argo CD: two instances per cluster, both installed by Apron.
  • Sequence: for the October lab rebuild, Apron renders its own templates (name-free, tested against today's clusters). The kubara catalog port follows the rebuild.
  • Not now: a second, Helm-only renderer (two engines to keep equal); Sveltos (a hub pushing into clusters, ruled out by ADR-0005); vCluster and existing clusters (later runtimes).

Naming. kubara calls its packaged unit a catalog, and a cluster's entry in config.yaml its cluster profile. Apron uses catalog for its service set, to match, and profile for a named cluster shape: dev, prod or baseline.

apron catalog+ profile: dev · prod · baseline kubara generatethe only rendererafter apron check Git: plain outputplatform-components/helm/* (charts)platform-configs/<cluster>/ (values)Argo CD ApplicationSets THREE WAYS TO INSTALL THE SAME OUTPUT apron upcreates the cluster tooany runtime kubara bootstrapexisting cluster,kubara users DIYhelm install argo-cd,apply the ApplicationSets
Figure 3One renderer, three ways in. DIY needs only Helm and Argo CD because what reaches Git is ordinary charts and manifests.

Technology Apron should build on, so Hangar doesn't end up imitating it:

  • Gateway API for every UI route. Both lab clusters already serve their UIs through a Gateway; the catalog ships HTTPRoutes, not Ingress.
  • Renovate to bump everything in apron.lock (kubara, catalog versions, chart pins) as reviewed PRs. kubara and its catalogs already use it.
  • OCI artifacts for publishing the apron catalog, as kubara publishes its own.
  • Argo CD Agent, later, for one view over many clusters without a hub that holds their credentials.
  • vCluster and Cluster API, later, as runtimes for per-PR clusters and real infrastructure.

Installing Apron on its own

Every Hangar component installs by itself. For Apron that means a person with a laptop and this one repo gets a working cluster without reading kubara's docs or cloning another Hangar repo. kubara changes what the script calls inside, not what the user runs. The tagline holds: one config file, one script, a known order.

Apron's main job is onboarding: point it at a Kubernetes cluster and it deploys Hangar there. Local runtimes are a convenience that creates the cluster first and then runs exactly the same onboarding. Two choices describe a cluster. The profile says what it runs: dev is the lower-zone control plane that also hosts Infisical; prod is the upper-zone workloads cluster. The runtime says where it runs: kiac (one Apple container VM per node, with Cilium and a Gateway built in), kind (Docker or Podman, with Calico), or an existing cluster you already run, such as EKS or AKS. Any profile runs on any runtime; runtime-specific pieces such as the CNI or the gateway's ports follow the runtime, not the profile. You also give each cluster its name. The lab's rebuild happens to put dev on kiac and prod on kind, because that's the best use of its two machines.

./apron init prod --name my-cluster --runtime existing --context my-cluster --out ../gitops-my-cluster
./apron up --out ../gitops-my-cluster      # onboard Hangar onto a cluster you already have

# the lab: create local clusters first, then the same onboarding
./apron init dev  --name dev  --runtime kiac --out ../gitops-dev
./apron up --out ../gitops-dev      # lower zone, control plane, hosts Infisical
./apron init prod --name prod --runtime kind --out ../gitops-prod
./apron up --out ../gitops-prod     # upper zone, workloads
./apron up prod --runtime kind --baseline-only
                                   # Apron alone: no Airframe, Glidepath or Autopilot
./apron resume --out ../gitops-dev   # runtime's own resume (e.g. kiac resume) + refresh hosts
./apron verify --out ../gitops-dev   # runtime health check, then every Argo CD app healthy
./apron down dev
APRON UP · ONE RUN, IN ORDER 1 · toolsPrerequisitespin kubara into./.bin kiac createcilium · gateway kind create+ calico v3.29.1 2 · runtimes/*.yaml 3 · configProfile → entryapron checkrefuses bad combos 4 · renderkubara generate--catalog ./catalogdiff, then push 5 · secretsPlant per clustergenerated, nevercommitted 6 · bootstrapkubara bootstrapArgo CD, ESO CRDs, ClusterSecretStore 7 · verifyWait for every app healthywrite /etc/hosts block, print URLs Recorded flags only: the --cp-memory incident can't recur. Steps 3 to 7 are the same on both runtimes. Only step 2 differs, and it reads from a file, never from typed flags.
Figure 4What apron up does. Blue is the only runtime-specific step. kubara appears in steps 4 and 6 as a tool the script runs.
ProfileReplaces in the labZone · rolesRuntimeTurns on
devthe dev clusterlower · control-plane, workloadsanyInfisical host, platform CI/CD, full service catalog, Autopilot, observability
prodthe prod clusterupper · workloadsanyAttached-tier catalog, Rollouts, Tower's cluster access (Tower itself deploys as an app); Infisical as a remote consumer
--baseline-onlynoneeitheranyArgo CD, cert-manager, ESO, Kyverno, Prometheus, Loki, Traefik. No other Hangar repo referenced

Self-contained, concretely. The apron catalog is a directory in the repo, passed to kubara as --catalog ./catalog, so no registry is needed; publishing it as OCI is for other users, not a requirement. The kubara binary and the general catalog version are pinned in apron.lock. Runtime flags live in the cluster's own config, recorded at init, which also fixes the lab's open gap: the old prod cluster's recreate steps were never written down.

What still needs Git. Argo CD reconciles from a repository, so up shows the generated diff and pushes only when told to. That is the one external dependency, the same as today.

Keeping one Argo CD per cluster

kubara's documented model is a hub that runs Argo CD and registers spokes, reading each spoke's kubeconfig from the secret backend. Glidepath ADR-0005 rejected exactly that: a hub holding every cluster's credentials is a path from dev to prod. kubara still fits, because nothing requires spokes. Declare every Hangar cluster as type: hub with argocd.selfManaged: enabled and it bootstraps and reconciles only itself, as Apron's clusters do now. kubara's own --local mode runs exactly this way.

The zone line maps onto repos. Keep one kubara repo per zone, or per cluster as today. Upper clusters pin argocd.repo.components.targetRevision to a tag, so a catalog bump reaches them only through a reviewed merge.

KUBARA DEFAULT · HUB AND SPOKE hub Argo CDholds spoke kubeconfigs spoke: dev spoke: prod One compromise reaches every spoke. HANGAR · EVERY CLUSTER A HUB Git (per zone)generated + reviewed devhub · lower staginghub · upper prodhub · upper Each pulls its own config. No cluster holds another's credentials.
Figure 5The same kubara output in two topologies. Arrows on the right point from each cluster to Git because each cluster pulls.
Worth a later look

kubara's examples include an Argo CD Agent lab in which spokes pull manifests over outbound mTLS, with no hub kubeconfigs. That gives Tower one place to see every cluster while still honouring ADR-0005's reason. It's a candidate for revisiting that ADR, not a v1 dependency.

Hangar on AWS and Azure

Hangar will install on EKS and AKS through a Terraform module. Terraform builds the cloud: network, cluster, DNS, workload identity and the cluster's Infisical identity. Apron takes over inside the cluster, exactly as it does on a local runtime. The home-lab rebuild doesn't use any of this; it's the path for clusters that live in a cloud account.

Three rules carry over from the lab. You name the cluster once, as cluster_name, and every resource takes its name from it. Terraform stops at Argo CD, so it never fights Argo CD over drift. Infisical is the only secrets backend: there is no AWS Secrets Manager or Azure Key Vault option.

terraform-hangar/
  modules/
    aws-cluster/        # VPC, EKS, node groups, EKS Pod Identity agent, Route 53 zone
    azure-cluster/      # VNet, AKS with OIDC issuer + workload identity, Azure DNS zone
    infisical-cluster/  # Infisical project, machine identity and its auth, project access
    apron-bootstrap/    # cloud-agnostic: Argo CD, repo creds, Infisical creds, root app
  hangar-aws/           # root: aws-cluster + infisical-cluster + apron-bootstrap
  hangar-azure/         # root: azure-cluster + infisical-cluster + apron-bootstrap
  examples/
    aws-prod/  azure-prod/
TERRAFORM · ONE APPLY hangar-awsor hangar-azurecluster_name = … aws-clusteror azure-cluster infisical-clusterinfisical provider apron-bootstraphelm + kubernetes WHAT EACH CREATES Cloud accountnetwork · EKS/AKS · DNS zone · OIDC issuer Infisical (Cloud or self-hosted)project <cluster_name> · machine identity INSIDE THE NEW CLUSTER Argo CDroot appTerraform stops here Apron baselinerendered cluster repoprod profile ESO · provider-infisicalread secrets apron-bootstrap writes the identity's creds to a Secret; the cluster then pulls everything.
Figure 6Terraform builds the cloud and the Infisical identity, then installs Argo CD and Apron's root app. Everything after that is GitOps, the same as on the lab clusters. Blue arrows are pulls.
ModuleCreatesKey inputsOutputs
aws-clusterVPC, EKS, managed node groups, EKS Pod Identity agent, Route 53 zonecluster_name, region, Kubernetes version, node sizesendpoint, CA, OIDC issuer URL, zone id
azure-clusterVNet, AKS with OIDC issuer and workload identity on, Azure DNS zonecluster_name, location, Kubernetes version, node sizesendpoint, CA, OIDC issuer URL, zone id
infisical-clusterinfisical_project, infisical_identity, its auth method, infisical_project_identitycluster_name, Infisical URL and orgidentity credentials for the cluster
apron-bootstrapargocd namespace, Argo CD, repo creds, Infisical creds Secret, root Applicationkubeconfig parts, cluster repo URL, profilethe cluster's fleet record

apron-bootstrap is apron up for a cluster that already exists. It runs the same steps from Argo CD onward, and the cluster repo it points at is rendered by Apron from the same cluster config, with runtime: existing. The issuer comes from the cloud: EKS and AKS publish their own OIDC issuers, so cloud clusters skip the lab's publish-to-hangarplatform.dev step, and the fleet record carries the provider's issuer URL.

Infisical, concretely. The infisical-cluster module uses Infisical's own Terraform provider. Version 1 uses Universal Auth, the method Hangar's provider-infisical already uses, so its client secret passes from Terraform to a Kubernetes Secret. That puts it in Terraform state, so state lives in an encrypted remote backend (S3 with KMS, or an Azure Storage account). Infisical also offers AWS Auth and Azure Auth, and the provider has resources for both. They would remove the stored secret, which matches Hangar's keyless direction, once External Secrets and provider-infisical are confirmed to support them.

Decide before the first cloud cluster

A cloud cluster must reach Infisical. The lab's Infisical runs on the dev cluster behind a home network, so AWS and Azure can't reach it. Pick one: Infisical Cloud, or a self-hosted Infisical with a public URL (for example a cloud cluster built with the dev profile, which hosts Infisical). The module takes the URL as an input either way.

Moving it forward upstream. kubara ships Terraform only for STACKIT and T Cloud, and its provider list is fixed in the CLI. The aws-cluster and azure-cluster modules are written as ordinary reusable modules first, then offered to kubara as AWS and Azure providers.

Gaps settled, and what's left

decided

Two Argo CD instances per cluster stay

Hangar keeps argocd-platform for the cluster's own baseline and argocd-apps for tenant apps (gitops-strategy §2). Apron installs both on every profile. kubara's bootstrap installs one Argo CD, so after the kubara port the second becomes an argocd-apps service in the apron catalog, together with tenant onboarding and the AppProject charts.

decided

Traefik is the gateway on every runtime

Apron installs and owns Traefik, the Gateway API CRDs and the Gateway on every cluster, the way the prod cluster already does, and every UI is an HTTPRoute on it. The runtime only decides how traffic reaches it: port mappings on kind, a NodePort on kiac (kiac's own --gateway Traefik is no longer used), and a LoadBalancer Service, so an NLB or Azure load balancer, on EKS and AKS. kubara's general catalog also ships Traefik, so this choice carries straight into the port. Because routes are Gateway API, a cloud cluster can later swap to its native controller without touching apps.

for the port

kubara's secret names differ from Hangar's

kubara's bootstrap Argo CD chart creates its own ExternalSecrets (the image pull secret and spoke credentials) and assumes a store named <cluster>-<stage> with keys at paths like <cluster>/<stage>/cluster_secrets/docker_config. Hangar uses one ClusterSecretStore, platform-secret-store, backed by Infisical projects named platform-cicd-<cluster> with flat keys such as registry-credentials-dockerconfigjson. Left alone, kubara's ExternalSecrets would look for a store and keys that don't exist and never sync. kubara lets later values-*.yaml files override its generated values, so Hangar points those references at its own store and keys; the lasting fix is a small upstream PR making the store name and key prefix configurable. Apron's own templates already use Hangar's names, so the rebuild isn't affected.

check

A young dependency

Config is at v1alpha5 and the CLI carries migrations between versions; releases come every two weeks. Pin the kubara binary and both catalog versions in CI, and upgrade on purpose.

Apron's purpose

Apron deploys Hangar onto a Kubernetes cluster, under the name you choose, and keeps it there. It onboards a cluster you already run, or creates a local one on kiac or kind first. Anything another platform could use goes upstream.

Apron owns

  • Onboarding any Kubernetes cluster to Hangar: the apron CLI's init, up, verify, check
  • Local runtimes as a convenience: kiac and kind recipes with recorded flags, plus resume and down
  • The dev, prod and baseline profiles
  • Keeping the rendered output installable without kubara (the DIY path)
  • The apron catalog: Hangar-only services, charts and value templates
  • Hangar's upstream work on kubara: services, rules, providers
  • Hangar values for kubara's general services
  • Zone and role rules, enforced by apron check in CI
  • Per-cluster secrets, cluster identity, and the fleet's clusters.yaml
  • Which kubara and catalog versions the fleet runs

kubara and others own

  • Generation, schema, bootstrap of Argo CD (kubara)
  • Generic add-ons like cert-manager or Kyverno (kubara general)
  • The clusters themselves: kiac and kind locally; EKS, AKS or Cluster API elsewhere (the Terraform modules build cloud clusters, then hand them to Apron)
  • Delivering and promoting apps (Glidepath, Tower)

Roadmap

v0 · built Aug 19

Template and script

retired
  • One config, one script, folder-ordered bootstrap. Solves day 0 and the dev/prod drift that prompted it.
v1

Adopt kubara, start contributing

next
  • Run kubara bootstrap --local with only the general catalog to learn its conventions on kind. Join the kubara Slack channel and introduce Hangar's use case.
  • Port Apron's templates to a kubara catalog (kubara catalog create apron), keeping the apron CLI as the entry point; port Infisical, Rollouts, Sloth and the second Argo CD first, written to kubara's own chart and changelog conventions so they can be upstreamed unchanged.
  • Point kubara's own ExternalSecrets at Hangar's store and keys through values-*.yaml overrides.
  • In CI on every Apron PR, run apron up prod --baseline-only on kind (the runtime CI can run), then install the same rendered output a second time by the DIY path to prove it needs no kubara. File kubara gaps as kubara issues, not Apron workarounds.

Done whenthe kubara-rendered output matches what v0.5 renders for both profiles, from a fresh clone of Apron alone, with no hand edits under platform-components/.

v2

Upstream the generic, migrate the fleet

planned
  • Open pull requests to kubara-io/catalogs for Argo Rollouts, Sloth, Thanos, Tempo and an Infisical secret store. Remove each from Apron as it ships in a general release.
  • Propose cross-service catalog rules as a kubara ADR, with apron check as the reference implementation.
  • Port the Hangar-only services: platform CI/CD, Autopilot, Backstage, the service catalog, the second Argo CD. Publish ghcr.io/jfillman/catalogs/apron as OCI.
  • Migrate the prod cluster, then dev, by diffing rendered manifests against the live repos until empty. After that, recreating either is apron down then apron up.

Done whena cert-manager bump is one change to a pinned catalog version, regenerated for every cluster and reviewed as one diff, and at least one Hangar service ships in kubara's general catalog.

v3

Fleet view and promotion

decide
  • Publish each cluster's catalog versions to the cluster registry so Tower shows who's behind.
  • Move catalog versions lower to upper with a PR at the zone line, by hand or as a Tower action.
  • Evaluate Argo CD Agent against ADR-0005, and share the result with the kubara maintainers either way.
  • Add a vcluster runtime; per-PR clusters inside dev become apron up pr-N --runtime vcluster.

Done whena new apron version reaches the dev cluster first and waits as a PR on every upper cluster.

v4

Apron as small as it can be

explore
  • With catalog rules upstream, move Apron's rules into Catalog.yaml; apron check becomes a thin call to kubara. The rest of the script stays, because the lab lifecycle is Apron's job.
  • kubara's local mode only knows kind. Offer kiac as a second local runtime upstream, using Apron's recipe.
  • Ship hangar-aws and hangar-azure Terraform modules on top of apron-bootstrap, with Infisical as the only secrets backend.
  • Add a Cluster API runtime through ClusterClass, so a real cluster is one more --runtime.
  • kubara's Terraform provider list is fixed in the CLI (STACKIT, T Cloud). Contribute a provider for wherever Hangar runs next, such as EKS, rather than building one inside Apron.

Done whenthe apron catalog contains only Hangar's own services, every rule runs inside kubara, and apron up still works from Apron alone.

Sources