mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
SSL_CERT_FILE, CURL_CA_BUNDLE and REQUESTS_CA_BUNDLE replace the trust store;
only NODE_EXTRA_CA_CERTS extends it. compose_ca.py pointed all four at the
deployment own root CA, so every OpenSSL and rustls client in every container
was blind to every public certificate. Measured here, one variable, same URL:
unset curl https://registry.npmjs.org/ -> 200
a single unrelated CA -> 000 unable to get local issuer certificate
that CA + the system bundle -> 200
PeerTube was the one process that hit it: its plugin install fetches from
registry.npmjs.org at runtime through a client that honours SSL_CERT_FILE, and
it failed identically in compose and in swarm with
invalid peer certificate: UnknownIssuer
Everything else reaches its artefacts at image build time, or through Node,
whose NODE_EXTRA_CA_CERTS is additive and therefore kept working.
The replacement was never a posture. e7e8cf8c03 calls these variables an
"env-based CA trust fallback", f1ea036bd2 adds them "instead of falling back to
a plain docker run without CA trust", e79183f96a wires the extra CA in "so npm
traffic through the cache validates". Every commit framed them as adding trust.
sys-ca-selfsigned now builds ca-bundle.crt beside the root CA on every node,
from that node own files: the stack host mints the CA and workers fetch it, so
there is no cross-node dependency. The bundle is the root CA concatenated with
the first present CA_BUNDLE_CANDIDATES entry, the SPOT fc0881ff33 introduced.
The cat argument list is assembled in Jinja, so a host with no public bundle
emits the root CA alone, which is exactly the previous behaviour, rather than an
empty argument that would fail. bundle_host joins the existing stray-directory
sweep and the build runs after it.
compose_ca.py uses the bundle only when the file exists and is non-empty, so a
host that has not built one keeps the previous behaviour instead of binding a
missing path that Docker would materialise as a directory. The php ini, msmtprc
and the Matrix flavour may name the container path with no fallback because the
bundle is written at task 99 and the php ini at task 123: no host can carry the
ini without the bundle.
CA_TRUST_CERT and NODE_EXTRA_CA_CERTS stay on the single certificate. keytool,
occ security:certificates:import and update-ca-certificates each take one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
48 lines
2.8 KiB
YAML
48 lines
2.8 KiB
YAML
---
|
|
TLS_ENABLED: true # nocheck: unused-var # consumed by plugins/lookup/{tls,email,cert}.py
|
|
TLS_MODE: "letsencrypt" # Valid values letsencrypt, self_signed, off
|
|
TLS_SELFSIGNED_BASE_PATH: "/etc/{{ SOFTWARE_DOMAIN }}/selfsigned"
|
|
TLS_SELFSIGNED_SCOPE: "global" # nocheck: unused-var # consumed by the self-signed cert generator outside the YAML/Jinja scope
|
|
CERTBOT_ACME_CHALLENGE_METHOD: "cloudflare" # webroot, cloudflare, or hetzner
|
|
CERTBOT_CREDENTIALS_DIR: /etc/certbot
|
|
CERTBOT_CREDENTIALS_FILE: "{{ CERTBOT_CREDENTIALS_DIR }}/{{ CERTBOT_ACME_CHALLENGE_METHOD }}.ini"
|
|
CERTBOT_DNS_PROPAGATION_WAIT_SECONDS: 300 # How long should the script wait for DNS propagation before continuing
|
|
CERTBOT_FLAVOR: san # Possible options: san (recommended, with a dns flavor like cloudflare, or hetzner), wildcard(doesn't function with www redirect), dedicated
|
|
LETSENCRYPT_WEBROOT_PATH: "/var/lib/letsencrypt/" # Path where Certbot stores challenge webroot files
|
|
LETSENCRYPT_BASE_PATH: "/etc/letsencrypt/" # Base directory containing Certbot configuration, account data, and archives
|
|
LETSENCRYPT_LIVE_PATH: "{{ LETSENCRYPT_BASE_PATH }}live/" # Symlink directory for the current active certificate and private key
|
|
CA_ROOT:
|
|
base_dir: "/etc/{{ SOFTWARE_DOMAIN }}/ca"
|
|
cert_host: "{{ SOFTWARE_DOMAIN | ca_cert_host }}"
|
|
key_host: "/etc/{{ SOFTWARE_DOMAIN }}/ca/root-ca.key"
|
|
openssl_conf_host: "/etc/{{ SOFTWARE_DOMAIN }}/ca/openssl-root-ca.cnf"
|
|
days: 3650
|
|
key_bits: 4096
|
|
force_regen: false # When true, delete key+cert and regenerate
|
|
subject:
|
|
C: "DE"
|
|
O: "{{ DOMAIN_PRIMARY }}"
|
|
OU: "Infinito.Nexus Root CA"
|
|
CN: "{{ (DOMAIN_PRIMARY ~ ' Root CA') if ((DOMAIN_PRIMARY ~ ' Root CA') | length <= 64) else DOMAIN_PRIMARY }}"
|
|
CA_TRUST:
|
|
cert_host: "{{ CA_ROOT.cert_host }}"
|
|
bundle_host: "{{ [CA_ROOT.base_dir, 'ca-bundle.crt'] | path_join }}"
|
|
inject_bundle_container: "/tmp/infinito/ca/ca-bundle.crt"
|
|
cert_container: "/etc/ssl/certs/infinito-ca.pem"
|
|
trust_name: "{{ DOMAIN_PRIMARY | lower }}"
|
|
wrapper_host: "{{ BIN_CA_TRUST }}"
|
|
inject_script: "{{ BIN_CA_INJECT }}"
|
|
inject_cert_container: "/tmp/infinito/ca/root-ca.crt"
|
|
inject_wrapper_container: "/tmp/infinito/bin/with-ca-trust.sh"
|
|
php_ini_host: "{{ BIN_CA_PHP_INI }}"
|
|
inject_php_ini_container: "/usr/local/etc/php/conf.d/zz-infinito-ca-trust.ini"
|
|
CA_TRUST_SYSTEMD_ENV:
|
|
- "CA_TRUST_CERT_HOST={{ CA_TRUST.cert_host }}"
|
|
- "CA_TRUST_WRAPPER_HOST={{ CA_TRUST.wrapper_host }}"
|
|
- "CA_TRUST_NAME={{ CA_TRUST.trust_name }}"
|
|
- "CA_TRUST_CERT_CONTAINER={{ CA_TRUST.inject_cert_container }}"
|
|
- "CA_TRUST_WRAPPER_CONTAINER={{ CA_TRUST.inject_wrapper_container }}"
|
|
CA_TRUST_SYSTEMD_ENV_SELFSIGNED: >-
|
|
{{ CA_TRUST_SYSTEMD_ENV if (TLS_MODE | lower) == 'self_signed' else [] }}
|
|
CA_CONTAINER_ENABLED: true # When falsy the container wrapper skips CA injection on `container run`
|