- Go 84.4%
- Python 10.5%
- Makefile 3.8%
- Go Template 0.7%
- Dockerfile 0.4%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .claude | ||
| .devcontainer | ||
| .github/workflows | ||
| .woodpecker | ||
| api/v1alpha1 | ||
| charts/authentik-operator | ||
| cmd | ||
| config | ||
| docs | ||
| hack | ||
| internal | ||
| scripts | ||
| test | ||
| .dockerignore | ||
| .gitignore | ||
| .golangci.yml | ||
| Dockerfile | ||
| GLOSSARY.md | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| mise.toml | ||
| PROJECT | ||
| README.md | ||
| renovate.json | ||
| Taskfile.yml | ||
| TODO.md | ||
operator-authentik
// TODO(user): Add simple overview of use/purpose
Description
// TODO(user): An in-depth paragraph about your project and overview of use
Authentik server image default
New AuthentikServer resources that omit spec.image use
ghcr.io/goauthentik/server:2026.8.5 for both server and worker. This is the
current patch in the supported 2026.8 release series as of 2026-10-24; see the
upstream release notes.
The registry does not publish a latest tag.
Keep the default on a fixed supported release. Update it through a reviewed
change after checking upstream release/support notes and registry availability;
regenerate config/crd/bases, copy the server CRD into the Helm chart, and run
make test, make test-e2e and chart validation. The fallback, API marker,
packaged CRDs and E2E expectations must agree. Repository Renovate runs weekly
on Sunday at 03:15 UTC and tracks the operator's image defaults; core's Renovate
updates explicit workload image pins separately. An explicit spec.image is
preserved, including an older version or latest; changing the default does not
rewrite existing pins. Operators should
pin existing stateful installations explicitly and approve upgrades separately.
The homelab is pinned to 2026.8.5; removing its obsolete Redis workload does not
migrate the database or change its credentials.
Supported Authentik versions and dependencies
Use Authentik 2025.10 or newer; the deployed supported release series is 2026.8.x.
Authentik removed Redis in 2025.10
and now uses PostgreSQL for caching, tasks and sessions. The operator creates no
Redis workload or Redis environment settings. On reconciliation it deletes an
obsolete <server-name>-redis Deployment and Service only when controlled by
that AuthentikServer UID; unowned resources and resources controlled by another
server are left untouched. PostgreSQL configuration and bootstrap credentials
are preserved.
Server startup health checks
The server's HTTP startup probe checks /-/health/live/ on port 9000 every ten
seconds, with a five-second request timeout and 60 failures allowed. Kubernetes
holds liveness and readiness probes until startup succeeds, giving the server
up to ten minutes to start while PostgreSQL and the migration worker recover
after a reboot. After startup, the existing live and ready endpoints continue
to check the running server. Readiness still controls whether it receives traffic.
This startup budget prevents premature liveness restarts; database contention must also be fixed in the postgres operator. It does not make a permanent lock deadlock safe.
Persistent local files
Set spec.dataVolumeClaimName to the name of an existing PersistentVolumeClaim
in the AuthentikServer namespace to enable persistent local files, including
background image uploads. Both server and worker mount that same claim read-write
as volume data at /data; their existing UID, GID and filesystem group are 1000.
The claim name must be nonempty when supplied. Omitting the field leaves both
workloads without a data volume.
spec:
host: auth.example.com
dataVolumeClaimName: authentik-data
Create and protect the claim separately before configuring it. The operator does
not create, adopt, resize or delete PVCs, including when this field is removed or
the AuthentikServer is deleted. Back up the stored files independently of the
PostgreSQL database. The claim must support simultaneous access by server and
worker: a ReadWriteOnce local-path claim works when both run on the same node;
multi-node deployments need storage and access modes that support their placement.
An unavailable or unschedulable claim prevents the affected pods from starting.
Getting Started
Release version and approval
Main and branch pushes validate without publishing. An approved version tag pushed to Forgejo is mirrored outward and triggers image, release-asset and Helm publication. Publishers stamp the chart version and appVersion from that tag; they refuse reused versions. Follow Operator releases for the read-only preflight and approval of the exact version, commit and effects. Publication alone does not update the homelab: once the artifacts exist, change core's pinned operator version and verify the live objects and original symptom.
API-client connection lifetime
Controllers construct API clients on each reconciliation. Clients keep their own URL and authorization headers while sharing the HTTP connection pool for their TLS mode. The explicit skip-verification mode uses a process-wide pool with at most ten idle connections in total, two per host and a 30-second idle timeout. Verifying clients continue using the standard HTTP client. Creating a fresh transport per reconciliation leaks idle connections and their goroutines, including when the URL uses internal HTTP; garbage collection alone does not close them. HOMEIT-490 reproduced 100 retained connections after 100 clients.
Run the connection-reuse, credential-isolation and TLS-isolation regressions with:
go test ./internal/authentik -run 'TestFreshClientsReuseConnections|TestClientTLSModesRemainIsolated'
After deployment, measure memory across startup with the full client/group/proxy backlog and repeated reconciliation. The homelab's 256Mi operator limit is an OOM mitigation, not proof of a bounded live working set or final resource sizing.
Prerequisites
- go version v1.24.6+
- docker version 17.03+.
- kubectl version v1.11.3+.
- Access to a Kubernetes v1.11.3+ cluster.
To Deploy on the cluster
Build and push your image to the location specified by IMG:
make docker-build docker-push IMG=<some-registry>/operator-authentik:tag
NOTE: This image ought to be published in the personal registry you specified. And it is required to have access to pull the image from the working environment. Make sure you have the proper permission to the registry if the above commands don’t work.
Install the CRDs into the cluster:
make install
Deploy the Manager to the cluster with the image specified by IMG:
make deploy IMG=<some-registry>/operator-authentik:tag
NOTE: If you encounter RBAC errors, you may need to grant yourself cluster-admin privileges or be logged in as admin.
Create instances of your solution You can apply the samples (examples) from the config/sample:
kubectl apply -k config/samples/
NOTE: Ensure that the samples has default values to test it out.
To Uninstall
Delete the instances (CRs) from the cluster:
kubectl delete -k config/samples/
Delete the APIs(CRDs) from the cluster:
make uninstall
UnDeploy the controller from the cluster:
make undeploy
Project Distribution
Following the options to release and provide this solution to the users.
By providing a bundle with all YAML files
- Build the installer for the image built and published in the registry:
make build-installer IMG=<some-registry>/operator-authentik:tag
NOTE: The makefile target mentioned above generates an 'install.yaml' file in the dist directory. This file contains all the resources built with Kustomize, which are necessary to install this project without its dependencies.
- Using the installer
Users can just run 'kubectl apply -f ' to install the project, i.e.:
kubectl apply -f https://raw.githubusercontent.com/<org>/operator-authentik/<tag or branch>/dist/install.yaml
By providing a Helm Chart
- Build the chart using the optional helm plugin
kubebuilder edit --plugins=helm/v2-alpha
- See that a chart was generated under 'dist/chart', and users can obtain this solution from there.
NOTE: If you change the project, you need to update the Helm Chart using the same command above to sync the latest changes. Furthermore, if you create webhooks, you need to use the above command with the '--force' flag and manually ensure that any custom configuration previously added to 'dist/chart/values.yaml' or 'dist/chart/manager/manager.yaml' is manually re-applied afterwards.
Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project
NOTE: Run make help for more information on all potential make targets
More information can be found via the Kubebuilder Documentation
License
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
End-to-end test fixtures
make test-e2e runs the operator in an isolated Kind cluster. The server fixture
omits spec.image, checks admission and both deployment images are 2026.8.5,
then waits for both deployments and status.ready=true. The client test reuses
that initialized server and its bootstrap secret. A second server against the
same test database would generate credentials that differ from its first-boot
initialization. Explicit image preservation is tested separately in the
controller regression tests.
The suite has a thirty-minute Go timeout so image builds, startup waits and failure diagnostics fit inside the overall deadline. Individual readiness waits remain bounded. Fixtures also check the public HTTPS URL and startup probe, and delete clients and servers before undeploying the controller so their finalizers can finish. Namespace cleanup has a bounded wait. Runtime credentials and data are not used by these isolated tests.
GitOps groups and access
Operator 0.2.0 adds AuthentikGroup and AuthentikClient.allowedGroups. See
ownership and cutover rules before
upgrading. User provisioning is outside this feature.
apiVersion: authentik.homelab.mortenolsen.pro/v1alpha1
kind: AuthentikGroup
metadata:
name: app-access
namespace: prod
spec:
serverRef: {name: authentik, namespace: shared}
members:
- id: 123
uuid: 11111111-2222-4333-8444-555555555555
Reference it from a client with
allowedGroups: [{name: app-access, namespace: prod}]. An empty list denies
access. Once a client has opted in, removing the list also denies access.
The group owns its complete direct membership; UI edits are drift. Remote renames
are repaired using the stable group ID and ownership UID, including recovery
when status is lost. Ambiguous ownership blocks writes. Deletion revokes and reads
back managed fields before releasing its finalizer, retaining the remote identity.
Backing groups
never grant Authentik superuser or role privileges, and the operator has no
special admin behavior. Inspect user IDs/UUIDs through the authenticated
Authentik API without logging credentials; never identify members by display name.
Local and Woodpecker PR validation uses mise install && task ci:quality
(build, make test including envtest, make lint, generated CRD/RBAC drift and Helm rendering).
The service-image delivery shape and existing GitHub mirror release workflow are
preserved: merging main validates without publishing. An explicitly approved
Forgejo version tag publishes the reviewed chart/image version. The new quality workflow uses the existing ci/mise image and no secrets;
it does not publish or change release mechanics.
Release ownership
See Operator releases for approved Forgejo tags, publication checks, version immutability and recovery. Main merges validate without publishing.
The PR runner obtains Python 3.13.16 through mise for the release-safety regression suite; it does not assume python3 is installed in the ci/mise base image.
The isolated Kind fixture provisions an empty managed group before its client and revokes that group before deleting the server. The PR quality task compiles this fixture; full Kind execution uses the existing mirrored E2E Tests workflow. Docker and Kind are not present in the Mission Control task container, so a local compile is not reported as a full isolated runtime acceptance run.
Forward-auth proxy providers
Operator 0.3.0 adds AuthentikProxyProvider for applications that cannot speak
OIDC and are protected by a reverse proxy using Authentik forward auth (for
example Istio ext_authz). See
the design and ownership rules.
apiVersion: authentik.homelab.mortenolsen.pro/v1alpha1
kind: AuthentikProxyProvider
metadata:
name: whoami
namespace: prod
spec:
serverRef: {name: authentik, namespace: shared}
name: whoami
externalHost: https://whoami.example.com
accessTokenValidity: hours=8
allowedGroups: [{name: admin, namespace: shared}]
The operator creates the forward_single provider and its application with
the same guarded access as AuthentikClient, then serves it from the embedded
outpost, whose authentik_host it sets to https://<server host>. Omitting
allowedGroups denies everyone. The reverse proxy must also route
/outpost.goauthentik.io/ on the protected host to the Authentik server for
the login callback.