feat(iam): wire all 9 consumer manifests to Zitadel OIDC

This commit is contained in:
2026-10-26 00:14:51 -07:00
parent a02bee50e2
commit e6ba83cd38
16 changed files with 7 additions and 268 deletions
-78
View File
@@ -1,78 +0,0 @@
# Homarr landing page with Authentik SSO
# Probe tuning (chart DOES expose these — the old PostSync patch-job was
# unnecessary and fragile: it only patched one Deployment revision, so any later
# rollout reverted to the chart's aggressive defaults). Homarr's first-boot icon
# updater blocks the event loop for ~50s ("icons updater took 49553ms"), during
# which /api/health/live can't answer within the default 10s×3 window → kubelet
# SIGTERMs the pod → CrashLoopBackOff (247 restarts, 503 at the ingress). Give
# liveness a wide window so the icon import can finish without a kill.
livenessProbe:
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 10
readinessProbe:
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 6
image:
repository: ghcr.io/homarr-labs/homarr
tag: "latest"
pullPolicy: Always
replicaCount: 1
# Configure SSO via environment variables
# Chart supports these via top-level env dict (not array)
env:
AUTH_PROVIDERS: "oidc,credentials"
AUTH_OIDC_ISSUER: "https://zitadel.riotpiao.com"
# AUTH_OIDC_URI (authorize endpoint) is REQUIRED in addition to ISSUER — homarr
# hides the "Sign in with Authentik" button entirely when it's absent (per the
# authentik Homarr integration + homarr SSO docs). This was the missing var.
AUTH_OIDC_URI: "https://zitadel.riotpiao.com/oauth/v2/authorize"
AUTH_OIDC_CLIENT_NAME: "Zitadel"
AUTH_OIDC_GROUPS_ATTRIBUTE: "groups"
AUTH_OIDC_SCOPE_OVERWRITE: "openid email profile groups"
AUTH_OIDC_AUTO_LOGIN: "false"
# Link the OIDC identity to an existing homarr account with the same email.
OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING: "true"
# The analytics cron blocked the (single-threaded) Next.js event loop for ~16s
# per run ("callback took longer than expected"), compounding CPU pressure.
DISABLE_ANALYTICS: "true"
BASE_URL: "https://homarr.riotpiao.com"
NEXTAUTH_URL: "https://homarr.riotpiao.com"
# Client credentials from homarr-oidc secret
# Chart doesn't support envFrom, so we add via extraEnv
extraEnv:
- name: AUTH_OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: homarr-oidc
key: client-id
- name: AUTH_OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: homarr-oidc
key: client-secret
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
resources:
requests:
cpu: 250m
memory: 384Mi
limits:
# Next.js 16 + bundled redis + the icon-updater (28k icons) saturated the old
# 500m limit; CPU throttling made Next.js abort with exit 134 (SIGABRT) and
# self-restart in a loop, so nginx saw no upstream and returned 502. Give it
# real CPU headroom.
cpu: "2"
memory: 1Gi
-7
View File
@@ -1,7 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: dashboard
# Probes are now tuned via homarr-values.yaml (chart-native); the old
# fix-probes-job PostSync hook is removed. homarr-secrets/auth-oidc/db-encryption
# Secrets are delivered by the sops-secrets (ksops) Application.
resources: []
-34
View File
@@ -171,40 +171,6 @@ spec:
syncOptions: syncOptions:
- CreateNamespace=true - CreateNamespace=true
--- ---
# Consolidated: homarr + homarr-patches → homarr
# Helm chart + values + PostSync hook patch (fix-probes-job.yaml)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: homarr
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "8"
spec:
project: homelab
sources:
- repoURL: https://homarr-labs.github.io/charts
chart: homarr
targetRevision: "*"
helm:
valueFiles:
- $values/k8s/apps/homarr/homarr-values.yaml
- repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
targetRevision: main
ref: values
- repoURL: https://forgejo.riotpiao.com/riotpiao-poimen/homelab.git
targetRevision: main
path: k8s/apps/homarr # PostSync hook: fix-probes-job.yaml
destination:
server: https://kubernetes.default.svc
namespace: dashboard
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
# Portfolio site at riotpiao.com - static Next.js site from rock/riotpiao.com repo. # Portfolio site at riotpiao.com - static Next.js site from rock/riotpiao.com repo.
# Points directly to infra/portfolio/base (bypassing repo's own argocd-apps.yaml # Points directly to infra/portfolio/base (bypassing repo's own argocd-apps.yaml
# which has wrong URLs). Image built by Forgejo Actions on rock/portfolio repo. # which has wrong URLs). Image built by Forgejo Actions on rock/portfolio repo.
-1
View File
@@ -38,7 +38,6 @@ spec:
- https://charts.zitadel.com - https://charts.zitadel.com
- https://strimzi.io/charts/ - https://strimzi.io/charts/
- https://charts.bitnami.com/bitnami - https://charts.bitnami.com/bitnami
- https://homarr-labs.github.io/charts
- https://go.temporal.io/helm-charts - https://go.temporal.io/helm-charts
- https://portainer.github.io/k8s/ - https://portainer.github.io/k8s/
# Substrate charts (cert-manager, ingress-nginx, reloader) — app-of-apps owned # Substrate charts (cert-manager, ingress-nginx, reloader) — app-of-apps owned
@@ -1,24 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: homarr-oidc
namespace: dashboard
type: Opaque
stringData:
client-id: ENC[AES256_GCM,data:IFNjfDMrObaxfGwJpiYqPP60,iv:0WR2C+DEsq8I031A9Bopotn5TYdISApbTF46jJBgtVs=,tag:LGijMS27pbbZnOLJqGNXQg==,type:str]
client-secret: ENC[AES256_GCM,data:q0MHjvuTIKbbMUZpsptOuo3zrabwaWxZS3MLqRdI1Rt7eod5ORAYeZmpllHmojRFve9x/SKkJ+sctafzwPuAPA==,iv:1ZLXOc3a85+MRx3v/XsW8JhsxbCQ26laou8PvvrQvH0=,tag:PRRTsyE2fGGS3dKPh43a8g==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpV1ZlMWxaNTlCUjJjbG9F
NzFGMXBXYThZT285UHA0bGdwNFJqQTNMckhvClFSTEdseExjbVFtbkdsTUpSSGVn
WGsyUmxvcVViVVVNZjFRdmJWZlB6TGcKLS0tIE01QjFtVFBGUlpXbjVJcDMwMzRS
MEh4dUZTZ3puaXF2Uk03Ym50QmdSM1EK6Kmdv3s8/4nI/6Uk4G5FOh1Gxp1u9eYI
L7MOW0TFkScTuDiu9iJB+CjB8b8Z0kwSYTigYj9ue2y0a1hDYCfQtg==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-10-26T03:56:19Z"
mac: ENC[AES256_GCM,data:tV7o9zY6dpTdTvNJY8GBkdIB71thoy79RQSHsczednmXXzlNFddZxR/UenJ87jJ1JyzMUKL3CxArYojpuamahQcSXifVar0kotgNCs67A7+xfhHudCnKLMWDfDOom6DdWto6bMNIk/0TF6Wy0m1hkSsxwkdqETVs3b6ZUg/l8Rc=,iv:PE7y5oVMEM9XKQnDZmdRFRR3blzz2SZQFLxOMyILuec=,tag:SM9vJU1zlQ02XJijSiGCMg==,type:str]
version: 3.13.2
@@ -1,23 +0,0 @@
apiVersion: ENC[AES256_GCM,data:FO4=,iv:kKIuJp4uGeX6vECsXk7w43F9S281jObQchmK8r1+kmA=,tag:x5LYd34dzNDLCma/78M4+w==,type:str]
kind: ENC[AES256_GCM,data:o4RTN8SK,iv:uyOJWjDmHIPuBl9Wc1S/HxUabV2yytWr1bntHW68sTI=,tag:3On0SnQVJ/ICMMryQe+8JQ==,type:str]
metadata:
name: ENC[AES256_GCM,data:a89dHmLdSeMHE7ZP0Q==,iv:OWJvJhFqJ7A0UGVJnZILzCJ/4VuVFib9sUDjXuwyqJQ=,tag:1XrIQn1GDh8RQ4vmQAu7+g==,type:str]
namespace: ENC[AES256_GCM,data:4wBVpZJgQGM9,iv:3Tn1u/2TP/+SnELu34PDf4Jauf2L4f8+MtgrPIlyKzk=,tag:L3qbKFBjm16g8KX5vUsK6A==,type:str]
type: ENC[AES256_GCM,data:mdrF9vUb,iv:7ukOgwXlnRf5mpJ/+6YXtyGRonnqehEgT4pJJIafw7c=,tag:90mt7jpNb3N80kCEi+R/rA==,type:str]
stringData:
db-encryption-key: ENC[AES256_GCM,data:NWJryAEd/eUJxbNiu05RzLF/l7GDxIQM7RQe3xKBz6XklgRAFwQxxjakcVd85pePUBaQYz3zttFglWhfJlWhkA==,iv:eUWbcs0B/mIheyAQ2+DyKgcA98CRKQGAVC3O0WIkfU8=,tag:be06X6AQqlohYlxuYoZiTg==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1Ym5yQ1pmWHZjVnYxbUVO
SkZ5dnI2OXR3cmZjZkM0K1ErMElLNktlK1JFCmpleFBrcXkwcDA4cGFuWWN6VDQv
dVV4NjB4MjEreENVQnZ2ejVLblRYOVUKLS0tIG9VbXJvUmQ3SzMzN3IrRDlac2sr
eGZNYXBoZFZDeisrVCtUMXVPaEpoNFkKjwhUU+Zsqv4Be+m558fET5UhF/2rO73J
AhGbJVaA7PaOCswPWiOLso26zD+MBB3VKHNdUFnenpoM16Nu4pOf5w==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
lastmodified: "2026-08-12T21:07:30Z"
mac: ENC[AES256_GCM,data:KrGQY/eOmihYCvQCbfcM6bZ6rfx4zKh62M8NM0VQr1//1dSHpOOh25dYGLuQeECnqLxSpGQNWzr2xjUYWs4NOdSEFGq6FL2iHE3LnqoBZspp/JFJYP6+z/8jSUojwKEW7OuZZdPN6gF2u+IPOeWbGftnjS7X+atoSkYag2ty2vk=,iv:IOPEgBizsxrVoK5oSdWmi0uCBUnReOEnMYXuwSBKTzA=,tag:9k/XQ/AE7wSFq5XMbY0FTA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.2
@@ -1,23 +0,0 @@
apiVersion: ENC[AES256_GCM,data:4OY=,iv:0Lgui0+X2oTlgCX5HEIIihEsGJD0C2+pDIOTCNi4r+g=,tag:uL7vlreaHjcLJjV7e5I7PQ==,type:str]
kind: ENC[AES256_GCM,data:x/ltkind,iv:KRBfS7COsTs/l3Fhyk5FvH7IVc+r/6M6FVOo+kPDe1Q=,tag:UuTbe213hDfK/WUtKS/doQ==,type:str]
metadata:
name: ENC[AES256_GCM,data:LpOEecTJBuGy5PqNSFM=,iv:Q+DCLGtw3wihhdAgEbzYHyQhFTPWFyE2iJKl9mYaA2E=,tag:E2wrig4lRXGDvSCHec5clQ==,type:str]
namespace: ENC[AES256_GCM,data:6kMVCXaF68NO,iv:gnCCkV7GKXA2HWOOeNUGnpAycf8U7pl6F8Vfo6DhLR4=,tag:0VdeySsuhUr2heXyGXZwBg==,type:str]
type: ENC[AES256_GCM,data:6muC3Zqh,iv:gBaC+6MXvZY/bIpy/cEG/zWwLBaUFMVfxAHa1OnwfnQ=,tag:v6NYyhAKAwovluHAXNaOVA==,type:str]
stringData:
SECRET_ENCRYPTION_KEY: ENC[AES256_GCM,data:jX9ULlaBYTSTFGRMplSder5rMrsz7THU3kgJSGef0r5rZvtoaAG9NVYU2QUEuD0sZgfqRooeMOkDCAqFc8qsuw==,iv:uOmx8w3XPKnoxfasf7gqi/bljxigpLwaAC30c2TroKg=,tag:Dmbu6m3+UZa1w0UR0LRh9g==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6TDVyNGRtYWgzMDYwdjdr
NXJWcGJZNUx6YzBGWm1nWlp0SlN3WXhaR0VBCjZ3bDBmUTFCUjg3U21wak90eHZK
NlRCTUZQSHhoS0ZSUGZ4UHhST01KNmMKLS0tIGUxcGo0NmJ2bmJ6eGJ3QWxzYVM5
c2Z6UkFjQmZ4ejIvK1JQQkZ0VFFIZ3cKA8UzmGsX+s3yOermOHqbnnEtekHCTqmC
R3Jyzf6OolZMJpNwbetcsOfgO61aM7LHl/Xb/hFLbLjZ+eECrt8VpA==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
lastmodified: "2026-08-12T18:02:01Z"
mac: ENC[AES256_GCM,data:HTrEEVDm8JqnVBFaY/FJknxma0nI95tRiwVc0K76k+2R4jgKCBA3EUAzPVS+gA4rTAeKHPSHrT2eidlkseT2WQUjqMRrpHcUsbSjNfpTEY2g/U0PIiOXZMRGfwmsQVgmu2fqeMOyzDSyya0scdWJXPraRPNZ+OpEkNVlm4rWcgs=,iv:KY3dnnmooJgsu66wc7gbzeIGUXZNgVrxAhpAwxoG+G8=,tag:7r6d41oTD136N57rtY7auA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.2
-3
View File
@@ -18,9 +18,6 @@ files:
- forgejo-secrets.enc.yaml - forgejo-secrets.enc.yaml
- grafana-oidc-secrets.enc.yaml - grafana-oidc-secrets.enc.yaml
- grafana-secrets.enc.yaml - grafana-secrets.enc.yaml
- homarr-auth-oidc.enc.yaml
- homarr-db-encryption.enc.yaml
- homarr-secrets.enc.yaml
- homelab-ca-secrets.enc.yaml - homelab-ca-secrets.enc.yaml
- loki-secrets.enc.yaml - loki-secrets.enc.yaml
- minio-secrets.enc.yaml - minio-secrets.enc.yaml
-25
View File
@@ -275,28 +275,3 @@ spec:
name: temporal-web name: temporal-web
port: port:
number: 8080 number: 8080
---
# NOTE: api.riotpiao.com is deliberately NOT here. Its namespace `api` is
# created in wave 7, and this Application syncs in wave 1 — an Ingress into a
# namespace that doesn't exist yet would fail and mark this whole app
# SyncFailed. It lives in k8s/apps/api/ingress.yaml, synced by the api-gw
# Application.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homarr
namespace: dashboard
spec:
ingressClassName: nginx
rules:
- host: homarr.riotpiao.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: homarr
port:
number: 7575
@@ -143,7 +143,10 @@ configs:
oidc.config: | oidc.config: |
name: Zitadel name: Zitadel
issuer: https://zitadel.riotpiao.com issuer: https://zitadel.riotpiao.com
clientID: 396757801210282367 # MUST be quoted: an unquoted 18-digit number is parsed as a float by the
# YAML parser and ArgoCD rejects it ("cannot unmarshal number into ...
# clientID of type string"). Same class of bug as Grafana's client_id.
clientID: "396757801210282367"
clientSecret: $oidc-secret:client-secret clientSecret: $oidc-secret:client-secret
requestedScopes: requestedScopes:
- openid - openid
+1 -1
View File
@@ -74,7 +74,7 @@ grafana.ini:
enabled: true enabled: true
name: Zitadel name: Zitadel
allow_sign_up: true # Allow sync to create/update users from OAuth claims allow_sign_up: true # Allow sync to create/update users from OAuth claims
client_id: 396757801965191169 client_id: "396757801965191169"
scopes: openid email profile groups scopes: openid email profile groups
auth_url: https://zitadel.riotpiao.com/oauth/v2/authorize auth_url: https://zitadel.riotpiao.com/oauth/v2/authorize
token_url: https://zitadel.riotpiao.com/oauth/v2/token token_url: https://zitadel.riotpiao.com/oauth/v2/token
-32
View File
@@ -1,32 +0,0 @@
# Scoped operator access for homarr-admins: the homarr Deployment + app
# secrets only. homarr-oidc, auth-oidc-secret, db-encryption stay excluded
# (security-managed, not app config). Inert until kube-apiserver's OIDC
# wiring lands.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: homarr-operator
namespace: dashboard
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
resourceNames: ["homarr"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["homarr-secrets"]
verbs: ["get", "list", "watch", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: homarr-admins-binding
namespace: dashboard
subjects:
- kind: Group
name: "oidc:homarr-admins"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: homarr-operator
apiGroup: rbac.authorization.k8s.io
-1
View File
@@ -10,7 +10,6 @@ resources:
- grafana-operator-role.yaml - grafana-operator-role.yaml
- minio-operator-role.yaml - minio-operator-role.yaml
- forgejo-operator-role.yaml - forgejo-operator-role.yaml
- homarr-operator-role.yaml
- portainer-operator-role.yaml - portainer-operator-role.yaml
- kmsvc-operator-role.yaml - kmsvc-operator-role.yaml
- temporal-operator-role.yaml - temporal-operator-role.yaml
-5
View File
@@ -351,11 +351,6 @@ OAuth2_PROVIDERS = {
"client_secret": "QxyWfESXqTD55aUyh6miYnny1QTCEuEwyC4escw9", "client_secret": "QxyWfESXqTD55aUyh6miYnny1QTCEuEwyC4escw9",
"redirect_uris": ["app.immich:///oauth-callback", "https://img.riotpiao.com/auth/login", "https://img.riotpiao.com/user/oauth2/callback"], "redirect_uris": ["app.immich:///oauth-callback", "https://img.riotpiao.com/auth/login", "https://img.riotpiao.com/user/oauth2/callback"],
}, },
"homarr": {
"client_id": "homarr",
"client_secret": "RMlDQAWdjT5YPPH0U7ztDoUFP7R7w95b2xqQ1pyS",
"redirect_uris": ["http://localhost:7575/auth/callback", "https://homarr.riotpiao.com/auth/callback"],
},
"argocd": { "argocd": {
"client_id": "argocd", "client_id": "argocd",
"client_secret_env": "AUTHENTIK_PROVIDER_ARGOCD_SECRET", "client_secret_env": "AUTHENTIK_PROVIDER_ARGOCD_SECRET",
+2 -3
View File
@@ -53,7 +53,7 @@ generate_secret() {
declare -A NEW_SECRETS declare -A NEW_SECRETS
for svc in api-gw minio poimen paperless grafana argocd forgejo homarr immich vault portfolio-agent memory-agent local-llm; do for svc in api-gw minio poimen paperless grafana argocd forgejo immich vault portfolio-agent memory-agent local-llm; do
NEW_SECRETS[$svc]=$(generate_secret) NEW_SECRETS[$svc]=$(generate_secret)
log " $svc: ${NEW_SECRETS[$svc]:0:15}..." log " $svc: ${NEW_SECRETS[$svc]:0:15}..."
done done
@@ -70,7 +70,6 @@ declare -A PROVIDER_PKS=(
[grafana]=6 [grafana]=6
[argocd]=7 [argocd]=7
[forgejo]=8 [forgejo]=8
[homarr]=9
[immich]=10 [immich]=10
[vault]=11 [vault]=11
) )
@@ -203,7 +202,7 @@ fi
log "" log ""
log "=== Summary ===" log "=== Summary ==="
log "Rotated 13 credentials:" log "Rotated 13 credentials:"
log " OAuth2 Providers: api-gw, minio, poimen, paperless, grafana, argocd, forgejo, homarr, immich, vault" log " OAuth2 Providers: api-gw, minio, poimen, paperless, grafana, argocd, forgejo, immich, vault"
log " Service Accounts: portfolio-agent, memory-agent, local-llm" log " Service Accounts: portfolio-agent, memory-agent, local-llm"
log "" log ""
-7
View File
@@ -98,9 +98,6 @@ OIDC_APPS = {
"grafana": {**_WEB, "redirect_uris": [ "grafana": {**_WEB, "redirect_uris": [
"http://localhost:3000/login/generic_oauth", "http://localhost:3000/login/generic_oauth",
"https://grafana.riotpiao.com/login/generic_oauth"]}, "https://grafana.riotpiao.com/login/generic_oauth"]},
"homarr": {**_WEB, "redirect_uris": [
"http://localhost:7575/auth/callback",
"https://homarr.riotpiao.com/auth/callback"]},
"immich": {**_WEB, "app_type_id": "OIDC_APP_TYPE_NATIVE", "redirect_uris": [ "immich": {**_WEB, "app_type_id": "OIDC_APP_TYPE_NATIVE", "redirect_uris": [
"app.immich:///oauth-callback", "https://img.riotpiao.com/auth/login", "app.immich:///oauth-callback", "https://img.riotpiao.com/auth/login",
"https://img.riotpiao.com/user/oauth2/callback"]}, "https://img.riotpiao.com/user/oauth2/callback"]},
@@ -362,10 +359,6 @@ def phase_apply(_args: argparse.Namespace) -> int:
SECRET_MAP = { SECRET_MAP = {
"grafana": [("grafana-oidc-secrets.enc.yaml", "grafana-oidc", "grafana": [("grafana-oidc-secrets.enc.yaml", "grafana-oidc",
"GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET", "secret")], "GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET", "secret")],
"homarr": [("homarr-auth-oidc.enc.yaml", "homarr-oidc",
"client-id", "id"),
("homarr-auth-oidc.enc.yaml", "homarr-oidc",
"client-secret", "secret")],
"minio": [("minio-secrets.enc.yaml", "minio-oidc", "minio": [("minio-secrets.enc.yaml", "minio-oidc",
"MINIO_IDENTITY_OPENID_CLIENT_SECRET", "secret")], "MINIO_IDENTITY_OPENID_CLIENT_SECRET", "secret")],
"paperless": [("paperless-ai-secrets.enc.yaml", "paperless-ai-config", "paperless": [("paperless-ai-secrets.enc.yaml", "paperless-ai-config",