From 61b61ce960be63657abdc19363aa235b48be99e5 Mon Sep 17 00:00:00 2001 From: Philipp Kolberg <39984529+PKizzle@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:23:12 +0100 Subject: [PATCH] outposts: Enhance config options for k8s outposts (#7363) * Allow specifying the service's ipFamilyPolicy and ipFamilies * Add documentation * Only create k8s TLS Ingress config if secretName is set * Fix linter issues. * Fix wrong attributes * Remove IP family configuration option This shall rather be configured using `kubernetes_json_patch` introduced with https://github.com/goauthentik/authentik/pull/6319 * Add test for k8s service reconciler * Fix linter issues --- authentik/outposts/controllers/k8s/service.py | 2 ++ .../proxy/controllers/k8s/ingress.py | 22 +++++++++----- tests/integration/test_outpost_kubernetes.py | 30 +++++++++++++++++++ website/docs/outposts/_config.md | 2 +- .../docs/outposts/integrations/kubernetes.md | 2 +- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/authentik/outposts/controllers/k8s/service.py b/authentik/outposts/controllers/k8s/service.py index 5a26f1c04b..f3cbb75e0b 100644 --- a/authentik/outposts/controllers/k8s/service.py +++ b/authentik/outposts/controllers/k8s/service.py @@ -33,6 +33,8 @@ class ServiceReconciler(KubernetesObjectReconciler[V1Service]): # priority than being updated. if current.spec.selector != reference.spec.selector: raise NeedsUpdate() + if current.spec.type != reference.spec.type: + raise NeedsUpdate() super().reconcile(current, reference) def get_reference_object(self) -> V1Service: diff --git a/authentik/providers/proxy/controllers/k8s/ingress.py b/authentik/providers/proxy/controllers/k8s/ingress.py index 842490821c..9c3c6755a6 100644 --- a/authentik/providers/proxy/controllers/k8s/ingress.py +++ b/authentik/providers/proxy/controllers/k8s/ingress.py @@ -56,7 +56,10 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]): proxy_provider: ProxyProvider external_host_name = urlparse(proxy_provider.external_host) expected_hosts.append(external_host_name.hostname) - if external_host_name.scheme == "https": + if ( + external_host_name.scheme == "https" + and self.controller.outpost.config.kubernetes_ingress_secret_name + ): expected_hosts_tls.append(external_host_name.hostname) expected_hosts.sort() expected_hosts_tls.sort() @@ -116,7 +119,10 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]): ): proxy_provider: ProxyProvider external_host_name = urlparse(proxy_provider.external_host) - if external_host_name.scheme == "https": + if ( + external_host_name.scheme == "https" + and self.controller.outpost.config.kubernetes_ingress_secret_name + ): tls_hosts.append(external_host_name.hostname) if proxy_provider.mode in [ ProxyMode.FORWARD_SINGLE, @@ -160,13 +166,15 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]): rules.append(rule) tls_config = None if tls_hosts: - tls_config = V1IngressTLS( - hosts=tls_hosts, - secret_name=self.controller.outpost.config.kubernetes_ingress_secret_name, - ) + tls_config = [ + V1IngressTLS( + hosts=tls_hosts, + secret_name=self.controller.outpost.config.kubernetes_ingress_secret_name, + ) + ] spec = V1IngressSpec( rules=rules, - tls=[tls_config], + tls=tls_config, ) if self.controller.outpost.config.kubernetes_ingress_class_name: spec.ingress_class_name = self.controller.outpost.config.kubernetes_ingress_class_name diff --git a/tests/integration/test_outpost_kubernetes.py b/tests/integration/test_outpost_kubernetes.py index d5454dbc20..099eddc87a 100644 --- a/tests/integration/test_outpost_kubernetes.py +++ b/tests/integration/test_outpost_kubernetes.py @@ -10,6 +10,7 @@ from kubernetes.client.exceptions import OpenApiException from authentik.core.tests.utils import create_test_flow from authentik.lib.config import CONFIG from authentik.outposts.controllers.k8s.deployment import DeploymentReconciler +from authentik.outposts.controllers.k8s.service import ServiceReconciler from authentik.outposts.controllers.k8s.triggers import NeedsUpdate from authentik.outposts.models import KubernetesServiceConnection, Outpost, OutpostType from authentik.outposts.tasks import outpost_connection_discovery @@ -91,6 +92,35 @@ class OutpostKubernetesTests(TestCase): deployment_reconciler.delete(deployment_reconciler.get_reference_object()) + @pytest.mark.timeout(120) + def test_service_reconciler(self): + """test that service requires update""" + controller = ProxyKubernetesController(self.outpost, self.service_connection) + service_reconciler = ServiceReconciler(controller) + + self.assertIsNotNone(service_reconciler.retrieve()) + + config = self.outpost.config + config.kubernetes_service_type = "NodePort" + config.kubernetes_json_patches = { + "service": [ + { + "op": "add", + "path": "/spec/ipFamilyPolicy", + "value": "PreferDualStack", + } + ] + } + self.outpost.config = config + + with self.assertRaises(NeedsUpdate): + service_reconciler.reconcile( + service_reconciler.retrieve(), + service_reconciler.get_reference_object(), + ) + + service_reconciler.delete(service_reconciler.get_reference_object()) + @pytest.mark.timeout(120) def test_controller_rename(self): """test that objects get deleted and re-created with new names""" diff --git a/website/docs/outposts/_config.md b/website/docs/outposts/_config.md index ce013b6254..97b3dd52fa 100644 --- a/website/docs/outposts/_config.md +++ b/website/docs/outposts/_config.md @@ -43,7 +43,7 @@ kubernetes_replicas: 1 kubernetes_namespace: authentik # Any additional annotations to add to the ingress object, for example cert-manager kubernetes_ingress_annotations: {} -# Name of the secret that is used for TLS connections +# Name of the secret that is used for TLS connections, leave empty to disable TLS kubernetes_ingress_secret_name: authentik-outpost-tls # Service kind created, can be set to LoadBalancer for LDAP outposts for example kubernetes_service_type: ClusterIP diff --git a/website/docs/outposts/integrations/kubernetes.md b/website/docs/outposts/integrations/kubernetes.md index f50d48a505..14016bdb3b 100644 --- a/website/docs/outposts/integrations/kubernetes.md +++ b/website/docs/outposts/integrations/kubernetes.md @@ -22,7 +22,7 @@ The following outpost settings are used: - `kubernetes_replicas`: Replica count for the deployment of the outpost - `kubernetes_namespace`: Namespace to deploy in, defaults to the same namespace authentik is deployed in (if available) - `kubernetes_ingress_annotations`: Any additional annotations to add to the ingress object, for example cert-manager -- `kubernetes_ingress_secret_name`: Name of the secret that is used for TLS connections +- `kubernetes_ingress_secret_name`: Name of the secret that is used for TLS connections, can be empty to disable TLS config - `kubernetes_ingress_class_name`: Optionally set the ingress class used for the generated ingress, requires authentik 2022.11.0 - `kubernetes_service_type`: Service kind created, can be set to LoadBalancer for LDAP outposts for example - `kubernetes_disabled_components`: Disable any components of the kubernetes integration, can be any of