mirror of
https://github.com/rubenhensen/k8scd.git
synced 2026-11-15 14:29:09 +01:00
113 lines
4.8 KiB
Markdown
113 lines
4.8 KiB
Markdown
# Authentik
|
|
|
|
Authentik is deployed as the central identity provider, providing OIDC and LDAP authentication for services in the cluster.
|
|
|
|
## Components
|
|
|
|
- **Authentik Server** — Helm chart deployment (`apps/templates/authentik-helm.yaml`)
|
|
- **PostgreSQL** — CloudNativePG cluster (`postgresql-cluster.yaml`)
|
|
- **Secrets** — ExternalSecrets from Vault (`external-secret.yaml`)
|
|
- **Blueprints** — Auto-configured providers:
|
|
- `blueprint-ldap.yaml` — LDAP provider (base DN: `DC=ldap,DC=goauthentik,DC=io`)
|
|
- `blueprint-mail-oidc.yaml` — OAuth2/OIDC provider for Stalwart mail
|
|
- `blueprint-vault-oidc.yaml` — OIDC provider for Vault
|
|
- `blueprint-argocd-oidc.yaml` — OIDC provider for ArgoCD
|
|
- `blueprint-freshrss-oidc.yaml` — OIDC provider for FreshRSS
|
|
- `blueprint-actualbudget-proxy.yaml` — Proxy provider for Actual Budget
|
|
- `blueprint-longhorn-oidc.yaml` — OIDC provider for Longhorn (Envoy Gateway SecurityPolicy)
|
|
- `blueprint-scouting.yaml` — immich's login with Scouts Online, see docs/immich-scouts-online.md
|
|
- `blueprint-session-duration.yaml` — Session lifetime of the default authentication flow
|
|
- **NetworkPolicies** (`networkpolicy.yaml`) — the pods reach each other, DNS and the internet,
|
|
not the LAN or other namespaces; the worker and the database also reach the API server
|
|
|
|
## Session lifetime
|
|
|
|
Authentik ships the login stage of `default-authentication-flow` with
|
|
`session_duration: seconds=0`, i.e. the SSO session dies when the browser closes.
|
|
`blueprint-session-duration.yaml` raises this to 30 days for every app that uses
|
|
that flow (FreshRSS, ArgoCD, Vault, Actual Budget, mail).
|
|
|
|
The expiry is **absolute** — Authentik does not extend a session on activity. A
|
|
sliding window has to come from the application itself; FreshRSS does this via
|
|
`OIDC_SESSION_INACTIVITY_TIMEOUT` (see `freshrss/freshrss-deployment.yaml`), which
|
|
Apache mod_auth_openidc refreshes on every request.
|
|
|
|
## LDAP Outpost
|
|
|
|
The LDAP outpost exposes Authentik's user directory over LDAP. It is used by
|
|
**Stalwart** (NixOS on node001), which connects via `ldap.rubenhensen.nl:389`.
|
|
The outpost itself talks to the server through `https://authentik.rubenhensen.nl/`.
|
|
|
|
Authentik's worker deploys the outpost and keeps its version equal to the
|
|
server's. After the upgrades to 2026.5 and 2026.8 it didn't follow on its
|
|
own; this rolls it over:
|
|
|
|
```bash
|
|
kubectl -n authentik exec deploy/authentik-worker -- ak shell -c '
|
|
from authentik.outposts.models import Outpost
|
|
from authentik.outposts.tasks import outpost_controller
|
|
outpost_controller.send(Outpost.objects.get(name="LDAP outpost").pk)'
|
|
```
|
|
|
|
Upgrades go one release at a time (2026.2 → 2026.5 → 2026.8); since 2026.8
|
|
authentik refuses to skip one.
|
|
|
|
### NodePort Service
|
|
|
|
The outpost is exposed externally via a NodePort service (`ldap-outpost-lb.yaml`):
|
|
- LDAP: `389 → 3389` (NodePort `30389`)
|
|
- LDAPS: `636 → 6636` (NodePort `30636`)
|
|
|
|
The router port-forwards `389 → 30389` on the cluster node to make it reachable at `ldap.rubenhensen.nl`.
|
|
|
|
**Important:** The pod selector is `app.kubernetes.io/name: authentik-outpost-ldap` (set by Authentik's outpost controller, not the outpost name).
|
|
|
|
### MicroK8s CA Certificate Fix
|
|
|
|
Authentik's outpost controller needs to talk to the Kubernetes API to deploy the LDAP outpost pod. This fails on MicroK8s because the default CA certificate is missing the `keyUsage` extension, which Python 3.13+ enforces strictly.
|
|
|
|
**Error:**
|
|
```
|
|
SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
|
|
CA cert does not include key usage extension (_ssl.c:1081)
|
|
```
|
|
|
|
**Root cause:** https://github.com/canonical/microk8s/issues/4864
|
|
|
|
**Fix applied (2026-03-21):** Regenerated the MicroK8s CA certificate with the `keyUsage` extension using the script from the issue above:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
cert_workspace="$HOME/fixed-certs"
|
|
mkdir -p "$cert_workspace"
|
|
cd "$cert_workspace"
|
|
|
|
# Generate new CA key
|
|
openssl genrsa -out ca.key 2048
|
|
|
|
# Generate CA cert WITH keyUsage extension
|
|
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
|
|
-out ca.crt \
|
|
-addext "keyUsage=critical,digitalSignature,keyCertSign" \
|
|
-subj "/CN=microk8s-ca"
|
|
|
|
# Verify the certificate has the extension
|
|
openssl x509 -in ca.crt -text -noout | grep -A 1 "Key Usage"
|
|
|
|
# Rotate the cluster CA
|
|
microk8s refresh-certs "$cert_workspace"
|
|
|
|
# Regenerate kubeconfig
|
|
mkdir -p ~/.kube
|
|
microk8s config > ~/.kube/config
|
|
```
|
|
|
|
**Note:** This must be re-applied after MicroK8s upgrades or cert rotations, as MicroK8s may regenerate the CA without the extension. The fix needs to run on every node in the cluster.
|
|
|
|
Checked 2026-10-25: the CA from this fix (`CN=microk8s-ca`, 2026-03-21, valid
|
|
until 2036) still has the extension after the refreshes to 1.34, 1.35 and
|
|
1.36. Check with
|
|
`openssl x509 -in /var/snap/microk8s/current/certs/ca.crt -noout -ext keyUsage`.
|