Skip to content

Repository files navigation

knr-ops

kubernetes-native resource operations

knr-ops logo

A GitOps pattern for managing cloud infrastructure through the Kubernetes API: no Terraform, no DSLs, no state files, no second toolchain. This repository is a working reference implementation of that pattern, with two environments: aws, which runs it end-to-end on AWS EKS, and local-host, which runs the same lifecycle on local clusters with no cloud account involved. It is not a product: fork it, strip it down, and adapt the layout to your own cloud and clusters.

A disposable local kind cluster bootstraps Flux and is then discarded: a CAPI pivot moves the control plane into a self-managed management cluster that reconciles itself and everything else from this repository. The aws environment reconciles:

  • a self-managed EKS management cluster (provisioned by CAPA, reconciled from Git by the Flux instance running inside it)
  • AWS EKS workload clusters provisioned via CAPA
  • per-cluster Flux instances delivered through CAPI addons
  • application workloads (the ACK S3, RDS, and IAM operators managing secure S3 buckets, PostgreSQL instances, and read-only IAM roles) running on each workload cluster

The local-host environment walks the identical chain with the CAPD Docker provider instead of CAPA: a local OCI registry, a one-control-plane/one-worker workload cluster, a second Flux instance, and a Podinfo app reachable from your laptop. It covers the complete GitOps, CAPI, and pivot lifecycle without provisioning AWS resources.

The imperative part of the lifecycle (bootstrap, pivot, and teardown) is a single Rust CLI, knr-bootstrap, that replaces the shell scripts as they complete parity runs. After the one-time bootstrap and pivot, everything is declared in Git as YAML. The aws environment declares 2 CAPI workload clusters: 4 node pools (ARM and GPU) across 2 regions, 2 S3 buckets, 2 RDS instances, 1 reader user, and one reader role per workload cluster. The repository also ships a Zarf air-gap bundle that packages the local-host deployment for offline installs. 0 HCL, 0 state files.

Who this is for

Platform engineers who already run Kubernetes and want to manage their own cloud infrastructure with the same API, RBAC, audit trail, and GitOps workflow they use for workloads. If you're reaching for Terraform/OpenTofu, Pulumi, or Crossplane to stand up cloud resources for Kubernetes, this pattern is the alternative: the cluster you already operate becomes the control plane. It is not a developer self-service portal; you are the consumer.

Problems the pattern solves

  • State files: drift, locking, corruption. Controllers reconcile actual state continuously instead of diffing a snapshot.
  • The plan/apply gap: PRs are reviewed as rendered Flux diffs (blast radius, image changes, render failures) by konflate: a GitHub Actions workflow runs it on every PR push as a merge gate, and an in-cluster instance posts the summary to the PR. You review byte-for-byte what reconciles. See docs/konflate.md.
  • Two toolchains: HCL for infra, YAML for workloads. One control plane means RBAC, policy, and audit cover both.
  • Lifecycle split: Terraform builds the cluster but can't manage what's in it. CAPI + Flux is one dependency graph from cluster to workload.
  • A control plane on a laptop: the management cluster is not a long-lived local kind cluster. The bootstrap kind cluster is disposable, and after the pivot the management cluster manages itself through the same GitOps flow it drives.

knr-ops aws architecture

knr-ops local-host architecture

knr-ops air-gap architecture

Prerequisites

The toolbox container is the primary lifecycle interface. A container user needs only the repository checkout and a running engine:

  • Docker, or Podman 5.5+; kind creates clusters through the mounted engine socket
  • The toolbox image. No semver release has been published yet, so build the current checkout with docker build -f bootstrap-rs/Dockerfile -t knr-ops-toolbox:dev .

A future matching v* tag publishes ghcr.io/polarsquad/knr-ops-toolbox for Linux amd64 and arm64 as X.Y.Z, X.Y, and stable latest, with a keyless signature and SPDX SBOM attestation. The aws environment additionally requires a GitHub PAT with read access, AWS credentials and service quotas, and an age private key.

Native development and air-gap work additionally need:

  • Mise 2026.8.10 or newer
  • Rust via rustup when building the CLI outside the image; the pin lives in bootstrap-rs/rust-toolchain.toml

Quickstart

Build the current checkout and run the complete local-host lifecycle with only Docker installed:

docker build -f bootstrap-rs/Dockerfile -t knr-ops-toolbox:dev .
mkdir -p .kube
docker run --rm -it \
  -v "$PWD:/workspace" -w /workspace \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$PWD/.kube:/root/.kube" \
  -e KUBECONFIG=/workspace/.kube/kind.yaml \
  knr-ops-toolbox:dev local-host

# Teardown uses the same mounts and the teardown subcommand:
docker run --rm -it \
  -v "$PWD:/workspace" -w /workspace \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$PWD/.kube:/root/.kube" \
  -e KUBECONFIG=/workspace/.kube/kind.yaml \
  knr-ops-toolbox:dev teardown local-host

Use ghcr.io/polarsquad/knr-ops-toolbox:<version> instead of the local image for a published release. The AWS form must also pass the Git source, PAT, age key path, and any AWS credential variables. Podman socket paths vary by host. scripts/toolbox-run.sh handles those mounts, loads .env without preserving quote characters, and persists kubeconfigs under .kube/; see Operations for both forms.

For hosts with mise, the lifecycle tasks call that wrapper. Installing the pinned native tools also enables key generation, validation, and inspection:

docker build -f bootstrap-rs/Dockerfile -t knr-ops-toolbox:dev .
export TOOLBOX_IMAGE=knr-ops-toolbox:dev
mise trust
mise install
cp .env.example .env        # AWS only: fill in the Git source and PAT
mise run sops-keygen         # first time only: age key for SOPS
mise run bootstrap           # toolbox: bootstrap, Flux handoff, then pivot
export KUBECONFIG="$PWD/.kube/knr-ops-mgmt.yaml"
flux get kustomizations --watch
mise run validate            # shell syntax, bootstrap.toml cross-check, overlays
mise run teardown            # toolbox: reverse-order lifecycle cleanup

Dependency versions are managed by Renovate (renovate.json5) running as the hosted GitHub App; they live in their native consumer files and update PRs open weekly. See Dependencies.

Environments (formerly profiles)

The shared toolchain is defined in mise.toml. AWS-specific tools are layered through mise.aws.toml; use the aws environment when those tools are needed. The local-host environment creates the management kind cluster, a local OCI registry, and the Flux Operator and FluxInstance. It publishes the mgmt/local-host/ and workload/local-host/ folders as the knr-ops:latest OCI artifact. Flux installs CAPI with its Docker infrastructure provider (CAPD), provisions a local one-control-plane/one-worker workload cluster, and installs a separate Flux instance there. That workload Flux instance reconciles Podinfo, providing an end-to-end local path from management-cluster bootstrap through workload delivery and application access. This covers the complete GitOps and CAPI lifecycle without provisioning AWS resources:

docker build -f bootstrap-rs/Dockerfile -t knr-ops-toolbox:dev .
export TOOLBOX_IMAGE=knr-ops-toolbox:dev
mise -E local-host install
mise -E local-host run bootstrap
export KUBECONFIG="$PWD/.kube/knr-ops-mgmt.yaml"
mise -E local-host run oci-push  # republish local management and workload paths
mise -E local-host run kubeconfigs
mise -E local-host run podinfo-port-forward  # http://localhost:9898
mise -E local-host run teardown

The Flux charts are pulled anonymously. The AWS environment requires a GitHub PAT so Flux can clone this repository; the local-host environment does not require GitHub or AWS credentials.

mise -E local-host run bootstrap waits for both the management and workload Flux reconciliation chains and surfaces workload reconciliation errors. A successful bootstrap, followed by the Podinfo port-forward, verifies the end-to-end local-host flow.

Local-host teardown deletes the CAPD workload cluster first, then removes the pre-pivot kind cluster or the post-pivot self-managed management containers, and removes the local registry last. AWS teardown discovers the active controller host, deletes the workload clusters, sweeps orphaned resources in both workload regions plus the self-managed management cluster, and removes the clusterawsadm CloudFormation stack.

The bootstrap CLI

The single knr-bootstrap binary implements bootstrap, the default pivot, and knr-bootstrap teardown. Repository-owned cluster names, paths, chart versions, provider manifests, and teardown targets come from bootstrap.toml; mise run validate cross-checks that file against the Git manifests. Sequence-level behavior and generic fallback defaults remain in the binary.

mise run bootstrap, pivot, and teardown now run the CLI through the toolbox wrapper. The shell scripts remain native reference and fallback paths until both environments complete parity runs; local-host has passed the full lifecycle, while AWS parity still gates retirement. See The bootstrap CLI for the interface, configuration, teardown controls, toolbox release, and current parity status.

Documentation

Page Contents
docs/bootstrap-cli.md The knr-bootstrap lifecycle CLI: toolbox distribution, interface, bootstrap.toml, pivot, teardown, parity status
docs/dependencies.md Renovate-managed dependency updates: covered surfaces, update procedure, intentional differences
docs/architecture.md Architecture diagram, reconciliation order, how workload apps are delivered
docs/aws-iam.md EKS Pod Identity, ACK controller IAM roles, per-cluster reader roles, the knr-ops-reader console user
docs/workload-resources.md S3 bucket security posture, RDS instances, known limitations
docs/konflate.md Rendered Flux PR review: GitHub Actions gate, in-cluster instance, write-back to PRs, tokens
docs/secrets.md SOPS + age secret management, key setup, credential rotation
docs/operations.md Toolbox runtime, prerequisites, quotas, bootstrap, pivot recovery, teardown, validation
docs/extending.md Adding a workload cluster, adding apps to the workload clusters, adding other providers (Azure, Talos, k0smotron)
docs/airgap.md Zarf air-gap bundle: package build, offline deploy, verification checklist, update drill

Repository layout

├── .github/workflows/             Validation, Rust/toolbox CI, signed releases
├── airgap/                        Zarf air-gap bundle, image inventory, scripts
├── bootstrap-rs/                  Lifecycle CLI, toolbox Dockerfile, Rust tests
├── bootstrap.toml                 Repository-owned lifecycle configuration
├── bootstrap.sh / pivot.sh /      Native shell references and fallback paths;
│   teardown.sh                    retained until both parity gates pass
├── scripts/toolbox-run.sh         Docker/Podman wrapper used by lifecycle tasks
├── tests/                         Config and Renovate coverage cross-checks
├── docs/                          Detailed documentation (see table above)
├── mise.toml / mise.*.toml        Pinned toolchain and AWS/local-host tasks
├── renovate.json5                 Hosted Renovate discovery and grouping rules
├── mgmt/aws/                      Synced by the MANAGEMENT cluster's Flux
│   ├── infrastructure/           cert-manager, CAPI operator, CAPA identity,
│   │                              ACK controllers, pod-identity roles,
│   │                              account-global IAM (reader console user),
│   │                              konflate (rendered Flux PR review)
│   ├── capi-providers/           capi-system, capa-system (SOPS creds),
│   │                              caaph-system
│   ├── addons/flux-apps/         Installs Flux on each workload cluster
│   │                              (HelmChartProxy + ClusterResourceSets)
│   └── clusters/                 EKS cluster defs: eu-north-1, eu-west-1
│                                  (ARM + GPU MachinePools); eu-north-1 also
│                                  carries the self-managed management cluster
├── mgmt/local-host/              OCI-synced CAPI/CAPD local workload cluster
│                                  and its management cluster definition
└── workload/                     Synced by each WORKLOAD cluster's Flux
    ├── base/                     ACK S3/RDS/IAM controllers, Bucket CRs,
    │                              DBInstance CRs, reader Role CRs
    ├── local-host/               OCI-synced Podinfo workload overlay
    ├── eu-north-01/              Per-cluster overlay (sync target)
    └── eu-west-01/               Per-cluster overlay (sync target)

License

This repository is licensed under the Apache License 2.0.

About

Kubernetes-Native Resource Operations

Resources

Stars

44 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages