From 67a2318a960435bfbfb5b37b29a096ad8378ba30 Mon Sep 17 00:00:00 2001 From: gwg313 Date: Thu, 18 Jun 2026 14:01:20 -0400 Subject: [PATCH] add soulsync Signed-off-by: gwg313 --- .gitignore | 2 + apps/soulsync/deployment.yaml | 158 ++++++++++++++++++ apps/soulsync/kustomization.yaml | 12 ++ apps/soulsync/namespace.yaml | 8 + apps/soulsync/network-policy.yaml | 45 +++++ apps/soulsync/protonvpn-wg-sealed.yaml | 16 ++ apps/soulsync/pvcs.yaml | 35 ++++ apps/soulsync/route.yaml | 83 +++++++++ apps/soulsync/service.yaml | 27 +++ apps/soulsync/storage.yaml | 45 +++++ management/platform-apps/kustomization.yaml | 1 + management/platform-apps/soulsync.yaml | 23 +++ .../policies/20-require/require-non-root.yaml | 12 ++ 13 files changed, 467 insertions(+) create mode 100644 apps/soulsync/deployment.yaml create mode 100644 apps/soulsync/kustomization.yaml create mode 100644 apps/soulsync/namespace.yaml create mode 100644 apps/soulsync/network-policy.yaml create mode 100644 apps/soulsync/protonvpn-wg-sealed.yaml create mode 100644 apps/soulsync/pvcs.yaml create mode 100644 apps/soulsync/route.yaml create mode 100644 apps/soulsync/service.yaml create mode 100644 apps/soulsync/storage.yaml create mode 100644 management/platform-apps/soulsync.yaml diff --git a/.gitignore b/.gitignore index 26d999e..b3f740d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .devenv +apps/**/protonvpn-wg-secret.yaml +apps/**/*-secret.yaml diff --git a/apps/soulsync/deployment.yaml b/apps/soulsync/deployment.yaml new file mode 100644 index 0000000..4206943 --- /dev/null +++ b/apps/soulsync/deployment.yaml @@ -0,0 +1,158 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: slskd + namespace: slskd + labels: + app: slskd +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: slskd + template: + metadata: + labels: + app: slskd + security.policy/allow-root: "true" + spec: + securityContext: + fsGroup: 1000 + initContainers: + - name: wireguard-config-init + image: busybox:1.37.0 + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + capabilities: + drop: + - ALL + command: + - sh + - -c + - mkdir -p /config/wg_confs && cp /secrets/wg0.conf /config/wg_confs/wg0.conf + volumeMounts: + - name: wg-secret + mountPath: /secrets + readOnly: true + - name: wg-config + mountPath: /config + + containers: + - name: protonvpn-wireguard + image: linuxserver/wireguard:1.0.20250521 + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + capabilities: + drop: + - ALL + add: + - NET_ADMIN + - NET_RAW + env: + - name: ALLOWEDIPS + value: "0.0.0.0/0" + volumeMounts: + - name: wg-config + mountPath: /config + + - name: slskd + image: slskd/slskd:0.25.1.65534-8e152ed6 + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + capabilities: + drop: + - ALL + ports: + - containerPort: 5030 + name: web-ui + env: + - name: SLSKD_APP_DIR + value: /app/config + - name: SLSKD_DOWNLOADS_DIR + value: /app/downloads + volumeMounts: + - name: slskd-config + mountPath: /app/config + - name: slskd-downloads + mountPath: /app/downloads + - name: slskd-music + mountPath: /app/music + readOnly: true + + - name: soulsync + image: boulderbadgedad/soulsync:2.7.3 + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + capabilities: + drop: + - ALL + ports: + - containerPort: 8080 + name: soulsync-ui + env: + - name: SLSKD_URL + value: "http://localhost:5030" + volumeMounts: + - name: soulsync-config + mountPath: /app/config + - name: soulsync-data + mountPath: /app/data + - name: slskd-downloads + mountPath: /app/downloads + - name: slskd-music + mountPath: /app/music + - name: soulsync-ephemeral + mountPath: /app/logs + subPath: logs + - name: soulsync-ephemeral + mountPath: /app/Transfer + subPath: Transfer + - name: soulsync-ephemeral + mountPath: /app/Staging + subPath: Staging + - name: soulsync-ephemeral + mountPath: /app/Stream + subPath: Stream + - name: soulsync-ephemeral + mountPath: /app/storage + subPath: storage + - name: soulsync-ephemeral + mountPath: /app/MusicVideos + subPath: MusicVideos + - name: soulsync-ephemeral + mountPath: /app/scripts + subPath: scripts + + volumes: + - name: wg-secret + secret: + secretName: protonvpn-wg-conf + - name: wg-config + emptyDir: {} + - name: slskd-config + persistentVolumeClaim: + claimName: slskd-config + - name: soulsync-config + persistentVolumeClaim: + claimName: soulsync-config + - name: soulsync-data + persistentVolumeClaim: + claimName: soulsync-data + - name: soulsync-ephemeral + emptyDir: {} + - name: slskd-downloads + persistentVolumeClaim: + claimName: slskd-downloads + - name: slskd-music + persistentVolumeClaim: + claimName: slskd-music diff --git a/apps/soulsync/kustomization.yaml b/apps/soulsync/kustomization.yaml new file mode 100644 index 0000000..37ac3fa --- /dev/null +++ b/apps/soulsync/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - namespace.yaml + - storage.yaml + - pvcs.yaml + - protonvpn-wg-sealed.yaml + - network-policy.yaml + - deployment.yaml + - service.yaml + - route.yaml diff --git a/apps/soulsync/namespace.yaml b/apps/soulsync/namespace.yaml new file mode 100644 index 0000000..721554f --- /dev/null +++ b/apps/soulsync/namespace.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: slskd + labels: + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/warn: privileged diff --git a/apps/soulsync/network-policy.yaml b/apps/soulsync/network-policy.yaml new file mode 100644 index 0000000..78cda90 --- /dev/null +++ b/apps/soulsync/network-policy.yaml @@ -0,0 +1,45 @@ +# ---------------------------------------------------- +# Ingress only from Gateway API +# ---------------------------------------------------- +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: allow-ingress + namespace: slskd +spec: + endpointSelector: + matchLabels: + app: slskd + + ingress: + - fromEntities: + - ingress + toPorts: + - ports: + - port: "5030" + protocol: TCP + - port: "8080" + protocol: TCP + +--- +# ---------------------------------------------------- +# VPN killswitch — only allow egress to ProtonVPN endpoint +# All other internet traffic is blocked, forcing it through the tunnel +# ---------------------------------------------------- +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: vpn-killswitch + namespace: slskd +spec: + endpointSelector: + matchLabels: + app: slskd + + egress: + - toCIDR: + - "149.50.216.205/32" + toPorts: + - ports: + - port: "51820" + protocol: UDP diff --git a/apps/soulsync/protonvpn-wg-sealed.yaml b/apps/soulsync/protonvpn-wg-sealed.yaml new file mode 100644 index 0000000..eb6068d --- /dev/null +++ b/apps/soulsync/protonvpn-wg-sealed.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + creationTimestamp: null + name: protonvpn-wg-conf + namespace: slskd +spec: + encryptedData: + wg0.conf: AgAzuAuXeEglkKYphbv3iAyXMTL+TG999w60f7ZYmLhuFLDDisgMTSWYH00sM0wMLIpxfxgDdFh19LYbIurLFp2ejij+zs3G2e+7cnltwWEjULbh1IntLTKYTBovq4zKb1sIaby6TPtnjUyfAME101xznQpkSDnFjqhOoNMcvX76o5Lg+NelyUC0+w40IG2G2wzJ/J1h7gVdEkqiQJ/eZd8VYRswP7KXu9p3QePhlVEo/+jSmyXt7gAfbqUrA6nbPmILtOZ80398Ybxq4E23pufC0ycNIBpvRvAV/Mfl1K6reGDMmfxPQW52axWlJzYBcYiPsHfTgJplLIqHSHnm+SL01e8Mk8K5Xq/O2DKjujwx7aUbGicSR80MkKe+uSzu2f6jiTpGznx0a5LuHLLhGBI0zPaYBKuL2oXPwW7E2iBWBbro2F6+sDIuVTXnZjMLisyNZMZhtuXvkzKb9yEBHmP3sdz3SHL/i8giskTcReU/+MrevakWNVbT2iXxVOqp8G1F/y+xeAYq5BZDWwwcKF4U4ALZQoJKfxBDFJSBNrgKKqwWmBt0Q88NUv/6uEy9boyjRmRfBf46XuajcphHQaHhhpp10+19Kp18dDISEGU0lf4XMj69NaRDv/WRpQYl1JuHSUxVrMnXH70s/n+HLUpcvcVOX5xwG8pCBi5nVZiYFlRqfn3p924sNbgg2XKbnNkiKI47+U0Y8U0QMVm7LEkwjFvEetG/hd1YPghcFprGtfHYU5xIeHT8Pk3cNmtL9s0OWYj4Sak7Im5RizsCt/L4SwcuC+tnVH08B5GpDlSOa4gRQ0PBH5y/WbU8TNjJRbms1Mi+Ct1VLvim1IdAUMXpUvN4bkfyQOSDQWZwR1WdY86pVKANm+toG/MoJHp/oX92NheJu9Fyk3gur9HCPrmcCtDRzsCBW2O42Wh6edhHxCL1040wqyG2HIefgydPyM9chchKYMddiYof2YrgLbgNXufG+hV/2oOqsBS5e/kyEYoTRxx0klyhgY83SO2QF1ZE9Rsq55MI1dMFW89DrCWrm0Q4Xq13at0wS2UtRFh37FfDNPDVZyd/E9K0xo6iadW8Qd2WpL/eefZtTsKdG7lXM78ViQL7vAzhhXDRxFeF+zQlzoNA+eMGcd4ICj53VARkzzupx9iUXd/1gXZJcJOc+PMzhbV01YtHteUUVt9+jSNqo3SkDOsWzMCBlEJ4q8rdYK3P1NDof4OWez9QTeo2afnfB3l7a3JRLSlm62ZPhu7SKkwtx1RkBEDJphuz/7R25oADZ9KuJiDnju/Dr1QywIicyL5O899D47j0C7d+1ZVv9i+Y8bzYpIs1La3J1GMxhd8SlVeEHfSaybV30RwX6lXC0fjOkXvvsw== + template: + metadata: + creationTimestamp: null + name: protonvpn-wg-conf + namespace: slskd + type: Opaque diff --git a/apps/soulsync/pvcs.yaml b/apps/soulsync/pvcs.yaml new file mode 100644 index 0000000..83a0ea3 --- /dev/null +++ b/apps/soulsync/pvcs.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: slskd-downloads + namespace: slskd +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: slskd-config + namespace: slskd +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: soulsync-data + namespace: slskd +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi diff --git a/apps/soulsync/route.yaml b/apps/soulsync/route.yaml new file mode 100644 index 0000000..13692b8 --- /dev/null +++ b/apps/soulsync/route.yaml @@ -0,0 +1,83 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: slskd + namespace: slskd +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: shared-edge-gateway + namespace: cilium-ingress + hostnames: + - slskd.local.gwg313.xyz + - slskd.gwg313.xyz + - slskd.zerotier.gwg313.xyz + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: "" + kind: Service + name: slskd + port: 80 + weight: 1 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: ReferenceGrant +metadata: + name: allow-gateway-to-slskd + namespace: slskd +spec: + from: + - group: gateway.networking.k8s.io + kind: Gateway + namespace: cilium-ingress + to: + - group: "" + kind: Service + name: slskd +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: soulsync + namespace: slskd +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: shared-edge-gateway + namespace: cilium-ingress + hostnames: + - soulsync.local.gwg313.xyz + - soulsync.gwg313.xyz + - soulsync.zerotier.gwg313.xyz + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: "" + kind: Service + name: soulsync + port: 80 + weight: 1 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: ReferenceGrant +metadata: + name: allow-gateway-to-soulsync + namespace: slskd +spec: + from: + - group: gateway.networking.k8s.io + kind: Gateway + namespace: cilium-ingress + to: + - group: "" + kind: Service + name: soulsync diff --git a/apps/soulsync/service.yaml b/apps/soulsync/service.yaml new file mode 100644 index 0000000..d0a7d3a --- /dev/null +++ b/apps/soulsync/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: slskd + namespace: slskd +spec: + selector: + app: slskd + ports: + - name: http + port: 80 + targetPort: 5030 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: soulsync + namespace: slskd +spec: + selector: + app: slskd + ports: + - name: http + port: 80 + targetPort: 8080 + type: ClusterIP diff --git a/apps/soulsync/storage.yaml b/apps/soulsync/storage.yaml new file mode 100644 index 0000000..9e7d100 --- /dev/null +++ b/apps/soulsync/storage.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: slskd-music-pv +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteMany # Elevated for SoulSync + persistentVolumeReclaimPolicy: Retain + storageClassName: manual + nfs: + path: /mnt/tank/media/music + server: truenas.local.gwg313.xyz + claimRef: + namespace: slskd + name: slskd-music +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: slskd-music + namespace: slskd +spec: + accessModes: + - ReadWriteMany + storageClassName: manual + volumeName: slskd-music-pv + resources: + requests: + storage: 10Gi +--- +# New PVC for SoulSync's internal database/state +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: soulsync-config + namespace: slskd +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi diff --git a/management/platform-apps/kustomization.yaml b/management/platform-apps/kustomization.yaml index ee644fc..1da5f99 100644 --- a/management/platform-apps/kustomization.yaml +++ b/management/platform-apps/kustomization.yaml @@ -18,3 +18,4 @@ resources: - navidrome.yaml - bytestash.yaml - stirling-pdf.yaml + - soulsync.yaml diff --git a/management/platform-apps/soulsync.yaml b/management/platform-apps/soulsync.yaml new file mode 100644 index 0000000..c803960 --- /dev/null +++ b/management/platform-apps/soulsync.yaml @@ -0,0 +1,23 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: soulsync + namespace: argocd + annotations: + argoproj.io/sync-wave: "0" +spec: + project: default + source: + repoURL: https://github.com/gwg313/homelab-gitops.git + targetRevision: main + path: apps/soulsync + destination: + server: https://kubernetes.default.svc + namespace: slskd + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - ServerSideApply=true diff --git a/platform/kyverno/policies/20-require/require-non-root.yaml b/platform/kyverno/policies/20-require/require-non-root.yaml index c902def..8372dee 100644 --- a/platform/kyverno/policies/20-require/require-non-root.yaml +++ b/platform/kyverno/policies/20-require/require-non-root.yaml @@ -17,6 +17,12 @@ spec: - resources: kinds: - Pod + exclude: + any: + - resources: + selector: + matchLabels: + security.policy/allow-root: "true" validate: message: "Pods must set runAsNonRoot=true." @@ -31,6 +37,12 @@ spec: - resources: kinds: - Pod + exclude: + any: + - resources: + selector: + matchLabels: + security.policy/allow-root: "true" validate: message: "All containers must set runAsNonRoot=true."