From ad9f500ad15dd036ecfa787c261c3f42e56eac4d Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 27 Oct 2023 16:29:10 +0200 Subject: [PATCH] crypto: fix race conditions when creating self-signed certificates on startup (#7344) Signed-off-by: Jens Langhammer --- authentik/crypto/apps.py | 45 +++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/authentik/crypto/apps.py b/authentik/crypto/apps.py index 559ca3db5..bed1ab811 100644 --- a/authentik/crypto/apps.py +++ b/authentik/crypto/apps.py @@ -1,13 +1,10 @@ """authentik crypto app config""" from datetime import datetime -from typing import TYPE_CHECKING, Optional +from typing import Optional from authentik.blueprints.apps import ManagedAppConfig from authentik.lib.generators import generate_id -if TYPE_CHECKING: - from authentik.crypto.models import CertificateKeyPair - MANAGED_KEY = "goauthentik.io/crypto/jwt-managed" @@ -23,33 +20,37 @@ class AuthentikCryptoConfig(ManagedAppConfig): """Load crypto tasks""" self.import_module("authentik.crypto.tasks") - def _create_update_cert(self, cert: Optional["CertificateKeyPair"] = None): + def _create_update_cert(self): from authentik.crypto.builder import CertificateBuilder from authentik.crypto.models import CertificateKeyPair - builder = CertificateBuilder("authentik Internal JWT Certificate") + common_name = "authentik Internal JWT Certificate" + builder = CertificateBuilder(common_name) builder.build( subject_alt_names=["goauthentik.io"], validity_days=360, ) - if not cert: - cert = CertificateKeyPair() - builder.cert = cert - builder.cert.managed = MANAGED_KEY - builder.save() + CertificateKeyPair.objects.update_or_create( + managed=MANAGED_KEY, + defaults={ + "name": common_name, + "certificate_data": builder.certificate, + "key_data": builder.private_key, + }, + ) def reconcile_managed_jwt_cert(self): """Ensure managed JWT certificate""" from authentik.crypto.models import CertificateKeyPair - certs = CertificateKeyPair.objects.filter(managed=MANAGED_KEY) - if not certs.exists(): - self._create_update_cert() - return - cert: CertificateKeyPair = certs.first() + cert: Optional[CertificateKeyPair] = CertificateKeyPair.objects.filter( + managed=MANAGED_KEY + ).first() now = datetime.now() - if now < cert.certificate.not_valid_before or now > cert.certificate.not_valid_after: - self._create_update_cert(cert) + if not cert or ( + now < cert.certificate.not_valid_before or now > cert.certificate.not_valid_after + ): + self._create_update_cert() def reconcile_self_signed(self): """Create self-signed keypair""" @@ -61,4 +62,10 @@ class AuthentikCryptoConfig(ManagedAppConfig): return builder = CertificateBuilder(name) builder.build(subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"]) - builder.save() + CertificateKeyPair.objects.get_or_create( + name=name, + defaults={ + "certificate_data": builder.certificate, + "key_data": builder.private_key, + }, + )