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 <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-02-28 08:20:17 -08:00
commit 7094ea7d3e
7 changed files with 252 additions and 0 deletions

View file

@ -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.

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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`.