diff --git a/SECURITY.md b/SECURITY.md index b88f63f36..baa74fc1c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,9 +6,9 @@ As authentik is currently in a pre-stable, only the latest "stable" version is s | Version | Supported | | -------- | ------------------ | -| 0.10.x | :white_check_mark: | | 0.11.x | :white_check_mark: | | 0.12.x | :white_check_mark: | +| 0.13.x | :white_check_mark: | ## Reporting a Vulnerability diff --git a/authentik/api/tests.py b/authentik/api/tests.py index 855958e21..262186484 100644 --- a/authentik/api/tests.py +++ b/authentik/api/tests.py @@ -11,9 +11,6 @@ from authentik.core.models import Token, TokenIntents class TestAPIAuth(TestCase): """Test API Authentication""" - def setUp(self) -> None: - super().setUp() - def test_valid(self): """Test valid token""" token = Token.objects.create( diff --git a/authentik/outposts/migrations/0014_auto_20201213_1407.py b/authentik/outposts/migrations/0014_auto_20201213_1407.py index 0f95e1416..5edf64bd3 100644 --- a/authentik/outposts/migrations/0014_auto_20201213_1407.py +++ b/authentik/outposts/migrations/0014_auto_20201213_1407.py @@ -1,7 +1,7 @@ # Generated by Django 3.1.4 on 2020-12-13 14:07 from django.apps.registry import Apps -from django.db import migrations +from django.db import migrations, models from django.db.backends.base.schema import BaseDatabaseSchemaEditor @@ -26,4 +26,13 @@ class Migration(migrations.Migration): ("authentik_outposts", "0013_auto_20201203_2009"), ] - operations = [migrations.RunPython(update_config_prefix)] + operations = [ + migrations.RunPython(update_config_prefix), + migrations.AlterField( + model_name="dockerserviceconnection", + name="url", + field=models.TextField( + help_text="Can be in the format of 'unix://' when connecting to a local docker daemon, or 'https://:2376' when connecting to a remote system." + ), + ), + ] diff --git a/authentik/outposts/models.py b/authentik/outposts/models.py index e21280d83..43a55590f 100644 --- a/authentik/outposts/models.py +++ b/authentik/outposts/models.py @@ -140,7 +140,14 @@ class OutpostServiceConnection(models.Model): class DockerServiceConnection(OutpostServiceConnection): """Service Connection to a Docker endpoint""" - url = models.TextField() + url = models.TextField( + help_text=_( + ( + "Can be in the format of 'unix://' when connecting to a local docker daemon, " + "or 'https://:2376' when connecting to a remote system." + ) + ) + ) tls_verification = models.ForeignKey( CertificateKeyPair, null=True, diff --git a/tests/integration/test_outpost_docker.py b/tests/integration/test_outpost_docker.py new file mode 100644 index 000000000..aecd1d1f6 --- /dev/null +++ b/tests/integration/test_outpost_docker.py @@ -0,0 +1,92 @@ +"""outpost tests""" +from shutil import rmtree +from tempfile import mkdtemp +from time import sleep + +from django.test import TestCase +from docker import DockerClient, from_env +from docker.models.containers import Container +from docker.types.healthcheck import Healthcheck + +from authentik.crypto.models import CertificateKeyPair +from authentik.flows.models import Flow +from authentik.outposts.apps import AuthentikOutpostConfig +from authentik.outposts.controllers.docker import DockerController +from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostType +from authentik.providers.proxy.models import ProxyProvider + + +class OutpostDockerTests(TestCase): + """Test Docker Controllers""" + + def _start_container(self, ssl_folder: str) -> Container: + client: DockerClient = from_env() + container = client.containers.run( + image="docker.beryju.org/proxy/library/docker:dind", + detach=True, + network_mode="host", + remove=True, + privileged=True, + healthcheck=Healthcheck( + test=["CMD", "docker", "info"], + interval=5 * 100 * 1000000, + start_period=5 * 100 * 1000000, + ), + environment={"DOCKER_TLS_CERTDIR": "/ssl"}, + volumes={ + f"{ssl_folder}/": { + "bind": "/ssl", + } + }, + ) + while True: + container.reload() + status = container.attrs.get("State", {}).get("Health", {}).get("Status") + if status == "healthy": + return container + sleep(1) + + def setUp(self): + super().setUp() + self.ssl_folder = mkdtemp() + self.container = self._start_container(self.ssl_folder) + # Ensure that local connection have been created + AuthentikOutpostConfig.init_local_connection() + self.provider: ProxyProvider = ProxyProvider.objects.create( + name="test", + internal_host="http://localhost", + external_host="http://localhost", + authorization_flow=Flow.objects.first(), + ) + authentication_kp = CertificateKeyPair.objects.create( + name="docker-authentication", + certificate_data=open(f"{self.ssl_folder}/client/cert.pem").read(), + key_data=open(f"{self.ssl_folder}/client/key.pem").read(), + ) + verification_kp = CertificateKeyPair.objects.create( + name="docker-verification", + certificate_data=open(f"{self.ssl_folder}/client/ca.pem").read(), + ) + self.service_connection = DockerServiceConnection.objects.create( + url="https://localhost:2376", + tls_verification=verification_kp, + tls_authentication=authentication_kp, + ) + self.outpost: Outpost = Outpost.objects.create( + name="test", + type=OutpostType.PROXY, + service_connection=self.service_connection, + ) + self.outpost.providers.add(self.provider) + self.outpost.save() + + def tearDown(self) -> None: + super().tearDown() + self.container.kill() + rmtree(self.ssl_folder) + + def test_docker_controller(self): + """test that deployment requires update""" + controller = DockerController(self.outpost, self.service_connection) + controller.up() + controller.down()