diff --git a/authentik/outposts/controllers/base.py b/authentik/outposts/controllers/base.py index fe342cb0f..583b41f9e 100644 --- a/authentik/outposts/controllers/base.py +++ b/authentik/outposts/controllers/base.py @@ -69,6 +69,9 @@ class BaseController: def get_container_image(self) -> str: """Get container image to use for this outpost""" + if self.outpost.config.container_image is not None: + return self.outpost.config.container_image + image_name_template: str = CONFIG.y("outposts.docker_image_base") return image_name_template % { "type": self.outpost.type, diff --git a/authentik/outposts/controllers/k8s/base.py b/authentik/outposts/controllers/k8s/base.py index de7c244a2..cdaa0be52 100644 --- a/authentik/outposts/controllers/k8s/base.py +++ b/authentik/outposts/controllers/k8s/base.py @@ -138,6 +138,8 @@ class KubernetesObjectReconciler(Generic[T]): "app.kubernetes.io/version": __version__, "app.kubernetes.io/managed-by": "goauthentik.io", "goauthentik.io/outpost-uuid": self.controller.outpost.uuid.hex, + "goauthentik.io/outpost-type": str(self.controller.outpost.type), + "goauthentik.io/outpost-name": slugify(self.controller.outpost.name), }, **kwargs, ) diff --git a/authentik/outposts/controllers/k8s/deployment.py b/authentik/outposts/controllers/k8s/deployment.py index 5d3d1a74c..71f1fa35b 100644 --- a/authentik/outposts/controllers/k8s/deployment.py +++ b/authentik/outposts/controllers/k8s/deployment.py @@ -1,6 +1,7 @@ """Kubernetes Deployment Reconciler""" from typing import TYPE_CHECKING +from django.utils.text import slugify from kubernetes.client import ( AppsV1Api, V1Container, @@ -11,6 +12,7 @@ from kubernetes.client import ( V1EnvVarSource, V1LabelSelector, V1ObjectMeta, + V1ObjectReference, V1PodSpec, V1PodTemplateSpec, V1SecretKeySelector, @@ -56,6 +58,8 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]): "app.kubernetes.io/name": "authentik-outpost", "app.kubernetes.io/managed-by": "goauthentik.io", "goauthentik.io/outpost-uuid": self.controller.outpost.uuid.hex, + "goauthentik.io/outpost-name": slugify(self.controller.outpost.name), + "goauthentik.io/outpost-type": str(self.controller.outpost.type), } def get_reference_object(self) -> V1Deployment: @@ -72,6 +76,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]): ) meta = self.get_object_meta(name=self.name) image_name = self.controller.get_container_image() + image_pull_secrets = self.outpost.config.kubernetes_image_pull_secrets return V1Deployment( metadata=meta, spec=V1DeploymentSpec( @@ -80,6 +85,9 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]): template=V1PodTemplateSpec( metadata=V1ObjectMeta(labels=self.get_pod_meta()), spec=V1PodSpec( + image_pull_secrets=[ + V1ObjectReference(name=secret) for secret in image_pull_secrets + ], containers=[ V1Container( name=str(self.outpost.type), @@ -124,7 +132,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]): ), ], ) - ] + ], ), ), ), diff --git a/authentik/outposts/models.py b/authentik/outposts/models.py index 48fbb325e..0303ec3d4 100644 --- a/authentik/outposts/models.py +++ b/authentik/outposts/models.py @@ -74,12 +74,15 @@ class OutpostConfig: docker_network: Optional[str] = field(default=None) docker_map_ports: bool = field(default=True) + container_image: Optional[str] = field(default=None) + kubernetes_replicas: int = field(default=1) kubernetes_namespace: str = field(default_factory=get_namespace) kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict) kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls") kubernetes_service_type: str = field(default="ClusterIP") kubernetes_disabled_components: list[str] = field(default_factory=list) + kubernetes_image_pull_secrets: Optional[list[str]] = field(default_factory=list) class OutpostModel(Model): diff --git a/website/docs/outposts/outposts.md b/website/docs/outposts/outposts.md index c8ee81ba8..5e3a7fadb 100644 --- a/website/docs/outposts/outposts.md +++ b/website/docs/outposts/outposts.md @@ -41,6 +41,9 @@ authentik_host_insecure: false authentik_host_browser: # Template used for objects created (deployments, services, secrets, etc) object_naming_template: ak-outpost-%(name)s +# Use a specific docker image for this outpost rather than the default. This also applies to Kubernetes +# outposts. +conatiner_image: ######################################## # Docker outpost specific settings ######################################## @@ -70,4 +73,7 @@ kubernetes_service_type: ClusterIP # - 'ingress' # - 'traefik middleware' kubernetes_disabled_components: [] +# If the above docker image is in a private repository, use these secrets to pull. +# NOTE: The secret must be created manually in the namespace first. +kubernetes_image_pull_secrets: [] ```