certauth/api/config.py
Jarian Cottingham 4bd538b217 fix: YubiKey CA signing, remove inline API copies, env-driven config
Critical: build_leaf_cert self-signed leaves with the leaf key instead of
the YubiKey-held Intermediate CA key. Now extracts TBS, signs via
pkcs11-tool (ECDSA-SHA384), reassembles, and verifies against the
intermediate CA public key before returning.

- setup-certauth.sh: ~1100 lines of stale inline api/ copies replaced with
  copy-from-repo (single source of truth); writes private
  /etc/certauth/certauth.env (0600); DB init loads env, no more
  swallowed errors; systemd unit gets EnvironmentFile=
- config.py: YubiKey serials no longer hard-coded (env, fail closed);
  aarch64-only PKCS#11 path replaced with arch-neutral default; all
  paths env-overridable (CERTAUTH_*)
- main.py: removed dead fastapi.security.CSRFProtection import (crashed
  startup); module-relative static/templates dirs; created_by resolved
  from the authenticated user instead of hard-coded 1; unclosed file
  handles fixed; domain_id 0 stored as NULL (FK bug)
- models.py: certificates.domain_id FK pointed at users(id), now domains(id)
- login: CSRF token now actually sent and validated
- tests: 23 tests (auth, API flows, DER helpers, signing pipeline)
- README, LICENSE, requirements.txt, pyproject.toml
2026-08-20 22:03:01 +00:00

62 lines
2.5 KiB
Python

"""CertAuth configuration.
All hardware identifiers and filesystem paths are environment-driven so the
service can run on aarch64/x86_64 and in test environments. Secrets and
YubiKey assignments fail closed at import time.
"""
import os
def _required(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} environment variable is required")
return value
# YubiKey hardware: serials must be supplied by the operator (auto-detected at
# setup time by setup-certauth.sh). Never hard-code device serials in source.
YK_ROOT_SERIAL = _required("YK_ROOT_SERIAL")
YK_INT_SERIAL = _required("YK_INT_SERIAL")
YK_ROOT_PIN = _required("YK_ROOT_PIN")
YK_INT_PIN = _required("YK_INT_PIN")
# Filesystem layout (defaults match the production layout created by
# setup-certauth.sh; override via environment for testing or custom installs).
CA_BASE = os.environ.get("CERTAUTH_CA_BASE", "/etc/ssl/ca")
ROOT_CA_PATH = os.environ.get("CERTAUTH_ROOT_CA", f"{CA_BASE}/root/root-ca.crt")
INT_CA_PATH = os.environ.get("CERTAUTH_INT_CA", f"{CA_BASE}/intermediate/intermediate-ca.crt")
CA_CHAIN_PATH = os.environ.get("CERTAUTH_CA_CHAIN", f"{CA_BASE}/ca-chain.crt")
ISSUED_DIR = os.environ.get("CERTAUTH_ISSUED_DIR", f"{CA_BASE}/issued")
TMP_DIR = os.environ.get("CERTAUTH_TMP_DIR", "/var/lib/certauth/tmp")
DB_PATH = os.environ.get("CERTAUTH_DB_PATH", "/var/lib/certauth/certauth.db")
# Extracted YubiKey public keys (written by setup-certauth.sh).
YK_PUB_ROOT = os.environ.get("YK_PUB_ROOT", "/tmp/yk1-root-pub.pem")
YK_PUB_INT = os.environ.get("YK_PUB_INT", "/tmp/yk2-int-pub.pem")
# PKCS#11 module for pkcs11-tool. Default works on both aarch64 and x86_64
# Ubuntu; override for nonstandard installs.
PKCS11_MODULE = os.environ.get("PKCS11_MODULE", "/usr/lib/opensc-pkcs11.so")
# Optional pkcs11-tool --token-label. Empty = match the setup-script
# invocation (key label only), which works with both YubiKeys attached.
PKCS11_TOKEN_LABEL = os.environ.get("PKCS11_TOKEN_LABEL", "")
# Leaf certificate subject defaults (match setup-certauth.sh defaults)
CA_ORG = os.environ.get("CA_ORG", "Home")
CA_COUNTRY = os.environ.get("CA_COUNTRY", "US")
# JWT / web session
JWT_SECRET = _required("JWT_SECRET")
SECRET_KEY = JWT_SECRET
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60
# Admin bootstrap account
ADMIN_USERNAME = os.environ.get("ADMIN_USERNAME", "certauth")
ADMIN_PASSWORD = _required("ADMIN_PASSWORD")
# PFX download default password (overridable per download)
PFX_DEFAULT_PASSWORD = os.environ.get("PFX_PASS", "certauth")