From 7094ea7d3e16ff45fb6a9afaacdf957c7da79590 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Sat, 28 Feb 2026 08:20:17 -0800 Subject: [PATCH] Start C2 Mikado chain: build authentik from source Create goal card and 4 prerequisite cards for building authentik from a custom Nix derivation instead of using pkgs.authentik from nixpkgs. This removes the dependency on the nixpkgs packaging timeline and gives full version control over authentik releases. Chain: mikado/authentik-source-build Leaf nodes: authentik-api-client-generation, authentik-python-backend-derivation Co-Authored-By: Claude Opus 4.6 --- .../authentik-source-build.infra.md | 1 + .../authentik-api-client-generation.md | 39 +++++++++++++ .../authentik-go-server-derivation.md | 52 +++++++++++++++++ .../authentik-python-backend-derivation.md | 47 +++++++++++++++ .../authentik/authentik-web-ui-derivation.md | 45 ++++++++++++++ .../authentik/build-authentik-from-source.md | 58 +++++++++++++++++++ docs/how-to/how-to.md | 10 ++++ 7 files changed, 252 insertions(+) create mode 100644 docs/changelog.d/authentik-source-build.infra.md create mode 100644 docs/how-to/authentik/authentik-api-client-generation.md create mode 100644 docs/how-to/authentik/authentik-go-server-derivation.md create mode 100644 docs/how-to/authentik/authentik-python-backend-derivation.md create mode 100644 docs/how-to/authentik/authentik-web-ui-derivation.md create mode 100644 docs/how-to/authentik/build-authentik-from-source.md diff --git a/docs/changelog.d/authentik-source-build.infra.md b/docs/changelog.d/authentik-source-build.infra.md new file mode 100644 index 0000000..8385723 --- /dev/null +++ b/docs/changelog.d/authentik-source-build.infra.md @@ -0,0 +1 @@ +Start C2 Mikado chain: build authentik from a custom Nix derivation (from source) to replace nixpkgs dependency and gain full version control. diff --git a/docs/how-to/authentik/authentik-api-client-generation.md b/docs/how-to/authentik/authentik-api-client-generation.md new file mode 100644 index 0000000..1624f72 --- /dev/null +++ b/docs/how-to/authentik/authentik-api-client-generation.md @@ -0,0 +1,39 @@ +--- +title: Generate Authentik API Clients +modified: 2026-02-28 +status: active +tags: + - how-to + - authentik + - nix +--- + +# Generate Authentik API Clients + +Build Go and TypeScript API client bindings from authentik's OpenAPI spec (`schema.yml`). These are build-time inputs for the Go server and web UI respectively. + +## Context + +Authentik maintains a separate repo ([`goauthentik/client-go`](https://github.com/goauthentik/client-go)) with pre-generated Go client code. The nixpkgs derivation fetches this and injects it into the Go vendor directory via a setup hook (`apiGoVendorHook`). The TypeScript client is generated inline from `schema.yml` using `openapi-generator-cli`. + +Both clients are generated from the same `schema.yml` OpenAPI spec in the main authentik repo. + +## What to Do + +1. Create a Nix derivation (`client-go`) that generates Go API client bindings from `schema.yml` using `openapi-generator-cli` +2. Create a Nix derivation (`client-ts`) that generates TypeScript fetch client bindings from the same spec +3. Create a setup hook (`apiGoVendorHook`) that replaces `goauthentik.io/api/v3` in the Go vendor directory with the generated client +4. Verify the generated code compiles (Go: `go build`, TypeScript: type-check with `tsc`) + +## Key Details + +- Source spec: `schema.yml` in the authentik repo root +- Go client replaces `vendor/goauthentik.io/api/v3/` in the server build +- TypeScript client replaces `web/node_modules/@goauthentik/api/` in the web UI build +- The nixpkgs derivation patches the generated Go client (`client-go-config.patch`) — check if still needed + +## Related + +- [[build-authentik-from-source]] — Parent goal +- [[authentik-go-server-derivation]] — Consumer of Go client +- [[authentik-web-ui-derivation]] — Consumer of TypeScript client diff --git a/docs/how-to/authentik/authentik-go-server-derivation.md b/docs/how-to/authentik/authentik-go-server-derivation.md new file mode 100644 index 0000000..f83275e --- /dev/null +++ b/docs/how-to/authentik/authentik-go-server-derivation.md @@ -0,0 +1,52 @@ +--- +title: Build Authentik Go Server +modified: 2026-02-28 +status: active +requires: + - authentik-api-client-generation + - authentik-python-backend-derivation +tags: + - how-to + - authentik + - nix +--- + +# Build Authentik Go Server + +Build the Go HTTP server binary (`cmd/server`) that serves the web UI, REST API, and spawns gunicorn for the Django backend. + +## Context + +The Go server is built with `buildGoModule` from the `cmd/server` subpackage. It's a Cobra-based binary that: + +- Serves static web assets and the REST API +- Runs an embedded reverse proxy outpost +- Spawns `gounicorn` (gunicorn) to run the Django application +- Manages health checks + +The nixpkgs derivation patches store paths into two Go source files so the compiled binary can find Python lifecycle scripts and web assets at runtime. + +## What to Do + +1. Create a `buildGoModule` derivation for `cmd/server` from the authentik source +2. Inject the generated Go API client into the vendor directory (via `apiGoVendorHook`) +3. Apply `substituteInPlace` patches to hardcode Nix store paths: + - `internal/gounicorn/gounicorn.go`: `./lifecycle` → `${authentik-django}/lifecycle` + - `web/static.go`: `./web` → `${authentik-django}/web` +4. Compute the `vendorHash` — note that the hook replaces vendored API code *after* hash verification, so the hash reflects `go.sum` only +5. Rename the output binary from `server` to `authentik` +6. Verify: `./authentik --help` runs successfully + +## Key Details + +- Go module: `goauthentik.io` +- Subpackage: `./cmd/server` +- CGO: disabled +- The `vendorHash` must be computed with the vendor replacement hook excluded (`overrideModAttrs`) +- Outpost binaries (`cmd/ldap`, `cmd/proxy`, `cmd/radius`) are separate and not needed for basic deployment + +## Related + +- [[build-authentik-from-source]] — Parent goal +- [[authentik-api-client-generation]] — Provides Go client (prerequisite) +- [[authentik-python-backend-derivation]] — Provides lifecycle scripts and web assets (prerequisite) diff --git a/docs/how-to/authentik/authentik-python-backend-derivation.md b/docs/how-to/authentik/authentik-python-backend-derivation.md new file mode 100644 index 0000000..5df7365 --- /dev/null +++ b/docs/how-to/authentik/authentik-python-backend-derivation.md @@ -0,0 +1,47 @@ +--- +title: Build Authentik Python Backend +modified: 2026-02-28 +status: active +tags: + - how-to + - authentik + - nix +--- + +# Build Authentik Python Backend + +Build `authentik-django` — the Python/Django application that forms the core backend of authentik. + +## Context + +This is the most complex component. The nixpkgs derivation uses `python3.override` with extensive `packageOverrides` to handle authentik's non-standard dependencies: + +- **4 in-tree Python packages** built from the monorepo: `ak-guardian`, `django-channels-postgres`, `django-dramatiq-postgres`, `django-postgres-cache` +- **Forked `djangorestframework`** from `authentik-community/django-rest-framework` (specific commit) +- **Pinned `dramatiq`** at 1.17.1 (upstream uses newer versions that break authentik) +- **Django 5** forced via `django_5` +- **60+ Python dependencies** from nixpkgs + +Post-install, the derivation patches hardcoded paths in `settings.py`, `default.yml`, `email/utils.py`, and `files/backends/file.py` to reference Nix store paths. + +## What to Do + +1. Create a Python package override set that builds the 4 in-tree packages from source +2. Pin the forked `djangorestframework` and `dramatiq` versions +3. Build `authentik-django` using `hatchling` as the build backend +4. Apply the 4 `substituteInPlace` patches for Nix store path references +5. Copy lifecycle scripts, `manage.py`, blueprints, and web assets into the output +6. Verify: `python -c "import authentik"` succeeds + +## Key Details + +- Build backend: `hatchling` +- Entry point: `manage.py` (Django management commands) +- Lifecycle scripts: `lifecycle/` directory (used by Go server and `ak` wrapper) +- Blueprints: `blueprints/` directory (YAML IaC definitions) +- The output must include `web/` assets (email templates reference them) + +## Related + +- [[build-authentik-from-source]] — Parent goal +- [[authentik-go-server-derivation]] — Depends on this for lifecycle scripts and web assets diff --git a/docs/how-to/authentik/authentik-web-ui-derivation.md b/docs/how-to/authentik/authentik-web-ui-derivation.md new file mode 100644 index 0000000..d6c29dd --- /dev/null +++ b/docs/how-to/authentik/authentik-web-ui-derivation.md @@ -0,0 +1,45 @@ +--- +title: Build Authentik Web UI +modified: 2026-02-28 +status: active +requires: + - authentik-api-client-generation +tags: + - how-to + - authentik + - nix +--- + +# Build Authentik Web UI + +Build the Lit-based TypeScript web frontend for authentik. + +## Context + +The web UI lives in `web/` in the authentik repo. It's built with Rollup and uses Lit web components. The nixpkgs derivation builds this in two phases: + +1. **`webui-deps`** — Fixed-output derivation that runs `npm ci` to fetch Node dependencies. Uses platform-specific output hashes (aarch64-linux vs x86_64-linux). +2. **`webui`** — Patches in the generated TypeScript API client (`client-ts`), then runs `npm run build`. Output includes `dist/` and `authentik/` static directories. + +There's also a **`website`** derivation (Docusaurus-based API docs at `website/`) that produces the `/help` endpoint. This is optional but included in the nixpkgs build. + +## What to Do + +1. Create a fixed-output derivation for `npm ci` in `web/` (platform-specific hashes) +2. Patch the generated TypeScript client into `web/node_modules/@goauthentik/api/` +3. Build with `npm run build` — produces `dist/` and `authentik/` directories +4. Optionally build the Docusaurus website (`website/`) for the `/help` endpoint +5. Verify: static assets exist and reference correct paths + +## Key Details + +- Build tool: Rollup (via npm scripts) +- Node.js version: `nodejs_24` in current nixpkgs (check upstream requirements) +- The TypeScript API client must be patched in before the build +- Fixed-output hashes break on any npm dependency change — will need updating per release +- Output is consumed by both `authentik-django` (email templates) and the Go server (static serving) + +## Related + +- [[build-authentik-from-source]] — Parent goal +- [[authentik-api-client-generation]] — Provides TypeScript client (prerequisite) diff --git a/docs/how-to/authentik/build-authentik-from-source.md b/docs/how-to/authentik/build-authentik-from-source.md new file mode 100644 index 0000000..ae93a2e --- /dev/null +++ b/docs/how-to/authentik/build-authentik-from-source.md @@ -0,0 +1,58 @@ +--- +title: Build Authentik from Source +modified: 2026-02-28 +status: active +branch: mikado/authentik-source-build +requires: + - authentik-go-server-derivation + - authentik-web-ui-derivation + - authentik-python-backend-derivation +tags: + - how-to + - authentik + - nix +--- + +# Build Authentik from Source + +Replace `pkgs.authentik` from nixpkgs with a custom Nix derivation that builds authentik from source. This removes the dependency on the nixpkgs packaging timeline and gives full version control. + +## Motivation + +The nix-container-builder runner on ringtail resolves `nixpkgs` via the NixOS nix registry, which pins to `nixos-25.11`. That channel lags behind upstream authentik releases — e.g. nixos-25.11 has 2025.10.1 while upstream is at 2025.12.4+. Building from source lets us target any release. + +This also serves as practice for packaging services from source using Nix, relying on nixpkgs only for satellite dependencies (Python interpreter, Node.js, Go toolchain, system libraries). + +## Architecture + +Authentik has four build components that must be assembled: + +1. **API client generation** — Go and TypeScript bindings generated from `schema.yml` (OpenAPI) +2. **Python backend** (`authentik-django`) — Django application with 60+ Python dependencies, including 4 in-tree packages and a forked `djangorestframework` +3. **Web UI** — Lit-based TypeScript frontend built with Rollup +4. **Go server** — HTTP server binary (`cmd/server`) that serves the web UI and spawns gunicorn for Django + +The final package is the `ak` bash wrapper that orchestrates Go server + Python worker. + +## Source + +Forge mirror: https://forge.ops.eblu.me/mirrors/authentik (upstream: `goauthentik/authentik`) + +Reference derivation: [nixpkgs `pkgs/by-name/au/authentik/package.nix`](https://github.com/NixOS/nixpkgs/tree/master/pkgs/by-name/au/authentik) + +## What to Do + +Once all prerequisites are complete: + +1. Assemble the component derivations into a final `ak`-wrapped package in `containers/authentik/` +2. Update `containers/authentik/default.nix` to use the custom derivation instead of `pkgs.authentik` +3. Build and push the container: `mise run container-build-and-release authentik` +4. Update `argocd/manifests/authentik/kustomization.yaml` with the new image tag +5. Update `service-versions.yaml` with the new version +6. Verify deployment: ArgoCD sync, UI login, OAuth2 flows + +## Related + +- [[build-authentik-container]] — Current nixpkgs-based build (to be replaced) +- [[deploy-authentik]] — Parent deployment goal +- [[agent-change-process]] — C2 methodology diff --git a/docs/how-to/how-to.md b/docs/how-to/how-to.md index bef1826..33a9b89 100644 --- a/docs/how-to/how-to.md +++ b/docs/how-to/how-to.md @@ -96,6 +96,16 @@ Mikado chain for deploying Authentik. Track progress with `mise run docs-mikado - [[create-authentik-secrets]] - [[migrate-grafana-to-authentik]] +## Authentik Source Build + +Mikado chain for building Authentik from a custom Nix derivation (from source). Track progress with `mise run docs-mikado build-authentik-from-source`. + +- [[build-authentik-from-source]] +- [[authentik-api-client-generation]] +- [[authentik-python-backend-derivation]] +- [[authentik-web-ui-derivation]] +- [[authentik-go-server-derivation]] + ## Grafana Mikado chain for upgrading Grafana to 12.x with kustomize and home-built containers. Track progress with `mise run docs-mikado upgrade-grafana`.