crypto: fix race conditions when creating self-signed certificates on startup (#7344)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-10-27 16:29:10 +02:00 committed by GitHub
parent 15d7175750
commit ad9f500ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 26 additions and 19 deletions

View File

@ -1,13 +1,10 @@
"""authentik crypto app config""" """authentik crypto app config"""
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING, Optional from typing import Optional
from authentik.blueprints.apps import ManagedAppConfig from authentik.blueprints.apps import ManagedAppConfig
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
if TYPE_CHECKING:
from authentik.crypto.models import CertificateKeyPair
MANAGED_KEY = "goauthentik.io/crypto/jwt-managed" MANAGED_KEY = "goauthentik.io/crypto/jwt-managed"
@ -23,33 +20,37 @@ class AuthentikCryptoConfig(ManagedAppConfig):
"""Load crypto tasks""" """Load crypto tasks"""
self.import_module("authentik.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.builder import CertificateBuilder
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
builder = CertificateBuilder("authentik Internal JWT Certificate") common_name = "authentik Internal JWT Certificate"
builder = CertificateBuilder(common_name)
builder.build( builder.build(
subject_alt_names=["goauthentik.io"], subject_alt_names=["goauthentik.io"],
validity_days=360, validity_days=360,
) )
if not cert: CertificateKeyPair.objects.update_or_create(
cert = CertificateKeyPair() managed=MANAGED_KEY,
builder.cert = cert defaults={
builder.cert.managed = MANAGED_KEY "name": common_name,
builder.save() "certificate_data": builder.certificate,
"key_data": builder.private_key,
},
)
def reconcile_managed_jwt_cert(self): def reconcile_managed_jwt_cert(self):
"""Ensure managed JWT certificate""" """Ensure managed JWT certificate"""
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
certs = CertificateKeyPair.objects.filter(managed=MANAGED_KEY) cert: Optional[CertificateKeyPair] = CertificateKeyPair.objects.filter(
if not certs.exists(): managed=MANAGED_KEY
self._create_update_cert() ).first()
return
cert: CertificateKeyPair = certs.first()
now = datetime.now() now = datetime.now()
if now < cert.certificate.not_valid_before or now > cert.certificate.not_valid_after: if not cert or (
self._create_update_cert(cert) now < cert.certificate.not_valid_before or now > cert.certificate.not_valid_after
):
self._create_update_cert()
def reconcile_self_signed(self): def reconcile_self_signed(self):
"""Create self-signed keypair""" """Create self-signed keypair"""
@ -61,4 +62,10 @@ class AuthentikCryptoConfig(ManagedAppConfig):
return return
builder = CertificateBuilder(name) builder = CertificateBuilder(name)
builder.build(subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"]) 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,
},
)