digitalboard.core/roles/ess_pro_compose/templates/generate-secrets.py.j2
Tobias Wüst 32eca6b923 feat(ess-pro/compose): deploy Element Server Suite Pro via Compose
initial commit of the converted role from helm charts for qubernetis to compose ansible role
2026-06-04 10:52:05 +02:00

102 lines
2.9 KiB
Django/Jinja

#!/usr/bin/env python3
# {{ ansible_managed }}
"""
Generate the ess-generated secret bundle the way the Helm chart's
init-secrets job does. Idempotent: only writes files that don't exist.
Mirrors `matrix-tools generate-secrets` arguments from chart v{{ ess_chart_version }}.
"""
import os
import secrets
import sys
from pathlib import Path
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec, ed25519, rsa
SECRETS_DIR = Path("{{ ess_compose_secrets_dir }}")
SECRETS_DIR.mkdir(mode=0o700, parents=True, exist_ok=True)
def write_if_missing(name, content_bytes):
p = SECRETS_DIR / name
if p.exists():
return False
# Atomic-ish write
tmp = p.with_suffix(p.suffix + ".tmp")
tmp.write_bytes(content_bytes)
os.chmod(tmp, 0o600)
tmp.rename(p)
return True
def rand32():
# `matrix-tools rand32` produces 32 url-safe characters
return secrets.token_urlsafe(24)[:32].encode()
def hex32():
return secrets.token_hex(32).encode()
def rsa_der():
key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
return key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
def ecdsa_prime256v1():
key = ec.generate_private_key(ec.SECP256R1())
return key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
def synapse_signing_key():
# Synapse expects: ed25519 <keyid> <unpadded-base64-seed>
import base64
key = ed25519.Ed25519PrivateKey.generate()
seed = key.private_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PrivateFormat.Raw,
encryption_algorithm=serialization.NoEncryption(),
)
# 4-char keyid like Synapse generates
keyid = secrets.token_hex(2)
b64 = base64.b64encode(seed).rstrip(b"=").decode()
return f"ed25519 a_{keyid} {b64}\n".encode()
SPEC = {
"POSTGRES_ADMIN_PASSWORD": rand32,
"POSTGRES_SYNAPSE_PASSWORD": rand32,
"POSTGRES_MATRIX_AUTHENTICATION_SERVICE_PASSWORD": rand32,
"SYNAPSE_MACAROON": rand32,
"SYNAPSE_REGISTRATION_SHARED_SECRET": rand32,
"SYNAPSE_WORKERS_REPLICATION_SECRET": rand32,
"SYNAPSE_SIGNING_KEY": synapse_signing_key,
"MAS_SYNAPSE_SHARED_SECRET": rand32,
"MAS_MATRIX_TOOLS_OIDC_CLIENT_SECRET": rand32,
"MAS_ENCRYPTION_SECRET": hex32,
"MAS_RSA_PRIVATE_KEY": rsa_der,
"MAS_ECDSA_PRIME256V1_PRIVATE_KEY": ecdsa_prime256v1,
"ELEMENT_CALL_LIVEKIT_SECRET": rand32,
"ADMIN_USER_PASSWORD": rand32,
}
created = []
for name, fn in SPEC.items():
if write_if_missing(name, fn()):
created.append(name)
if created:
print("CREATED:", " ".join(created))
else:
print("NOCHANGE")
sys.exit(0)