14 Commits
Author SHA1 Message Date
Scooby Husky a869a5a67f Add CNPG ScheduledBackup for authentik/n8n/nextcloud - WAL archiving alone isn't restorable
Found while building the VPS replica clusters (Phase 2): all three
CNPG clusters' backup.barmanObjectStore blocks only configure continuous
WAL archiving. CNPG's bootstrap.recovery needs at least one real Backup
object in the object store before it has anything to restore -
'no target backup found', confirmed live against pg-authentik. This gap
was systemic (gitlab has it too, not fixed here - out of scope for
tonight, no VPS standby depends on it).

immediate: true fires one backup right away in addition to the daily
01:00 schedule, to unblock the in-progress VPS restore now rather than
waiting up to 24h for the first scheduled run.
2026-08-17 22:49:50 -05:00
Scooby HuskyandClaude Sonnet 5 7d73542645 Fix nextcloud-pvc-sync: add fsGroup for data access, fix restic cache dir
Now that the endpoint/credentials are fixed and this job can actually
reach the VPS, it surfaced two more real bugs: no fsGroup (couldn't read
the PVC data at all - nextcloud's real Deployment uses fsGroup 33/www-data,
this job never matched it) and no writable cache dir for runAsUser 65534
(restic defaults to $HOME/.cache).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:05:38 -05:00
Scooby HuskyandClaude Sonnet 5 2fc7fb5b59 Fix Nextcloud Redis config: use externalRedis, not redis (bundled subchart toggle)
redis.enabled: true was unintentionally deploying the chart's BUNDLED redis
subchart (redis-21.1.3, StatefulSet nextcloud-redis-replicas) alongside
the actual redis-operator instance - that key's schema is pure subchart
passthrough (auth/image/master/replica), it has no host field. The
host/existingSecret keys previously set there were silently ignored.
Found while investigating why nextcloud-redis-replicas-0 was
crash-looping on failed liveness probes (confirmed via : the correct key for pointing at an external Redis
is the separate externalRedis: block).

This means Nextcloud's config.php may never have been correctly pointed
at the redis-operator instance despite apps/nextcloud/manifests/redis-cr.yaml
existing and being healthy - worth confirming file-locking/caching
actually engages after this deploys.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 20:54:28 -05:00
Scooby HuskyandClaude Sonnet 5 018eb3570f Build real pod-egress routing to the VPS, fix everything blocked by its absence
Root cause of tonight's earlier CrowdSec/CNPG-backup workarounds: no node
in the cluster had any route into the Netbird mesh CIDR (100.108.0.0/16)
for pod-originated traffic. The per-namespace netbird 'router' pods are
inbound-only infrastructure (external peers reaching K8s services); their
own architecture has no reverse path.

Fix, in two parts:

1. infrastructure/netbird/manifests/egress-daemonset.yaml - one netbird
   client per node, hostNetwork so its wt0 interface lives in the node's
   real network namespace, plus a sidecar that adds a host route sending
   100.108.0.0/16 out via it. hostNetwork requires a scoped Kyverno
   PolicyException (infrastructure/kyverno/policies/netbird-egress-exception.yaml)
   to the disallow-host-namespaces STIG policy - narrowly for this one
   DaemonSet by name, not a namespace-wide exclusion.

2. Discovered the route alone wasn't enough for k3s NodePort traffic
   (vps-minio:30900): Netbird manages its own nftables ACLs independent of
   iptables/Kyverno, and its forward chain (netbird-rt-fwd) only permits
   *established* connections through a peer acting as a router - never new
   ones, by design, unless a Netbird 'Network Route' policy is explicitly
   configured (it isn't, for this VPS). Locally-terminated connections
   (tinyproxy) go through a separate, already-permissive ACL chain, which
   is why the CrowdSec proxy fix from earlier tonight worked. Replicated
   that working pattern for MinIO: minio-forward.service on the VPS host
   (systemd, socat) forwards 100.108.113.41:9000 -> MinIO's ClusterIP,
   avoiding the NodePort path entirely.

Re-enabled everything that was disabled/suspended earlier tonight because
of this gap, pointed at the new endpoint:
- CrowdSec CAPI/console-enroll (removed DISABLE_ONLINE_API, restored the
  VPS proxy env vars)
- n8n/nextcloud/authentik CNPG backup.barmanObjectStore
- vault-raft-snapshot CronJob (unsuspended)
- nextcloud PVC content sync CronJob endpoint

vps-minio.netbird.internal is retired everywhere - it was never actually
resolvable (Netbird has no DNS configured) even before today's routing
fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 20:36:13 -05:00
Scooby HuskyandClaude Sonnet 5 2c8d29c51f Disable VPS MinIO backup on n8n/nextcloud/authentik CNPG clusters
Discovered while debugging pg-n8n's recurring 'Instance Status Extraction
Error': the root cause is the same missing pod-egress route to the Netbird
mesh found tonight while fixing CrowdSec - continuousArchiving kept failing
to connect to vps-minio.netbird.internal, and CNPG correctly holds
Ready=False while archiving is broken (a real condition, not cosmetic).
That's what was driving these three apps' ArgoCD health flapping.

No node in the cluster has any route into 100.108.0.0/16 for
pod-originated traffic - the per-namespace netbird 'router' pods
(gitlab, vault, argocd, etc.) are inbound-only infrastructure, not egress
gateways. gitlab's own CNPG backup is unaffected (points at a local
in-cluster MinIO, not the VPS).

Commented out rather than deleted - re-enable once real pod-egress
routing exists, tracked as a separate task. No data loss: this is WAL
archiving/backup, not the live database.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 19:45:04 -05:00
Scooby Husky 9bb4ada1f5 Fix Redis CR permission denied on PVC (needs fsGroup)
redis-nextcloud-0 was CrashLoopBackOff: "mkdir: can't create directory
'/node-conf': Permission denied" and same for appendonlydir - the pod
had no podSecurityContext, so it couldn't write to its own PVC-backed
data directories. Added fsGroup/runAsUser: 1000 matching the
opstree/redis image's default non-root user. Verified live: Redis now
starts cleanly ("Ready to accept connections").
2026-08-17 17:20:16 -05:00
Scooby Husky a8b16fa4cb Fix Redis CR apiVersion/schema - v1beta2 doesn't exist, blocked whole nextcloud sync
apps/nextcloud/manifests/redis-cr.yaml used redis.redis.opstreelabs.in/v1beta2
(guessed, flagged as unverified when written) - the actually-installed CRD
only has v1beta1. ArgoCD validates all resource API groups/versions before
syncing anything, so this one bad apiVersion blocked the ENTIRE nextcloud
Application from syncing at all (every resource showed OutOfSync, not just
this one).

Also fixed against the live CRD schema: redisSecret belongs nested under
kubernetesConfig, not top-level, and redisExporter.image is required by the
schema even when enabled: false.

Verified live: kubectl apply succeeded and the Redis resource was created
before committing this.
2026-08-17 16:56:20 -05:00
Scooby Husky 99b8ca6be9 Fix Nextcloud OIDC client_id/secret - was hardcoded empty
apps/nextcloud/values.yaml had oidc_login_client_id/secret as literal
empty strings, causing "client_id is missing or invalid" on login.
The matching Authentik blueprint (infrastructure/authentik/nextcloud-
blueprint.yaml) already defines fixed credentials for this OAuth2
provider - just never got copied over. Filled in to match.

Also found and left alone: an orphaned nextcloud-oidc-config ConfigMap
(from January) that already had the correct values but isn't actually
mounted by the current Deployment (which uses nextcloud-config instead)
- harmless dead resource, not the active config path.
2026-08-17 16:33:47 -05:00
Scooby Husky ee71e4f46f Fix DDNS/failover Cloudflare zone name and add restricted PSS securityContext
- ZONE_NAME was "kube.huskypup.net" in both the home-ip-ddns CronJob and
  the VPS failover watcher - that's a record, not a Cloudflare zone (the
  actual zone is the parent "huskypup.net"). Caused home-ip-ddns to fail
  every run (zone lookup returned zero results, curl -f exit 22) -
  confirmed live and fixed.
- Added seccompProfile/non-root/dropped-capabilities securityContext to
  the three CronJobs added this session that were missing it (flagged by
  the cluster's "restricted" PodSecurity admission). Repointed the raft
  snapshot job's mc binary install from /usr/local/bin to /tmp so it
  still works running as non-root.
2026-08-17 15:55:47 -05:00
Scooby Husky 7990f1fa47 Add VPS warm-standby/backup site (Phase 0-1b)
Foundation for a DR/backup path using an always-on VPS as a second
ArgoCD-managed cluster, plus DB/backup standardization work that fell
out of it:

- vps-standby ArgoCD cluster destination + AppProject, MinIO backup
  receiver, VPS bootstrap script (k3s, Netbird, cert-manager)
- Dual-site DNS failover watcher + home-IP DDNS CronJob, Cloudflare
  token moved out of git into Vault+ExternalSecret
- Nextcloud migrated from ad-hoc MariaDB to CNPG + redis-operator
  (matches n8n/Authentik/GitLab's backup-native pattern)
- Authentik's CNPG manifests moved into the actual ArgoCD-synced
  manifests/ path (were present but never wired into the sync path)
- Vault raft-snapshot CronJob, CNPG barmanObjectStore backups
  (Authentik/n8n/Nextcloud), Nextcloud file-PVC restic sync - all
  targeting the new VPS MinIO receiver

See VPS Warm-Standby plan doc for full design rationale.
2026-08-17 14:59:26 -05:00
Scooby HuskyandClaude Opus 4.6 131cbca4a6 Fix ArgoCD ServerSideDiff permanent OutOfSync diffs
Add explicit CRD/API defaults to manifests that were causing ArgoCD's
SSA dry-run to produce results different from live state:

- HTTPRoutes: add group, kind, weight defaults to parentRefs/backendRefs
- Kyverno ClusterPolicies: add skipBackgroundRequests, allowExistingViolations
- Tetragon TracingPolicies: add return, maxData, resolve, returnCopy defaults
- Gateway certificateRefs: add group="" default
- Guacamole Gateway: add group="" to certificateRefs

Add ignoreDifferences for resources that legitimately differ:
- Cilium cert Secrets (auto-generated, data always differs)
- Istio ValidatingWebhookConfiguration failurePolicy (istiod mutates)
- Crowdsec LAPI Secrets (randomly generated)
- ServiceMonitor/PodMonitor relabeling action defaults
- StatefulSet volumeClaimTemplates apiVersion/kind defaults

Persist argocd-cm ignoreDifferences config in ArgoCD Helm values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 17:32:59 -05:00
Scooby HuskyandClaude Opus 4.6 7436462a10 Fix nextcloud PVC size to match cluster capacity (200Gi)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 04:09:14 -05:00
Scooby HuskyandClaude Opus 4.6 7640fb895b Fix degraded ArgoCD applications
- frigate: Remove duplicate PVCs (Helm manages them), update config size to 15Gi
- gitlab: Fix sync-admin-job secretKeyRef schema error, fetch password via kubectl
- nextcloud: Remove duplicate PVC, remove invalid pod-level securityContext
- rook-ceph: Update cephfs-smb-pvc to 50Gi, remove unsupported dashboard.config
- nessus: Add privileged PSS label for NET_ADMIN/NET_RAW capabilities
- scylla-manager: Add privileged PSS label for SYS_NICE capability
- n8n: Create missing n8n-main-persistence PVC
- projects: Add authentik namespace to applications project destinations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 00:05:29 -05:00
Scooby Husky aacb8eebbe Initial commit 2026-03-09 20:21:35 -05:00