Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Catallaxy is a declarative Kubernetes platform built on the NixOS module system. It lets you define multi-cluster environments entirely in Nix, producing rendered manifests and runtime tooling as build outputs — no imperative orchestration required.

The name

The term “catallaxy” comes from F.A. Hayek’s description of a spontaneous order: a complex, coordinated system that emerges not from central planning, but from independent actors following their own rules. In economics, this is the market. In catallaxy, it is your infrastructure.

Each component — cert-manager, ArgoCD, Prometheus, Kanidm, and many others — is a self-contained declaration. It defines its own options, its own defaults, and writes its own manifests into the appropriate deployment phase. No component knows the full picture. Yet through Nix’s lazy evaluation and the module system’s merge semantics, these independent declarations compose into a coherent, cross-referenced, multi-cluster platform.

There is no imperative glue. No ordering logic scattered across scripts. Components declare what they need, reference what they depend on, and the system resolves it all at build time.

What it does

You write Nix modules that describe your lab — its clusters, their components, networking, identity, observability, and anything else you need. Catallaxy evaluates those modules and produces:

  • Rendered Kubernetes manifests — Helm charts templated, typed resources serialized, raw YAML collected, all organized by deployment phase.
  • A deployment package — manifests bundled with metadata, ready for application via kapp, ArgoCD, or Fleet.
  • Runtime tooling — a CLI (cata) that handles cluster lifecycle, secret management, PKI, DNS, and operational commands defined in your lab configuration.

The system has two layers:

  • Nix modules define the configuration DSL, perform type checking, resolve cross-references between clusters, and render all manifests at build time.
  • A Rust CLI (cata) orchestrates runtime operations: evaluating Nix expressions, applying manifests to clusters, managing secrets, and running ops commands.

Status

Catallaxy is functional and in active use, but the API is not yet stable. Expect breaking changes between minor versions. Feedback and contributions are welcome.

Where to go from here

  • Getting Started — install prerequisites and stand up your first lab.
  • The architecture and component reference sections cover the internals in detail.

Why Catallaxy

Kubernetes platform engineering has an accidental complexity problem: YAML sprawl across environments, deployment ordering that lives in tribal knowledge, brittle bash glue that breaks silently, and a bootstrap chicken-and-egg that someone has to solve by hand every time.

Catallaxy treats your platform like a compilation problem. Declare components in typed Nix modules. Cross-cluster references resolve through lazy evaluation at build time. Phase ordering is a dependency graph, not a runbook. The same declarations compile to kapp, ArgoCD, or Fleet output without changing component code.

The problems we keep solving by hand

YAML sprawl

Every Kubernetes environment accumulates YAML. Helm values files for dev, staging, prod. Kustomize overlays stacked on top of overlays. Patches for patches. Across a multi-cluster platform, you end up with thousands of lines of templated configuration, most of it duplicated with minor variations. When something needs to change, you grep across directories and hope you found every copy.

Tribal knowledge

How do you deploy this platform from scratch? Which namespace needs to exist before the operator can start? What order do the Helm releases go in? Where does the CA certificate come from, and which components need it injected? The answers live in someone’s head, a runbook that’s three versions behind, or a Slack thread from last year. Every new team member re-discovers this the hard way.

Brittle procedural scripting

The gap between “here are my Helm charts” and “here is a running platform” gets filled with scripts. Bash that shells out to kubectl, helm, and jq in careful sequence. Python wrappers that parse YAML to generate more YAML. CI pipelines stitched together with retry loops, sleep statements, and post-deploy health checks that paper over ordering bugs. These scripts work until they don’t — and when they break, they break silently or in ways that are hard to diagnose.

The bootstrap problem

Your child clusters get GitOps, declarative config, drift detection, and automated reconciliation. But the management cluster that runs all of that? It was click-ops’d into existence on AWS. Someone followed a wiki page, clicked through a console, ran some Terraform, and manually applied a handful of Helm charts until ArgoCD was alive enough to take over.

The management plane is always manual. Always imperative. Always a special case that doesn’t get the same rigor as everything it manages. And when you need to rebuild it — disaster recovery, region migration, new environment — you discover how much institutional knowledge was baked into that original bootstrap sequence that nobody wrote down completely.

No type safety

Helm values are untyped YAML. A misspelled key is silently ignored. A wrong type produces valid YAML that fails at apply time — or worse, applies successfully and breaks at runtime. You find out when the on-call gets paged, not when the configuration was written. There is no compile step, no editor completion, no structural guarantee that what you wrote matches what the chart expects.

Non-reproducible builds

The same Helm chart, the same values file, can produce different output depending on the Helm binary version, which OCI registry responded, whether a transitive dependency was cached, or what the network looked like at build time. “It worked yesterday” is not an explanation, but it’s often all you have. Diffing what actually changed between two deploys requires forensic effort.

How Catallaxy addresses this

Catallaxy replaces ad-hoc tooling with a compiler-like approach: declare what you want, and the system resolves it into exactly the manifests each cluster needs.

Nix as the foundation

The NixOS module system provides typed options with defaults, lazy evaluation for cross-references, and deterministic builds. Your entire platform — every component, every cluster, every environment variation — is a single Nix expression that evaluates to a set of Kubernetes manifests. Cross-cluster references (like pointing one cluster’s OTEL collector at another cluster’s Tempo endpoint) resolve at build time through lazy evaluation. No runtime service discovery. No ordering scripts. No glue.

Single-file components

Each infrastructure component is a self-contained Nix module. It declares its own options, its own defaults, and writes its own manifests into the appropriate deployment phase. Want to understand what the cert-manager component does? Read one file. Want to add a new component? Write one file. There is no configuration scattered across multiple directories, no implicit dependencies between files, and no hidden wiring.

Phase-based ordering

CRDs before operators. Operators before infrastructure. Infrastructure before apps. This ordering is declared as a dependency graph that the build system resolves, not as a sequence of steps in a script. The bootstrap problem — which resources must exist before others can be created — becomes a build-time property. Phases that have no content are automatically dropped. The CLI deploys phases in order, waiting for CRDs to be established before deploying resources that depend on them.

Type-checked configuration

Kubernetes resources are typed from OpenAPI specs and CRD schemas. Helm values are structured Nix attrsets, not free-form YAML. Structural errors surface at nix eval time, before anything is rendered or applied. Your editor can provide completion. Your CI can catch misconfigurations. You find problems when you write the code, not when you deploy it.

Reproducible by construction

Manifests are Nix store derivations — content-addressed, cacheable, and deterministic. Same inputs always produce the same outputs, regardless of when or where you build them. You can diff the rendered manifests between any two configurations and see exactly what changed, down to the individual YAML resource. No forensic effort required.

Multiple deployment targets

The same component declarations compile to output for kapp (direct apply), ArgoCD, or Fleet. Switching deployment strategy is a single option change — no component code needs to be rewritten. The rendering pipeline transforms the same intermediate representation into strategy-specific directory layouts and metadata.

Who this is for

Catallaxy is for platform engineers and DevOps practitioners who:

  • Have felt the pain of managing multi-cluster Kubernetes environments with ad-hoc tooling
  • Are comfortable with (or willing to learn) Nix as an infrastructure tool
  • Want their platform defined in code that is typed, reproducible, and reviewable
  • Are tired of tribal knowledge and want a single source of truth that compiles

If you recognize that Nix’s guarantees — purity, reproducibility, lazy evaluation, composability — are exactly what infrastructure configuration needs, this project is for you.

Getting started

See Prerequisites to set up your environment, then walk through the Quick Start to stand up a working multi-cluster lab.

Prerequisites

Catallaxy requires two things on your system. Everything else is provided by the flake.

Nix with flakes enabled

Install Nix using the Determinate Systems installer, which enables flakes by default:

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -o install-self

If you already have Nix installed, ensure flakes are enabled. Add the following to ~/.config/nix/nix.conf if it is not already present:

experimental-features = nix-command flakes

Docker

A running Docker daemon is required for local development. Catallaxy uses k3d to run K3s clusters inside Docker containers.

Install Docker through your system’s package manager or from docker.com. Verify it is running:

docker info

That is everything

You do not need to install kubectl, Helm, kapp, k3d, talosctl, or any other Kubernetes tooling. The catallaxy flake provides all of these through its dev shell. When you run nix develop, every tool the CLI needs is available on your PATH.

This is intentional. Pinning tool versions in the flake eliminates “works on my machine” issues and ensures the CLI, the manifest renderer, and the cluster tooling all agree on versions.

Quick Start

This guide walks you through standing up the example homelab — a multi-cluster local environment with networking, identity, GitOps, observability, and more — all running in Docker via k3d.

Clone the repository

git clone https://github.com/onepunchtech/catallaxy.git
cd catallaxy

Enter the dev shell

nix develop

This drops you into a shell with every tool catallaxy needs: cata, kubectl, helm, kapp, k3d, and others. You do not need any of these installed on your system.

Bring the lab up

cata --flake ./examples/labs#homelab.local lab up

This is the main command. It evaluates the lab configuration defined in examples/labs/flake.nix for the lab named homelab, provisions k3d clusters, and applies all rendered manifests in phase order. Phases run from CRDs and namespaces through networking, operators, infrastructure, GitOps, databases, and applications.

The --flake ./examples/labs#homelab argument points to the flake directory and selects the homelab lab by name. This pattern is used for all cata commands.

Set up DNS

cata --flake ./examples/labs#homelab.local lab dns --setup

Configures your local DNS resolution so that *.homelab.test domains route to the lab’s ingress. This lets you access services by name in your browser without editing /etc/hosts.

Trust the lab CA

cata --flake ./examples/labs#homelab.local lab trust --setup

Adds the lab’s certificate authority to your system’s trust store. The lab generates its own CA via cert-manager, and this command ensures your browser and CLI tools trust the TLS certificates it issues. Without this, you will see certificate warnings on every service.

Verify the lab is running

cata --flake ./examples/labs#homelab.local lab status

Shows the state of each cluster and its components. Once everything is healthy, the lab’s services are accessible at their configured domains:

Additional services depend on which components are enabled in the lab configuration.

Tear it down

cata --flake ./examples/labs#homelab.local lab down      # stop clusters (preserves state)
cata --flake ./examples/labs#homelab.local lab destroy    # delete everything

lab down stops clusters but preserves state — run lab up to restart. lab destroy deletes clusters, services, and network completely.

Next steps

The example lab is a useful reference, but the real power is defining your own. See Creating Your Own Lab to set up a standalone flake that imports catallaxy as an input.

Creating Your Own Lab

The example lab is bundled with catallaxy for reference, but real usage starts with your own flake. You define your lab topology in Nix modules and catallaxy evaluates them into rendered manifests and runtime tooling.

Quick start

nix flake init -t github:onepunchtech/catallaxy#consumer

This creates a working consumer flake with a custom component example.

Minimal flake

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    catallaxy.url = "github:onepunchtech/catallaxy";
  };

  outputs = { nixpkgs, flake-utils, catallaxy, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        mkLab = catallaxy.${system}.mkLab;
      in {
        labs."my-platform" = (mkLab {
          modules = [ ./lab.nix ];
        }).config.lab.out.cliConfig;
      }
    );
}

mkLab takes a list of NixOS-style modules and evaluates them through catallaxy’s module system — the same one that powers the example labs.

Define your lab topology

Create lab.nix alongside the flake:

{ config, lib, ... }:
{
  lab.name = "my-platform";
  lab.dns.zone = "mylab.test";

  lab.clusters.app = { ... }: {
    cluster.name = "app";
    cluster.kubernetes = {
      distribution = "k3s";
      controlPlanes = 1;
      workers = 0;
    };

    components.cert-manager.enable = true;
    components.gateway.enable = true;
  };
}

Each component is a self-contained module. Enabling it causes it to write its Helm charts, resources, and configuration into the appropriate deployment phase. The phase system handles ordering and dependencies.

Custom components

Add your own components as modules:

mkLab {
  modules = [
    ./lab.nix
    ./components/my-app.nix    # Custom component
  ];
}

See Writing Components for the full guide.

Splitting configuration across files

As your lab grows, split it into aspects (features), clusters, and environment overlays:

mkLab {
  modules = [
    ./topology.nix        # Cluster definitions
    ./networking.nix       # Gateway, DNS, cert-manager
    ./identity.nix         # Kanidm users, groups, OAuth2
    ./observability.nix    # Prometheus, Loki, Grafana
    ./env/local.nix        # Environment-specific overrides
  ];
};

This is the pattern the example lab uses: aspects define features, clusters compose aspects, and environments provide thin overrides for local, staging, or production targets.

Cross-cluster references

Components can reference values from other clusters through the lab argument:

{ config, lab, ... }:
{
  components.otel-collector = {
    enable = true;
    exporters.otlp.endpoint = lab.clusters.obs.components.tempo.ref.otlpGrpc;
  };
}

Every component exposes a ref attribute set with computed, read-only values — endpoints, namespaces, service names. Refs are always available, even when the component is disabled.

Running your lab

nix develop github:onepunchtech/catallaxy
cata --flake '.#my-platform' lab up
cata --flake '.#my-platform' lab down       # Stop (preserves state)
cata --flake '.#my-platform' lab destroy    # Delete everything

Building manifests without applying

nix build '.#labPackages.x86_64-linux."my-platform"'

This produces the full deployment package — manifests, metadata, images list, and ops tooling — as a store path you can inspect, diff, or ship to CI.

Architecture Overview

Catallaxy is a declarative Kubernetes platform built on two foundations: the NixOS module system for configuration and manifest rendering, and a Rust CLI for runtime orchestration. This separation keeps the build-time logic pure and reproducible while giving operators a single command-line tool for day-to-day cluster management.

Two-Layer System

flowchart TD
    A["User Configuration<br/>(Nix modules / flake)"]
    B["<b>Nix Layer</b> (build-time)<br/>Module evaluation<br/>Type checking & defaults<br/>Helm template rendering<br/>Typed K8s resource generation<br/>Strategy-specific output<br/>(kapp / argocd / fleet)"]
    C["<b>Rust CLI</b> (runtime)<br/>Cluster provisioning (k3d)<br/>Manifest application (kapp)<br/>Secret injection (SOPS)<br/>PKI management<br/>Backup/restore (Velero)<br/>CAPI bootstrap & pivot"]
    D["Kubernetes Clusters"]

    A -->|"nix eval / nix build"| B
    B -->|"JSON config + store paths"| C
    C -->|"kubectl / kapp"| D

Nix layer – Everything that can be computed at build time lives here. The NixOS module system evaluates lab and cluster configurations, resolves cross-references between components and clusters, renders Helm charts via helm template, generates typed Kubernetes resources, and packages everything into Nix store derivations. The output is deterministic: the same configuration always produces the same manifests.

Rust CLI – The cata binary handles operations that require interacting with the outside world: provisioning clusters, applying manifests, managing secrets, issuing PKI certificates, and orchestrating CAPI bootstrap sequences. It calls nix eval and nix build to obtain configuration data and rendered manifests, then uses external tools (kubectl, kapp, k3d, sops, velero) to act on them.

Multipass Compiler Analogy

The system can be understood as a multi-pass compiler where Kubernetes manifests are the compiled output:

PassWhat it doesWhere it lives
DeclarationHigh-level NixOS options define the user interface. Components declare options like enable, namespace, phase, and domain-specific settings.modules/lab/cluster/components/
Intermediate RepresentationsThe module system computes intermediate representations: phase bundles (Helm charts + typed resources + raw YAML), provisioning config, cluster topology, and software bill of materials.modules/lab/cluster/out.nix, modules/lab/out.nix
Target RenderingStrategy-specific renderers transform the IR into deployment-ready output for kapp, ArgoCD, or Fleet. Each renderer produces a different directory layout.lib/renderers/kapp.nix, lib/renderers/argocd.nix, lib/renderers/fleet.nix

This multi-pass design means the same component declarations can target different CD systems without changing any component code.

Separation of Eval, Build, and Runtime

The three phases have distinct responsibilities and never cross boundaries:

Eval Phase (nix eval)

The CLI calls nix eval --json to obtain cluster and lab configuration as JSON. This evaluates the module system but does not build any derivations. The result contains:

  • Cluster metadata (name, provider, network config)
  • Component settings (enabled state, versions, namespaces)
  • Provisioner configuration (k3d cluster names, images, ports)
  • Lab topology (cluster names, services, DNS info)

Build Phase (nix build)

When manifests are needed, the CLI calls nix build on the lab package or cluster manifests output. This triggers Helm chart rendering, resource serialization, and strategy-specific packaging – all inside the Nix sandbox. The output is a Nix store path containing:

  • Numbered phase directories (00-crds/, 01-namespaces/, etc.)
  • Rendered YAML manifests within each phase
  • A .phase-order file encoding deployment sequence
  • A .deploy-config file with strategy-specific settings
  • A metadata.json file with topology and SBOM data

Runtime Phase (cata CLI)

The CLI reads the built store paths and orchestrates deployment:

  1. Provision clusters via k3d (or CAPI bootstrap for production)
  2. Discover phases from the rendered manifest directory
  3. Deploy phases sequentially via kapp, injecting SOPS secrets at the appropriate phase boundaries
  4. Wait for CRDs to be established before deploying phases that depend on them

This separation means Nix never needs network access during builds (no import-from-derivation), and the CLI never needs to understand Helm charts or Nix module evaluation.

Lab, Cluster, and Component Hierarchy

Catallaxy organizes infrastructure in a four-level hierarchy: Lab > Cluster > Component > Phase/Bundle. Each level adds structure and enables cross-references that the NixOS module system resolves through lazy evaluation.

Labs

A lab is a multi-cluster environment. It defines which clusters exist, how they relate to each other, what infrastructure services run alongside them (DNS, registry, ingress proxy), and what deployment strategy to use.

# examples/labs/labs/default.nix
{ config, lib, ... }:
{
  lab.name = "homelab.local";
  lab.cd.strategy = "kapp";

  lab.clusters.core = { imports = [ ../clusters/core.nix ]; };
  lab.clusters.obs  = { imports = [ ../clusters/obs.nix ]; };
  lab.clusters.mgmt = { imports = [ ../clusters/mgmt.nix ]; };
}

Labs provide:

  • Cluster composition – Which clusters exist and what modules they import
  • Shared infrastructure – DNS servers, container registries, TLS ingress proxies (all managed as Docker containers alongside the clusters)
  • Deployment strategy – Whether to render output for kapp (direct apply), ArgoCD, or Fleet
  • Ops commands – Component-aware shell scripts for operational tasks like resetting passwords or triggering backups
  • Environment layering – A lab is composed from aspects (feature modules) and environment deltas (provisioner, DNS, TLS settings) via mkLab

Example Lab Structure

examples/labs/
  flake.nix                # Composes: mkLab [ labs/default.nix envs/local.nix ]
  aspects/                 # Pure feature modules (no env awareness)
    networking.nix
    identity.nix
    gitops.nix
  clusters/                # Aspect composition
    core.nix               # = networking + identity + gitops + ...
    obs.nix                # = networking + monitoring
  labs/
    default.nix            # Lab topology + shared ops
  envs/                    # Thin environment deltas
    local.nix              # k3d provisioner, local DNS
    prod.nix               # DO provisioner, ACME TLS

This layering means the same cluster definitions can target local k3d development or production cloud clusters by swapping only the environment file.

Clusters

A cluster is a single Kubernetes cluster with its own set of enabled components, phase ordering, and provisioner configuration. Clusters are defined as NixOS module evaluations within a lab.

# examples/labs/clusters/core.nix
{ config, lib, lab, ... }:
{
  imports = [
    ../aspects/networking.nix
    ../aspects/identity.nix
    ../aspects/gitops.nix
  ];

  cluster.name = "core";
  cluster.kubernetes.version = "1.31";
  cluster.kubernetes.workers = 0;
}

Each cluster configuration produces:

  • cluster.out.phases – Merged phase bundles with rendered manifest derivations
  • cluster.out.phaseOrder – Sorted list of phase names for deployment sequencing
  • cluster.out.topology – Computed topology map (name, provider, nodes, network, enabled components)
  • cluster.out.sbom – Software bill of materials (component versions)

Components

A component is a self-contained infrastructure unit defined in a single Nix file. Components declare their own options and write Helm charts, typed Kubernetes resources, or raw YAML into phase bundles when enabled.

The Single-File Component Pattern

Every component follows this structure:

# modules/lab/cluster/components/<category>/<name>.nix
{ config, lib, cataCharts, k8sSpecs, ... }:
let
  cfg = config.components.<name>;
in
{
  # 1. Option declarations
  options.components.<name> = {
    enable = lib.mkEnableOption "<Name>";

    phase = lib.mkOption {
      type = lib.types.str;
      default = "<phase>";
      description = "Deployment phase";
    };

    namespace = lib.mkOption {
      type = lib.types.str;
      default = "<name>";
    };

    chart = lib.mkOption {
      type = lib.types.package;
      default = cataCharts.<name>.chart;
    };

    ref = lib.mkOption {
      type = lib.types.attrs;
      readOnly = true;
      description = "Computed references for cross-component wiring";
    };

    # ... domain-specific options
  };

  # 2. Configuration (always evaluated, even when disabled)
  config = lib.mkMerge [
    # Computed refs -- always available so other components can reference them
    {
      components.<name>.ref = {
        namespace = cfg.namespace;
        serviceName = "<name>";
        port = 8080;
        url = "http://${cfg.ref.serviceName}.${cfg.ref.namespace}.svc:${toString cfg.ref.port}";
      };
    }

    # Phase writer -- only active when enabled
    (lib.mkIf cfg.enable {
      phases.${cfg.phase}.bundles.<name> = {
        createNamespaces = [ cfg.namespace ];
        helmCharts.<name> = {
          chart = cfg.chart;
          namespace = cfg.namespace;
          releaseName = "<name>";
          values = {
            # Helm values here
          };
        };
      };
    })
  ];
}

The ref Pattern

The ref attribute is the key mechanism for cross-component wiring. It is:

  • readOnly – Set by the component itself, not overridable by users
  • Always computed – Available even when the component is disabled, so other components can safely reference it without guards
  • Lazy – Nix’s lazy evaluation means the ref values are only computed when accessed

This enables patterns like:

# In the OTEL collector component
config.components.otel-collector.exporters.otlp.endpoint =
  config.components.tempo.ref.otlpGrpcEndpoint;

The OTEL collector can reference Tempo’s endpoint regardless of evaluation order. If Tempo is disabled, the ref still exists (with its default values), though the OTEL collector’s configuration would need to handle that case.

Cross-Cluster References via lab

Components receive a lab argument that provides access to all clusters in the lab. This enables cross-cluster wiring through Nix’s lazy evaluation:

# In core cluster's OTEL collector
{ config, lib, lab, ... }:
{
  components.otel-collector.exporters.otlp.endpoint =
    lab.clusters.obs.components.tempo.ref.otlpGrpc;
}

This works because:

  1. The lab evaluates all clusters as NixOS modules with a shared lab argument
  2. Nix’s lazy evaluation means cluster A can reference cluster B’s computed values without creating circular dependencies (as long as the dependency graph is acyclic at the value level)
  3. The ref pattern ensures the target values exist even if the referenced component is disabled

Practical Example: Observability Pipeline

flowchart LR
    subgraph core["core cluster"]
        A["otel-collector<br/>(agent mode)"]
    end
    subgraph obs["obs cluster"]
        B["otel-gateway<br/>(gateway mode)"]
        C["loki / tempo"]
    end

    A -->|"OTLP/gRPC"| B
    B --> C

The core cluster’s OTEL collector is configured to export to the obs cluster’s gateway endpoint. This endpoint URL is computed from the obs cluster’s component refs and resolved at Nix evaluation time – no runtime service discovery needed.

Registering New Components

When adding a new component:

  1. Create the component file at modules/lab/cluster/components/<category>/<name>.nix
  2. Add the import to modules/lab/cluster/components/<category>/default.nix
  3. If creating a new category, add it to modules/lab/cluster/components/default.nix

When adding a new Helm chart for a component:

  1. Add the chart definition to lib/charts.nix with repository URL, version, and content hash

Manifest Rendering Pipeline

The manifest pipeline transforms high-level component declarations into deployment-ready Kubernetes YAML. It runs entirely at Nix build time, producing deterministic output in the Nix store.

Pipeline Stages

flowchart TD
    A["<b>1. Bundle Accumulation</b><br/>(per-phase)"]
    B["<b>2. Phase Merging</b><br/>(cluster.out.phases)"]
    C["<b>3. Strategy Rendering</b><br/>(kapp / argocd / fleet)"]
    D["<b>4. Lab Packaging</b><br/>(lab.out.package)"]
    E["Nix store path"]

    A -->|"helmCharts, resources, yamls,<br/>createNamespaces into bundles"| B
    B -->|"merge bundles per phase<br/>into single derivations"| C
    C -->|"strategy-specific renderer"| D
    D -.->|"all clusters' manifests +<br/>metadata.json"| E

Stage 1: Bundle Accumulation

Components write their Kubernetes resources into bundles within their assigned phase. A bundle is the finest-grained deployment unit and can contain three types of content:

phases.${cfg.phase}.bundles.cert-manager = {
  # Namespaces to create (collected across all phases, created in the namespaces phase)
  createNamespaces = [ cfg.namespace ];

  # Helm charts to render via helm template
  helmCharts.cert-manager = {
    chart = cfg.chart;
    namespace = cfg.namespace;
    releaseName = "cert-manager";
    values = {
      crds.enabled = true;
      replicaCount = 1;
    };
    extraOpts = [ "--include-crds" ];
    kustomize = {
      enable = false;
      patches = [];
      resources = [];
    };
  };

  # Typed Kubernetes resources (checked by the NixOS module type system)
  resources.lab-ca-issuer = {
    apiVersion = "cert-manager.io/v1";
    kind = "ClusterIssuer";
    metadata.name = "lab-ca";
    spec.ca.secretName = "lab-ca-ca-secret";
  };

  # Raw YAML (strings, paths, or derivations)
  yamls = [ ];
};

Helm Charts

Helm charts are rendered using helm template inside a Nix derivation (lib/render.nix:renderHelmChart). The rendering process:

  1. Writes values.yaml from the Nix attrset
  2. Runs helm template with the specified release name, namespace, and extra options
  3. Post-processes the output to inject metadata.namespace into namespaced resources (since helm template does not apply namespace like helm install does)
  4. Optionally applies kustomize patches if kustomize.enable = true

Typed Resources

Resources defined in resources are Nix attribute sets that conform to Kubernetes API types generated from OpenAPI specs and CRDs. The type system catches structural errors at nix eval time.

Raw YAML

The yamls list accepts strings (inline YAML), paths, or derivations. CRD YAML files are automatically split by API group for manageability.

Stage 2: Phase Merging

The cluster.out.phases option (modules/lab/cluster/out.nix) merges all bundles within each phase:

  1. Collect all namespaces from all bundles across all phases
  2. Merge bundle contents per phase: fold all helmCharts, resources, and yamls from all bundles in that phase
  3. Inject namespace YAMLs into the namespaces phase
  4. Render derivations via render.renderPhase, which produces a store path containing all YAML files for that phase
  5. Filter empty phases – phases with no content are dropped

The result is an attrset where each key is a phase name and each value contains:

{
  order = 10;           # Numeric ordering
  dependsOn = [ ... ];  # Phase dependencies
  keepResources = false;
  pruneStrategy = "default";
  waitForReady = true;
  timeout = "10m";
  waitForCRDs = false;
  crdNames = [];
  package = <derivation>;  # Rendered YAML files
}

Stage 3: Strategy Rendering

The lab.out.manifests option (modules/lab/out.nix) passes each cluster’s merged phases through a strategy-specific renderer from lib/renderers/. The lab’s cd.strategy setting selects the renderer.

kapp Renderer

Produces a flat directory structure with numbered phase directories:

kapp-core/
  core/
    00-crds/
      cilium-crds.yaml
    01-namespaces/
      namespaces-resources.yaml
    02-networking/
      cilium.yaml
      traefik.yaml
    03-operators/
      cert-manager.yaml
    ...
    .phase-order          # Ordered list of phase names
    .deploy-strategy      # "kapp"
    .deploy-config        # waitTimeout: 10m

The kapp renderer also applies resource name prefixing (when lab.prefix is set) and generates .crd-wait files for phases that require CRDs to be established before deployment.

ArgoCD Renderer

Produces Application and ApplicationSet resources that point to a git repository. The rendered manifests are organized for ArgoCD to discover and sync.

Fleet Renderer

Produces Bundle resources for Rancher Fleet, with similar directory organization but Fleet-specific metadata.

Stage 4: Lab Packaging

The lab.out.package option combines all clusters’ rendered manifests into a single Nix derivation:

lab-homelab.local/
  metadata.json           # Pretty-printed lab metadata
  manifests/
    core -> /nix/store/...-kapp-core/core
    obs  -> /nix/store/...-kapp-obs/obs
    mgmt -> /nix/store/...-kapp-mgmt/mgmt
  bin/
    homelab.local-ops     # Lab ops tool (if defined)

The metadata.json file contains:

  • Lab name and prefix
  • List of cluster names
  • CD strategy and config
  • Per-cluster topology (provider, nodes, network, enabled components)
  • Per-cluster software bill of materials (component versions)
  • Per-cluster namespace lists (used by lint checks)

How the CLI Consumes the Pipeline Output

When the user runs cata lab up, the CLI:

  1. Calls nix eval to get the lab’s CLI config (cluster names, services, DNS, etc.)
  2. Provisions infrastructure services (DNS, registry, ingress) as Docker containers
  3. Provisions each cluster via k3d
  4. Calls nix build on the lab package, triggering the full rendering pipeline
  5. For each cluster, discovers phases from the .phase-order file
  6. Deploys phases sequentially via kapp, waiting for CRDs and injecting SOPS secrets at phase boundaries

The cata lab publish command follows the same build step but instead pushes the rendered manifests to a git repository for GitOps consumption.

Built-in Phase Ordering

Phases are deployed in numeric order. The built-in phases and their default ordering:

OrderPhasePurpose
-10crdsCustom Resource Definitions
-5namespacesNamespace creation (auto-collected from all bundles)
0networkingCNI, gateway, service mesh
10operatorsOperator deployments (cert-manager, CNPG, etc.)
20secretsSecret injection and external secret sync
30infrastructureInfrastructure services (DNS, storage, registries)
40gitopsGitOps controllers (ArgoCD)
50databasesDatabase instances
90appsApplication workloads
100workloadsUser workloads

Components select their phase via the phase option. Phases that end up empty (no bundles with content) are automatically excluded from the rendered output.

The NixOS Module System

Catallaxy uses the NixOS module system as its configuration engine. This is the same system that powers NixOS (the Linux distribution), but applied to Kubernetes cluster configuration instead of operating system configuration. This page explains why it was chosen and how Catallaxy uses its key features.

Why NixOS Modules

The NixOS module system provides several properties that are difficult to achieve with other configuration tools:

Type Checking at Evaluation Time

Every option has a declared type. When a user sets a value that does not match the expected type, the error is caught during nix eval – before any manifest is rendered or any cluster is touched.

# This declaration...
options.components.cert-manager.namespace = lib.mkOption {
  type = lib.types.str;
  default = "cert-manager";
};

# ...means this is caught immediately:
components.cert-manager.namespace = 42;
# error: A definition for option `components.cert-manager.namespace`
# is not of type `string`.

The type system extends to complex structures. Kubernetes resources are typed using NixOS module types generated from OpenAPI specs and CRDs, so structural errors in resource definitions are caught at evaluation time rather than at apply time.

Lazy Evaluation and Cross-References

Nix is a lazy language: values are only computed when they are needed. This enables circular module references that would cause infinite loops in eager languages.

# Module A sets a value that references module B
config.components.otel-collector.endpoint =
  config.components.tempo.ref.otlpGrpc;

# Module B sets a value that references module A
config.components.tempo.forwarders =
  [ config.components.otel-collector.ref.receiverEndpoint ];

As long as the dependency graph is acyclic at the value level (no value depends on itself), Nix resolves everything correctly. This is what makes the ref pattern and cross-cluster references possible.

Merge Semantics

When multiple modules set the same option, the module system merges them according to the option’s type:

  • Attribute sets are recursively merged
  • Lists are concatenated
  • Scalars cause an error (unless one uses mkDefault, mkForce, or priority)

This is how components from different files accumulate bundles into the same phase without coordination:

# cert-manager writes to phases.operators.bundles
phases.operators.bundles.cert-manager.helmCharts.cert-manager = { ... };

# prometheus also writes to phases.operators.bundles
phases.operators.bundles.prometheus.helmCharts.prometheus = { ... };

The module system merges these two definitions into a single phases.operators.bundles attrset.

Defaults and Overrides

Options can have defaults (mkDefault), and users can override them at multiple priority levels:

# Component sets a default phase
phase = lib.mkDefault "operators";

# User overrides it in their cluster config
components.cert-manager.phase = "infrastructure";

This enables the environment layering pattern: aspects define feature defaults, and environment deltas override provisioner settings, DNS configuration, and TLS mode.

Assertions

Modules can declare assertions that are checked after evaluation:

config.assertions = [
  {
    assertion = config.components.cert-manager.acme.enable
                -> config.components.cert-manager.acme.email != "";
    message = "ACME email must be set when ACME is enabled";
  }
];

Failed assertions are collected and reported as a single error, giving the user a complete list of problems to fix.

The out Pattern

Computed output values follow a convention of being placed under an out attribute. These are readOnly options that the module system computes from other configuration values.

Cluster-Level out

cluster.out (modules/lab/cluster/out.nix) computes:

  • topology – Name, provider, node counts, network config, and which components are enabled
  • sbom – Software bill of materials (component versions)
  • phases – Merged phase bundles rendered as Nix store derivations
  • phaseOrder – Sorted list of phase names
# cluster.out.phases is computed by merging all bundles per phase
# and rendering them through lib/render.nix
config.cluster.out.phases = let
  mergePhase = phaseName: phaseCfg:
    let
      bundleValues = lib.attrValues phaseCfg.bundles;
      allHelmCharts = lib.foldl' (acc: b: acc // b.helmCharts) {} bundleValues;
      allResources  = lib.foldl' (acc: b: acc // b.resources) {} bundleValues;
      allYamls      = lib.concatMap (b: b.yamls) bundleValues;
    in
    render.renderPhase phaseName {
      helmCharts = allHelmCharts;
      resources  = allResources;
      yamls      = allYamls;
    };
in
  lib.mapAttrs mergePhase config.phases;

Lab-Level out

lab.out (modules/lab/out.nix) computes:

  • cliConfig – JSON-serializable config that the Rust CLI needs (cluster names, services, DNS, registry, ops tool path)
  • allClusters – All evaluated cluster configs (used for cross-cluster references)
  • manifests – Per-cluster rendered manifest packages, passed through the strategy renderer
  • package – Single derivation combining all clusters’ manifests with metadata

Component-Level ref

Components use ref for their computed outputs. Unlike out, refs are always set (even when the component is disabled) so that other components can reference them safely:

config = lib.mkMerge [
  # Always set, regardless of enable state
  {
    components.tempo.ref = {
      namespace = cfg.namespace;
      otlpGrpc = "tempo-distributor.${cfg.namespace}.svc:4317";
      otlpHttp = "tempo-distributor.${cfg.namespace}.svc:4318";
    };
  }

  # Only writes to phases when enabled
  (lib.mkIf cfg.enable {
    phases.${cfg.phase}.bundles.tempo = { ... };
  })
];

Avoiding Import From Derivation (IFD)

Import From Derivation (IFD) occurs when Nix needs to build a derivation during evaluation in order to import its output. IFD breaks parallelism, defeats caching, and makes evaluation unpredictable.

Catallaxy avoids IFD by keeping all configuration data as Nix expressions:

  • Helm chart references are Nix store paths (fetched at flake lock time, not at eval time)
  • Kubernetes API types are pre-generated Nix files committed to the repository
  • Component configurations are pure Nix attrsets, not derived from external data

The only place derivations appear during evaluation is in out options that produce store paths for rendered manifests. These are types.raw or types.package options that Nix builds lazily – they are not imported back into the evaluation.

Module Evaluation Entry Points

The Rust CLI interacts with the Nix module system through two flake outputs:

clusters.<system>.<name> (eval)

Returns a JSON-serializable representation of a cluster’s configuration. The lib/eval.nix:clusterConfigToJSON function strips the evaluated config down to the fields the CLI needs.

labPackages.<system>."<name>" (build)

Triggers a full build of the lab package, producing rendered manifests for all clusters. This is the primary entry point for cata lab up and cata lab apply.

The CLI uses nix eval --json for the first and nix build --no-link --print-out-paths for the second, keeping a clean separation between configuration inspection and manifest production.

Nix-Specific Conventions

A few conventions specific to how Catallaxy uses the module system:

  • Do not use mkIf inside resources or yamls values. Use lib.optionalAttrs or if/then/else instead. mkIf produces a NixOS module merge operation, which does not work inside attribute values that are passed directly to derivation builders.
  • Charts come from cataCharts.<name>, defined in lib/charts.nix. Components accept a chart option so users can override the chart derivation.
  • Lab names support dots (e.g., homelab.local). The CLI quotes them in nix eval: labs.{system}."homelab.local".
  • All ref attributes are readOnly, preventing users from accidentally overriding computed wiring values.

The Rust CLI

The cata binary is a Rust CLI built with clap and tokio. It handles all runtime operations: provisioning clusters, applying manifests, managing secrets and PKI, orchestrating backups, and bootstrapping CAPI management clusters.

The CLI does not contain any Kubernetes manifest logic. It delegates configuration evaluation and manifest rendering to Nix, then uses external tools (kubectl, kapp, k3d, sops, velero, clusterctl, ykman) to act on the results.

Global Options

cata [OPTIONS] <COMMAND>

Options:
  --flake <FLAKE>    Flake reference (path, URL, or ref#name) [env: CATALLAXY_FLAKE] [default: .]
  -v, --verbose      Verbose output

The --flake flag specifies the Nix flake containing the lab/cluster configuration. The fragment after # (e.g., ./examples/labs#homelab.local) is used as the default lab or cluster name for subcommands.

How the CLI Interacts with Nix

The CLI communicates with the Nix layer through two mechanisms:

nix eval --json – Used to read configuration without building anything. Returns cluster config, lab config, or cluster/lab name lists as JSON.

nix build --no-link --print-out-paths – Used to build rendered manifests. Returns the Nix store path containing the built output.

The CLI resolves flake references (path + optional fragment) and constructs the correct attribute path for each operation. For example, cata --flake ./examples/labs#homelab.local lab up evaluates labs.x86_64-linux."homelab.local" and builds labPackages.x86_64-linux."homelab.local".

Runtime Dependencies

The CLI shells out to external tools that must be available in PATH. When built via nix build .#cata, all runtime tools are wrapped into the binary’s path. Inside nix develop, they are provided by the dev shell.

Required tools: nix, docker, kubectl, kapp, k3d

Optional tools (command-specific): sops, velero, clusterctl, ykman, certutil, gh/glab

Components Overview

Catallaxy ships with built-in components. Each component is a self-contained module that declares configuration options and writes Kubernetes resources into deployment phases when enabled.

Components are defined in modules/lab/cluster/components/. Enable them in your cluster configuration with components.<name>.enable = true.

Component catalog

CNI

ComponentDescription
ciliumeBPF-based CNI and network policy engine. Provides pod networking, service mesh, and network observability.

Gateway

ComponentDescription
gatewayGateway API controller (Traefik). Manages ingress via HTTPRoute and TLSRoute resources. Configures TLS termination and passthrough.

PKI

ComponentDescription
cert-managerX.509 certificate management. Automates certificate issuance and renewal using the lab CA or ACME.
trust-managerDistributes CA bundles across namespaces as ConfigMaps. Ensures all services trust the lab CA.

Observability

ComponentDescription
prometheusMetrics collection and alerting (kube-prometheus-stack). Includes Prometheus, Alertmanager, and recording/alerting rules.
grafanaDashboards and visualization. Connects to Prometheus, Loki, and Tempo as data sources. Supports OIDC login via Kanidm.
lokiLog aggregation. Receives logs from OpenTelemetry collectors and provides LogQL query interface.
tempoDistributed tracing backend. Receives traces via OTLP and integrates with Grafana.
otel-collectorOpenTelemetry Collector. Deployed as agent (DaemonSet) and/or gateway (Deployment) to collect and forward logs, metrics, and traces.

Databases

ComponentDescription
cnpgCloudNativePG operator. Manages PostgreSQL clusters with automated failover, backups, and connection pooling.
redis-operatorRedis operator. Manages Redis instances and clusters.

Filesystems

ComponentDescription
openebsLocal persistent volume provisioner. Provides storage classes backed by node-local paths.
seaweedfsDistributed object storage. Provides S3-compatible storage for backups, Loki chunks, and Tempo blocks.

Registries

ComponentDescription
zotOCI-compliant container registry. Lightweight registry for local image caching and distribution.

Secrets

ComponentDescription
external-secretsSyncs secrets from external providers (Vault, AWS, etc.) into Kubernetes Secrets.
sopsSOPS-based secret decryption. Decrypts encrypted secret files at deployment time.

Identity

ComponentDescription
kanidmIdentity provider. Provides OIDC/OAuth2 authentication, user management, and WebAuthn/TOTP support.
kaniopKanidm operator. Declaratively manages Kanidm users, groups, and OAuth2 client registrations as Kubernetes resources.

GitOps

ComponentDescription
argocdArgo CD continuous delivery. Manages application deployments from Git repositories. Supports OIDC login via Kanidm.

Source Control

ComponentDescription
forgejoSelf-hosted Git forge. Lightweight GitHub/Gitea alternative with OAuth2 login, issue tracking, and CI integration.

Provisioning

ComponentDescription
cluster-apiCluster API operator (CAPI). Provisions and manages Kubernetes clusters declaratively.
crossplaneCrossplane universal control plane. Manages cloud infrastructure (DNS, compute, storage) as Kubernetes resources.

DNS

ComponentDescription
external-dnsSynchronizes Kubernetes Gateway/Ingress resources with external DNS providers (CoreDNS, Cloudflare, Route53).

VPN

ComponentDescription
netbirdWireGuard-based mesh VPN. Provides secure connectivity between clusters and external networks.

Backups

ComponentDescription
veleroCluster backup and restore. Supports scheduled backups to S3-compatible storage and cross-cluster migration.

Custom

ComponentDescription
customDeploy custom applications using components.custom.apps.<name>. Supports Helm charts, typed resources, raw YAML, and Gateway API routing without writing a full component module. See the Custom Components recipe.

Cross-component wiring

Components expose computed values through ref attributes. These are always available, even when the component is disabled, allowing safe cross-references:

{ config, ... }:
let
  certManagerRef = config.components.cert-manager.ref;
  kanidmRef = config.components.kanidm.ref;
in
{
  # Use certManagerRef.caBundleConfigMap, kanidmRef.oidcEndpoint, etc.
}

For cross-cluster references, use the lab argument:

{ lab, ... }:
{
  components.otel-collector.exporters.otlp.endpoint =
    lab.clusters.obs.components.tempo.ref.otlpGrpc;
}

See Adding Components for the full component authoring guide.

Homelab OIDC Setup

This recipe walks through standing up the example homelab with full OIDC authentication. By the end, you will have a local Kubernetes lab where ArgoCD, Grafana, and Forgejo all authenticate through Kanidm as the identity provider.

Prerequisites

  • Nix with flakes enabled
  • Docker (for k3d)
  • Enter the dev shell: nix develop

Step 1: Start the lab

cata --flake ./examples/labs#homelab lab up

This provisions all clusters defined in the lab (by default, a core cluster and an obs cluster via k3d), evaluates the Nix modules, renders manifests, and applies them phase by phase. The process takes several minutes on first run as Helm charts are templated and resources are deployed in dependency order.

Step 2: Trust the lab CA

cata --flake ./examples/labs#homelab lab trust --setup

The lab generates its own certificate authority. This command installs the lab CA into your system trust store so that browsers and CLI tools accept TLS certificates issued for *.homelab.test domains without warnings.

To remove the CA later:

cata --flake ./examples/labs#homelab lab trust --teardown

Step 3: Configure local DNS

cata --flake ./examples/labs#homelab lab dns --setup

This configures your local resolver so that *.homelab.test domains resolve to 127.0.0.1 (where k3d exposes its ingress). The exact mechanism depends on your OS (systemd-resolved, dnsmasq, etc.).

To remove the DNS configuration later:

cata --flake ./examples/labs#homelab lab dns --teardown

Step 4: Initialize a user account

cata --flake ./examples/labs#homelab lab ops init-user lab-admin

This resets (or creates) the lab-admin account in Kanidm and prints a temporary password. The init-user command is a lab ops command – it understands the lab topology. It knows which cluster runs Kanidm, which namespace the pod lives in, and how to exec into it. You do not need to figure out contexts or namespaces yourself.

Lab ops commands are defined in the lab’s Nix configuration and have full access to component refs:

lab.ops.commands.init-user = {
  description = "Reset a kanidm account password";
  package = pkgs.writeShellApplication {
    name = "init-user";
    runtimeInputs = [ pkgs.kubectl ];
    text = ''
      kubectl --context k3d-core exec -n ${kanidmRef.namespace} kanidm-default-0 -- \
        kanidmd recover-account "$1"
    '';
  };
};

Step 5: Log in to Kanidm

Open https://idm.homelab.test in your browser. Log in with the lab-admin username and the temporary password from the previous step. You will be prompted to set a new password and configure WebAuthn or TOTP.

Step 6: Access services via OIDC

With your Kanidm account set up, all OIDC-enabled services authenticate through it:

ServiceURLNotes
ArgoCDhttps://argocd.homelab.testClick “Log in via Kanidm”
Grafanahttps://grafana.homelab.testClick “Sign in with Kanidm”
Forgejohttps://git.homelab.testClick the Kanidm OAuth2 option

Each service has its OAuth2 client registered in Kanidm automatically via the kaniop operator. Group memberships in Kanidm map to roles in each service – for example, members of the grafana-editors group get the Editor role in Grafana.

How it works

The OIDC integration is wired through cross-component references:

  1. cert-manager issues TLS certificates for all services using the lab CA.
  2. kanidm runs as the identity provider with its own TLS certificate.
  3. kaniop manages OAuth2 client registrations in Kanidm declaratively, creating client secrets as Kubernetes Secrets.
  4. Each service (ArgoCD, Grafana, Forgejo) references the Kanidm OIDC endpoint and its client secret via component ref attributes.

Because everything is evaluated at Nix build time, the URLs, namespaces, and secret names are consistent and type-checked. There is no manual coordination between services.

Troubleshooting

Browser shows certificate warnings: Run cata lab trust --setup and restart your browser.

DNS does not resolve: Run cata lab dns --setup. On systemd-resolved systems, you may need to restart the resolver.

OIDC login fails: Check that Kanidm is running and the OAuth2 clients are registered:

kubectl --context k3d-core get oauth2clients -n kanidm

Temporary password expired: Re-run cata lab ops init-user lab-admin to get a fresh one.

Backup and Restore

Catallaxy uses Velero for cluster backup and restore in it’s example. However you can extend catallaxy to use whatever k8s backup strategy you want. For local development, backups are stored in SeaweedFS (S3-compatible). For production, Velero supports AWS S3, GCP Cloud Storage, and Azure Blob Storage.

Enabling Backups

Enable Velero and a storage backend on the cluster that holds your stateful workloads:

# aspects/backups.nix
{ ... }:
{
  components.seaweedfs.enable = true;

  components.velero = {
    enable = true;
    local.enable = true; # SeaweedFS-backed storage for local dev
    schedules.daily = {
      schedule = "0 2 * * *";
      ttl = "168h"; # 7 days
    };
  };
}

Deploy with cata lab up or cata lab apply. Velero will start taking scheduled backups automatically.

Cloud Storage (Production)

For production, point Velero at a real S3 bucket:

components.velero = {
  enable = true;
  backupStorageLocation = {
    provider = "aws";
    bucket = "my-velero-backups";
    s3 = {
      region = "us-east-1";
    };
  };
};

Using Velero

Backups are managed directly via the velero CLI or through lab ops commands.

On-Demand Backup

# Via ops commands (if configured in your lab)
cata lab ops backup create

# Or directly via velero CLI
velero backup create my-backup --include-namespaces forgejo,kanidm

List and Inspect

velero backup get
velero backup describe my-backup
velero backup logs my-backup

Restore

velero restore create --from-backup my-backup
velero restore create --from-backup my-backup --include-namespaces forgejo

Schedules

velero schedule get
velero schedule trigger daily

Cross-Cluster Migration

Migrate workloads between clusters by backing up on one and restoring on another. Both clusters must have Velero configured with access to the same backup storage location.

# On source cluster
velero backup create migration-backup

# On target cluster
velero restore create --from-backup migration-backup

Management Cluster Pivot

For environments with cloud management clusters, catallaxy handles the pivot automatically during lab up when a cluster self-provisions (declares itself in its own Crossplane kubernetesClusters). The planner generates bootstrap → pivot → destroy steps. See Bootstrap & Pivot for details.

Custom Components

The components.custom.apps option lets you deploy your own applications alongside the built-in infrastructure components. Custom apps support Helm charts, typed Kubernetes resources, raw YAML, and optional Gateway API routing – all without writing a full component module.

Example: Helm chart deployment

Deploy an application using a Helm chart:

# In your cluster configuration
{ cataCharts, ... }:
{
  components.custom.apps.my-app = {
    namespace = "my-app";
    phase = "apps";

    helmCharts.my-app = {
      chart = cataCharts.my-app.chart;  # if registered in lib/charts.nix
      # or use an inline chart path
      namespace = "my-app";
      values = {
        replicas = 2;
        image.tag = "v1.2.3";
        ingress.enabled = false;  # use Gateway API instead
      };
    };
  };
}

The chart is rendered at Nix build time and deployed during the specified phase. The namespace is created automatically unless you set createNamespace = false.

Example: Resources with a Gateway route

Deploy raw Kubernetes resources and expose them via the Gateway API:

{ config, lib, ... }:
let
  labDomain = config.cluster.lab.domain;  # e.g., "homelab.test"
in
{
  components.custom.apps.whoami = {
    namespace = "whoami";
    phase = "apps";

    resources = {
      whoami-deployment = {
        apiVersion = "apps/v1";
        kind = "Deployment";
        metadata = {
          name = "whoami";
          namespace = "whoami";
        };
        spec = {
          replicas = 1;
          selector.matchLabels.app = "whoami";
          template = {
            metadata.labels.app = "whoami";
            spec.containers = [
              {
                name = "whoami";
                image = "traefik/whoami:v1.10";
                ports = [ { containerPort = 80; } ];
              }
            ];
          };
        };
      };

      whoami-service = {
        apiVersion = "v1";
        kind = "Service";
        metadata = {
          name = "whoami";
          namespace = "whoami";
        };
        spec = {
          selector.app = "whoami";
          ports = [
            {
              port = 80;
              targetPort = 80;
            }
          ];
        };
      };
    };

    gateway = {
      enable = true;
      domain = "whoami.${labDomain}";
      serviceName = "whoami";
      servicePort = 80;
    };
  };
}

When gateway.enable = true, Catallaxy automatically generates an HTTPRoute (or TLSRoute for passthrough mode) pointing to your service. The route is added to the same bundle as your resources.

Gateway options

OptionDefaultDescription
gateway.enablefalseGenerate a Gateway API route
gateway.mode"terminate""terminate" for HTTPRoute, "passthrough" for TLSRoute
gateway.domain""Hostname for the route
gateway.serviceNameapp nameBackend service name
gateway.servicePort80Backend service port
gateway.gatewayRef"default-gateway"Name of the Gateway resource to attach to
gateway.gatewayNamespace"kube-system"Namespace of the Gateway resource

Custom app options reference

OptionDefaultDescription
enabletrueWhether to deploy this app
phase"apps"Deployment phase
namespaceapp nameKubernetes namespace
createNamespacetrueAuto-create the namespace
helmCharts{}Helm charts (same shape as phase bundle helmCharts)
resources{}Typed Kubernetes resource definitions
yamls[]Raw YAML manifests (strings or paths)

When to use custom apps vs. a full component

Use components.custom.apps when:

  • You need to deploy an application that is specific to your lab.
  • The app does not need cross-component ref wiring.
  • You want a quick deployment without writing a module.

Write a full component module (see Adding Components) when:

  • Other components need to reference this component via ref attributes.
  • The component has complex configuration options that benefit from the NixOS module type system.
  • You intend to contribute the component upstream.

Secrets Management

Catallaxy uses a three-layer model for secrets: stores, managed secrets, and projections.

The Model

Stores          → Where encrypted values are stored (one SOPS file per store)
Managed Secrets → Source-of-truth keys that reference a store
Projections     → How managed secrets map to K8s Secrets per cluster/namespace

Setup

1. Install SOPS and age

SOPS is included in the devshell. For age keys:

# Generate an age key (or use a YubiKey)
age-keygen -o ~/.config/sops/age/keys.txt

# For YubiKey:
age-plugin-yubikey  # Follow prompts to set up

2. Configure .sops.yaml

Create .sops.yaml at the repo root with creation rules matching your store paths:

creation_rules:
  # Prod secrets — encrypt with your age key
  - path_regex: secrets/homelab\.prod/.*\.enc\.yaml$
    age: age1...your-public-key...

  # Local dev secrets
  - path_regex: secrets/homelab\.local/.*\.enc\.yaml$
    age: age1...your-public-key...

3. Declare stores and managed secrets

In your lab config:

# Stores — each becomes one SOPS file
lab.secrets.stores.cloud-creds = { backend = "sops"; };

# Managed secrets — source-of-truth keys
lab.secrets.managed = {
  do-token = {
    store = "cloud-creds";
    keys.token = { };         # Manual entry via secrets edit
  };
  cf-token = {
    store = "cloud-creds";
    keys.token = { };
  };
  db-password = {
    store = "cloud-creds";
    keys.password = {
      generator = "alphanumeric";  # Auto-generated
      length = 32;
    };
  };
};

4. Generate and edit secrets

# Generate SOPS files (creates placeholders, auto-generates where configured)
cata secrets generate

# Edit a store to fill in manual values
cata secrets edit cloud-creds

# List all secrets and their status
cata secrets list

Projections

Projections map managed secrets into Kubernetes Secrets with optional transforms:

# In a cluster config:
secrets.projections.cloudflare-api-token = {
  source = "cf-token";           # From lab.secrets.managed
  namespace = "cert-manager";    # Target K8s namespace
  phase = "operators";           # Injected before this phase deploys
  keys.api-token.from = "token"; # Key mapping: K8s key ← managed key
};

secrets.projections.db-credentials = {
  source = "db-password";
  namespace = "forgejo";
  phase = "databases";
  keys = {
    password.from = "password";
    credentials = {
      from = "password";
      transform = "json-wrap";   # Wraps as {"password": "value"}
      jsonKey = "password";
    };
  };
};

Transforms

TransformDescription
none (default)Passthrough — value as-is
base64Base64-encode the value
json-wrapWrap as JSON: {"<jsonKey>": "<value>"}

Phase Ordering

Projections must be in a phase that runs before or during the phase of components that reference them. A Nix assertion validates this at build time:

Projection 'my-secret' is in phase 'infrastructure' (order 30)
but namespace 'my-ns' has components in phase 'operators' (order 10).
The secret won't exist when the component deploys.

The projection-ref lint check also validates that secretKeyRef names match declared projection names.

Per-Environment Keys

Use different age keys per environment in .sops.yaml:

creation_rules:
  - path_regex: secrets/.*\.prod/.*
    age: age1...prod-yubikey...

  - path_regex: secrets/.*\.staging/.*
    age: age1...staging-key...

  - path_regex: secrets/.*\.local/.*
    age: age1...dev-key...

YubiKey Workflow

With age-plugin-yubikey, SOPS prompts for the YubiKey PIN during decryption. During lab up, secrets are decrypted once (during the ensure-secrets step) and cached in memory for all subsequent cluster deployments. This avoids repeated PIN prompts when Crossplane provisioning creates long gaps between cluster deploys.

CLI Commands

cata secrets generate          # Generate SOPS files for all stores
cata secrets edit <store>      # Decrypt, edit, re-encrypt a store
cata secrets decrypt <store>   # Decrypt to stdout
cata secrets rotate <store>    # Rotate encryption keys
cata secrets list              # Show stores, managed secrets, and projections

Operational Runbook

Lab Lifecycle

Starting a Lab

cata lab up                    # Deploy everything
cata lab plan                  # Preview the deployment plan
cata lab plan --teardown       # Preview the teardown plan

Updating a Lab

cata apply <cluster>                    # Apply all phases to a cluster
cata apply <cluster> --phase operators  # Apply a single phase
cata lab apply                          # Apply to all clusters in a lab

Stopping a Lab

cata lab down         # Stop clusters (preserves state, restartable with lab up)
cata lab destroy      # Delete everything: clusters, cloud resources, services, network

Troubleshooting

ProgressDeadlineExceeded

Symptom: kapp reports a deployment stuck in ProgressDeadlineExceeded on re-runs.

Cause: A previous deploy failed (e.g., missing secret), leaving the deployment in a stale error state. On re-run, kapp sees no spec change (noop) and fails on the stale status.

Fix: The CLI auto-restarts stuck deployments before each kapp deploy. If the underlying issue is fixed (e.g., secret now exists), re-running lab up should resolve it automatically.

Secret Not Found (CreateContainerConfigError)

Symptom: CreateContainerConfigError: secret "X" not found

Possible causes:

  1. Projection phase too late: The secret projection is in a phase that runs after the component. Check with cata lab lint — the projection-ref check catches this.
  2. SOPS decryption failed: YubiKey wasn’t available or PIN wasn’t entered. Check the ensure-secrets step output.
  3. Store file missing: Run cata secrets generate then cata secrets edit <store>.

ACME Certificate Not Issued

Symptom: Certificate stuck in False status, challenges pending.

Check:

kubectl get challenges -A
kubectl describe challenge <name> -n <ns>

Common causes:

  • API token missing Zone:Read: Cloudflare token needs both Zone:Read and DNS:Edit
  • Wrong domain filter: domainFilters must be the Cloudflare zone name (e.g., praxioticsystems.com), not a subdomain
  • DNS negative cache: NXDOMAIN cached for 30 minutes (SOA minimum TTL). Wait or use a different resolver to verify.

Crossplane Resource Not Ready

Symptom: wait-for-resources stuck, managed resources show SYNCED=False.

Check:

kubectl get managed                    # See all managed resources
kubectl describe <kind>/<name>         # Check status.conditions
kubectl get providerconfig             # Verify credentials

Common causes:

  • Wrong credentials: Check the secret referenced by ProviderConfig
  • API quota exceeded: DigitalOcean droplet limit reached
  • Provider not healthy: kubectl get providers — check HEALTHY status

Backup & Restore

Creating a Backup

Velero schedules are configured per-cluster. To trigger a manual backup:

cata lab ops backup create

Restoring from Backup

velero restore create --from-backup <backup-name>

Checking Backup Status

velero backup get
velero schedule get

Certificate Management

ACME (Production)

Certificates are auto-renewed by cert-manager 30 days before expiry. No manual action needed.

To force renewal:

kubectl delete certificate <name> -n <ns>
# cert-manager will re-issue automatically

Self-Signed CA (Local Dev)

The lab CA is generated during lab up and distributed via trust-manager. Certificates are valid for 1 year by default.

CLI Commands

The cata CLI orchestrates runtime operations for Catallaxy labs. It evaluates Nix expressions, applies manifests to clusters, and manages secrets, PKI, and images.

Most commands require a --flake argument pointing to your lab flake:

cata --flake '.#homelab.local' <command>

Lab Lifecycle

cata lab up

Provision all clusters, render manifests, and apply them phase by phase.

cata lab up

cata lab down

Stop lab clusters. Preserves state — clusters can be restarted with lab up.

cata lab down

cata lab destroy

Destroy lab completely — deletes clusters, cloud resources, services, and network. Not reversible.

cata lab destroy

cata lab init

Initialize lab infrastructure without applying manifests.

cata lab init

cata lab status

Show the status of all clusters and services.

cata lab status

cata lab list

List all labs defined in the flake.

cata lab list

cata lab plan

Show the computed deployment plan without executing.

cata lab plan
cata lab plan --teardown   # show teardown plan

cata lab lint

Validate rendered manifests against property checks.

cata lab lint
cata lab lint --skip image-pin,crd-schema   # skip specific checks
cata lab lint --path /nix/store/...-lab-*    # lint a pre-built package

cata lab apply

Apply manifests to all clusters without provisioning.

cata lab apply
cata lab apply --phase operators   # specific phase

Lab Publishing

cata lab publish

Render manifests and push to a Git repository for GitOps consumption.

cata lab publish
cata lab publish --pr         # create a pull request
cata lab publish --dry-run    # preview without pushing

Lab Ops

cata lab ops <args...>

Run lab-defined operational commands.

cata lab ops idm init-user lab-admin
cata lab ops database shell

Local Environment

cata lab dns

Configure local DNS resolution for lab domains.

cata lab dns --setup
cata lab dns --teardown

cata lab trust

Install or remove the lab CA from the system trust store.

cata lab trust --setup
cata lab trust --teardown
cata lab trust --export   # print CA PEM to stdout

Cluster Lifecycle

cata cluster up

Provision and apply manifests to a single cluster.

cata cluster up core

cata cluster down

Stop a single cluster (alias: cluster destroy).

cata cluster down core

Apply

cata apply <cluster>

Apply manifests to a cluster with fine-grained control.

cata apply core
cata apply core --phase networking
cata apply core --dry-run
cata apply core --force   # bypass GitOps strategy check

PKI

cata pki init

Initialize the PKI CA for a cluster (generates root CA if needed).

cata pki init core

cata pki issue <user>

Issue a client certificate for a user.

cata pki issue admin

cata pki provision <user>

Write a certificate to a YubiKey PIV slot.

cata pki provision admin

cata pki list

List CA and certificate status.

cata pki list core

cata pki kubeconfig <user>

Generate a kubeconfig entry using the client certificate.

cata pki kubeconfig admin

Secrets

cata secrets generate

Generate SOPS-encrypted secret files for all stores.

cata secrets generate

cata secrets edit <store>

Decrypt, edit, and re-encrypt a secrets store.

cata secrets edit cloud-creds

cata secrets decrypt <store>

Decrypt a store to stdout.

cata secrets decrypt cloud-creds

cata secrets encrypt <file>

Encrypt a plaintext file.

cata secrets encrypt secrets.yaml
cata secrets encrypt secrets.yaml --output secrets.enc.yaml

cata secrets rotate <store>

Rotate encryption keys on a SOPS file.

cata secrets rotate cloud-creds

cata secrets list

Show all stores, managed secrets, and projections.

cata secrets list

Images

cata images list

List all container images used by a lab.

cata images list

cata images mirror

Mirror lab images to a target registry using crane.

cata images mirror --registry ghcr.io/my-org
cata images mirror --registry ghcr.io/my-org --dry-run

cata images prefetch

Prefetch lab images into a local registry (e.g., Zot).

cata images prefetch --registry localhost:5050

Kubeconfig

cata kubeconfig sync

Sync kubeconfig entries for lab clusters.

cata kubeconfig sync

Code Generation

cata generate

Generate Kubernetes API types from OpenAPI specs and CRDs (development use).

nix run .#generate-k8s-types

Module Options

Auto-generated reference for all catallaxy module options. Options are split across pages by category to keep each page fast to load.

Lab options

Top-level lab configuration: name, environment, CD strategy, DNS, networking, ingress, registry, and ops commands.

Cluster options

Per-cluster configuration nested under lab.clusters.<name>: Kubernetes settings, provisioners, phases, authentication, and storage.

Component options

Each component declares options under lab.clusters.<name>.components.<name>. Pages are grouped by category:

CategoryComponents
CNICilium
Gateway and DNSGateway, External DNS
PKIcert-manager, trust-manager
ObservabilityPrometheus, Grafana, Loki, Tempo, OTEL Collector
DatabasesCloudNativePG, Redis Operator
FilesystemsOpenEBS, SeaweedFS
SecretsExternal Secrets, SOPS
IdentityKanidm, Kaniop, OIDC
GitOpsArgoCD
Source ControlForgejo
ProvisioningCluster API, Crossplane
OtherVelero, Netbird, Zot, Custom

How options are structured

Every component follows the same pattern:

options.components.<name> = {
  enable = mkEnableOption "<Name>";
  phase = mkOption { default = "<phase>"; };
  namespace = mkOption { default = "<namespace>"; };
  chart = mkOption { ... };
  ref = mkOption { readOnly = true; };
};

The ref attribute provides computed values for cross-component wiring. It is always set, even when the component is disabled, so other components can reference it safely.

Lab Options

Options for configuring the lab environment, CD strategy, DNS, networking, and operations.

bgpRouter.asn

BGP Autonomous System Number for the router

Type: signed integer

Default: 65000

Declared in: modules/lab/bgp-router.nix


bgpRouter.containerName

Docker container name for the BGP router

Type: string

Default: "catallaxy-router"

Declared in: modules/lab/bgp-router.nix


bgpRouter.enable

Whether to enable Lab BGP router (FRRouting) for LoadBalancer IP advertisement.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/bgp-router.nix


bgpRouter.image

FRRouting container image

Type: string

Default: "frrouting/frr:latest"

Declared in: modules/lab/bgp-router.nix


bgpRouter.lbPool

IP pool CIDR for LoadBalancer service allocation

Type: string

Default: "172.19.200.0/24"

Declared in: modules/lab/bgp-router.nix


bgpRouter.out.service

Computed container service definition for the BGP router

Type: attribute set

Default: { }

Declared in: modules/lab/bgp-router.nix


bgpRouter.peerASN

BGP ASN for Cilium nodes (peers)

Type: signed integer

Default: 65001

Declared in: modules/lab/bgp-router.nix


bgpRouter.peerAddress

IP address where the BGP router is reachable by Cilium nodes (Docker network gateway)

Type: string

Default: "172.19.0.1"

Declared in: modules/lab/bgp-router.nix


cd.argocd.repoUrl

Git repository URL for manifest storage

Type: string

Default: ""

Declared in: modules/lab/types.nix


cd.argocd.targetBranch

Git branch to commit rendered manifests to

Type: string

Default: "main"

Declared in: modules/lab/types.nix


cd.clusterPaths

Per-cluster targetPath overrides. Key = cluster name, value = path in repo. Default: manifests/

Type: attribute set of string

Default: { }

Declared in: modules/lab/types.nix


cd.fleet.repoUrl

Git repository URL for manifest storage

Type: string

Default: ""

Declared in: modules/lab/types.nix


cd.fleet.targetBranch

Git branch to commit rendered manifests to

Type: string

Default: "main"

Declared in: modules/lab/types.nix


cd.git.branch

Target branch for manifest publishing

Type: string

Default: "main"

Declared in: modules/lab/types.nix


cd.git.path

Subdirectory within the repo for manifests (empty = repo root)

Type: string

Default: ""

Declared in: modules/lab/types.nix


cd.git.prBaseBranch

Base branch for PRs (the branch to merge into)

Type: string

Default: "main"

Declared in: modules/lab/types.nix


cd.git.prEnabled

Create a PR/MR instead of pushing directly to the target branch

Type: boolean

Default: false

Declared in: modules/lab/types.nix


cd.git.provider

Git provider for PR/MR creation

Type: one of "github", "gitlab", "forgejo"

Default: "github"

Declared in: modules/lab/types.nix


cd.git.repo

Git repository URL for publishing rendered manifests (e.g. git@github.com:org/manifests.git)

Type: string

Default: ""

Declared in: modules/lab/types.nix


cd.kapp.waitTimeout

Timeout waiting for resources to reconcile

Type: string

Default: "10m"

Declared in: modules/lab/types.nix


cd.strategy

CD strategy for delivering manifests to all clusters:

  • kapp: Direct apply via kapp (fast, no git, ideal for local dev)
  • argocd: Render manifests to git, ArgoCD syncs from there
  • fleet: Render manifests to git, Fleet syncs from there

Type: one of "kapp", "argocd", "fleet"

Default: "kapp"

Declared in: modules/lab/types.nix


clusters

Cluster configurations. Each cluster is provisioned directly by the CLI (e.g. via k3d for local dev). Any cluster can optionally enable CAPI to manage external clusters.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/types.nix


dns.containerName

Docker container name for the DNS server

Type: string

Default: "catallaxy-dns"

Declared in: modules/lab/dns.nix


dns.enable

Whether to enable Lab DNS server (Knot DNS with RFC2136 for ExternalDNS).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/dns.nix


dns.hostPort

Host-mapped port for the DNS server (for host access). Avoids 5353 which conflicts with mDNS.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 5354

Declared in: modules/lab/dns.nix


dns.image

Knot DNS container image

Type: string

Default: "cznic/knot:latest"

Declared in: modules/lab/dns.nix


dns.out.dnsInfo

DNS server info for host resolver configuration

Type: attribute set

Default: { }

Declared in: modules/lab/dns.nix


dns.out.service

Computed container service definition for the lab DNS server

Type: attribute set

Default: { }

Declared in: modules/lab/dns.nix


dns.port

Port for the DNS server (as seen from clusters, defaults to hostPort)

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 5354

Declared in: modules/lab/dns.nix


dns.server

IP address where the DNS server is reachable from clusters (Docker gateway by default)

Type: string

Default: "172.19.0.1"

Declared in: modules/lab/dns.nix


dns.tsigKeyname

TSIG key name for RFC2136 dynamic updates

Type: string

Default: "externaldns-key"

Declared in: modules/lab/dns.nix


dns.tsigSecret

Base64-encoded TSIG secret (pre-generated for local dev)

Type: string

Default: "kp4bgnFAVCmajGIqOW7rj0MNwRNZHBqMvYaLTwzPHgI="

Declared in: modules/lab/dns.nix


dns.tsigSecretAlg

TSIG algorithm

Type: string

Default: "hmac-sha256"

Declared in: modules/lab/dns.nix


dns.zone

DNS zone for the lab (defaults to ‘.test’)

Type: string

Default: "docs-placeholder.test"

Declared in: modules/lab/dns.nix


environment

Lab environment. Components can adjust defaults based on this:

  • development: minimal replicas, relaxed resource limits, self-signed TLS
  • staging: moderate replicas, production-like config, self-signed or ACME TLS
  • production: HA replicas, strict resource limits, ACME TLS, destructive ops require –force

Type: one of "development", "staging", "production"

Default: "development"

Declared in: modules/lab/types.nix


images.allowedRegistries

When non-empty, the lint check warns about images from registries not in this list. Example: [“ghcr.io” “registry.k8s.io” “docker.io”]

Type: list of string

Default: [ ]

Declared in: modules/lab/images.nix


images.pins

Pinned container images. Each pin declares an image with optional tag and digest. Components can reference pins via lab.images.pins.<name>.ref to get the full image reference string.

Example: lab.images.pins.grafana = { image = “docker.io/grafana/grafana”; tag = “11.4.0”; digest = “sha256:abc123…”; };

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/images.nix


images.pins.<name>.digest

Image digest (e.g., sha256:abc123…). Immutable — ensures reproducibility.

Type: null or string

Declared in: modules/lab/images.nix


images.pins.<name>.image

Full image path (e.g., docker.io/grafana/grafana)

Type: string

Declared in: modules/lab/images.nix


images.pins.<name>.ref

Computed full image reference (image:tag@digest)

Type: string

Declared in: modules/lab/images.nix


images.pins.<name>.tag

Image tag (e.g., 11.4.0). Mutable — use digest for reproducibility.

Type: null or string

Declared in: modules/lab/images.nix


images.requireDigest

When true, the lint check errors on container images without digest pins. Use this to enforce reproducible deployments.

Type: boolean

Default: false

Declared in: modules/lab/images.nix


lint.checks

Custom lint checks that run on rendered manifests. Each check is a shell command executed per YAML file. Checks run alongside built-in checks during cata lab lint.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/lint.nix


lint.checks.<name>.command

Shell command to execute per YAML file. Environment variables: $FILE — path to the YAML manifest file $CLUSTER — name of the cluster being checked Exit 0 = pass, non-zero = fail. Stdout = diagnostic message (shown to user on failure).

Type: string

Declared in: modules/lab/lint.nix


lint.checks.<name>.description

Human-readable description of what this check validates

Type: string

Declared in: modules/lab/lint.nix


lint.checks.<name>.severity

Error = fails the lint, Warning = reported but doesn’t fail

Type: one of "error", "warning"

Default: "warning"

Declared in: modules/lab/lint.nix


name

Unique name for this lab

Type: string

Example: "homelab"

Declared in: modules/lab/types.nix


network.dockerSubnet

Subnet for the lab

Type: string

Default: "172.19.0.0/16"

Declared in: modules/lab/network.nix


ops.commands

Lab-global operational commands. These are not cluster-specific and appear directly in the ops tool under their category.

Components contribute cluster-scoped commands via the cluster-level ops.<name> option. Same-named commands from different clusters are automatically merged (enum options get their values unioned).

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/ops.nix


ops.commands.<name>.args

Positional arguments

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/ops.nix


ops.commands.<name>.args.*.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/ops.nix


ops.commands.<name>.args.*.name

This option has no description.

Type: string

Declared in: modules/lab/ops.nix


ops.commands.<name>.args.*.required

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/ops.nix


ops.commands.<name>.category

Subcommand group (e.g. ‘backup’, ‘database’)

Type: string

Default: "general"

Declared in: modules/lab/ops.nix


ops.commands.<name>.description

One-line description shown in help

Type: string

Declared in: modules/lab/ops.nix


ops.commands.<name>.options

Named options (flags)

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/ops.nix


ops.commands.<name>.options.<name>.default

This option has no description.

Type: null or string

Declared in: modules/lab/ops.nix


ops.commands.<name>.options.<name>.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/ops.nix


ops.commands.<name>.options.<name>.required

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/ops.nix


ops.commands.<name>.options.<name>.type

This option has no description.

Type: one of "string", "enum", "bool"

Default: "string"

Declared in: modules/lab/ops.nix


ops.commands.<name>.options.<name>.values

Valid values for enum type

Type: list of string

Default: [ ]

Declared in: modules/lab/ops.nix


ops.commands.<name>.package

Package providing the command binary

Type: package

Declared in: modules/lab/ops.nix


ops.out.tool

Generated lab operations CLI tool (null if no commands defined)

Type: null or package

Declared in: modules/lab/ops.nix


out.allClusters

Computed attrset of all clusters in the lab. Keys are cluster names, values are evaluated cluster configs. Use this for cross-cluster references.

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/out.nix


out.bootstrapManifests

Per-cluster kapp-format manifests for direct-apply bootstrap. When strategy is kapp, this equals manifests. Otherwise renders with kapp for use by lab up (which always direct-applies).

Type: attribute set of package

Default: { }

Declared in: modules/lab/out.nix


out.cliConfig

JSON-serializable lab configuration for the CLI. Contains the fields that cata lab commands need: management, clusterNames, services, network, registryPort, dnsInfo.

Type: attribute set

Default: { }

Declared in: modules/lab/out.nix


out.clusterNames

List of all cluster names in the lab

Type: list of string

Default: [ ]

Declared in: modules/lab/out.nix


out.deploymentPlan

Computed deployment plan — an ordered list of typed steps for the CLI to execute. Inspect with cata lab plan.

Type: list of (submodule)

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.bootstrapContext

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.cluster

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.clusters

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.ephemeral

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.name

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.provisioner

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.resources

This option has no description.

Type: list of attribute set of string

Default: [ ]

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.skipIfReachable

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.stores

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.target

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.targetContext

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.deploymentPlan.*.type

This option has no description.

Type: string

Declared in: modules/lab/planner.nix


out.labNamespaces

Per-cluster list of lab-created namespaces (before prefix application). Used by checks to verify prefix completeness.

Type: attribute set of list of string

Default: { }

Declared in: modules/lab/out.nix


out.manifests

Per-cluster rendered manifest packages. Each package contains the strategy-specific directory layout (kapp, argocd, or fleet) with human-readable YAML manifests.

Type: attribute set of package

Default: { }

Declared in: modules/lab/out.nix


out.package

Single package containing all lab outputs. Includes metadata.json (pretty-printed) and manifests/ directory with symlinks to each cluster’s rendered manifests.

Type: package

Declared in: modules/lab/out.nix


out.teardownPlan

Computed teardown plan — an ordered list of typed steps for safe lab destruction. Inspect with cata lab plan --teardown.

Type: list of (submodule)

Declared in: modules/lab/planner.nix


out.teardownPlan.*.bootstrapContext

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.cluster

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.clusters

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/planner.nix


out.teardownPlan.*.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/planner.nix


out.teardownPlan.*.ephemeral

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/planner.nix


out.teardownPlan.*.name

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.provisioner

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.resources

This option has no description.

Type: list of attribute set of string

Default: [ ]

Declared in: modules/lab/planner.nix


out.teardownPlan.*.skipIfReachable

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.stores

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/planner.nix


out.teardownPlan.*.target

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.targetContext

This option has no description.

Type: null or string

Declared in: modules/lab/planner.nix


out.teardownPlan.*.type

This option has no description.

Type: string

Declared in: modules/lab/planner.nix


prefix

Global name prefix applied to all rendered output. Use for multi-tenancy on shared clusters or running multiple lab instances. When set, resource names, namespaces, fleet bundles, and ArgoCD apps are all prefixed. Empty string = disabled.

Type: string

Default: ""

Example: "dev"

Declared in: modules/lab/types.nix


proxy.containerName

Docker container name for the ingress

Type: string

Default: "catallaxy-ingress"

Declared in: modules/lab/proxy.nix


proxy.enable

Whether to enable Lab ingress (HAProxy for domain-based routing to k3d clusters).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/proxy.nix


proxy.httpPort

Host port for HTTP (redirects to HTTPS)

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 80

Declared in: modules/lab/proxy.nix


proxy.httpsPort

Host port for HTTPS

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 443

Declared in: modules/lab/proxy.nix


proxy.image

HAProxy container image

Type: string

Default: "haproxy:3.1-alpine"

Declared in: modules/lab/proxy.nix


proxy.out.service

Computed container service definition for the lab ingress

Type: attribute set

Default: { }

Declared in: modules/lab/proxy.nix


registry.containerName

Docker container name for the registry

Type: string

Default: "catallaxy-registry"

Declared in: modules/lab/registry.nix


registry.enable

Whether to enable Lab registry for image caching (Zot OCI registry as pull-through cache).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/registry.nix


registry.image

Zot registry container image

Type: string

Default: "ghcr.io/project-zot/zot-linux-amd64:v2.1.1"

Declared in: modules/lab/registry.nix


registry.port

Host port for the registry

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 5050

Declared in: modules/lab/registry.nix


registry.service

Computed container service definition for the lab registry

Type: attribute set

Default: { }

Declared in: modules/lab/registry.nix


secrets.managed

Managed secrets. Each declares source keys that live in a store. Components project these into Kubernetes Secrets via cluster-level secrets.projections.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/secrets.nix


secrets.managed.<name>.keys

Source key definitions — these appear in the SOPS file

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/secrets.nix


secrets.managed.<name>.keys.<name>.generator

Generator for this key’s value. null means the value is set manually via cata secrets edit.

Type: null or one of "base64", "hex", "alphanumeric", "uuid"

Declared in: modules/lab/secrets.nix


secrets.managed.<name>.keys.<name>.length

Length of generated value

Type: null or (positive integer, meaning >0)

Declared in: modules/lab/secrets.nix


secrets.managed.<name>.store

Name of the secret store this secret belongs to

Type: string

Declared in: modules/lab/secrets.nix


secrets.stores

Secret stores. Each store maps to one SOPS file (or one Vault path). SOPS files are at: secrets//.enc.yaml

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/secrets.nix


secrets.stores.<name>.backend

Storage backend:

  • sops: encrypted YAML files in git
  • vault: HashiCorp Vault (future)
  • external: managed outside catallaxy

Type: one of "sops", "vault", "external"

Default: "sops"

Declared in: modules/lab/secrets.nix


Cluster Options

Options for configuring individual clusters within a lab, including Kubernetes settings, provisioners, phases, and authentication.

All options are under lab.clusters.<name>.

cluster.certSANs

Extra Subject Alternative Names added to CAPI cluster API server certificates. Includes 127.0.0.1 so kubeconfigs rewritten for host access work with valid TLS.

Type: list of string

Default:

[
  "127.0.0.1"
  "localhost"
]

Declared in: modules/lab/cluster/types.nix


cluster.kubernetes.controlPlanes

Number of control plane nodes

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/types.nix


cluster.kubernetes.distribution

Kubernetes distribution to use

Type: one of "talos", "k3s", "k8s"

Default: "talos"

Declared in: modules/lab/cluster/types.nix


cluster.kubernetes.version

Kubernetes API version for type generation (e.g., ‘1.31’)

Type: string

Default: "1.31"

Declared in: modules/lab/cluster/types.nix


cluster.kubernetes.workers

Number of worker nodes

Type: unsigned integer, meaning >=0

Default: 1

Declared in: modules/lab/cluster/types.nix


cluster.name

Unique name for this cluster

Type: string

Example: "local"

Declared in: modules/lab/cluster/types.nix


cluster.network.podSubnet

Pod network CIDR

Type: string

Default: "10.244.0.0/16"

Declared in: modules/lab/cluster/types.nix


cluster.network.serviceSubnet

Service network CIDR

Type: string

Default: "10.96.0.0/12"

Declared in: modules/lab/cluster/types.nix


cluster.out.phaseOrder

Phase names sorted by deployment order

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/out.nix


cluster.out.phases

Computed phases with rendered manifest packages. Each entry has: order, dependsOn, keepResources, pruneStrategy, waitForReady, timeout, package (derivation).

Type: raw value

Default: { }

Declared in: modules/lab/cluster/out.nix


cluster.out.sbom

Software bill of materials

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/out.nix


cluster.out.topology

Computed topology/network map

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/out.nix


cluster.provider

Computed provider category (derived from cluster.provisioner)

Type: one of "docker", "crossplane", "external"

Declared in: modules/lab/cluster/types.nix


cluster.provisioner

How this cluster is provisioned:

  • k3d: k3s-in-Docker (local development)
  • talos: Talos-in-Docker (local development)
  • crossplane: Provisioned via Crossplane from another cluster
  • external: Pre-existing cluster, just configure it

Type: one of "k3d", "talos", "crossplane", "external"

Default: "k3d"

Declared in: modules/lab/cluster/types.nix


cluster.ref.kubeContext

Kubernetes context name for kubectl/velero/etc. Set by provisioner modules.

Type: string

Declared in: modules/lab/cluster/types.nix


cluster.security.auditLogging.enable

Enable Kubernetes API server audit logging. Provisioner-specific.

Type: boolean

Default: false

Declared in: modules/lab/cluster/types.nix


cluster.security.networkPolicies.enable

Generate default-deny NetworkPolicies for lab namespaces. Components add allow rules.

Type: boolean

Default: false

Declared in: modules/lab/cluster/types.nix


cluster.security.podSecurity.default

Default PSA level for lab namespaces. Components can override per-namespace.

Type: one of "restricted", "baseline", "privileged"

Default: "restricted"

Declared in: modules/lab/cluster/types.nix


cluster.security.podSecurity.enable

Apply Pod Security Admission labels to lab-managed namespaces

Type: boolean

Default: false

Declared in: modules/lab/cluster/types.nix


cluster.security.podSecurity.namespaceOverrides

Per-namespace PSA level overrides (e.g., kube-system = privileged)

Type: attribute set of (one of "restricted", "baseline", "privileged")

Default: { }

Declared in: modules/lab/cluster/types.nix


cluster.talos.cniNone

Disable built-in CNI (for Cilium)

Type: boolean

Default: true

Declared in: modules/lab/cluster/types.nix


cluster.talos.kubeProxyDisabled

Disable kube-proxy (for Cilium kube-proxy replacement)

Type: boolean

Default: true

Declared in: modules/lab/cluster/types.nix


cluster.talos.version

Talos version

Type: string

Default: "v1.13.0"

Declared in: modules/lab/cluster/types.nix


compose

This option has no description.

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster


databases.postgres

This option has no description.

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster


databases.redis

This option has no description.

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster


lifecycle.teardown

Ordered teardown steps executed before cluster deprovisioning

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster


lifecycle.teardown.*.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster


lifecycle.teardown.*.name

Step name for display

Type: string

Declared in: modules/lab/cluster


lifecycle.teardown.*.order

Execution order (lower = first)

Type: signed integer

Default: 0

Declared in: modules/lab/cluster


lifecycle.teardown.*.package

Script to execute for this step

Type: package

Declared in: modules/lab/cluster


lifecycle.teardown.*.waitTimeout

How long to wait for completion

Type: string

Default: "5m"

Declared in: modules/lab/cluster


ops

Operational commands contributed by components (auto-collected by lab.ops)

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster


ops.<name>.args

Positional arguments

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster


ops.<name>.args.*.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster


ops.<name>.args.*.name

This option has no description.

Type: string

Declared in: modules/lab/cluster


ops.<name>.args.*.required

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster


ops.<name>.category

Subcommand group (e.g. ‘backup’, ‘database’)

Type: string

Default: "general"

Declared in: modules/lab/cluster


ops.<name>.description

This option has no description.

Type: string

Declared in: modules/lab/cluster


ops.<name>.options

Named options (flags) for this command

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster


ops.<name>.options.<name>.default

This option has no description.

Type: null or string

Declared in: modules/lab/cluster


ops.<name>.options.<name>.description

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster


ops.<name>.options.<name>.required

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster


ops.<name>.options.<name>.type

This option has no description.

Type: one of "string", "enum", "bool"

Default: "string"

Declared in: modules/lab/cluster


ops.<name>.options.<name>.values

Valid values for enum type

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster


ops.<name>.package

This option has no description.

Type: package

Declared in: modules/lab/cluster


phases

Not all kubernetes resources can be installed at once. There is an ordering to it. Phases are the mechanism to declare that a bundle has a dependency on another.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles

Set of bundles that belong in this phase.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.createNamespaces

Namespaces to create for this phase

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts

Helm charts to render for this phase. Charts are rendered at build time using helm template, with optional kustomize patching.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.chart

Helm chart derivation

Type: package

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.createNamespace

Whether to create the namespace if it doesn’t exist

Type: boolean

Default: true

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.extraOpts

Extra options to pass to helm template

Type: list of string

Default:

[
  "--skip-tests"
]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.kustomize

Kustomize patching configuration

Type: submodule

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.kustomize.enable

Enable kustomize-based patching of helm output

Type: boolean

Default: false

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.kustomize.patches

Strategic merge patches to apply to helm output. Each patch is an attribute set that will be merged with matching resources.

Type: list of (attribute set)

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.kustomize.patchesJson6902

JSON Patch (RFC 6902) operations to apply to helm output.

Type: list of (attribute set)

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.kustomize.resources

Additional resources to include alongside helm output. Can be paths to YAML files or inline YAML strings.

Type: list of (absolute path or string)

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.namespace

Kubernetes namespace for the release

Type: string

Default: "default"

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.releaseName

Helm release name (defaults to attribute name)

Type: string

Default: "‹name›"

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.helmCharts.<name>.values

Helm values to pass to the chart

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources

Typed Kubernetes resources to include in this phase. Resources are validated against the generated K8s 1.31 API types and CRD types.

Type: attribute set of (open submodule of (attribute set))

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.apiVersion

Kubernetes API version (e.g., ‘v1’, ‘apps/v1’)

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.data

Data for ConfigMap/Secret resources

Type: null or (attribute set of string)

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.kind

Kubernetes resource kind (e.g., ‘Service’, ‘Deployment’)

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata

Resource metadata

Type: open submodule of (attribute set)

Default:

{
  name = "‹name›";
}

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.annotations

Arbitrary non-identifying metadata attached to objects.

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.finalizers

List of finalizers that must be empty before the object is deleted.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.generateName

Optional prefix for generated names when name is not specified.

Type: null or string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.labels

Map of string keys and values for organizing and categorizing objects.

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.name

Resource name. Must be unique within a namespace.

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.namespace

Namespace for the resource. Null for cluster-scoped resources.

Type: null or string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences

List of objects depended by this object.

Type: list of (open submodule of (attribute set))

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences.*.apiVersion

API version of the referent.

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences.*.blockOwnerDeletion

If true, the owner cannot be deleted until this reference is removed.

Type: null or boolean

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences.*.controller

If true, this reference points to the managing controller.

Type: null or boolean

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences.*.kind

Kind of the referent.

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences.*.name

Name of the referent.

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.metadata.ownerReferences.*.uid

UID of the referent.

Type: string

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.spec

Resource spec (structure depends on kind)

Type: null or (attribute set)

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.resources.<name>.stringData

String data for Secret resources

Type: null or (attribute set of string)

Declared in: modules/lab/cluster/phases


phases.<name>.bundles.<name>.yamls

Raw YAML manifests to include in this phase. Use this as an escape hatch when typed resources don’t fit. Can be inline strings or paths to YAML files.

Type: list of (string or absolute path)

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.crdNames

CRD names to wait for (used when waitForCRDs = true)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.dependsOn

Phases that must complete before this one

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/phases


phases.<name>.keepResources

Prevent deletion of resources in this phase

Type: boolean

Default: false

Declared in: modules/lab/cluster/phases


phases.<name>.order

Numeric ordering (lower = deployed earlier)

Type: signed integer

Declared in: modules/lab/cluster/phases


phases.<name>.pruneStrategy

Resource pruning behavior:

  • default: normal prune
  • never: never prune
  • orphan: orphan on deletion

Type: one of "default", "never", "orphan"

Default: "default"

Declared in: modules/lab/cluster/phases


phases.<name>.timeout

Timeout for this phase’s deployment

Type: string

Default: "10m"

Declared in: modules/lab/cluster/phases


phases.<name>.waitForCRDs

Wait for CRDs to be established before deploying this phase

Type: boolean

Default: false

Declared in: modules/lab/cluster/phases


phases.<name>.waitForReady

Wait for all resources to become ready

Type: boolean

Default: true

Declared in: modules/lab/cluster/phases


provisioner.docker.clusterName

Docker cluster name

Type: string

Default: "catallaxy-‹name›"

Declared in: modules/lab/provisioners/docker.nix


provisioner.docker.colima.cpu

Number of CPUs for the VM

Type: signed integer

Default: 4

Declared in: modules/lab/provisioners/docker.nix


provisioner.docker.colima.disk

Disk size in GiB for the VM

Type: signed integer

Default: 60

Declared in: modules/lab/provisioners/docker.nix


provisioner.docker.colima.enable

Use Colima on macOS (auto-detected, ignored on Linux)

Type: boolean

Default: true

Declared in: modules/lab/provisioners/docker.nix


provisioner.docker.colima.memory

Memory in GiB for the VM

Type: signed integer

Default: 8

Declared in: modules/lab/provisioners/docker.nix


provisioner.docker.colima.profile

Colima profile name (isolates from other VMs)

Type: string

Default: "catallaxy"

Declared in: modules/lab/provisioners/docker.nix


provisioner.docker.waitTimeout

Timeout waiting for cluster to be ready

Type: string

Default: "10m"

Declared in: modules/lab/provisioners/docker.nix


provisioner.k3d.autoDeployManifests

Manifests to mount into k3s auto-deploy directory (/var/lib/rancher/k3s/server/manifests/). k3s applies these at boot. Used for pre-deploying CNI (Cilium) so nodes become Ready immediately.

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.autoDeployManifests.*.content

Nix store path to rendered manifest YAML

Type: absolute path

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.autoDeployManifests.*.name

Manifest filename (without .yaml)

Type: string

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.clusterName

k3d cluster name

Type: string

Default: "‹name›"

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.extraApiServerArgs

Extra kube-apiserver arguments passed to k3d via –k3s-arg “–kube-apiserver-arg=@server:*”. Automatically populated from components.oidc and pki-auth.

Type: list of string

Default: [ ]

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.extraVolumes

Extra volume mounts for k3d server nodes (e.g., CA certs)

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.extraVolumes.*.containerPath

Path inside k3d node

Type: string

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.extraVolumes.*.hostPath

Path on the Docker host

Type: string

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.image

Custom k3s image (null = k3d default)

Type: null or string

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.network

Docker network to create k3d cluster on (uses –network flag). When set, all clusters share this network for cross-cluster DNS.

Type: null or string

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.noFlannel

Disable default Flannel CNI (for Cilium)

Type: boolean

Default: true

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.noServiceLB

Disable default ServiceLB (Klipper)

Type: boolean

Default: true

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.noTraefik

Disable default Traefik ingress

Type: boolean

Default: true

Declared in: modules/lab/provisioners/k3d.nix


provisioner.k3d.ports

Port mappings for k3d (passed as -p flags). Format: “:@server:0” e.g. “8080:80@server:0”

Type: list of string

Default: [ ]

Declared in: modules/lab/provisioners/k3d.nix


resources

This option has no description.

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster


secrets.projections

Secret projections map lab-level managed secrets into Kubernetes Secrets. Each projection creates one K8s Secret with keys derived from a source managed secret, optionally transformed (base64, json-wrap).

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.keys

Key mappings from source managed secret to K8s Secret keys

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.keys.<name>.from

Source key name in the managed secret

Type: string

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.keys.<name>.jsonKey

JSON key name for json-wrap transform (defaults to the projection key name)

Type: null or string

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.keys.<name>.transform

Transform to apply when projecting:

  • none: passthrough
  • base64: base64-encode the value
  • json-wrap: wrap as JSON object {“”: “”}

Type: one of "none", "base64", "json-wrap"

Default: "none"

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.namespace

Kubernetes namespace for the projected Secret

Type: string

Default: "default"

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.phase

Deployment phase for injection

Type: string

Default: "secrets"

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.ref

Computed references for this projected secret

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/secrets


secrets.projections.<name>.source

Name of the lab-level managed secret (lab.secrets.managed.)

Type: string

Declared in: modules/lab/cluster/components/secrets


secrets.sops.ageKeyFile

Path to age private key for decryption

Type: null or absolute path

Declared in: modules/lab/cluster/components/secrets/sops.nix


secrets.sops.defaultEncryptedSuffix

File suffix for encrypted files

Type: string

Default: ".enc.yaml"

Declared in: modules/lab/cluster/components/secrets/sops.nix


secrets.sops.enable

Whether to enable SOPS secrets management.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/secrets/sops.nix


storage.s3Buckets

This option has no description.

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster


CNI Options

Options for: cilium.

All options are under lab.clusters.<name>.components.

cilium.bandwidthManager.bbr

Enable BBR TCP congestion control

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.bandwidthManager.enable

Enable bandwidth manager for rate limiting

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.bgp.enable

Enable BGP control plane for advertising routes to external routers

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.bgp.localASN

Local BGP Autonomous System Number for this cluster

Type: signed integer

Default: 65001

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.bgp.peers

BGP peers to establish sessions with

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.bgp.peers.*.address

BGP peer IP address

Type: string

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.bgp.peers.*.asn

BGP peer Autonomous System Number

Type: signed integer

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.chart

Cilium Helm chart derivation (default: cataCharts.cilium)

Type: package

Default: <derivation helm-chart-https-helm.cilium.io-cilium-1.17.2>

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.clusterMesh.clusterID

Unique cluster ID within the mesh (0-255)

Type: unsigned integer, meaning >=0

Default: 0

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.clusterMesh.clusterName

Cluster name for mesh identity (default: cluster.name)

Type: null or string

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.clusterMesh.enable

Enable multi-cluster networking via ClusterMesh

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.egressGateway.enable

Enable egress gateway for controlled outbound traffic

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.enable

Whether to enable Cilium CNI.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.encryption.enable

Enable transparent encryption of pod-to-pod traffic

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.encryption.nodeEncryption

Also encrypt node-to-node traffic

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.encryption.type

Encryption backend (WireGuard recommended)

Type: one of "wireguard", "ipsec"

Default: "wireguard"

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.enable

Enable Kubernetes Gateway API support (replaces legacy Ingress)

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.tls.domain

Base domain for wildcard cert (e.g. homelab.test → *.homelab.test)

Type: string

Default: ""

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.tls.enable

Enable HTTPS listener on the default Gateway with cert-manager TLS

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.tls.issuerRef

cert-manager issuer for the Gateway wildcard certificate

Type: submodule

Default:

{
  kind = "ClusterIssuer";
  name = "lab-ca";
}

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.tls.issuerRef.kind

Issuer kind

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.tls.issuerRef.name

cert-manager Issuer or ClusterIssuer name

Type: string

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.gatewayAPI.tls.passthrough.enable

Enable TLS passthrough listener on the Gateway (for backends that terminate TLS themselves)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.hubble.enable

Enable Hubble network observability

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.hubble.relay.enable

Enable Hubble Relay

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.hubble.ui.enable

Enable Hubble UI dashboard

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.ingressController.enable

Enable Cilium’s native ingress controller

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.ingressController.loadbalancerMode

LoadBalancer mode for ingress

Type: one of "shared", "dedicated"

Default: "shared"

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.ipam.mode

IP Address Management mode

Type: one of "kubernetes", "cluster-pool"

Default: "kubernetes"

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.k8sServiceHost

Kubernetes API server host. When null, auto-configured based on cluster provider:

  • external (CAPI): uses Kubernetes service ClusterIP (10.96.0.1)
  • docker (k3d): uses localhost

Type: null or string

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.k8sServicePort

Kubernetes API server port. When null, auto-configured based on cluster provider:

  • external (CAPI): 443 (Kubernetes service port)
  • docker (k3d): 6443

Type: null or string

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.kubeProxyReplacement

Replace kube-proxy with eBPF-based load balancing

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.l2.announcements

Enable L2 (ARP/NDP) announcements for service IPs

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.lbIPAM.enable

Enable LoadBalancer IP Address Management

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.lbIPAM.pools

IP address pools for LoadBalancer services

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.lbIPAM.pools.*.cidrs

CIDR ranges for IP allocation

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.lbIPAM.pools.*.name

Pool name

Type: string

Default: "default"

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.networkPolicy.clusterNetworkPolicy

Enable CiliumClusterwideNetworkPolicy CRD

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.networkPolicy.enable

Enable Kubernetes NetworkPolicy enforcement

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.networkPolicy.hostFirewall

Enable host-level firewall enforcement

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.networkPolicy.policyAuditMode

Audit mode — log policy violations instead of enforcing

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.operator.replicas

Number of Cilium operator replicas

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.phase

Deployment phase this component belongs to

Type: string

Default: "networking"

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.ref

Computed references for Cilium

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/cni/cilium.nix


cilium.version

Cilium version

Type: string

Default: "1.16.3"

Declared in: modules/lab/cluster/components/cni/cilium.nix


Gateway and DNS Options

Options for: gateway, external-dns.

All options are under lab.clusters.<name>.components.

external-dns.chart

ExternalDNS Helm chart derivation (default: cataCharts.external-dns)

Type: package

Default:

<derivation helm-chart-https-kubernetes-sigs.github.io-external-dns-external-dns-1.16.1>

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.defaultTargets

Override the target IP/hostname for all DNS records (e.g. [“127.0.0.1”] for local dev)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.domainFilters

Domains to manage (empty = all)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.enable

Whether to enable ExternalDNS.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.env

Extra environment variables (e.g. API tokens from secrets)

Type: list of (attribute set)

Default: [ ]

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.excludeDomains

Domains to exclude from management

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.extraArgs

Provider-specific extra arguments (e.g. { cloudflare-proxied = “true”; })

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.interval

Sync interval

Type: string

Default: "1m"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.logLevel

Log verbosity level

Type: one of "debug", "info", "warning", "error"

Default: "info"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.namespace

Namespace for ExternalDNS

Type: string

Default: "external-dns"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.policy

Record management policy (sync creates+updates+deletes)

Type: one of "sync", "upsert-only", "create-only"

Default: "sync"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.provider

DNS provider (cloudflare, route53, google, azure-dns, etc.)

Type: string

Default: "cloudflare"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.ref

Computed references for ExternalDNS

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.host

DNS server host for RFC2136 updates

Type: string

Default: ""

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.port

DNS server port

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 53

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.tsigAxfr

Enable AXFR (zone transfer) using TSIG. Not needed for basic operation.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.tsigKeyname

TSIG key name for authenticating DNS updates

Type: string

Default: "externaldns-key"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.tsigSecret

Base64-encoded TSIG secret

Type: string

Default: ""

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.tsigSecretAlg

TSIG secret algorithm

Type: one of "hmac-sha256", "hmac-sha512", "hmac-sha1"

Default: "hmac-sha256"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.rfc2136.zone

DNS zone to manage (e.g. ‘lab.test.’)

Type: string

Default: ""

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.serviceAccount.annotations

ServiceAccount annotations (for AWS IRSA, GCP Workload Identity, etc.)

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.sources

Kubernetes resource types to watch for DNS records

Type: list of string

Default:

[
  "service"
  "ingress"
  "gateway-httproute"
  "gateway-tlsroute"
]

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.triggerLoopOnEvent

React to resource events immediately rather than waiting for interval

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.txtOwnerId

TXT record ownership ID (defaults to cluster name)

Type: null or string

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.txtPrefix

Prefix for TXT ownership records

Type: string

Default: "externaldns-"

Declared in: modules/lab/cluster/components/external-dns.nix


external-dns.version

ExternalDNS Helm chart version

Type: string

Default: "1.15.0"

Declared in: modules/lab/cluster/components/external-dns.nix


gateway.chart

Traefik Helm chart derivation

Type: package

Default: <derivation helm-chart-https-traefik.github.io-charts-traefik-35.2.0>

Declared in: modules/lab/cluster/components/gateway.nix


gateway.className

GatewayClass name

Type: string

Default: "traefik"

Declared in: modules/lab/cluster/components/gateway.nix


gateway.controller

Gateway controller to deploy:

  • traefik: deploy Traefik v3 (default, good for k3d labs)
  • external: skip controller deployment (use with Cilium or pre-installed controller)

Type: one of "traefik", "external"

Default: "traefik"

Declared in: modules/lab/cluster/components/gateway.nix


gateway.controllerName

Gateway controller name for the GatewayClass

Type: string

Default: "traefik.io/gateway-controller"

Declared in: modules/lab/cluster/components/gateway.nix


gateway.enable

Whether to enable Gateway API (standalone, CNI-agnostic).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/gateway.nix


gateway.gatewayName

Gateway resource name (components reference this via gateway.gatewayRef)

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/gateway.nix


gateway.namespace

Namespace for the Gateway resource

Type: string

Default: "kube-system"

Declared in: modules/lab/cluster/components/gateway.nix


gateway.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.domain

Base domain for wildcard cert (e.g. homelab.test)

Type: string

Default: ""

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.enable

Enable HTTPS listener with cert-manager TLS

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.issuerRef

This option has no description.

Type: submodule

Default:

{
  kind = "ClusterIssuer";
  name = "lab-ca";
}

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.issuerRef.kind

This option has no description.

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.issuerRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.passthrough.enable

Enable TLS passthrough listener (for backends that terminate TLS themselves)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/gateway.nix


gateway.tls.passthrough.port

Traefik entryPoint port for TLS passthrough (must differ from websecure port)

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 8444

Declared in: modules/lab/cluster/components/gateway.nix


PKI Options

Options for: cert-manager, trust-manager, pki-auth.

All options are under lab.clusters.<name>.components.

cert-manager.acme.dns01.cloudflare.apiToken

Cloudflare API token (if set, auto-creates the Secret)

Type: null or string

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.cloudflare.apiTokenSecretName

Name of Secret containing the Cloudflare API token (key: api-token)

Type: string

Default: "cloudflare-api-token"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.provider

Public DNS provider for ACME DNS01 challenges

Type: one of "none", "cloudflare", "route53"

Default: "none"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.route53.accessKeyID

AWS access key ID (for explicit credentials)

Type: string

Default: ""

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.route53.hostedZoneID

Route53 hosted zone ID

Type: string

Default: ""

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.route53.region

AWS region for Route53

Type: string

Default: "us-east-1"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.route53.secretAccessKey

AWS secret access key (if set, auto-creates the Secret)

Type: null or string

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.dns01.route53.secretAccessKeySecretName

Name of Secret containing AWS secret access key (key: secret-access-key)

Type: string

Default: "route53-credentials"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.email

Email for ACME registration

Type: string

Default: ""

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.enable

Create an ACME ClusterIssuer for Let’s Encrypt

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.issuerName

Name of the ACME ClusterIssuer

Type: string

Default: "letsencrypt"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.server

ACME server URL (use staging for testing)

Type: string

Default: "https://acme-v02.api.letsencrypt.org/directory"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.acme.solvers

Raw ACME solver config (overrides dns01 provider if set)

Type: list of (attribute set)

Default: [ ]

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.chart

cert-manager Helm chart derivation (default: cataCharts.cert-manager)

Type: package

Default: <derivation helm-chart-https-charts.jetstack.io-cert-manager-1.17.2>

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.enable

Whether to enable cert-manager.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.namespace

Namespace for cert-manager

Type: string

Default: "cert-manager"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.ref

Computed references for cert-manager

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.selfSignedCA.enable

Create a self-signed CA ClusterIssuer

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.selfSignedCA.issuerName

Name of the ClusterIssuer backed by the self-signed CA

Type: string

Default: "lab-ca"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


cert-manager.version

cert-manager version

Type: string

Default: "v1.16.1"

Declared in: modules/lab/cluster/components/pki/cert-manager.nix


pki-auth.ca.commonName

CA certificate Common Name

Type: string

Default: "catallaxy-‹name›-ca"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.ca.keyAlgorithm

CA private key algorithm

Type: one of "ecdsa-p256", "ecdsa-p384", "ed25519", "rsa-2048", "rsa-4096"

Default: "ecdsa-p256"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.ca.validity

CA certificate validity period

Type: string

Default: "10y"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.defaults.keyAlgorithm

Default key algorithm for client certificates

Type: one of "ecdsa-p256", "ecdsa-p384", "ed25519", "rsa-2048", "rsa-4096"

Default: "ecdsa-p256"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.defaults.renewBefore

Renew certificate this long before expiry

Type: string

Default: "30d"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.defaults.validity

Default client certificate validity

Type: string

Default: "1y"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.enable

Whether to enable PKI-based authentication (client certificates).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.namespace

Namespace for PKI auth RBAC resources

Type: string

Default: "pki-auth"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.rbac

Map of ClusterRoleBinding name → cert Organization → ClusterRole

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.rbac.<name>.clusterRole

ClusterRole to bind to this group

Type: string

Default: "cluster-admin"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.rbac.<name>.organization

Certificate Organization value (Kubernetes group name)

Type: string

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.ref

Computed references for PKI auth

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users

Users who receive client certificates for Kubernetes auth

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.commonName

Certificate Common Name — becomes the Kubernetes username. Typically an email address.

Type: string

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.keyAlgorithm

Override key algorithm for this user

Type: null or string

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.organizations

Certificate Organization fields — become Kubernetes groups. Bind these to ClusterRoles via the rbac option.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.validity

Override certificate validity for this user

Type: null or string

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.yubikey.pinPolicy

YubiKey PIN policy

Type: one of "once", "always", "never"

Default: "once"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.yubikey.serialNumber

YubiKey serial number for automatic provisioning. When set, cata pki provision will target this specific device.

Type: null or string

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.yubikey.slot

PIV slot for the certificate (9a=authentication, 9c=signing)

Type: string

Default: "9a"

Declared in: modules/lab/cluster/auth/pki.nix


pki-auth.users.<name>.yubikey.touchPolicy

YubiKey touch policy (always=tap every use, cached=tap once per 15s)

Type: one of "always", "cached", "never"

Default: "always"

Declared in: modules/lab/cluster/auth/pki.nix


trust-manager.chart

This option has no description.

Type: package

Default: <derivation helm-chart-https-charts.jetstack.io-trust-manager-0.22.1>

Declared in: modules/lab/cluster/components/pki/trust-manager.nix


trust-manager.enable

Whether to enable trust-manager (CA bundle distribution).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/pki/trust-manager.nix


trust-manager.namespace

This option has no description.

Type: string

Default: "cert-manager"

Declared in: modules/lab/cluster/components/pki/trust-manager.nix


trust-manager.phase

This option has no description.

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/pki/trust-manager.nix


trust-manager.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/pki/trust-manager.nix


Observability Options

Options for: prometheus, grafana, loki, tempo, otel-collector.

All options are under lab.clusters.<name>.components.

grafana.adminCredentialsSecret

Existing secret with admin-user and admin-password keys

Type: null or string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.chart

Grafana Helm chart derivation (default: cataCharts.grafana)

Type: package

Default: <derivation helm-chart-https-grafana.github.io-helm-charts-grafana-10.5.15>

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.datasources.loki.url

Loki URL. Auto-configured from components.loki.ref when null and Loki is enabled.

Type: null or string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.datasources.prometheus.url

Prometheus URL. Auto-configured from components.prometheus.ref when null and Prometheus is enabled.

Type: null or string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.datasources.tempo.url

Tempo URL. Auto-configured from components.tempo.ref when null and Tempo is enabled.

Type: null or string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.domain

Domain for Grafana external access

Type: string

Default: "grafana.local"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.enable

Whether to enable Grafana.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.gateway.enable

Enable HTTPRoute for external access via Gateway API

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.gateway.gatewayNamespace

Namespace of the Gateway resource

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.gateway.gatewayRef

Name of the Gateway resource to attach to

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.namespace

Namespace for Grafana

Type: string

Default: "grafana"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.allowSignUp

Allow OIDC users to be created on first login

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.autoLogin

Automatically redirect to OIDC provider (skip login page)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.clientId

OAuth2 client ID

Type: string

Default: "grafana"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.clientSecretRef

Reference to Secret containing OIDC client secret

Type: null or (submodule)

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.clientSecretRef.key

Key within the secret

Type: string

Default: "client-secret"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.clientSecretRef.name

Secret containing OIDC client secret

Type: string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.enable

Whether to enable OIDC authentication via Kanidm.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.issuerUrl

OIDC issuer URL (e.g., from Kanidm ref)

Type: string

Default: ""

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.name

Display name for OIDC provider on login page

Type: string

Default: "Kanidm"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.roleAttributePath

JMESPath expression for mapping OIDC claims to Grafana roles

Type: string

Default:

"contains(groups[*], 'grafana-admins') && 'Admin' || contains(groups[*], 'grafana-editors') && 'Editor' || 'Viewer'"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.scopes

OIDC scopes to request

Type: list of string

Default:

[
  "openid"
  "email"
  "profile"
  "groups"
]

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsCaBundleConfigMap

ConfigMap containing CA bundle for OIDC provider (from trust-manager)

Type: null or (submodule)

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsCaBundleConfigMap.key

Key within the ConfigMap

Type: string

Default: "ca.crt"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsCaBundleConfigMap.name

ConfigMap containing CA bundle

Type: string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsCaCertSecretRef

Reference to Secret containing CA certificate for OIDC provider

Type: null or (submodule)

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsCaCertSecretRef.key

Key within the secret

Type: string

Default: "ca.crt"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsCaCertSecretRef.name

Secret containing CA certificate

Type: string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.oidc.tlsSkipVerify

Skip TLS certificate verification for OIDC provider

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.persistence.enable

Enable persistent storage for Grafana

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.persistence.size

PVC size for Grafana data

Type: string

Default: "10Gi"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.persistence.storageClass

Storage class for PVC

Type: null or string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.plugins

Grafana plugins to install (e.g., grafana-tempoexplore-app)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.ref

Computed references for Grafana

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.replicas

Number of Grafana replicas

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.sidecar.dashboards.enable

Enable sidecar for auto-loading dashboards from ConfigMaps

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.sidecar.dashboards.searchNamespace

Namespace(s) to search for dashboard ConfigMaps. null = own namespace, ‘ALL’ = all namespaces.

Type: null or string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.tls.issuerRef

cert-manager issuer reference for Grafana TLS certificate

Type: null or (submodule)

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.tls.issuerRef.kind

Issuer kind

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.tls.issuerRef.name

Issuer or ClusterIssuer name

Type: string

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.tls.secretName

Name of the TLS Secret created by cert-manager

Type: string

Default: "grafana-tls"

Declared in: modules/lab/cluster/components/observability/grafana.nix


grafana.version

Grafana Helm chart version

Type: string

Default: "8.5.2"

Declared in: modules/lab/cluster/components/observability/grafana.nix


loki.chart

Loki Helm chart derivation (default: cataCharts.loki)

Type: package

Default: <derivation helm-chart-https-grafana.github.io-helm-charts-loki-6.30.1>

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.deploymentMode

Loki deployment topology

Type: one of "SingleBinary", "SimpleScalable", "Distributed"

Default: "SingleBinary"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.enable

Whether to enable Loki log aggregation.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.namespace

Namespace for Loki

Type: string

Default: "loki"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.ref

Computed references for Loki

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.replicas

Replicas (SingleBinary mode) or read/write replicas (SimpleScalable)

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.retention

Log retention period (default 31 days)

Type: string

Default: "744h"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.persistence.size

PVC size for local storage (filesystem mode)

Type: string

Default: "50Gi"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.persistence.storageClass

Storage class for PVCs

Type: null or string

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.s3.bucket

S3 bucket name

Type: string

Default: "loki-chunks"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.s3.endpoint

S3 endpoint URL (for S3-compatible storage). Use config.components.seaweedfs.ref.s3Endpoint for SeaweedFS.

Type: null or string

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.s3.region

S3 region

Type: string

Default: "us-east-1"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.s3.secretName

Secret with S3 credentials (access-key-id, secret-access-key keys)

Type: null or string

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.storage.type

Storage backend type

Type: one of "filesystem", "s3"

Default: "filesystem"

Declared in: modules/lab/cluster/components/observability/loki.nix


loki.version

Loki Helm chart version

Type: string

Default: "6.16.0"

Declared in: modules/lab/cluster/components/observability/loki.nix


otel-collector.agent.enable

Whether to enable OTEL agent (DaemonSet for log collection).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.excludeNamespaces

Namespaces to exclude from log collection (otel namespace auto-excluded)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.gateway.endpoint

Gateway OTLP endpoint (defaults to local gateway if not set)

Type: null or string

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.namespaces

Namespaces to collect logs from (empty = all namespaces)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.resources.limits.cpu

This option has no description.

Type: string

Default: "200m"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.resources.limits.memory

This option has no description.

Type: string

Default: "256Mi"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.resources.requests.cpu

This option has no description.

Type: string

Default: "50m"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.agent.resources.requests.memory

This option has no description.

Type: string

Default: "128Mi"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.chart

OpenTelemetry Collector Helm chart derivation

Type: package

Default:

<derivation helm-chart-https-open-telemetry.github.io-opentelemetry-helm-charts-opentelemetry-collector-0.156.0>

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.enable

Whether to enable OpenTelemetry Collector.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.exporters.loki.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.exporters.loki.endpoint

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.exporters.otlp.endpoint

OTLP gRPC endpoint for traces/metrics/logs (e.g., host:4317)

Type: null or string

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.exporters.otlphttp.endpoint

OTLP HTTP endpoint for traces/metrics/logs (e.g., http://host:4318)

Type: null or string

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.exporters.prometheus.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.exporters.prometheus.endpoint

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.enable

Whether to enable OTEL gateway (Deployment for receiving/forwarding).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.external.domain

Domain for external access

Type: null or string

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.external.enable

Whether to enable Expose gateway externally.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.external.tls.issuerRef

cert-manager issuer for the external gateway TLS certificate

Type: null or (submodule)

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.external.tls.issuerRef.kind

This option has no description.

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.external.tls.issuerRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.external.tls.secretName

This option has no description.

Type: string

Default: "otel-gateway-tls"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.replicas

Number of gateway replicas

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.resources.limits.cpu

This option has no description.

Type: string

Default: "500m"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.resources.limits.memory

This option has no description.

Type: string

Default: "512Mi"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.resources.requests.cpu

This option has no description.

Type: string

Default: "100m"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.gateway.resources.requests.memory

This option has no description.

Type: string

Default: "256Mi"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.namespace

Namespace for OpenTelemetry Collector

Type: string

Default: "otel"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.ports.otlpGrpc

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 4317

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.ports.otlpHttp

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 4318

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.ports.prometheus

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 8889

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.ref

Computed references for the OpenTelemetry Collector

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.tls.caBundleConfigMap

ConfigMap containing the CA bundle for TLS verification on gateway exporters. When null, exporters use tls.insecure=true.

Type: null or string

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.tls.caBundleKey

Key within the CA bundle ConfigMap

Type: string

Default: "ca.crt"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


otel-collector.version

OpenTelemetry Collector Helm chart version

Type: string

Default: "0.96.0"

Declared in: modules/lab/cluster/components/observability/otel-collector.nix


prometheus.alertmanager.enable

Enable Alertmanager

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.chart

kube-prometheus-stack Helm chart derivation (default: cataCharts.prometheus)

Type: package

Default:

<derivation helm-chart-https-prometheus-community.github.io-helm-charts-kube-prometheus-stack-72.5.0>

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.defaultRules

Override default alert rule groups (e.g., { kubeEtcd = false; } to disable etcd rules)

Type: attribute set of boolean

Default: { }

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.enable

Whether to enable Prometheus (kube-prometheus-stack).

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.externalLabels

External labels added to all metrics (e.g., cluster name for multi-cluster)

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.gateway.domain

Domain for external remote-write ingestion

Type: string

Default: ""

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.gateway.enable

Expose Prometheus remote-write endpoint externally via Gateway API

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.gateway.gatewayNamespace

This option has no description.

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.gateway.gatewayRef

This option has no description.

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.grafana.enable

Enable the bundled Grafana (disable when using components.grafana)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.grafana.forceDeployDashboards

Deploy Kubernetes dashboard ConfigMaps even when bundled Grafana is disabled

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.kubeStateMetrics.enable

Enable kube-state-metrics

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.namespace

Namespace for Prometheus

Type: string

Default: "prometheus"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.nodeExporter.enable

Enable Node Exporter for host metrics

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.ref

Computed references for Prometheus

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.remoteWrite

Remote write endpoints for forwarding metrics

Type: list of (attribute set)

Default: [ ]

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.replicas

Number of Prometheus replicas

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.retention

Metrics retention period

Type: string

Default: "15d"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.serviceMonitorSelector

Label selector for ServiceMonitors (empty = all)

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.storage.size

PVC size for Prometheus TSDB

Type: string

Default: "50Gi"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.storage.storageClass

Storage class for PVC

Type: null or string

Declared in: modules/lab/cluster/components/observability/prometheus.nix


prometheus.version

kube-prometheus-stack Helm chart version

Type: string

Default: "65.1.0"

Declared in: modules/lab/cluster/components/observability/prometheus.nix


tempo.chart

Tempo Helm chart derivation (default: cataCharts.tempo)

Type: package

Default: <derivation helm-chart-https-grafana.github.io-helm-charts-tempo-1.21.0>

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.deploymentMode

Tempo deployment topology

Type: one of "monolithic", "distributed"

Default: "monolithic"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.enable

Whether to enable Tempo distributed tracing.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.namespace

Namespace for Tempo

Type: string

Default: "tempo"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.receivers.otlp.grpc

Enable OTLP gRPC receiver

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.receivers.otlp.http

Enable OTLP HTTP receiver

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.ref

Computed references for Tempo

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.retention

Trace retention period (default 7 days)

Type: string

Default: "168h"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.persistence.size

PVC size for trace storage (filesystem mode)

Type: string

Default: "20Gi"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.persistence.storageClass

Storage class for PVCs

Type: null or string

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.s3.bucket

S3 bucket name

Type: string

Default: "tempo-traces"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.s3.endpoint

S3 endpoint URL (for S3-compatible storage). Use config.components.seaweedfs.ref.s3Endpoint for SeaweedFS.

Type: null or string

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.s3.region

S3 region

Type: string

Default: "us-east-1"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.s3.secretName

Secret with S3 credentials

Type: null or string

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.storage.type

Trace storage backend

Type: one of "filesystem", "s3"

Default: "filesystem"

Declared in: modules/lab/cluster/components/observability/tempo.nix


tempo.version

Tempo Helm chart version

Type: string

Default: "1.10.3"

Declared in: modules/lab/cluster/components/observability/tempo.nix


Databases Options

Options for: cnpg, redis-operator.

All options are under lab.clusters.<name>.components.

cnpg.chart

Custom chart derivation. When null, uses nixhelm default.

Type: package

Default:

<derivation helm-chart-https-cloudnative-pg.github.io-charts-cloudnative-pg-0.23.0>

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters

Declarative PostgreSQL clusters managed by CNPG

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.backup.enable

Enable automated backups

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.backup.retentionPolicy

Backup retention policy

Type: string

Default: "30d"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.backup.schedule

Cron schedule for backups

Type: string

Default: "0 0 * * *"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.createNamespace

Whether to create the namespace (set to false if another app manages it)

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.databases

Databases to create in this cluster

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.databases.<name>.extensions

PostgreSQL extensions to enable for this database

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.databases.<name>.owner

Database owner username

Type: string

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.databases.<name>.userPasswordSecretRef

Reference to Secret containing the database user’s password

Type: null or (submodule)

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.databases.<name>.userPasswordSecretRef.key

Key within the secret

Type: string

Default: "password"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.databases.<name>.userPasswordSecretRef.name

Secret containing user password

Type: string

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.enable

Enable this PostgreSQL cluster

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.instances

Number of PostgreSQL instances (replicas)

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.monitoring.enable

Enable Prometheus metrics

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.namespace

Namespace for this cluster

Type: string

Default: "databases"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.postgresql.parameters

PostgreSQL configuration parameters

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.postgresql.version

PostgreSQL major version

Type: string

Default: "16"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.ref

Computed references for this cluster

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.storage.size

PVC size for each instance

Type: string

Default: "10Gi"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.storage.storageClass

Storage class for PVCs. Null uses the cluster default.

Type: null or string

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.superuserPasswordSecretRef

Reference to Secret containing superuser password for bootstrap

Type: null or (submodule)

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.superuserPasswordSecretRef.key

Key within the secret

Type: string

Default: "password"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.clusters.<name>.superuserPasswordSecretRef.name

Secret name containing superuser password

Type: string

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.enable

Whether to enable CloudNativePG operator.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.namespace

Namespace for the CloudNativePG operator

Type: string

Default: "cnpg-system"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.ref

Computed references for CNPG

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/databases/cnpg.nix


cnpg.version

CloudNativePG operator chart version

Type: string

Default: "0.22.0"

Declared in: modules/lab/cluster/components/databases/cnpg.nix


redis-operator.chart

Custom chart derivation. When null, uses nixhelm default.

Type: package

Default:

<derivation helm-chart-https-ot-container-kit.github.io-helm-charts-redis-operator-0.18.2>

Declared in: modules/lab/cluster/components/redis-operator.nix


redis-operator.enable

Whether to enable Redis operator.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/redis-operator.nix


redis-operator.namespace

Namespace for the Redis operator

Type: string

Default: "redis-operator"

Declared in: modules/lab/cluster/components/redis-operator.nix


redis-operator.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/redis-operator.nix


redis-operator.ref

Computed references for Redis operator

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/redis-operator.nix


redis-operator.version

Redis operator chart version

Type: string

Default: "0.18.0"

Declared in: modules/lab/cluster/components/redis-operator.nix


Filesystems Options

Options for: openebs, seaweedfs.

All options are under lab.clusters.<name>.components.

openebs.chart

Custom chart derivation. When null, uses nixhelm default.

Type: package

Default:

<derivation helm-chart-https-charts.containeroo.ch-local-path-provisioner-0.0.30>

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.enable

Whether to enable OpenEBS storage operator.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.engine

Storage engine:

  • hostpath: local path provisioner (dev/single-node)
  • lvm: LVM-based local storage
  • zfs: ZFS-based local storage
  • mayastor: replicated NVMe-oF storage (production HA)

Type: one of "hostpath", "lvm", "zfs", "mayastor"

Default: "hostpath"

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.mayastor.cpuCount

CPU cores allocated to each Mayastor instance

Type: positive integer, meaning >0

Default: 2

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.mayastor.replicas

Number of Mayastor IO engine replicas

Type: positive integer, meaning >0

Default: 3

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.namespace

Namespace for OpenEBS

Type: string

Default: "openebs"

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.ref

Computed references for OpenEBS

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.storageClasses

StorageClass definitions to create

Type: attribute set of (submodule)

Default:

{
  openebs-default = {
    isDefault = true;
  };
}

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.storageClasses.<name>.isDefault

Set as the cluster’s default StorageClass

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.storageClasses.<name>.reclaimPolicy

PV reclaim policy

Type: one of "Delete", "Retain"

Default: "Delete"

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.storageClasses.<name>.volumeBindingMode

Volume binding mode

Type: one of "WaitForFirstConsumer", "Immediate"

Default: "WaitForFirstConsumer"

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


openebs.version

OpenEBS version

Type: string

Default: "4.1.1"

Declared in: modules/lab/cluster/components/filesystems/openebs.nix


seaweedfs.chart

Custom chart derivation. When null, uses nixhelm default.

Type: package

Default: <derivation helm-chart-https-seaweedfs.github.io-seaweedfs-helm-seaweedfs-4.0.0>

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.enable

Whether to enable SeaweedFS distributed storage.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.filer.replicas

Number of filer replicas (2+ for production)

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.filer.s3.enable

Enable S3 API gateway on the filer

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.filer.storage

Storage size for filer metadata

Type: string

Default: "10Gi"

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.master.replicas

Number of master server replicas (3 for production)

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.master.storage

Storage size for master metadata

Type: string

Default: "10Gi"

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.namespace

Namespace for SeaweedFS

Type: string

Default: "seaweedfs"

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.ref

Computed references for SeaweedFS

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.s3.enable

Enable S3 API

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.s3.port

S3 API port

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 8333

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.version

SeaweedFS version

Type: string

Default: "3.71"

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.volume.replicas

Number of volume server replicas (3+ for production)

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.volume.storage

Storage size per volume server

Type: string

Default: "50Gi"

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


seaweedfs.volume.storageClass

StorageClass for volume server PVCs (null = cluster default)

Type: null or string

Declared in: modules/lab/cluster/components/filesystems/seaweedfs.nix


Secrets Options

Options for: external-secrets, sops.

All options are under lab.clusters.<name>.components.

external-secrets.chart

External Secrets Helm chart derivation (default: cataCharts.external-secrets)

Type: package

Default: <derivation helm-chart-https-charts.external-secrets.io-external-secrets-0.15.0>

Declared in: modules/lab/cluster/components/secrets/external-secrets.nix


external-secrets.enable

Whether to enable External Secrets Operator.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/secrets/external-secrets.nix


external-secrets.namespace

Namespace for External Secrets Operator

Type: string

Default: "external-secrets"

Declared in: modules/lab/cluster/components/secrets/external-secrets.nix


external-secrets.phase

Deployment phase this component belongs to

Type: string

Default: "secrets"

Declared in: modules/lab/cluster/components/secrets/external-secrets.nix


external-secrets.ref

Computed references for External Secrets Operator

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/secrets/external-secrets.nix


external-secrets.version

External Secrets Operator version

Type: string

Default: "0.10.0"

Declared in: modules/lab/cluster/components/secrets/external-secrets.nix


Identity Options

Options for: kanidm, kaniop, oidc.

All options are under lab.clusters.<name>.components.

kanidm.backup.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.backup.schedule

This option has no description.

Type: string

Default: "0 2 * * *"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.chart

This option has no description.

Type: package

Default: <derivation helm-chart-https-datosh.github.io-kanidm-kanidm-0.2.1>

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.domain

This option has no description.

Type: string

Default: "idm.example.com"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.enable

Whether to enable Kanidm identity management.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.gateway.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.gateway.gatewayNamespace

This option has no description.

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.gateway.gatewayRef

This option has no description.

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.gateway.mode

TLS mode: ‘terminate’ uses HTTPRoute + BackendTLSPolicy, ‘passthrough’ uses TLSRoute (raw TLS to backend)

Type: one of "terminate", "passthrough"

Default: "terminate"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.accountPolicy

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.accountPolicy.authSessionExpiry

This option has no description.

Type: signed integer

Default: 86400

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.accountPolicy.credentialTypeMinimum

This option has no description.

Type: one of "any", "mfa", "passkey", "attested_passkey"

Default: "any"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.accountPolicy.passwordMinimumLength

This option has no description.

Type: signed integer

Default: 12

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.accountPolicy.privilegeExpiry

This option has no description.

Type: signed integer

Default: 900

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.entryManagedBy

Group or account that manages this group

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.mail

Group email addresses

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.members

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.posixAttributes

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.groups.<name>.posixAttributes.gidnumber

This option has no description.

Type: null or signed integer

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.instanceName

This option has no description.

Type: string

Default: "kanidm"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.namespace

This option has no description.

Type: string

Default: "kanidm"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2ClientNamespaceSelector

Namespace selector for KanidmOAuth2Client discovery. {} = all namespaces.

Type: null or (attribute set)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.allowInsecureClientDisablePkce

Disable PKCE enforcement for confidential clients whose OIDC library doesn’t support it (e.g. Dex)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.allowLocalhostRedirect

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.claimMap

Custom claim mappings from group membership

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.claimMap.*.joinStrategy

This option has no description.

Type: one of "csv", "ssv", "array"

Default: "array"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.claimMap.*.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.claimMap.*.valuesMap

This option has no description.

Type: list of (submodule)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.claimMap.*.valuesMap.*.group

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.claimMap.*.valuesMap.*.values

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.disableConsentPrompt

Skip user consent screen (for admin-managed apps)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.displayName

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.namespace

Namespace for this OAuth2Client CR and its generated secret. null = kanidm namespace.

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.origin

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.preferShortUsername

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.public

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.redirectUrls

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.scopeMap

This option has no description.

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.scopeMap.*.group

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.scopeMap.*.scopes

This option has no description.

Type: list of string

Default:

[
  "openid"
  "email"
  "groups"
]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.secretTemplate

Extra labels for the kaniop-generated credential secret

Type: null or (attribute set of string)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.strictRedirectUrl

Require exact redirect URL matching

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.supScopeMap

Supplementary scopes (optional claims not used for authz)

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.supScopeMap.*.group

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.oauth2Clients.<name>.supScopeMap.*.scopes

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.origin

This option has no description.

Type: string

Default: "https://idm.example.com"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.phase

This option has no description.

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.replicas

This option has no description.

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts

Service accounts (bots/daemons) with API tokens

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.accountExpire

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.accountValidFrom

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.apiTokens

This option has no description.

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.apiTokens.*.expiry

RFC3339 expiry (e.g. 2026-12-31T00:00:00Z)

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.apiTokens.*.label

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.apiTokens.*.purpose

This option has no description.

Type: one of "readonly", "readwrite"

Default: "readonly"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.apiTokens.*.secretName

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.displayName

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.entryManagedBy

Group or account that manages this service account

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.serviceAccounts.<name>.mail

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.storage.size

This option has no description.

Type: string

Default: "10Gi"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.storage.storageClass

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.tls.issuerRef

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.tls.issuerRef.kind

This option has no description.

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.tls.issuerRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.tls.secretName

This option has no description.

Type: string

Default: "kanidm-tls"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.accountExpire

ISO 8601 timestamp — account expires after this time

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.accountValidFrom

ISO 8601 timestamp — account is invalid before this time

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.credential

This option has no description.

Type: one of "token", "password", "passkey"

Default: "token"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.credentialsTokenTtl

This option has no description.

Type: signed integer

Default: 3600

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.displayName

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.email

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.groups

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.legalName

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.passwordSecretRef

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.passwordSecretRef.key

This option has no description.

Type: string

Default: "password"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.passwordSecretRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.posixAttributes

POSIX/Unix attributes for SSH and Linux integration

Type: null or (submodule)

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.posixAttributes.gidnumber

Unix UID/GID (auto-generated if null)

Type: null or signed integer

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.users.<name>.posixAttributes.loginshell

This option has no description.

Type: string

Default: "/bin/bash"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kanidm.version

This option has no description.

Type: string

Default: "1.4.2"

Declared in: modules/lab/cluster/components/idm/kanidm.nix


kaniop.chart

Custom chart derivation. When null, uses OCI chart.

Type: package

Default: <derivation helm-chart-oci-ghcr.io-pando85-helm-charts-kaniop-0.6.1>

Declared in: modules/lab/cluster/components/idm/kaniop.nix


kaniop.enable

Whether to enable Kaniop operator for declarative Kanidm management.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/idm/kaniop.nix


kaniop.namespace

Namespace for Kaniop operator (same as Kanidm)

Type: string

Default: "kanidm"

Declared in: modules/lab/cluster/components/idm/kaniop.nix


kaniop.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/idm/kaniop.nix


kaniop.ref

Computed references for Kaniop

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/idm/kaniop.nix


kaniop.version

Kaniop operator version

Type: string

Default: "0.6.1"

Declared in: modules/lab/cluster/components/idm/kaniop.nix


oidc.caSecretRef

Reference to Secret containing the OIDC issuer CA certificate

Type: null or (submodule)

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.caSecretRef.key

Key within the secret

Type: string

Default: "ca.crt"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.caSecretRef.name

Secret name containing CA cert

Type: string

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.caSecretRef.namespace

Secret namespace

Type: string

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.clientId

OIDC client ID registered in the identity provider

Type: string

Default: "kubernetes"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.enable

Whether to enable OIDC authentication for Kubernetes API server.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.groupsClaim

JWT claim containing group memberships

Type: string

Default: "groups"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.groupsPrefix

Prefix added to OIDC groups to avoid collisions

Type: string

Default: "oidc:"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.issuerUrl

OIDC issuer URL for the Kubernetes API server. Use config.components.kanidm.ref.oauth2Clients..issuer or lab.clusters..components.kanidm.ref.oauth2Clients..issuer for type-safe integration.

Type: string

Default: ""

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.namespace

Namespace for OIDC RBAC resources

Type: string

Default: "kube-system"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.rbac

Map of ClusterRoleBinding name to OIDC group + ClusterRole

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.rbac.<name>.clusterRole

ClusterRole to bind to the OIDC group

Type: string

Default: "cluster-admin"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.rbac.<name>.group

OIDC group name (groupsPrefix will be prepended)

Type: string

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.ref

Computed references for OIDC

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.usernameClaim

JWT claim to use as the Kubernetes username

Type: string

Default: "email"

Declared in: modules/lab/cluster/auth/oidc.nix


oidc.usernamePrefix

Prefix added to OIDC usernames to avoid collisions

Type: string

Default: "oidc:"

Declared in: modules/lab/cluster/auth/oidc.nix


GitOps Options

Options for: argocd.

All options are under lab.clusters.<name>.components.

argocd.chart

ArgoCD Helm chart derivation (default: cataCharts.argocd)

Type: package

Default: <derivation helm-chart-https-argoproj.github.io-argo-helm-argo-cd-8.0.2>

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.domain

Domain for ArgoCD external access

Type: string

Default: ""

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.enable

Whether to enable ArgoCD.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.gateway.enable

Enable HTTPRoute for external access via Gateway API

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.gateway.gatewayNamespace

Namespace of the Gateway resource

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.gateway.gatewayRef

Name of the Gateway resource to attach to

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.ha

Install HA version of ArgoCD

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.namespace

Namespace for ArgoCD

Type: string

Default: "argocd"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.caBundleConfigMap

ConfigMap containing CA bundle for OIDC issuer TLS verification (from trust-manager)

Type: null or string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.caBundleKey

Key within the CA bundle ConfigMap

Type: string

Default: "ca.crt"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.clientId

OAuth2 client ID

Type: string

Default: "argocd"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.clientSecretRef

Reference to Secret containing OIDC client secret

Type: null or (submodule)

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.clientSecretRef.key

Key within the secret

Type: string

Default: "client-secret"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.clientSecretRef.name

Secret containing OIDC client secret

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.enable

Whether to enable OIDC authentication.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.issuerUrl

OIDC issuer URL

Type: string

Default: ""

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.oidc.name

Display name for OIDC provider

Type: string

Default: "Kanidm"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.phase

Deployment phase this component belongs to

Type: string

Default: "gitops"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.ref

Computed references for ArgoCD

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories

Repository credentials for ArgoCD

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.enableLfs

Enable Git LFS for this repository

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.insecure

Skip TLS certificate verification

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.passwordSecretRef

Reference to Secret containing repository password or access token

Type: null or (submodule)

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.passwordSecretRef.key

Key within the secret

Type: string

Default: "password"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.passwordSecretRef.name

Secret containing password/token

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.project

ArgoCD project to associate this repository with

Type: string

Default: "default"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.sshPrivateKeySecretRef

Reference to Secret containing SSH private key for repository access

Type: null or (submodule)

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.sshPrivateKeySecretRef.key

Key within the secret

Type: string

Default: "ssh-privatekey"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.sshPrivateKeySecretRef.name

Secret containing SSH private key

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.tlsClientCertSecretRef

Reference to Secret containing TLS client certificate for repository access

Type: null or (submodule)

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.tlsClientCertSecretRef.certKey

Key for the certificate

Type: string

Default: "tls.crt"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.tlsClientCertSecretRef.keyKey

Key for the private key

Type: string

Default: "tls.key"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.tlsClientCertSecretRef.name

Secret containing TLS client certificate

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.type

Repository type

Type: one of "git", "helm"

Default: "git"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.url

Repository URL

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.usernameSecretRef

Reference to Secret containing repository username

Type: null or (submodule)

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.usernameSecretRef.key

Key within the secret

Type: string

Default: "username"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.repositories.<name>.usernameSecretRef.name

Secret containing username

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.tls.issuerRef

cert-manager issuer reference for ArgoCD TLS certificate

Type: null or (submodule)

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.tls.issuerRef.kind

Issuer kind

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.tls.issuerRef.name

Issuer or ClusterIssuer name

Type: string

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.tls.secretName

Name of the TLS Secret created by cert-manager

Type: string

Default: "argocd-tls"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


argocd.version

ArgoCD version

Type: string

Default: "v2.13.0"

Declared in: modules/lab/cluster/components/gitops/argocd.nix


Source Control Options

Options for: forgejo.

All options are under lab.clusters.<name>.components.

forgejo.admin.existingSecret

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.chart

Custom chart derivation

Type: package

Default: <derivation helm-chart-oci-codeberg.org-forgejo-contrib-forgejo-5.1.0>

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.host

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.name

This option has no description.

Type: string

Default: "forgejo"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.port

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 5432

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.secretRef

This option has no description.

Type: submodule

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.secretRef.key

This option has no description.

Type: string

Default: "password"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.secretRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.ssl

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.database.user

This option has no description.

Type: string

Default: "forgejo"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.domain

Domain for Forgejo external access

Type: string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.enable

Whether to enable Forgejo git forge.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.gateway.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.gateway.gatewayNamespace

This option has no description.

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.gateway.gatewayRef

This option has no description.

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.namespace

Namespace for Forgejo

Type: string

Default: "forgejo"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.adminGroup

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.autoDiscoverUrl

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.clientId

This option has no description.

Type: string

Default: "forgejo"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.clientSecretRef

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.clientSecretRef.key

This option has no description.

Type: string

Default: "client-secret"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.clientSecretRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.enable

Whether to enable OIDC authentication via Kanidm.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.groupsClaim

This option has no description.

Type: string

Default: "groups"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.issuerUrl

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.providerName

This option has no description.

Type: string

Default: "Kanidm"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.scopes

This option has no description.

Type: list of string

Default:

[
  "openid"
  "email"
  "profile"
  "groups"
]

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.oidc.usernameClaim

This option has no description.

Type: string

Default: "preferred_username"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.phase

Deployment phase this component belongs to

Type: string

Default: "apps"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.replicas

This option has no description.

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.server.httpPort

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 3000

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.server.lfsEnabled

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.server.sshPort

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 22

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.storage.size

This option has no description.

Type: string

Default: "10Gi"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.storage.storageClass

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.tls.issuerRef

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.tls.issuerRef.kind

This option has no description.

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.tls.issuerRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.tls.secretName

This option has no description.

Type: string

Default: "forgejo-tls"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


forgejo.version

Forgejo version

Type: string

Default: "11.0.14"

Declared in: modules/lab/cluster/components/source-control/forgejo.nix


Provisioning Options

Options for: cluster-api, crossplane.

All options are under lab.clusters.<name>.components.

cluster-api.bootstrapProviders

This option has no description.

Type: list of (one of "kubeadm", "talos")

Default:

[
  "talos"
]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.chart

This option has no description.

Type: package

Default:

<derivation helm-chart-https-kubernetes-sigs.github.io-cluster-api-operator-cluster-api-operator-0.27.0>

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.apiServerExtraArgs

This option has no description.

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.aws.controlPlaneInstanceType

This option has no description.

Type: string

Default: "t3.large"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.aws.region

This option has no description.

Type: string

Default: "us-east-1"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.aws.sshKeyName

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.aws.workerInstanceType

This option has no description.

Type: string

Default: "t3.large"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.certSANs

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.clientCaCert

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.digitalocean.controlPlaneSize

This option has no description.

Type: string

Default: "s-2vcpu-4gb"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.digitalocean.image

This option has no description.

Type: string

Default: "ubuntu-24-04-x64"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.digitalocean.region

This option has no description.

Type: string

Default: "nyc1"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.digitalocean.sshKeys

SSH key fingerprints or IDs

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.digitalocean.workerSize

This option has no description.

Type: string

Default: "s-2vcpu-4gb"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.docker.loadBalancerImage

This option has no description.

Type: string

Default: "kindest/haproxy:v20230606-42a2262b"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.controlPlaneType

This option has no description.

Type: string

Default: "cpx31"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.network.cidr

This option has no description.

Type: string

Default: "10.0.0.0/8"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.network.enabled

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.placementGroup

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.region

This option has no description.

Type: string

Default: "fsn1"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.sshKeyName

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.hetzner.workerType

This option has no description.

Type: string

Default: "cpx31"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.infrastructureProvider

This option has no description.

Type: one of "docker", "digitalocean", "hetzner", "aws", "gcp", "azure", "vsphere"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.controlPlane.machineType

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.controlPlane.replicas

This option has no description.

Type: signed integer

Default: 3

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.version

This option has no description.

Type: string

Default: "v1.31.0"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers

This option has no description.

Type: list of (submodule)

Default:

[
  {
    name = "default";
    replicas = 3;
  }
]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.labels

This option has no description.

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.machineType

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.name

Name of the worker pool

Type: string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.replicas

This option has no description.

Type: signed integer

Default: 3

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.taints

This option has no description.

Type: list of (submodule)

Default: [ ]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.taints.*.effect

This option has no description.

Type: one of "NoSchedule", "PreferNoSchedule", "NoExecute"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.taints.*.key

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.kubernetes.workers.*.taints.*.value

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.network.podCIDR

This option has no description.

Type: string

Default: "10.244.0.0/16"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.network.serviceCIDR

This option has no description.

Type: string

Default: "10.96.0.0/12"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.registryMirror.enable

Configure containerd registry mirrors on CAPI cluster nodes

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.registryMirror.endpoint

Registry mirror endpoint (e.g., http://docker-host:port)

Type: string

Default: "http://172.17.0.1:5050"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.registryMirror.registries

Upstream registries to mirror through the cache

Type: list of string

Default:

[
  "docker.io"
  "ghcr.io"
  "quay.io"
  "registry.k8s.io"
]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.talos.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.clusters.<name>.talos.version

This option has no description.

Type: string

Default: "v1.8.0"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.controlPlaneProviders

This option has no description.

Type: list of (one of "kubeadm", "talos")

Default:

[
  "talos"
]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.enable

Whether to enable Cluster API.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.infrastructureProviders

This option has no description.

Type: list of (one of "docker", "digitalocean", "aws", "gcp", "azure", "hetzner", "vsphere")

Default: [ ]

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.isManagementCluster

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.namespace

This option has no description.

Type: string

Default: "capi-system"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.phase

This option has no description.

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.aws

This option has no description.

Type: string

Default: "2.7.0"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.core

This option has no description.

Type: string

Default: "1.13.2"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.digitalocean

This option has no description.

Type: string

Default: "1.6.0"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.docker

This option has no description.

Type: string

Default: "1.9.0"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.hetzner

This option has no description.

Type: string

Default: "1.0.0-beta.40"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.talosBootstrap

This option has no description.

Type: string

Default: "0.6.7"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.providerVersions.talosControlPlane

This option has no description.

Type: string

Default: "0.5.13"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


cluster-api.version

This option has no description.

Type: string

Default: "1.9.0"

Declared in: modules/lab/cluster/components/provisioning/cluster-api.nix


crossplane.chart

This option has no description.

Type: package

Default: <derivation helm-chart-https-charts.crossplane.io-stable-crossplane-1.18.2>

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.apiToken

Cloudflare API token (for dev/lab use). For production, use SOPS-encrypted secrets.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.credentialSecretRef

This option has no description.

Type: null or (submodule)

Default:

{
  key = "credentials";
  name = "cf-credentials";
  namespace = "crossplane-system";
}

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.credentialSecretRef.key

This option has no description.

Type: string

Default: "credentials"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.credentialSecretRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.credentialSecretRef.namespace

This option has no description.

Type: string

Default: "crossplane-system"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records.<name>.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records.<name>.proxied

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records.<name>.ttl

This option has no description.

Type: signed integer

Default: 300

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records.<name>.type

This option has no description.

Type: one of "A", "AAAA", "CNAME", "MX", "TXT", "SRV", "NS"

Default: "A"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records.<name>.value

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.records.<name>.zoneRef

Name of the Crossplane Zone resource to reference

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.tunnels

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.tunnels.<name>.accountId

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.tunnels.<name>.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.tunnels.<name>.secret

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.zones

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.zones.<name>.accountId

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.zones.<name>.domain

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.cloudflare.zones.<name>.plan

This option has no description.

Type: string

Default: "free"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.apiToken

DO API token (for dev/lab use). For production, use SOPS-encrypted secrets.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.credentialSecretRef

This option has no description.

Type: null or (submodule)

Default:

{
  key = "credentials";
  name = "do-credentials";
  namespace = "crossplane-system";
}

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.credentialSecretRef.key

This option has no description.

Type: string

Default: "credentials"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.credentialSecretRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.credentialSecretRef.namespace

This option has no description.

Type: string

Default: "crossplane-system"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets.<name>.image

This option has no description.

Type: string

Default: "ubuntu-24-04-x64"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets.<name>.region

This option has no description.

Type: string

Default: "nyc1"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets.<name>.size

This option has no description.

Type: string

Default: "s-2vcpu-4gb"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets.<name>.sshKeys

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets.<name>.userData

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.droplets.<name>.vpcUuid

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters

DigitalOcean managed Kubernetes (DOKS) clusters

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.autoUpgrade

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.ha

Enable HA control plane

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.nodePool.autoScale

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.nodePool.maxNodes

This option has no description.

Type: null or signed integer

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.nodePool.minNodes

This option has no description.

Type: null or signed integer

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.nodePool.name

This option has no description.

Type: string

Default: "default"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.nodePool.nodeCount

This option has no description.

Type: signed integer

Default: 2

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.nodePool.size

This option has no description.

Type: string

Default: "s-2vcpu-4gb"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.region

This option has no description.

Type: string

Default: "nyc1"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.surgeUpgrade

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.kubernetesClusters.<name>.version

Kubernetes version slug (e.g., ‘1.36.0-do.0’). Find valid versions with doctl kubernetes options versions.

Type: string

Default: "1.36.0-do.0"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.loadBalancers

This option has no description.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.loadBalancers.<name>.dropletTag

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.loadBalancers.<name>.forwardingRules

This option has no description.

Type: list of (attribute set)

Default:

[
  {
    entryPort = 80;
    entryProtocol = "http";
    targetPort = 80;
    targetProtocol = "http";
  }
]

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.digitalocean.loadBalancers.<name>.region

This option has no description.

Type: string

Default: "nyc1"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.enable

Whether to enable Crossplane infrastructure provisioning.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.namespace

This option has no description.

Type: string

Default: "crossplane-system"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.phase

This option has no description.

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.providerVersions.cloudflare

This option has no description.

Type: string

Default: "0.2.5"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.providerVersions.digitalocean

This option has no description.

Type: string

Default: "0.3.2"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.providerVersions.helm

This option has no description.

Type: string

Default: "1.2.0"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.providerVersions.kubernetes

This option has no description.

Type: string

Default: "1.2.1"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.providers

Crossplane providers to install

Type: list of (one of "digitalocean", "cloudflare", "kubernetes", "helm")

Default: [ ]

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


crossplane.version

This option has no description.

Type: string

Default: "1.18.2"

Declared in: modules/lab/cluster/components/provisioning/crossplane.nix


Other Components Options

Options for: velero, netbird, zot, custom.

All options are under lab.clusters.<name>.components.

custom.apps

Custom applications to deploy. Each app gets its own bundle within the specified phase. Supports Helm charts, typed resources, raw YAML, and optional Gateway API routing.

Type: attribute set of (submodule)

Default: { }

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.createNamespace

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.domain

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.gatewayNamespace

This option has no description.

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.gatewayRef

This option has no description.

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.mode

This option has no description.

Type: one of "terminate", "passthrough"

Default: "terminate"

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.serviceName

Backend service name for the HTTPRoute/TLSRoute

Type: string

Default: "‹name›"

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.gateway.servicePort

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 80

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.helmCharts

Helm charts to deploy (same shape as phase bundle helmCharts)

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.namespace

Kubernetes namespace (defaults to app name)

Type: string

Default: "‹name›"

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.phase

Deployment phase (apps, workloads, infrastructure, etc.)

Type: string

Default: "apps"

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.resources

Typed Kubernetes resources

Type: attribute set of (attribute set)

Default: { }

Declared in: modules/lab/cluster/components/custom.nix


custom.apps.<name>.yamls

Raw YAML manifests

Type: list of (string or absolute path)

Default: [ ]

Declared in: modules/lab/cluster/components/custom.nix


netbird.chart

Custom chart derivation. When null, uses nixhelm default.

Type: package

Default: <derivation helm-chart-https-charts.jaconi.io-netbird-0.15.0>

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.domain

Domain name for the Netbird management server

Type: string

Default: "vpn.example.com"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.enable

Whether to enable Netbird mesh VPN.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.idp.clientID

OIDC client ID

Type: string

Default: "netbird"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.idp.clientSecretRef

Reference to the OIDC client secret. Use config.secrets.managed..ref.secretRef for type-safe refs.

Type: null or (attribute set)

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.idp.issuer

OIDC issuer URL. Use config.components.kanidm.ref.oidcIssuer for type-safe Kanidm integration.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.management.replicas

Number of management server replicas

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.management.storage.size

PVC size for management server data

Type: string

Default: "5Gi"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.management.storage.storageClass

StorageClass (null = cluster default)

Type: null or string

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.namespace

Namespace for Netbird

Type: string

Default: "netbird"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.phase

Deployment phase this component belongs to

Type: string

Default: "infrastructure"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.ref

Computed references for Netbird

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.signal.replicas

Number of signal server replicas

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.turn.domain

Domain for the TURN server

Type: string

Default: "turn.example.com"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.turn.enable

Enable TURN relay for NAT traversal

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/vpn/netbird.nix


netbird.version

Netbird version

Type: string

Default: "0.31.0"

Declared in: modules/lab/cluster/components/vpn/netbird.nix


velero.backupStorageLocation.bucket

Bucket/container name for backups

Type: string

Default: "velero-backups"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.credentialsSecret

Name of the secret containing storage credentials

Type: string

Default: "velero-credentials"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.prefix

Prefix within the bucket for backups

Type: string

Default: ""

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.provider

Backup storage provider

Type: one of "aws", "gcp", "azure", "seaweedfs", "filesystem"

Default: "seaweedfs"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.s3.endpoint

S3 endpoint URL

Type: null or string

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.s3.insecureSkipTLSVerify

Skip TLS verification

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.s3.region

S3 region

Type: string

Default: "seaweedfs"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.backupStorageLocation.s3.s3ForcePathStyle

Use path-style S3 URLs

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.chart

Velero Helm chart derivation (default: cataCharts.velero)

Type: package

Default: <derivation helm-chart-https-vmware-tanzu.github.io-helm-charts-velero-9.0.1>

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.enable

Whether to enable Velero backup and restore.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.fileSystemBackup.enable

Enable file system backups using restic/kopia

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.fileSystemBackup.uploaderType

Uploader type for file system backups

Type: one of "restic", "kopia"

Default: "kopia"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.local.enable

Enable local development mode using SeaweedFS

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.namespace

Namespace for Velero

Type: string

Default: "velero"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.phase

Deployment phase this component belongs to

Type: string

Default: "operators"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.ref

Computed references for Velero

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.resources.limits.cpu

This option has no description.

Type: string

Default: "1000m"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.resources.limits.memory

This option has no description.

Type: string

Default: "512Mi"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.resources.requests.cpu

This option has no description.

Type: string

Default: "100m"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.resources.requests.memory

This option has no description.

Type: string

Default: "128Mi"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules

Named backup schedules

Type: attribute set of (submodule)

Default:

{
  daily = {
    schedule = "0 2 * * *";
    ttl = "168h";
  };
  weekly = {
    schedule = "0 3 * * 0";
    ttl = "720h";
  };
}

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.defaultVolumesToFsBackup

Use file-system backup for volumes by default (restic/kopia)

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.enable

Whether this schedule is enabled

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.excludedNamespaces

Namespaces to exclude from backup

Type: list of string

Default:

[
  "kube-system"
  "velero"
]

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.excludedResources

Resources to exclude from backup

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.includeClusterResources

Whether to include cluster-scoped resources

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.includedNamespaces

Namespaces to include (empty = all)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.includedResources

Resources to include (empty = all)

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.schedule

Cron schedule for backups

Type: string

Default: "0 2 * * *"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.snapshotVolumes

Whether to snapshot PVs (requires volume snapshotter)

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.schedules.<name>.ttl

Time to live for backups (e.g., 720h = 30 days)

Type: string

Default: "720h"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.version

Velero Helm chart version

Type: string

Default: "7.2.1"

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.volumeSnapshotLocation.config

Provider-specific configuration

Type: attribute set of string

Default: { }

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.volumeSnapshotLocation.enable

Enable volume snapshot location

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/backups/velero.nix


velero.volumeSnapshotLocation.provider

Volume snapshot provider

Type: one of "aws", "gcp", "azure", "csi"

Default: "csi"

Declared in: modules/lab/cluster/components/backups/velero.nix


zot.auth.enable

This option has no description.

Type: boolean

Default: false

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.auth.htpasswdSecret

This option has no description.

Type: string

Default: "zot-htpasswd"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.chart

This option has no description.

Type: package

Default: <derivation helm-chart-https-zotregistry.dev-helm-charts-zot-0.1.113>

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.domain

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.enable

Whether to enable Zot OCI-native container registry.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.gateway.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.gateway.gatewayNamespace

This option has no description.

Type: null or string

Default: "kube-system"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.gateway.gatewayRef

This option has no description.

Type: string

Default: "default-gateway"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.http.port

This option has no description.

Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)

Default: 5000

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.namespace

This option has no description.

Type: string

Default: "zot"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.adminGroups

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.clientId

This option has no description.

Type: string

Default: "zot"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.clientSecretRef

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.clientSecretRef.key

This option has no description.

Type: string

Default: "client-secret"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.clientSecretRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.enable

Whether to enable OIDC authentication via Kanidm.

Type: boolean

Default: false

Example: true

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.groupsClaim

This option has no description.

Type: string

Default: "groups"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.issuerUrl

This option has no description.

Type: string

Default: ""

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.readOnlyGroups

This option has no description.

Type: list of string

Default: [ ]

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.scopes

This option has no description.

Type: list of string

Default:

[
  "openid"
  "email"
  "groups"
]

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.oidc.usernameClaim

This option has no description.

Type: string

Default: "preferred_username"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.phase

This option has no description.

Type: string

Default: "apps"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.ref

This option has no description.

Type: attribute set

Default: { }

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.replicas

This option has no description.

Type: positive integer, meaning >0

Default: 1

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.search.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.storage.dedupe

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.storage.rootDirectory

This option has no description.

Type: string

Default: "/var/lib/zot"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.storage.size

This option has no description.

Type: string

Default: "50Gi"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.storage.storageClass

This option has no description.

Type: null or string

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.tls.issuerRef

This option has no description.

Type: null or (submodule)

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.tls.issuerRef.kind

This option has no description.

Type: string

Default: "ClusterIssuer"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.tls.issuerRef.name

This option has no description.

Type: string

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.tls.secretName

This option has no description.

Type: string

Default: "zot-tls"

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.ui.enable

This option has no description.

Type: boolean

Default: true

Declared in: modules/lab/cluster/components/registries/zot.nix


zot.version

This option has no description.

Type: string

Default: "0.1.62"

Declared in: modules/lab/cluster/components/registries/zot.nix


Phases

Phases control the order in which Kubernetes resources are deployed. Not all resources can be applied at once – CRDs must exist before custom resources that use them, operators must be running before their managed resources are created, and databases should be ready before applications that depend on them.

Each phase has a numeric order (lower values deploy first) and a dependsOn list that declares explicit dependencies on other phases. Components write their resources into phase bundles, and the CLI applies phases in order.

Built-in phases

PhaseOrderDepends onDescription
crds-10Custom Resource Definitions. Deployed first so that all subsequent phases can create custom resources.
namespaces-5crdsNamespace creation. Ensures target namespaces exist before resources are deployed into them.
networking0namespacesCNI (Cilium), Gateway API controller (Traefik), and core networking. Must be ready before anything that needs pod networking or ingress.
operators10networkingOperator deployments: cert-manager, external-dns, trust-manager, CNPG operator, kaniop, and others. These controllers must be running before their custom resources are created in later phases.
secrets20operatorsSecret management: external-secrets stores, SOPS decryption, and generated secrets. Depends on operators because some secrets are managed by operator-created controllers.
infrastructure30operators, secretsCore infrastructure services: Kanidm, Prometheus, Loki, Tempo, Zot registry, and similar. These are long-running services that applications depend on.
gitops40operators, secretsGitOps controllers: ArgoCD. Deployed after operators and secrets so that it has access to credentials and can manage application delivery.
databases50operators, secretsDatabase instances: CNPG PostgreSQL clusters, Redis. Depends on operators (for the database controllers) and secrets (for credentials).
apps90infrastructure, databasesApplications: Forgejo, Grafana, and custom apps. Deployed late because they typically depend on databases, identity providers, and other infrastructure.
workloads100infrastructure, databasesUser workloads. The final phase for anything that depends on the full platform being ready.

Phase configuration options

Each phase supports these options:

OptionTypeDefaultDescription
orderint(varies)Numeric ordering. Lower values deploy first.
dependsOnlist of strings(varies)Phases that must complete before this one.
keepResourcesboolfalsePrevent deletion of resources in this phase.
pruneStrategyenum"default""default", "never", or "orphan". Controls resource cleanup.
waitForReadybooltrueWait for all resources to become ready before proceeding.
timeoutstring"10m"Timeout for this phase’s deployment.
waitForCRDsboolfalseWait for CRDs to be established before deploying.
crdNameslist of strings[]CRD names to wait for when waitForCRDs is true.
bundlesattrs{}Bundles of resources belonging to this phase.

Bundles

Each phase contains bundles. A bundle is the finest-grained deployment unit and contains:

  • helmCharts – Helm charts to template and deploy
  • resources – Typed Kubernetes resource definitions (Nix attribute sets)
  • yamls – Raw YAML manifests (strings or file paths)
  • createNamespaces – Namespaces to create for this bundle

Components write into bundles by setting phases.<phase>.bundles.<component-name>. Multiple components can write to the same phase but use separate bundles.

Custom phases

You can define custom phases for specialized ordering needs:

phases.pre-apps = {
  order = 85;
  dependsOn = [ "infrastructure" "databases" ];
  waitForReady = true;
  timeout = "5m";
};

Components can target custom phases via their phase option:

components.custom.apps.my-app.phase = "pre-apps";

Why ordering matters

Without phase ordering, common failures include:

  • Custom resources applied before their CRDs exist (API server rejects them)
  • Pods scheduled before the CNI is running (they never get an IP)
  • Applications starting before their databases are ready (crash loops)
  • OAuth2 clients created before the identity provider is running (registration fails)
  • Certificate requests submitted before cert-manager’s webhook is ready (timeouts)

Phases encode these dependencies declaratively so that the CLI (or GitOps engine) applies resources in a safe order every time.

Security

Catallaxy provides three cluster-level security features that derive policies from existing component configuration. Enable with simple toggles — the system generates the right policies.

Pod Security Standards

Kubernetes Pod Security Admission labels control what pods can do in each namespace.

cluster.security.podSecurity = {
  enable = true;
  default = "restricted";  # "restricted" | "baseline" | "privileged"
};

When enabled, all lab-managed namespaces get PSA labels:

metadata:
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted

Per-Namespace Overrides

Components that need elevated privileges (Cilium, kaniop, etc.) can override per namespace:

cluster.security.podSecurity.namespaceOverrides = {
  kube-system = "privileged";
  kanidm = "baseline";
};

PSA Levels

LevelDescription
restrictedNo host networking, no root, no privilege escalation. Most secure.
baselinePrevents known privilege escalations. Allows most workloads.
privilegedUnrestricted. For system components (CNI, node agents).

Network Policies

Default-deny network policies restrict pod-to-pod traffic. When enabled, each lab namespace gets a policy that blocks all traffic except:

  • DNS (UDP/TCP 53) — pods can resolve names
  • Same-namespace — pods in the same namespace can talk to each other
cluster.security.networkPolicies.enable = true;

Cross-Namespace Access

Components that need cross-namespace traffic add their own allow rules in their phase bundles. Use the mkNetworkPolicy helper:

{ config, lib, ... }:
let
  catallaxyLib = config._module.args.catallaxyLib or {};
in
lib.mkIf config.cluster.security.networkPolicies.enable {
  phases.apps.bundles.my-app.resources.my-app-netpol =
    catallaxyLib.mkNetworkPolicy {
      name = "allow-gateway-ingress";
      namespace = "my-app";
      podSelector.matchLabels."app" = "my-app";
      policyTypes = ["Ingress"];
      ingress = [{
        from = [{ namespaceSelector.matchLabels."kubernetes.io/metadata.name" = "kube-system"; }];
        ports = [{ port = 8080; }];
      }];
    };
}

Built-in Components

Built-in components will progressively add their own network policies when this feature is enabled. The default-deny baseline ensures nothing is open by accident.

Audit Logging

Kubernetes API server audit logging records who did what.

cluster.security.auditLogging.enable = true;

Provisioner Behavior

ProvisionerBehavior
k3dAdds --audit-policy-file and --audit-log-path API server args. Audit policy mounted from host.
DOKSManaged by DigitalOcean. This option is a no-op.
TalosMachine config for audit policy (future).

k3d Audit Policy

When enabled on k3d, an audit policy file is mounted at /etc/kubernetes/audit/policy.yaml. The default policy logs:

  • All authentication events
  • All resource creation/deletion
  • Metadata for read operations

Audit logs are written to /var/log/kubernetes/audit.log inside the k3d node container.

Enabling All Security Features

# In your cluster config:
cluster.security = {
  podSecurity.enable = true;
  networkPolicies.enable = true;
  auditLogging.enable = true;
};

This gives you defense-in-depth: pod restrictions, network segmentation, and an audit trail — all derived from your existing lab configuration.

Image Management

Catallaxy provides declarative control over container images for reproducibility and security.

Image Pins

Pin container images at the lab level with optional digest verification:

lab.images.pins = {
  grafana = {
    image = "docker.io/grafana/grafana";
    tag = "11.4.0";
    digest = "sha256:abc123...";  # Optional — ensures bit-for-bit reproducibility
  };
  prometheus = {
    image = "quay.io/prometheus/prometheus";
    tag = "v3.0.0";
  };
};

Each pin computes a ref — the full image reference string:

Configurationref value
tag onlydocker.io/grafana/grafana:11.4.0
digest onlydocker.io/grafana/grafana@sha256:abc123
tag + digestdocker.io/grafana/grafana:11.4.0@sha256:abc123

Components can reference pins: lab.images.pins.grafana.ref

Image Policy

Require Digest

When enabled, the lint check errors on any container image without a digest pin:

lab.images.requireDigest = true;

This enforces that every image in your rendered manifests is pinned to a specific build. Tags are mutable (a registry can serve a different image for the same tag), but digests are immutable.

Allowed Registries

Restrict which registries images can come from:

lab.images.allowedRegistries = [
  "ghcr.io"
  "registry.k8s.io"
  "docker.io"
];

The lint check warns about images from registries not in this list. Leave empty (default) to allow all registries.

Lint Check

The image-pin lint check scans rendered manifests for container image references in Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs.

It always warns about:

  • :latest tags — mutable and non-reproducible

With policy enabled:

  • Missing digests (when requireDigest = true) — Error
  • Unapproved registries (when allowedRegistries is set) — Warning

Suppression

Skip the check for specific resources:

metadata:
  annotations:
    catallaxy.io/lint-skip: image-pin

Pull-Through Cache

For rate limiting protection, use Zot as a pull-through cache:

components.zot = {
  enable = true;
  sync.enable = true;  # Pull-through cache from Docker Hub, Quay, GHCR, registry.k8s.io
};

This caches images locally on first pull. Combined with image pins, you get both availability and reproducibility.

Lint System

Catallaxy’s lint system validates rendered manifests against universal properties. It’s the primary mechanism for catching configuration errors before deployment.

Built-in Checks

CheckWhat it validates
schemaEvery resource has apiVersion, kind, metadata.name
identityNo duplicate (apiVersion, kind, namespace, name) tuples
prefixResources and namespaces use the lab prefix
selectorService selectors match workload pod labels
referenceConfigMap/Secret references point to existing resources
projection-refsecretKeyRef names match declared projections with correct phase/namespace
image-pinContainer images use digest pins and approved registries
crd-schemaCustom Resources validate against CRD OpenAPI schemas
missing-crdWarns when a CR has no matching CRD in the manifest set

Running Lint

cata lab lint                # Lint the default lab
cata lab lint --path <pkg>   # Lint a pre-built lab package

In CI, nix flake check runs lint on all example labs automatically.

Skipping Checks

Per-resource:

metadata:
  annotations:
    catallaxy.io/lint-skip: reference,image-pin

Per-run:

cata lab lint --skip image-pin --skip crd-schema

Custom Lint Checks

Define custom property checks in Nix that run shell commands on rendered manifests:

lab.lint.checks = {
  no-default-namespace = {
    description = "Resources must not use the default namespace";
    severity = "error";
    command = ''
      results=$(yq -N 'select(.metadata.namespace == "default") | .metadata.name' "$FILE" 2>/dev/null)
      if [ -n "$results" ]; then
        echo "Found resources in default namespace: $results"
        exit 1
      fi
    '';
  };

  no-latest-tags = {
    description = "Container images must not use :latest";
    severity = "warning";
    command = ''
      results=$(yq -N '
        select(.kind == "Deployment" or .kind == "StatefulSet") |
        .spec.template.spec.containers[] |
        select(.image | test(":latest$")) |
        .image
      ' "$FILE" 2>/dev/null)
      if [ -n "$results" ]; then
        echo "$results"
        exit 1
      fi
    '';
  };

  require-resource-limits = {
    description = "Containers must have resource limits";
    severity = "warning";
    command = ''
      results=$(yq -N '
        select(.kind == "Deployment" or .kind == "StatefulSet") |
        .spec.template.spec.containers[] |
        select(.resources.limits == null) |
        .name
      ' "$FILE" 2>/dev/null)
      if [ -n "$results" ]; then
        echo "Missing resource limits: $results"
        exit 1
      fi
    '';
  };
};

Shell Command Interface

Each check receives:

  • $FILE — path to a YAML manifest file
  • $CLUSTER — name of the cluster being checked

Available tools: yq, jq, standard Unix tools.

Return values:

  • Exit 0 → check passes
  • Non-zero → check fails; stdout becomes the diagnostic message

Severity

  • "error" — fails the lint (non-zero exit from cata lab lint)
  • "warning" — reported but doesn’t fail

Nix Assertions (Config-Level Properties)

For properties that can be checked at Nix evaluation time (before rendering), use assertions:

config.assertions = [
  {
    assertion = config.components.my-app.enable -> config.components.cnpg.enable;
    message = "my-app requires PostgreSQL (enable components.cnpg)";
  }
  {
    assertion = config.cluster.security.networkPolicies.enable || !config.components.my-app.enable;
    message = "my-app requires network policies to be enabled";
  }
];

Assertions fire at nix eval time — before any manifests are rendered. They catch configuration-level contradictions immediately.

Testing Strategy

Catallaxy’s testing is property-based:

  1. Nix assertions — config-level properties checked at eval time
  2. Lint checks — manifest-level properties checked on rendered YAML
  3. E2E — deploy examples and verify they work
nix flake check     # Runs lint on all example labs (CI-friendly)
cata lab up          # E2E: deploy and verify
cata lab down        # Clean up

No traditional unit tests — correctness comes from universal properties that hold across all configurations.

Extending Catallaxy

Catallaxy is designed to be extended without forking. Teams can add custom components, Helm charts, provisioners, and operational commands by writing NixOS modules that compose with the built-in components.

Architecture

The extensibility model is simple: the Nix module system is the extension mechanism.

Components write to a shared namespace (phases.${name}.bundles.${name}), and the rendering pipeline consumes those bundles to produce Kubernetes manifests. The bundle type is the stable contract:

bundleType = {
  resources = attrsOf kubernetesResourceType;  # Typed K8s resources
  helmCharts = attrsOf helmChartType;          # Helm charts with values
  yamls = listOf (either str path);            # Raw YAML strings or files
  createNamespaces = listOf str;               # Namespaces to create
};

Everything upstream of bundles (component options, user config) is the frontend. Everything downstream (rendering, strategy layout) is the backend. Your custom modules operate in the frontend — declaring options and producing bundles.

Getting Started

nix flake init -t github:onepunch/catallaxy#consumer

This creates a consumer flake with a working custom component example.

Extension Points

WhatHowExample
Custom componentModule writing to phases.bundlesWriting Components
Custom Helm charthelmCharts.${name} in a bundleHelm Charts
Custom phasephases.${name}.order = NPhase Ordering
Secret projectionssecrets.projections.${name}Secrets
Ops commandsops.${name}Ops Commands
Lifecycle hookslifecycle.teardownLifecycle

Writing Custom Components

A component is a NixOS module that declares high-level options and writes Kubernetes resources into phase bundles. This is the same pattern used by all built-in components (ArgoCD, Prometheus, Kanidm, etc.).

The Pattern

Every component follows three parts:

  1. Options — what the user configures
  2. Refs — computed values other components can read
  3. Phase writer — produces bundles when enabled
{ config, lib, ... }:
let
  cfg = config.components.my-app;
in
{
  # 1. Options
  options.components.my-app = {
    enable = lib.mkEnableOption "my-app";
    phase = lib.mkOption { type = lib.types.str; default = "apps"; };
    namespace = lib.mkOption { type = lib.types.str; default = "my-app"; };
    domain = lib.mkOption { type = lib.types.str; };
    ref = lib.mkOption { type = lib.types.attrs; readOnly = true; };
  };

  config = lib.mkMerge [
    # 2. Refs (always computed, even when disabled)
    {
      components.my-app.ref = {
        namespace = cfg.namespace;
        url = "http://my-app.${cfg.namespace}.svc.cluster.local";
      };
    }

    # 3. Phase writer (only when enabled)
    (lib.mkIf cfg.enable {
      phases.${cfg.phase}.bundles.my-app = {
        resources = { /* K8s resources */ };
        helmCharts = { /* Helm charts */ };
        createNamespaces = [ cfg.namespace ];
      };
    })
  ];
}

Bundle Type

The bundle is the contract between your component and the rendering pipeline:

resources

Typed Kubernetes resource definitions as Nix attribute sets:

resources.my-deployment = {
  apiVersion = "apps/v1";
  kind = "Deployment";
  metadata = { name = "my-app"; namespace = cfg.namespace; };
  spec = { /* ... */ };
};

helmCharts

Helm charts with values:

helmCharts.my-app = {
  chart = myChartDerivation;  # A Nix derivation containing the chart
  releaseName = "my-app";
  namespace = cfg.namespace;
  createNamespace = true;
  values = {
    replicaCount = 3;
    image.tag = cfg.version;
  };
};

yamls

Raw YAML strings or file paths (for resources that don’t fit the typed model):

yamls = [
  ./manifests/custom-crd.yaml
  (builtins.toJSON { apiVersion = "v1"; kind = "ConfigMap"; /* ... */ })
];

createNamespaces

Namespaces that should be created before this bundle deploys:

createNamespaces = [ cfg.namespace ];

Phase Ordering

Components target a phase by name. Built-in phases and their order:

PhaseOrderUse for
crds-10Custom Resource Definitions
namespaces-5Namespace creation (automatic)
networking0CNI, Gateway, DNS
operators10Controllers and operators
secrets20Secret management
infrastructure30Core services (identity, monitoring)
gitops40GitOps controllers
databases50Database instances
apps90Applications
workloads100User workloads

Custom phases can be defined with any order value.

Using mkComponent

For simple components, use the mkComponent helper:

# In your flake:
catallaxy.lib.mkComponent {
  name = "my-app";
  phase = "apps";
  options = {
    domain = lib.mkOption { type = lib.types.str; };
    replicas = lib.mkOption { type = lib.types.int; default = 1; };
  };
  module = cfg: {
    phases.apps.bundles.my-app = {
      helmCharts.my-app = {
        chart = myChart;
        releaseName = "my-app";
        namespace = cfg.namespace;
        values = { host = cfg.domain; replicas = cfg.replicas; };
      };
      createNamespaces = [ cfg.namespace ];
    };
  };
}

Cross-Component References

Components expose computed values via ref for other components to consume:

# In your component:
components.my-app.ref = {
  url = "http://my-app.${cfg.namespace}.svc.cluster.local:8080";
  namespace = cfg.namespace;
};

# In another component:
config.components.my-app.ref.url  # → "http://my-app.my-app.svc.cluster.local:8080"

Consumer Flake

Pass your component modules to mkLab:

{
  inputs.catallaxy.url = "github:onepunch/catallaxy";

  outputs = { catallaxy, ... }:
    catallaxy.lib.eachDefaultSystem (system: {
      labs."my-platform" = (catallaxy.${system}.mkLab {
        modules = [ ./lab.nix ./components/my-app.nix ];
      }).config.lab.out.cliConfig;
    });
}

Contributing Guide

Setting up the development environment

All build tools are provided by the Nix dev shell:

nix develop

This gives you cargo, talosctl, kubectl, kapp, helm, k3d, and all other tools needed to build and test Catallaxy.

Building

Rust CLI

cd cli/
cargo build
cargo watch -x run   # rebuild on changes

Full wrapped CLI (Nix)

nix build .#cata

The Nix-built binary includes all runtime tools in its PATH (kubectl, kapp, helm, etc.), so it works without entering the dev shell.

Rendered manifests

nix build '.#labPackages.x86_64-linux."homelab.local"'

This evaluates the example lab modules and renders all Kubernetes manifests, which is useful for verifying that module changes produce correct output.

Checking your work

Full check suite

nix flake check

This runs:

  • CLI build
  • Nix formatting check (nixfmt)
  • Rust formatting check (rustfmt)
  • cata lab lint on all example labs

Formatting

nix fmt

Formats all Nix, Rust, and YAML files. Run this before submitting changes.

Code style

Nix

  • Minimal comments. Prefer clear naming and structure over inline documentation.
  • Use optionalAttrs or if/then/else for conditional attribute values. Do NOT use mkIf inside values passed to resources or yamls – it does not work as expected in that context.
  • Components follow the single-file pattern: options and phase writer in one file. See Adding Components.
  • ref attributes are always readOnly and always set (even when the component is disabled).

Rust

  • Standard Rust conventions. Format with rustfmt (included in nix fmt).
  • The CLI shells out to external tools (nix eval, kapp, kubectl, helm) rather than reimplementing their logic.

General

  • No auto-generated comments or boilerplate.
  • Keep diffs small and focused.
  • Test changes with nix flake check before submitting.

Project structure

PathDescription
cli/src/Rust CLI source
modules/lab/Lab-level Nix modules
modules/lab/cluster/Cluster-level modules
modules/lab/cluster/components/Component modules
modules/lab/cluster/phases/Phase definitions
lib/Shared Nix libraries (eval, render, charts)
lib/renderers/Output strategies (kapp, argocd, fleet)
examples/labs/Example lab configurations
docs/Documentation (this mdBook site)

Testing

There are no traditional unit tests yet. The CLI has assert_cmd in dev-dependencies but no test files. Validation is done via nix flake check, which evaluates all example labs and runs cata lab lint.

To manually test changes:

  1. Run nix flake check to verify the build and lint pass.
  2. Build rendered manifests to inspect the output: nix build '.#labPackages.x86_64-linux."homelab.local"'
  3. For runtime testing, stand up the example lab: cata --flake ./examples/labs#homelab lab up

Adding Components

Components are self-contained infrastructure units. Each component is a single Nix file that declares its configuration options and writes Kubernetes resources into phase bundles when enabled.

Step 1: Create the component file

Create a new file at modules/lab/cluster/components/<category>/<name>.nix.

If the component fits an existing category (e.g., observability, databases, pki), place it there. If you need a new category, create a directory for it.

Step 2: Write the component module

Follow this template:

{ config, lib, cataCharts, ... }:
let
  inherit (lib) mkOption mkEnableOption mkIf types;
  cfg = config.components.<name>;
in
{
  options.components.<name> = {
    enable = mkEnableOption "<Name>";

    phase = mkOption {
      type = types.str;
      default = "<phase>";
      description = "Deployment phase";
    };

    namespace = mkOption {
      type = types.str;
      default = "<namespace>";
    };

    chart = mkOption {
      type = types.package;
      default = cataCharts.<name>.chart;
      description = "Helm chart to use";
    };

    # Component-specific options go here

    ref = mkOption {
      type = types.attrs;
      readOnly = true;
      description = "Cross-component reference values";
    };
  };

  config = lib.mkMerge [
    # Computed refs -- always available, even when disabled.
    # This lets other components reference this component's values
    # without requiring it to be enabled.
    {
      components.<name>.ref = {
        namespace = cfg.namespace;
        # Add any values other components might need:
        # endpoint = "http://<name>.${cfg.namespace}.svc:8080";
      };
    }

    # Phase writer -- only active when enabled
    (mkIf cfg.enable {
      phases.${cfg.phase}.bundles.<name> = {
        createNamespaces = [ cfg.namespace ];

        helmCharts.<name> = {
          chart = cfg.chart;
          namespace = cfg.namespace;
          values = {
            # Helm values go here
          };
        };

        # Optional: typed Kubernetes resources
        # resources = { ... };

        # Optional: raw YAML manifests
        # yamls = [ ... ];
      };
    })
  ];
}

Key conventions

  • ref is always set. Even when the component is disabled, ref values must be available so other components can reference them without conditional checks.
  • mkIf is fine at the top level (around the phase writer block), but do NOT use mkIf inside resources or yamls values. Use optionalAttrs or if/then/else instead.
  • Charts come from cataCharts. Register your chart in lib/charts.nix first (see Adding Charts), then reference it as cataCharts.<name>.chart.
  • CRDs go in the crds phase. If your chart has CRDs, write them into a separate bundle:
(mkIf cfg.enable {
  phases.crds.bundles."<name>-crds".yamls = [ cataCharts.<name>.crds ];
  phases.${cfg.phase}.bundles.<name>.helmCharts.<name> = { ... };
})

Step 3: Register the component

Add an import to the category’s default.nix:

# modules/lab/cluster/components/<category>/default.nix
{ ... }:
{
  imports = [
    ./<existing-component>.nix
    ./<name>.nix  # add this line
  ];
}

Step 4: Register a new category (if needed)

If you created a new category directory, add it to the top-level component registry:

# modules/lab/cluster/components/default.nix
{ ... }:
{
  imports = [
    ./backups
    ./cni
    # ...existing categories...
    ./<new-category>     # add this line
  ];
}

And create a default.nix in your new category directory:

# modules/lab/cluster/components/<new-category>/default.nix
{ ... }:
{
  imports = [
    ./<name>.nix
  ];
}

Step 5: Verify

Run the full check suite:

nix flake check

This evaluates all example labs and runs lint, catching missing imports, type errors, and evaluation failures.

To inspect the rendered output:

nix build '.#labPackages.x86_64-linux."homelab.local"'

Cross-component references

Components can reference other components via the ref attribute. This is how services wire together without hardcoding values:

{ config, ... }:
let
  certManagerRef = config.components.cert-manager.ref;
in
{
  # Use certManagerRef.caBundleConfigMap, certManagerRef.caBundleKey, etc.
}

For cross-cluster references, use the lab argument:

{ config, lab, ... }:
{
  components.otel-collector.exporters.otlp.endpoint =
    lab.clusters.obs.components.tempo.ref.otlpGrpc;
}

Adding Charts

Helm charts are centrally managed in lib/charts.nix. Each chart is fetched at Nix evaluation time with a pinned version and integrity hash.

Step 1: Add the chart definition

Open lib/charts.nix and add an entry to the chartDefs attribute set:

chartDefs = {
  # ... existing charts ...

  my-chart = {
    repo = "https://example.github.io/helm-charts";
    chart = "my-chart";
    version = "1.2.3";
    chartHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
  };
};

Required fields

FieldDescription
repoHelm repository URL. Supports https:// and oci:// prefixes.
chartChart name within the repository.
versionExact chart version to fetch.
chartHashSRI hash of the chart archive. Use a dummy value first, then fix it (see below).

Step 2: Get the chart hash

Set chartHash to an empty string or a dummy value, then build. Nix will report a hash mismatch and show the correct hash:

nix build .#cata 2>&1 | grep "got:"

Copy the sha256-... hash from the error output and paste it into chartHash.

Step 3: Add CRDs (if applicable)

If the chart installs CRDs, add a crd attribute. There are three CRD source types:

From the chart’s crds/ directory

my-chart = {
  repo = "...";
  chart = "my-chart";
  version = "1.2.3";
  chartHash = "sha256-...";
  crd = {
    type = "chart";
  };
};

From a URL

my-chart = {
  # ...
  crd = {
    type = "url";
    url = "https://github.com/example/releases/download/v1.2.3/crds.yaml";
    hash = "sha256-...";
  };
};

From a GitHub repository

my-chart = {
  # ...
  crd = {
    type = "github";
    owner = "example";
    repo = "my-project";
    rev = "v1.2.3";
    hash = "sha256-...";
    crdPath = "config/crd/bases";
  };
};

The hash for GitHub sources is the fetchFromGitHub hash. Use the same dummy-value-and-fix approach to obtain it.

Step 4: Use the chart in a component

Reference the chart in your component module via cataCharts:

{ cataCharts, ... }:
{
  options.components.my-component = {
    chart = mkOption {
      type = types.package;
      default = cataCharts.my-chart.chart;
    };
  };

  config = mkIf cfg.enable {
    # Deploy CRDs in the crds phase
    phases.crds.bundles.my-component-crds.yamls = [ cataCharts.my-chart.crds ];

    # Deploy the chart in the appropriate phase
    phases.${cfg.phase}.bundles.my-component.helmCharts.my-component = {
      chart = cfg.chart;
      namespace = cfg.namespace;
      values = { ... };
    };
  };
}

The cataCharts.<name> attribute set provides:

AttributeDescription
chartThe fetched chart derivation (passed to Helm)
crdsCRD derivation, or null if no CRDs are defined
versionChart version string

Step 5: Verify

nix flake check

This ensures the chart fetches correctly and all labs that use it still evaluate.

Roadmap

Completed features are in the CHANGELOG. This page shows what’s planned.

Next

  • Management cluster pivot — bootstrap on k3d, self-provision in cloud, migrate state, destroy bootstrap
  • Registry mirror integration — configure containerd to use lab Zot as pull-through cache
  • Component network policies — built-in components declare cross-namespace allow rules when networkPolicies.enable

Later

  • On-premises support (Talos Linux on bare metal)
  • Performance benchmarking for large multi-cluster labs
  • Computed SBOMs from image set and rendered manifests
  • cata images lock — resolve tags to digests automatically (lockfile pattern)

Ideas

  • Automated testing framework for lab configurations
  • Global image registry rewrite for air-gapped environments