mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
82 lines
3.1 KiB
Python
82 lines
3.1 KiB
Python
"""Install root certificates into the system's CA store.
|
|
|
|
Certificates from the configuration are dropped into the "local" CA
|
|
directory, then the real `update-ca-certificates` binary is invoked to
|
|
rebuild the trust store (bundle + hashed symlinks) exactly like it would on
|
|
a real Debian/Ubuntu system, instead of reimplementing that logic here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
import logging
|
|
import subprocess
|
|
|
|
from id_configurator.context import Context
|
|
from id_configurator.modules.base import Module, register
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_LOCAL_CERTS_DIR = "usr/local/share/ca-certificates"
|
|
_CERTSCONF = "etc/ca-certificates.conf"
|
|
_CERTSDIR = "usr/share/ca-certificates"
|
|
_ETCCERTSDIR = "etc/ssl/certs"
|
|
|
|
|
|
@register
|
|
class CertificatesModule(Module):
|
|
name = "certificates"
|
|
|
|
def is_relevant(self, context: Context) -> bool:
|
|
return bool(context.config.configurations.certificates)
|
|
|
|
def apply(self, context: Context) -> None:
|
|
configured_names = {
|
|
certificate.name
|
|
for certificate in context.config.configurations.certificates
|
|
}
|
|
for existing in context.iter_src_dir(_LOCAL_CERTS_DIR):
|
|
if existing.stem not in configured_names:
|
|
context.write_file(
|
|
f"{_LOCAL_CERTS_DIR}/{existing.name}", existing.read_bytes()
|
|
)
|
|
for certificate in context.config.configurations.certificates:
|
|
content = base64.b64decode(certificate.content)
|
|
context.write_file(f"{_LOCAL_CERTS_DIR}/{certificate.name}.crt", content)
|
|
logger.info("installed root certificate %s", certificate.name)
|
|
self._update_ca_certificates_conf(context)
|
|
|
|
@staticmethod
|
|
def _update_ca_certificates_conf(context: Context) -> None:
|
|
etccertsdir = context.dst_path(_ETCCERTSDIR)
|
|
localcertsdir = context.dst_path(_LOCAL_CERTS_DIR)
|
|
etccertsdir.mkdir(parents=True, exist_ok=True)
|
|
localcertsdir.mkdir(parents=True, exist_ok=True)
|
|
|
|
args = [
|
|
"update-ca-certificates",
|
|
"--etccertsdir",
|
|
str(etccertsdir),
|
|
"--localcertsdir",
|
|
str(localcertsdir),
|
|
]
|
|
certsconf = context.src_path(_CERTSCONF)
|
|
if certsconf is not None and certsconf.is_file():
|
|
args += ["--certsconf", str(certsconf)]
|
|
certsdir = context.src_path(_CERTSDIR)
|
|
if certsdir is not None and certsdir.is_dir():
|
|
args += ["--certsdir", str(certsdir)]
|
|
|
|
logger.debug("running: %s", " ".join(args))
|
|
try:
|
|
result = subprocess.run(args, check=True, capture_output=True, text=True)
|
|
except FileNotFoundError as exc:
|
|
raise RuntimeError(
|
|
"update-ca-certificates is not available; the ca-certificates package must be installed "
|
|
"in the environment running id-configurator"
|
|
) from exc
|
|
except subprocess.CalledProcessError as exc:
|
|
raise RuntimeError(f"update-ca-certificates failed:\n{exc.stderr}") from exc
|
|
if result.stderr:
|
|
logger.debug("%s", result.stderr.strip())
|