From 57ac95bdec7ba416e3ebbddb94ebb7767f22ff72 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sat, 15 Aug 2026 12:08:50 +1000 Subject: [PATCH] jellyfin: back up the config PVC with a k8up Schedule Protect the jellyfin-config PVC (library metadata, plugins, config XML) with daily restic backups to the new Ceph RGW config-backup bucket. - Add a k8up.io Schedule: daily backup (02:00), weekly prune (Sun 03:00, keep 14 daily/8 weekly/12 monthly) and weekly check (Sun 04:00) - Source S3 creds from the cephrgw BucketAccess Secret and the restic repo password from Vault via a VaultStaticSecret (kv path kubernetes/namespace/jellyfin/default/k8up-restic) - Add the namespace VaultAuth (default role/SA) VSO needs to sync it - Mount the reflected vault-ca-cert into the restic pods so restic trusts the internal unkin.net CA on s3.ceph.unkin.net - Wire the new files into the jellyfin kustomization --- apps/base/jellyfin/kustomization.yaml | 3 ++ apps/base/jellyfin/schedule.yaml | 58 +++++++++++++++++++++++ apps/base/jellyfin/vaultauth.yaml | 20 ++++++++ apps/base/jellyfin/vaultstaticsecret.yaml | 24 ++++++++++ 4 files changed, 105 insertions(+) create mode 100644 apps/base/jellyfin/schedule.yaml create mode 100644 apps/base/jellyfin/vaultauth.yaml create mode 100644 apps/base/jellyfin/vaultstaticsecret.yaml diff --git a/apps/base/jellyfin/kustomization.yaml b/apps/base/jellyfin/kustomization.yaml index edab63d..33ded07 100644 --- a/apps/base/jellyfin/kustomization.yaml +++ b/apps/base/jellyfin/kustomization.yaml @@ -8,6 +8,9 @@ resources: - cnpg_pooler.yaml - cnpg_backup.yaml - cephrgw-config-backup.yaml + - vaultauth.yaml + - vaultstaticsecret.yaml + - schedule.yaml - pvc-config.yaml - pvc-transcode.yaml - pvc-media-tv.yaml diff --git a/apps/base/jellyfin/schedule.yaml b/apps/base/jellyfin/schedule.yaml new file mode 100644 index 0000000..6043a18 --- /dev/null +++ b/apps/base/jellyfin/schedule.yaml @@ -0,0 +1,58 @@ +--- +# k8up Schedule: restic backups of the jellyfin-config PVC (library metadata, +# plugins, config XML) to the dedicated Ceph RGW config-backup bucket. S3 creds +# come from the cephrgw BucketAccess Secret (jellyfin-config-backup-s3); the +# restic repo password comes from Vault via the jellyfin-k8up-restic Secret. +# +# s3.ceph.unkin.net presents the internal unkin.net CA, which the k8up/restic +# image does not trust by default, so the reflected vault-ca-cert Secret is +# mounted into every job pod and pointed at via backend.tlsOptions.caCert. +apiVersion: k8up.io/v1 +kind: Schedule +metadata: + name: jellyfin-config + namespace: jellyfin +spec: + backend: + repoPasswordSecretRef: + name: jellyfin-k8up-restic + key: password + s3: + endpoint: https://s3.ceph.unkin.net + bucket: jellyfin-config-backup + accessKeyIDSecretRef: + name: jellyfin-config-backup-s3 + key: AWS_ACCESS_KEY_ID + secretAccessKeySecretRef: + name: jellyfin-config-backup-s3 + key: AWS_SECRET_ACCESS_KEY + tlsOptions: + caCert: /etc/k8up/ca/ca.crt + volumeMounts: + - name: vault-ca + mountPath: /etc/k8up/ca + readOnly: true + backup: + schedule: "0 2 * * *" + failedJobsHistoryLimit: 3 + successfulJobsHistoryLimit: 3 + volumes: + - name: vault-ca + secret: + secretName: vault-ca-cert + prune: + schedule: "0 3 * * 0" + retention: + keepDaily: 14 + keepWeekly: 8 + keepMonthly: 12 + volumes: + - name: vault-ca + secret: + secretName: vault-ca-cert + check: + schedule: "0 4 * * 0" + volumes: + - name: vault-ca + secret: + secretName: vault-ca-cert diff --git a/apps/base/jellyfin/vaultauth.yaml b/apps/base/jellyfin/vaultauth.yaml new file mode 100644 index 0000000..9fbc2c2 --- /dev/null +++ b/apps/base/jellyfin/vaultauth.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultAuth +metadata: + name: default + namespace: jellyfin + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + allowedNamespaces: + - jellyfin + kubernetes: + audiences: + - vault + role: default + serviceAccount: default + tokenExpirationSeconds: 600 + method: kubernetes + mount: k8s/au/syd1 + vaultConnectionRef: vso-system/default diff --git a/apps/base/jellyfin/vaultstaticsecret.yaml b/apps/base/jellyfin/vaultstaticsecret.yaml new file mode 100644 index 0000000..9de7ef2 --- /dev/null +++ b/apps/base/jellyfin/vaultstaticsecret.yaml @@ -0,0 +1,24 @@ +--- +# restic repository password for the k8up jellyfin-config backups. Seeded at +# kv/kubernetes/namespace/jellyfin/default/k8up-restic (key: password); the +# default k8s role's templated policy already grants read here, so no +# terraform-vault change is needed. VSO syncs it into the jellyfin-k8up-restic +# Secret that the Schedule references via backend.repoPasswordSecretRef. +apiVersion: secrets.hashicorp.com/v1beta1 +kind: VaultStaticSecret +metadata: + name: jellyfin-k8up-restic + namespace: jellyfin + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + destination: + create: true + name: jellyfin-k8up-restic + overwrite: true + hmacSecretData: true + mount: kv + path: kubernetes/namespace/jellyfin/default/k8up-restic + refreshAfter: 5m + type: kv-v2 + vaultAuthRef: default