Strip sha256 hash and update to 2026.8.3
Validate and deploy Authentik / validate (push) Successful in 16s
Validate and deploy Authentik / deploy (push) Successful in 1m14s

This commit is contained in:
2026-10-14 20:16:26 +02:00
parent 19f5e330a2
commit c85f09b3bb
8 changed files with 125 additions and 23 deletions
+1 -7
View File
@@ -1,10 +1,8 @@
name: Validate and deploy Authentik
on: {push: {}, pull_request: {}}
env:
AUTHENTIK_CHART_VERSION: 2026.8.0
AUTHENTIK_CHART_SHA256: fb51f1ab970a15e37f8d2b4fe2767cea33afe7e6f84bee646d2690f31fcde7e5
AUTHENTIK_CHART_VERSION: 2026.8.3
HELM_VERSION: v4.2.2
HELM_SHA256: 9adafecab4d406853bba163a70e9f104f47dbbf65ce24b7653bae7e36150bcb6
KUBECTL_VERSION: v1.36.3
KUBERNETES_API: https://host.containers.internal:6443
KUBERNETES_TLS_SERVER_NAME: 192.168.0.2
@@ -16,7 +14,6 @@ jobs:
- uses: actions/checkout@v4
- run: |
curl -fsSL -o "$RUNNER_TEMP/helm.tgz" "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz"
printf '%s %s\n' "$HELM_SHA256" "$RUNNER_TEMP/helm.tgz" | sha256sum -c
tar -xzf "$RUNNER_TEMP/helm.tgz" -C "$RUNNER_TEMP" --strip-components=1 linux-amd64/helm
echo "$RUNNER_TEMP" >> "$GITHUB_PATH"
- run: bash test.sh
@@ -28,11 +25,8 @@ jobs:
- uses: actions/checkout@v4
- run: |
curl -fsSL -o "$RUNNER_TEMP/helm.tgz" "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz"
printf '%s %s\n' "$HELM_SHA256" "$RUNNER_TEMP/helm.tgz" | sha256sum -c
tar -xzf "$RUNNER_TEMP/helm.tgz" -C "$RUNNER_TEMP" --strip-components=1 linux-amd64/helm
curl -fsSL -o "$RUNNER_TEMP/kubectl" "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
curl -fsSL -o "$RUNNER_TEMP/kubectl.sha" "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl.sha256"
printf '%s %s\n' "$(cat "$RUNNER_TEMP/kubectl.sha")" "$RUNNER_TEMP/kubectl" | sha256sum -c
chmod 700 "$RUNNER_TEMP/helm" "$RUNNER_TEMP/kubectl"; echo "$RUNNER_TEMP" >> "$GITHUB_PATH"
- env: {KUBE_CONFIG_BASE64: "${{ secrets.KUBE_CONFIG_BASE64 }}"}
run: |
+19 -2
View File
@@ -1,16 +1,27 @@
# Authentik on Kubernetes
Authentik `2026.8.0` is rendered from the pinned official chart. `values.yaml`
Authentik `2026.8.3` is rendered from the pinned official chart. `values.yaml`
contains only public configuration; the ignored legacy `authentik-values.yaml`
is retained locally. Runtime credentials live in `authentik-runtime` and the
existing PostgreSQL Secret, and neither is readable by CI.
The LDAP, RADIUS, and RAC outposts are managed by Authentik and keep their
image pins in its database. `install.sh` runs `update-outpost-images.sh` after
the chart upgrade so their images match the server release.
`authentik-blueprints` declaratively creates the Argo CD OIDC application,
provider, and group claim. Its client secret comes from
`ARGOCD_OIDC_CLIENT_SECRET` in `authentik-runtime`; `install.sh` generates it
once when absent and mirrors it into the labeled `argocd-oidc` Secret. Only the
existing `authentik Admins` group is mapped to Argo CD administrator access.
The same blueprint creates an admin-only forward-auth application for
Kubernetes Dashboard. Its proxy provider contains no committed credential and
is served by the embedded proxy outpost. `install.sh` applies the blueprint and
idempotently attaches the provider to that outpost; it deliberately does not
replace the outpost's complete provider list because other repositories own
those applications.
Copy `authentik-secrets.env.example` to the ignored `authentik-secrets.env`,
preserve the existing values, and run `./install.sh` for administrator secret
updates. Run `./test.sh` for a secret-free render and schema validation.
@@ -18,13 +29,19 @@ The installer refuses a PostgreSQL password mismatch instead of attempting a
blind rotation; rotate the database role and both Kubernetes Secrets together
during a dedicated maintenance window.
The public Authentik and embedded-outpost routes have no Traefik request-rate
or concurrent-request limit: browser login flows and protected applications can
legitimately generate large bursts. Two server replicas, a PodDisruptionBudget,
and explicit resource requests keep one busy client or node from removing the
only healthy authentication endpoint.
Run `./create-ci-kubeconfig.sh` and store its final line as the Gitea Actions
secret `KUBE_CONFIG_BASE64`. CI can update only exact existing Authentik chart,
Ingress, Middleware, and event-filter objects; it cannot read Secrets, create
objects, delete objects, or manage the Ceph object user.
`authentik-client-credentials-event-filter` is a local compatibility patch
introduced on 2026-08-30. It replaces Authentik's private
introduced on 2026-08-30 and reviewed against upstream `2026.8.3`. It replaces Authentik's private
`providers/oauth2/token/client_credentials.py` module to retain application
password grants while suppressing loopback (`::1`) login-event noise. Recheck
or remove it on every Authentik upgrade because it is not an upstream chart
+1 -1
View File
@@ -4,7 +4,7 @@ metadata:
name: authentik-outpost-path
namespace: authentik
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.priority: "10000"
spec:
rules:
+1 -1
View File
@@ -13,7 +13,7 @@ rules:
verbs: [get, patch, update]
- apiGroups: [policy]
resources: [poddisruptionbudgets]
resourceNames: [authentik-postgresql]
resourceNames: [authentik-postgresql, authentik-server]
verbs: [get, patch, update]
- apiGroups: [""]
resources: [serviceaccounts]
+29 -4
View File
@@ -2,18 +2,22 @@
set -eu
chart_version=2026.8.0
chart_sha256=fb51f1ab970a15e37f8d2b4fe2767cea33afe7e6f84bee646d2690f31fcde7e5
chart_version=2026.8.3
project_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
secret_file=${AUTHENTIK_SECRET_FILE:-$project_dir/authentik-secrets.env}
for command in helm kubectl openssl base64 curl sha256sum; do
for command in helm kubectl openssl base64 curl; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "Required command not found: $command" >&2
exit 1
fi
done
if [ "$(kubectl config current-context)" != 'kubernetes-admin@kubernetes' ]; then
echo 'Expected the homelab Kubernetes context; refusing to install Authentik.' >&2
exit 1
fi
kubectl apply --filename "$project_dir/authentik-namespace.yaml"
if [ -f "$secret_file" ]; then
@@ -99,10 +103,31 @@ chart_archive=$(mktemp)
trap 'rm -f "$oidc_secret_file" "$oidc_patch_file" "$postgres_password_file" "$chart_archive"' EXIT HUP INT TERM
curl --fail --silent --show-error --location --output "$chart_archive" \
"https://github.com/goauthentik/helm/releases/download/authentik-${chart_version}/authentik-${chart_version}.tgz"
printf '%s %s\n' "$chart_sha256" "$chart_archive" | sha256sum --check >&2
helm upgrade --install --namespace authentik authentik "$chart_archive" \
--version "$chart_version" --values "$project_dir/values.yaml" \
--take-ownership --force-conflicts --rollback-on-failure \
--wait --timeout 15m
sh "$project_dir/update-outpost-images.sh"
# Apply the Dashboard blueprint immediately, then make its provider available
# through the embedded outpost. The relationship is idempotent, but is not
# expressed in the blueprint because replacing the outpost's provider list
# would detach providers owned by other repositories.
dashboard_blueprint_attempt=1
while ! kubectl --namespace authentik exec deployment/authentik-worker -- \
ak apply_blueprint /blueprints/mounted/cm-authentik-blueprints/kubernetes-dashboard.yaml; do
if [ "$dashboard_blueprint_attempt" -ge 5 ]; then
echo "Dashboard blueprint failed after $dashboard_blueprint_attempt attempts." >&2
exit 1
fi
dashboard_blueprint_attempt=$((dashboard_blueprint_attempt + 1))
echo "Dashboard blueprint conflicted; retrying attempt $dashboard_blueprint_attempt/5." >&2
sleep 5
done
kubectl --namespace authentik exec deployment/authentik-worker -- \
ak shell --command \
'from authentik.outposts.models import Outpost; from authentik.providers.proxy.models import ProxyProvider; outpost = Outpost.objects.get(name="authentik Embedded Outpost"); provider = ProxyProvider.objects.get(name="Kubernetes Dashboard"); outpost.providers.add(provider)'
kubectl apply --filename "$project_dir/authentik-outpost-path.yaml"
kubectl apply --filename "$project_dir/authentik-media-redirect.yaml"
+1 -3
View File
@@ -1,10 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
project_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
version=${AUTHENTIK_CHART_VERSION:-2026.8.0}
digest=${AUTHENTIK_CHART_SHA256:-fb51f1ab970a15e37f8d2b4fe2767cea33afe7e6f84bee646d2690f31fcde7e5}
version=${AUTHENTIK_CHART_VERSION:-2026.8.3}
output=${1:?Usage: render.sh OUTPUT_FILE}
chart=$(mktemp); trap 'rm -f "${chart}"' EXIT
curl -fsSL -o "${chart}" "https://github.com/goauthentik/helm/releases/download/authentik-${version}/authentik-${version}.tgz"
printf '%s %s\n' "${digest}" "${chart}" | sha256sum -c >&2
helm template authentik "${chart}" --namespace authentik --values "${project_dir}/values.yaml" > "${output}"
+8 -2
View File
@@ -1,9 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd); work=$(mktemp -d); trap 'rm -rf "${work}"' EXIT
sh -n "$dir/install.sh"; bash -n "$dir/render.sh" "$dir/create-ci-kubeconfig.sh" "$dir/test.sh"
sh -n "$dir/install.sh" "$dir/update-outpost-images.sh"; bash -n "$dir/render.sh" "$dir/create-ci-kubeconfig.sh" "$dir/test.sh"
"$dir/render.sh" "$work/authentik.yaml"
grep -Eq '^kind: Secret$' "$work/authentik.yaml" && { echo "Chart rendered a Secret" >&2; exit 1; }
image=ghcr.io/yannh/kubeconform:v0.7.0@sha256:85dbef6b4b312b99133decc9c6fc9495e9fc5f92293d4ff3b7e1b30f5611823c
image=ghcr.io/yannh/kubeconform:v0.7.0
for file in "$work/authentik.yaml" "$dir/authentik-outpost-path.yaml" "$dir/authentik-media-redirect.yaml" "$dir/ci-deployer.yaml"; do docker run --rm -i "$image" -strict -exit-on-error -ignore-missing-schemas -summary < "$file"; done
grep -q 'replicas: 2' "$work/authentik.yaml"
grep -q 'cpu: 500m' "$work/authentik.yaml"
if grep -Eq 'router.middlewares:|inFlightReq:|rateLimit:' "$work/authentik.yaml" "$dir/authentik-outpost-path.yaml"; then
echo "Public Authentik request limiting must remain disabled." >&2
exit 1
fi
echo "Authentik public desired state is valid and contains no Secrets."
+65 -3
View File
@@ -1,6 +1,4 @@
global:
image:
digest: sha256:21000cebe8e51eca0620034096586d675cedec8925ac750f7f8966d86eeb0da0
env:
- name: AUTHENTIK_STORAGE__MEDIA__BACKEND
value: s3
@@ -42,6 +40,20 @@ serviceAccount:
create: true
name: authentik
server:
# Keep authentication available during a pod or worker-node failure. The
# chart's default soft pod anti-affinity spreads these replicas when the
# cluster has capacity on more than one node.
replicas: 2
pdb:
enabled: true
minAvailable: 1
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
# Deliberately leave CPU unlimited so login bursts can use idle cores.
memory: 2Gi
env:
- name: AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS
value: 127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fe80::/10,::1/128
@@ -50,7 +62,7 @@ server:
- name: AUTHENTIK_WEB__MAX_REQUESTS
value: '0'
podAnnotations:
authentik.brunner.ninja/client-credentials-event-filter: 2026.8.0-1
authentik.brunner.ninja/client-credentials-event-filter: 2026.8.3-1
volumeMounts:
- name: client-credentials-event-filter
mountPath: /authentik/providers/oauth2/token/client_credentials.py
@@ -80,6 +92,12 @@ server:
timeoutSeconds: 10
worker:
enabled: true
livenessProbe:
timeoutSeconds: 10
readinessProbe:
timeoutSeconds: 10
startupProbe:
timeoutSeconds: 10
geoip:
enabled: false
postgresql:
@@ -151,6 +169,50 @@ additionalObjects:
name: Argo CD
provider: !KeyOf argocd-provider
launch_url: https://cd.brunner.ninja
kubernetes-dashboard.yaml: |
version: 1
metadata:
name: Kubernetes Dashboard forward authentication
labels:
blueprints.goauthentik.io/description: Admin-only access to Kubernetes Dashboard
entries:
- model: authentik_providers_proxy.proxyprovider
id: kubernetes-dashboard-provider
state: present
identifiers:
name: Kubernetes Dashboard
attrs:
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-explicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
client_type: confidential
grant_types:
- authorization_code
- refresh_token
mode: forward_single
internal_host: ""
external_host: https://kubernetes.brunner.ninja
property_mappings:
- !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/proxy/scope-proxy]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
- model: authentik_core.application
id: kubernetes-dashboard-application
state: present
identifiers:
slug: kubernetes-dashboard
attrs:
name: Kubernetes Dashboard
provider: !KeyOf kubernetes-dashboard-provider
launch_url: https://kubernetes.brunner.ninja
- model: authentik_policies.policybinding
state: present
identifiers:
target: !KeyOf kubernetes-dashboard-application
group: !Find [authentik_core.group, [name, authentik Admins]]
order: 0
attrs:
enabled: true
- apiVersion: v1
kind: ConfigMap
metadata: