# qBittorrent DURABLE WebUI credential (WS-APPS). SOPS-encrypted (age), decrypted in-cluster by Flux. # # WHY THIS FILE EXISTS (defect, measured on prod 2026-09-13): # qBittorrent.conf on the config PVC carried NEITHER `WebUI\Username` NOR # `WebUI\Password_PBKDF2`. qBittorrent 5.x treats that as "no credential set" and generates a NEW # random `admin` password on EVERY process start, announcing it ONLY on stdout ("A temporary # password is provided for this session: ..."). Consequences, both real: (a) Sonarr's and Radarr's # saved download-client credentials stop working at the next qbittorrent pod restart, silently # breaking Completed Download Handling; (b) a human operator has no stable login at all and must # read the pod log after every restart. # # HOW IT IS APPLIED: catalog/qbittorrent.yaml's app container reads BOTH keys below as env # (QBT_WEBUI_USERNAME / QBT_WEBUI_PASSWORD) and its `lifecycle.postStart` hook — the same idiom as # gitea's break-glass admin bootstrap — DERIVES the PBKDF2-HMAC-SHA512 digest qBittorrent stores # and asserts both keys into /config/qBittorrent/qBittorrent.conf on EVERY container start, then # verifies the WebUI actually accepts them. Level-triggered: a pod restart, a config-PVC restore # from an older backup, and a rebuild-from-git onto an EMPTY PVC all end with this SAME # credential, because the hook re-asserts it on every start rather than once. # # webui-username: the WebUI account name. qBittorrent has exactly ONE local account, and `admin` is # the name its own temporary-password path uses, so keeping it avoids inventing a second identity. # webui-password: the durable plaintext. It is ALSO what Sonarr's and Radarr's download-client # entries store in their own databases (app state on their config PVCs, NOT in git — see # DECISIONS-LOG), so rotating it here means re-pointing both arrs. # Deliberately alphanumeric: it travels through a urlencoded WebAPI login body and two arr JSON # payloads, and a shell/URL-special character in any of those is a bug waiting to happen. # # NEVER put a value in a comment: SOPS does NOT encrypt comments. # Recover with: infra/devcontainer/dev.sh run sops -d apps/wave-0/qbittorrent-bootstrap-secret.sops.yaml apiVersion: v1 kind: Secret metadata: name: qbittorrent-bootstrap namespace: qbittorrent labels: app.kubernetes.io/name: qbittorrent type: Opaque stringData: webui-username: ENC[AES256_GCM,data:P022nG0=,iv:MXcCXsD5hs7MAJ+OAYHkZ3pXep7XGPqeAExChoqna08=,tag:WE34mxtfQRgiwPRaDA12pQ==,type:str] webui-password: ENC[AES256_GCM,data:+Lx0Ny7SBZeF/CzQYm8umntw27ewyXS7unWObpl0fCg=,iv:JkAtublBMS7SJUutAFip1XjdmsKnGe+S2E9QDT4rCJk=,tag:MYptPVgoEUEpXe5kmg1xIg==,type:str] sops: kms: [] gcp_kms: [] azure_kv: [] hc_vault: [] age: - recipient: age175l8mdpdfu7hq0aml3exs3gykarwjmuvr23sq56s3wjejnyk44wsp4mfzg enc: | -----BEGIN AGE ENCRYPTED FILE----- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1aWpUY04wZHoyWVdPbGU2 TC9vaU5oYmhWSVh3YWVTdzkvU3Axdlh6QVFZCkV4MldaZXNyam5CejQyZStyczJ3 UStFd0hRQmRsNGZLVEVTRnVjWXp6SVkKLS0tICtkWlRqVGN5OWYvVnZUaHYvbEZv VWtHMVdDU3hmdXo1TndLb05zQzJ0S28KfqlDBTocO0ZAKtH6ad/00EeVRqZ7WMwv FP2evd5vyn95QQICWhY/LH6EKbwVVlcIlL7i9l8K3kK4Ebdk54mAyw== -----END AGE ENCRYPTED FILE----- lastmodified: "2026-09-13T05:23:23Z" mac: ENC[AES256_GCM,data:hQ7jIgFqpNcFY5H4AfMxuslC2R/2wGmGWtghemOmTUUipSdoGdbNjWGQhxzk40lFjw6Zj2b+buOpXpg70s4xr+4feusqa2TJ3+bxAuRWmuZpTQAU2OaO5v0SdDEs3gwKm2mA3JFo/e6POm/P/kf2GIECcyU1AciZQt6ws7UJmQc=,iv:6SF0ZAuzHQThD/FGbWhFfa4dXU8hyW8jWFiDmwgfFU8=,tag:31i8HM2s/mGeS4zvFxO53Q==,type:str] pgp: [] encrypted_regex: ^(data|stringData)$ version: 3.9.4