sops-encrypt TURN password + Authentik client secret; homelab render-vps-configs

The IONOS netbird VPS held two credentials in plaintext that were the last
holdouts from the homelab's sops+age secrets pattern:
  - /root/turn-pass.txt  (coturn long-term-credential password)
  - PKCEAuthorizationFlow.ProviderConfig.ClientSecret inline in
    /opt/management.json (Authentik OIDC client secret)

This commit moves both into sops-encrypted YAML in the repo and adds a render
command that recreates the VPS config files from templates + decrypted secrets:

* secrets/turn-shared-secret.yaml      — encrypted `password: <coturn pwd>`
* secrets/netbird-authentik-oidc.yaml  — encrypted `client_secret: <...>`
  Both recipients = hubris + apps + republic-laptop (same 3 as hello.yaml).
* vps/turnserver.conf.tmpl + vps/management.json.tmpl — templates with
  {{TURN_PASSWORD}} + {{AUTHENTIK_CLIENT_SECRET}} placeholders.
* bin/homelab new subcommand `render-vps-configs`:
  - Decrypts both secrets locally (works on any recipient).
  - Substitutes placeholders into templates.
  - Diffs against current VPS state via ssh, prompts, applies atomically
    (write `.new` then mv), restarts coturn + netbird-mgmt.
  - --dry-run + -y flags. Hops through hubris when not running on hubris
    itself, since VPS sshd is locked to hubris's pubkey.
* inventory.yaml adds the VPS as `kind: external` (new kind; reserved for
  ssh-managed hosts that aren't homelab clients themselves — no age key,
  no /opt/homelab-context). hosts/netbird-vps.yaml regenerated.
* SHARED_SECRETS list includes both new secrets so re-keys on enrollment
  changes pick them up automatically.

After this lands + the 5-min sync propagates to hubris, run from hubris PVE
shell (or any client; hubris just skips the extra ssh hop):

  homelab render-vps-configs --dry-run    # see plan, no changes
  homelab render-vps-configs -y           # apply + restart services

Once verified working, the plaintext `/root/turn-pass.txt` should be deleted
on the VPS (the rendered /etc/turnserver.conf no longer needs it as a
reference).
This commit is contained in:
2026-05-21 22:21:06 +02:00
parent 21063015c7
commit 8ef17dba3d
9 changed files with 420 additions and 4 deletions

75
vps/management.json.tmpl Normal file
View File

@@ -0,0 +1,75 @@
{
"_comment": "Rendered from this template by `homelab render-vps-configs`. DO NOT edit /opt/management.json on the VPS directly; it is recreated from this template on each render. Secret placeholders are {{TURN_PASSWORD}} and {{AUTHENTIK_CLIENT_SECRET}}.",
"Stuns": [
{"Proto": "udp", "URI": "stun:stun.l.google.com:19302", "Username": "", "Password": null},
{"Proto": "udp", "URI": "stun:stun1.l.google.com:19302", "Username": "", "Password": null},
{"Proto": "udp", "URI": "stun:stun.cloudflare.com:3478", "Username": "", "Password": null}
],
"TURNConfig": {
"Turns": [
{"Proto": "tcp", "URI": "turn:netbird.hubris.network:3478?transport=tcp", "Username": "netbird", "Password": "{{TURN_PASSWORD}}"}
],
"CredentialsTTL": "12h",
"Secret": "not-used-when-time-based-false",
"TimeBasedCredentials": false
},
"Relay": {
"Addresses": ["rels://netbird.hubris.network:443"],
"CredentialsTTL": "24h",
"Secret": "f6vaBSTqv53Jl9Fr+zUkzJ6iIsKv0RoYt++hKRqq58Q"
},
"Signal": {
"Proto": "https",
"URI": "netbird.hubris.network:443",
"Username": "",
"Password": null
},
"ReverseProxy": {
"TrustedHTTPProxies": ["172.30.0.0/24"],
"TrustedHTTPProxiesCount": 0,
"TrustedPeers": ["0.0.0.0/0"]
},
"Datadir": "",
"DataStoreEncryptionKey": "U60qK19PEpe6LSocYs1OR+qeoE2rUq6tN+W20NAC+gs=",
"StoreConfig": {"Engine": "sqlite"},
"DisableDefaultPolicy": false,
"HttpConfig": {
"Address": "0.0.0.0:80",
"AuthIssuer": "https://auth.hubris.network/application/o/netbird/",
"AuthAudience": "netbird-dashboard",
"AuthUserIDClaim": "sub",
"AuthKeysLocation": "https://auth.hubris.network/application/o/netbird/jwks/",
"OIDCConfigEndpoint": "https://auth.hubris.network/application/o/netbird/.well-known/openid-configuration",
"IdpSignKeyRefreshEnabled": true,
"CertFile": "",
"CertKey": ""
},
"IdpManagerConfig": {
"ManagerType": "none"
},
"DeviceAuthorizationFlow": {
"Provider": "hosted",
"ProviderConfig": {
"ClientID": "netbird-dashboard",
"Audience": "netbird-dashboard",
"Domain": "auth.hubris.network",
"TokenEndpoint": "https://auth.hubris.network/application/o/token/",
"DeviceAuthEndpoint": "https://auth.hubris.network/application/o/device/",
"Scope": "openid profile email offline_access",
"UseIDToken": false
}
},
"PKCEAuthorizationFlow": {
"ProviderConfig": {
"ClientID": "netbird-dashboard",
"ClientSecret": "{{AUTHENTIK_CLIENT_SECRET}}",
"Audience": "netbird-dashboard",
"Domain": "auth.hubris.network",
"TokenEndpoint": "https://auth.hubris.network/application/o/token/",
"AuthorizationEndpoint": "https://auth.hubris.network/application/o/authorize/",
"Scope": "openid profile email offline_access",
"UseIDToken": false,
"RedirectURLs": ["http://localhost:53000/"]
}
}
}

23
vps/turnserver.conf.tmpl Normal file
View File

@@ -0,0 +1,23 @@
# coturn for netbird symmetric-NAT peers — rendered from this template by
# `homelab render-vps-configs`. DO NOT edit /etc/turnserver.conf on the VPS
# directly; that file is recreated from this template on each render.
listening-port=3478
listening-ip=0.0.0.0
relay-ip=82.165.190.79
external-ip=82.165.190.79
min-port=49152
max-port=49999
fingerprint
lt-cred-mech
realm=netbird.hubris.network
user=netbird:{{TURN_PASSWORD}}
no-stun
no-multicast-peers
no-cli
no-loopback-peers
no-tlsv1
no-tlsv1_1
no-udp