Files
home-network-k3s-impl/apps/nextcloud.yaml
T
jakman85andClaude Opus 4.8 4be6752c71 feat(apps): onboard nextcloud (Phase 6) — first CNPG-DB + OIDC-target patterns
Onboard nextcloud (docs/13 row 7): public, DR-critical file sync backed by an
external PostgreSQL. Establishes the reusable CNPG-DB pattern for later DB-backed
services.

- catalog/nextcloud.yaml: ServiceDefinition (image nextcloud:31-apache :80, public,
  internet, data 20Gi longhorn @/var/www/html, backup daily-offcluster, auth oidc
  +platform-admins, ingress nextcloud.home.keithjackson.dev, dependency
  nextcloud-db:5432). Uses schema 1.2.0 env for the Postgres connection, break-glass
  admin, trusted-domain + OVERWRITE* proxy settings.
- apps/nextcloud-db.yaml: CloudNativePG Cluster in a dedicated nextcloud-db namespace
  (modeled on keycloak-db; no default-deny, mirroring the verified keycloak posture),
  inheritedMetadata stamps app.kubernetes.io/name=nextcloud-db so the rendered egress
  CNP matches. initdb consumes a pre-provisioned owner secret.
- apps/nextcloud-db-app.sops.yaml + apps/nextcloud-bootstrap-secret.sops.yaml: SOPS
  (age) — shared DB password mirrored across the two namespaces (Pods cannot read a
  Secret cross-namespace), plus the break-glass local admin.
- apps/nextcloud.yaml: rendered manifests (catalog/render.py --no-image-automation).
- apps/kustomization.yaml: wire in the four new resources.

OIDC realm-client wiring DEFERRED (WS-APPS step-3 escape hatch): editing the reconciled
realm import in platform-config risks the running Keycloak realm / whole platform-config
apply, and nextcloud OIDC needs post-install occ steps with no first-class env — nextcloud
comes up INSTALLED on the break-glass local admin (as Gitea did); the Keycloak client is a
follow-up. Off-cluster backup awaits Velero/OQ-BKP (intent declared).

Gates: render --selftest PASS; other apps byte-identical; ci l0 17/17; l1 3/3; lint clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-26 01:32:00 -05:00

265 lines
6.1 KiB
YAML

---
# Namespace (trust zone; default-deny + policies apply)
apiVersion: v1
kind: Namespace
metadata:
name: nextcloud
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: nextcloud
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
---
# PVC nextcloud-data (R-STATE)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nextcloud-data
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 20Gi
---
# Deployment (R-PLAT-02)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextcloud
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: nextcloud
template:
metadata:
labels:
app.kubernetes.io/name: nextcloud
homelab.keithjackson.dev/egress-class: internet
homelab.keithjackson.dev/auth-mode: oidc
annotations:
homelab.keithjackson.dev/auth-mode: oidc
homelab.keithjackson.dev/auth-groups: platform-admins
spec:
containers:
- name: nextcloud
image: nextcloud:31-apache
ports:
- containerPort: 80
env:
- name: POSTGRES_HOST
value: nextcloud-db-rw.nextcloud-db.svc.cluster.local
- name: POSTGRES_DB
value: nextcloud
- name: POSTGRES_USER
value: nextcloud
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: nextcloud-bootstrap
key: db-password
- name: NEXTCLOUD_ADMIN_USER
valueFrom:
secretKeyRef:
name: nextcloud-bootstrap
key: admin-username
- name: NEXTCLOUD_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: nextcloud-bootstrap
key: admin-password
- name: NEXTCLOUD_TRUSTED_DOMAINS
value: nextcloud.home.keithjackson.dev
- name: OVERWRITEHOST
value: nextcloud.home.keithjackson.dev
- name: OVERWRITEPROTOCOL
value: https
- name: OVERWRITECLIURL
value: https://nextcloud.home.keithjackson.dev
volumeMounts:
- name: data
mountPath: /var/www/html
volumes:
- name: data
persistentVolumeClaim:
claimName: nextcloud-data
---
# Service
apiVersion: v1
kind: Service
metadata:
name: nextcloud
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
spec:
selector:
app.kubernetes.io/name: nextcloud
ports:
- name: port-80
port: 80
targetPort: 80
---
# CiliumNetworkPolicy egress allow (R-NET-02): nextcloud-allow-nextcloud-db-5432
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: nextcloud-allow-nextcloud-db-5432
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
spec:
endpointSelector:
matchLabels:
app.kubernetes.io/name: nextcloud
egress:
- toEndpoints:
- matchLabels:
app.kubernetes.io/name: nextcloud-db
k8s:io.kubernetes.pod.namespace: nextcloud-db
toPorts:
- ports:
- port: '5432'
protocol: TCP
---
# CiliumNetworkPolicy gateway-ingress allow (R-NET-01/02): nextcloud-allow-gateway-ingress
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: nextcloud-allow-gateway-ingress
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
spec:
endpointSelector:
matchLabels:
app.kubernetes.io/name: nextcloud
ingress:
- fromEntities:
- ingress
toPorts:
- ports:
- port: '80'
protocol: TCP
---
# CiliumNetworkPolicy world egress allow (egress class governs the path; R-NET-05): nextcloud-allow-internet-egress
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: nextcloud-allow-internet-egress
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
spec:
endpointSelector:
matchLabels:
app.kubernetes.io/name: nextcloud
egress:
- toEntities:
- world
---
# HTTPRoute nextcloud-80 (R-TLS/R-DNS)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nextcloud-80
namespace: nextcloud
labels:
app.kubernetes.io/name: nextcloud
annotations:
homelab.keithjackson.dev/auth-mode: oidc
homelab.keithjackson.dev/auth-groups: platform-admins
spec:
parentRefs:
- name: shared
namespace: gateway
sectionName: https
hostnames:
- nextcloud.home.keithjackson.dev
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: nextcloud
port: 80
---
# ServiceMonitor (R-OBS-01)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nextcloud
namespace: nextcloud
labels:
release: kube-prometheus-stack
app.kubernetes.io/name: nextcloud
spec:
selector:
matchLabels:
app.kubernetes.io/name: nextcloud
namespaceSelector:
matchNames:
- nextcloud
endpoints:
- port: metrics
interval: 30s
---
# PrometheusRule SLI alerts (R-OBS-01)
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: nextcloud-slis
namespace: nextcloud
labels:
release: kube-prometheus-stack
app.kubernetes.io/name: nextcloud
spec:
groups:
- name: nextcloud.slis
rules:
- alert: nextcloud-down
expr: up{job="nextcloud"} == 0
for: 5m
labels:
severity: critical
service: nextcloud
annotations:
summary: nextcloud is down
description: 'nextcloud has been unreachable for 5m (SLI: up).'