--- # Namespace (trust zone; default-deny + policies apply) apiVersion: v1 kind: Namespace metadata: name: radarr labels: homelab.keithjackson.dev/app-namespace: 'true' gateway-access: shared annotations: homelab.keithjackson.dev/backup-policy: daily-offcluster --- # Default-deny baseline (R-NET-01): deny all, allow only DNS apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: radarr labels: homelab.keithjackson.dev/baseline: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress ingress: [] egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system ports: - protocol: UDP port: 53 - protocol: TCP port: 53 --- # PersistentVolume radarr-media - static external NFS (bulk tier) apiVersion: v1 kind: PersistentVolume metadata: name: radarr-media labels: app.kubernetes.io/name: radarr spec: capacity: storage: 9Ti accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: '' mountOptions: - nfsvers=4.1 - hard - noatime - timeo=600 - retrans=2 nfs: server: ${BULK_NFS_SERVER} path: /mnt/Storage/plex claimRef: namespace: radarr name: radarr-media --- # PVC radarr-config (R-STATE) apiVersion: v1 kind: PersistentVolumeClaim metadata: name: radarr-config namespace: radarr labels: app.kubernetes.io/name: radarr spec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 5Gi --- # PVC radarr-media (R-STATE) apiVersion: v1 kind: PersistentVolumeClaim metadata: name: radarr-media namespace: radarr labels: app.kubernetes.io/name: radarr spec: accessModes: - ReadWriteMany storageClassName: '' volumeName: radarr-media resources: requests: storage: 9Ti --- # Deployment (R-PLAT-02) apiVersion: apps/v1 kind: Deployment metadata: name: radarr namespace: radarr labels: app.kubernetes.io/name: radarr spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/name: radarr template: metadata: labels: app.kubernetes.io/name: radarr homelab.keithjackson.dev/egress-class: vpn homelab.keithjackson.dev/auth-mode: forward-auth annotations: homelab.keithjackson.dev/auth-mode: forward-auth homelab.keithjackson.dev/auth-groups: media-users,platform-admins spec: containers: - name: radarr image: lscr.io/linuxserver/radarr:5.28.0 ports: - containerPort: 7878 env: - name: PUID value: '1000' - name: PGID value: '3000' - name: TZ value: Etc/UTC volumeMounts: - name: config mountPath: /config - name: media mountPath: /media - name: oauth2-proxy image: quay.io/oauth2-proxy/oauth2-proxy:v7.8.1 imagePullPolicy: IfNotPresent args: - --http-address=0.0.0.0:4180 - --reverse-proxy=true - --provider=oidc - --oidc-issuer-url=https://keycloak.${BASE_DOMAIN}/realms/homelab - --upstream=http://127.0.0.1:7878 - --email-domain=* - --scope=openid email profile - --oidc-groups-claim=groups - --allowed-group=media-users - --allowed-group=platform-admins - --skip-provider-button=true - --redirect-url=https://radarr.${BASE_DOMAIN}/oauth2/callback - --api-route=^/api/ - --api-route=^/signalr/ - --cookie-name=_oauth2_proxy_radarr - --cookie-domain=radarr.${BASE_DOMAIN} - --whitelist-domain=.${BASE_DOMAIN} - --cookie-secure=true - --cookie-refresh=2m30s - --pass-access-token=true - --set-xauthrequest=true - --metrics-address=0.0.0.0:44180 env: - name: OAUTH2_PROXY_CLIENT_ID valueFrom: secretKeyRef: name: radarr-oauth2-proxy key: client-id - name: OAUTH2_PROXY_CLIENT_SECRET valueFrom: secretKeyRef: name: radarr-oauth2-proxy key: client-secret - name: OAUTH2_PROXY_COOKIE_SECRET valueFrom: secretKeyRef: name: radarr-oauth2-proxy key: cookie-secret ports: - name: http containerPort: 4180 protocol: TCP - name: metrics containerPort: 44180 protocol: TCP resources: requests: cpu: 25m memory: 64Mi limits: memory: 128Mi securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL livenessProbe: httpGet: path: /ping port: http initialDelaySeconds: 5 periodSeconds: 15 readinessProbe: httpGet: path: /ping port: http initialDelaySeconds: 5 periodSeconds: 15 securityContext: fsGroup: 3000 volumes: - name: config persistentVolumeClaim: claimName: radarr-config - name: media persistentVolumeClaim: claimName: radarr-media --- # Service apiVersion: v1 kind: Service metadata: name: radarr namespace: radarr labels: app.kubernetes.io/name: radarr spec: selector: app.kubernetes.io/name: radarr ports: - name: port-7878 port: 7878 targetPort: 7878 - name: authproxy port: 4180 targetPort: 4180 --- # CiliumNetworkPolicy egress allow (R-NET-02): radarr-allow-qbittorrent-8080 apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-qbittorrent-8080 namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr egress: - toEndpoints: - matchLabels: app.kubernetes.io/name: qbittorrent k8s:io.kubernetes.pod.namespace: qbittorrent toPorts: - ports: - port: '8080' protocol: TCP --- # CiliumNetworkPolicy egress allow (R-NET-02): radarr-allow-jackett-9117 apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-jackett-9117 namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr egress: - toEndpoints: - matchLabels: app.kubernetes.io/name: jackett k8s:io.kubernetes.pod.namespace: jackett toPorts: - ports: - port: '9117' protocol: TCP --- # CiliumNetworkPolicy egress allow (R-NET-02): radarr-allow-plex-32400 apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-plex-32400 namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr egress: - toEndpoints: - matchLabels: app.kubernetes.io/name: plex k8s:io.kubernetes.pod.namespace: plex toPorts: - ports: - port: '32400' protocol: TCP --- # CiliumNetworkPolicy reciprocal ingress allow (R-NET-02): radarr-allow-seerr-7878 apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-seerr-7878 namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr ingress: - fromEndpoints: - matchLabels: app.kubernetes.io/name: seerr k8s:io.kubernetes.pod.namespace: seerr toPorts: - ports: - port: '7878' protocol: TCP --- # CiliumNetworkPolicy gateway-ingress allow (R-NET-01/02): radarr-allow-gateway-ingress apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-gateway-ingress namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr ingress: - fromEntities: - ingress toPorts: - ports: - port: '4180' protocol: TCP --- # CiliumNetworkPolicy monitoring scrape ingress allow (R-NET-02/R-OBS-01): radarr-allow-monitoring-scrape apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-monitoring-scrape namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr ingress: - fromEndpoints: - matchLabels: k8s:io.kubernetes.pod.namespace: monitoring toPorts: - ports: - port: '44180' protocol: TCP --- # CiliumNetworkPolicy world egress allow (egress class governs the path; R-NET-05): radarr-allow-internet-egress apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: radarr-allow-internet-egress namespace: radarr labels: app.kubernetes.io/name: radarr spec: endpointSelector: matchLabels: app.kubernetes.io/name: radarr egress: - toEntities: - world - toEndpoints: - matchLabels: io.kubernetes.pod.namespace: keycloak app: keycloak --- # HTTPRoute radarr-7878 (R-TLS/R-DNS) apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: radarr-7878 namespace: radarr labels: app.kubernetes.io/name: radarr annotations: homelab.keithjackson.dev/auth-mode: forward-auth homelab.keithjackson.dev/auth-groups: media-users,platform-admins external-dns.alpha.kubernetes.io/controller: none spec: parentRefs: - name: shared namespace: gateway sectionName: https hostnames: - radarr.${BASE_DOMAIN} rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: radarr port: 4180 --- # PrometheusRule SLI alerts (R-OBS-01) apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: radarr-slis namespace: radarr labels: release: kube-prometheus-stack app.kubernetes.io/name: radarr spec: groups: - name: radarr.slis rules: - alert: radarr-down expr: kube_deployment_status_replicas_available{namespace="radarr", deployment="radarr"} == 0 or absent(kube_deployment_status_replicas_available{namespace="radarr", deployment="radarr"}) for: 5m labels: severity: critical service: radarr annotations: summary: radarr is down description: 'radarr: its Deployment has no available/ready replica for 5m, or the signal is gone entirely (SLI: up, via kube_deployment_status_replicas_available).'