Commit Graph
4354 Commits
Author SHA1 Message Date
k.rennerandClaude Opus 4.6 5225f9e35c feat: Add Authentik OIDC authentication to Grafana
Configure Grafana to use the K8s-internal Authentik instance for
OAuth2 login. Infrastructure Admins group gets Admin role, others Viewer.

Client credentials stored in SOPS-encrypted secret.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 09:50:25 +02:00
k.rennerandClaude Opus 4.6 8009b23d8e fix: Allow ingress-nginx to reach authentik namespace
The nginx egress policy only allowed traffic to the apps namespace.
Authentik is now in its own namespace, so nginx couldn't proxy to it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 08:59:18 +02:00
k.rennerandClaude Opus 4.6 ca64f1be4e feat: Add auth.k.renner.uno test ingress for Authentik
Internal-only test ingress (no Cloudflare proxy) for validating
K8s Authentik before DNS cutover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:58:48 +02:00
k.rennerandClaude Opus 4.6 d4652ba931 fix: Temporarily remove test ingress to allow HelmRelease upgrade
The chart ingress still has auth.k.renner.uno from a prior deploy.
Need to let the HelmRelease upgrade remove it first, then add the
standalone test ingress in a follow-up commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:57:17 +02:00
k.rennerandClaude Opus 4.6 8401d55968 fix: Use internal-only test ingress for auth.k.renner.uno
Revert Cloudflared wildcard route - k.renner.uno is internal only.
Create separate ingress for auth.k.renner.uno without cloudflare-proxied
annotation so only UniFi ExternalDNS picks it up (A record to VIP).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:50:04 +02:00
k.rennerandClaude Opus 4.6 dbee836941 feat: Add *.k.renner.uno test domain for K8s services
Add wildcard Cloudflared route for *.k.renner.uno to test K8s services
before doing DNS cutover from old infrastructure. Add auth.k.renner.uno
as additional host on Authentik ingress.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:48:37 +02:00
k.rennerandClaude Opus 4.6 6d4f83ba5f fix: Remove unnecessary namespace access from apps network policy
Only grant access that is currently needed. Database and monitoring
namespace access was added speculatively - removed per least-privilege.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:31:55 +02:00
k.rennerandClaude Opus 4.6 d80cb2de69 feat: Move Authentik to dedicated namespace
Isolate Authentik (identity provider) from the shared apps namespace:
- Create authentik namespace
- Move all resources (HelmRelease, CNPG cluster, secrets) to authentik ns
- Add dedicated FluxCD Kustomization for Authentik
- Add Cilium network policies for authentik namespace
- Update DB hostname FQDN to authentik namespace

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:30:57 +02:00
k.rennerandClaude Opus 4.6 4692d4c646 fix: Allow CNPG operator and monitoring to reach apps namespace
The CNPG operator in the database namespace needs to reach port 8000
on PostgreSQL pods for status extraction. Without this, it cannot
determine cluster health or create replica instances.

Also allow monitoring namespace for Prometheus scraping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:26:04 +02:00
k.rennerandClaude Opus 4.6 74189481e9 fix: Rename Authentik DB to avoid K8s service link collision
K8s injects AUTHENTIK_DB_RW_*, AUTHENTIK_SERVER_* env vars because
services are named authentik-*. Authentik parses ALL AUTHENTIK_*
env vars and crashes. Rename DB cluster to ak-pg to avoid collision.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:31:31 +02:00
k.rennerandClaude Opus 4.6 d045c090fe fix: Pass Authentik secrets via global.env, not nested values
The Authentik config parser fails with 'Attr has no get' when
secrets are passed via nested value fields. Use global.env with
secretKeyRef for PostgreSQL password, secret key, and SMTP password.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:25:20 +02:00
k.rennerandClaude Opus 4.6 739a67e900 feat: Deploy Authentik via official Helm chart
CloudNativePG PostgreSQL (2 replicas), Authentik Helm chart with
2 server + 2 worker replicas. Same secret key as existing deployment.
SOPS secrets, Cloudflared tunnel route, ingress with TLS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:18:15 +02:00
k.rennerandClaude Opus 4.6 07ba0645af fix: Add HelmRepository to external-dns-unifi
The UniFi ExternalDNS is in infrastructure but references the
HelmRepository from apps/external-dns which deploys later.
Duplicate the HelmRepository definition.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:52:57 +02:00
k.rennerandClaude Opus 4.6 dae490a849 feat: Add bootstrap script with progress bar
Automates the full cluster bootstrap. Usage: GITEA_TOKEN=xxx ./kubernetes/bootstrap.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:50:39 +02:00
k.rennerandClaude Opus 4.6 e972fc1f41 revert: Disable ownCloud — needs proper Helm chart configuration
ci/woodpecker/manual/deploy-infrastructure Pipeline was successful
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 21:21:12 +02:00
k.rennerandClaude Opus 4.6 be7d70c681 feat: Deploy ownCloud using official oCIS Helm chart
ci/woodpecker/cron/security-scan Pipeline was successful
Use the official owncloud/ocis-charts Helm chart from Git instead
of custom manifests. The chart handles NATS, service discovery,
collaboration, and all internal wiring correctly.

- FluxCD GitRepository source for the chart
- ONLYOFFICE deployed as a simple Deployment + Service
- Minimal values: domain, ingress, and ONLYOFFICE integration
- Chart manages its own secrets, NATS, and service registry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 22:21:20 +02:00
k.rennerandClaude Opus 4.6 c11183d6c9 revert: Disable ownCloud deployment until ONLYOFFICE integration is solved
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 22:01:53 +02:00
k.rennerandClaude Opus 4.6 cc2a653628 fix: Disable IP filter, rely on network policies for security
ONLYOFFICE IP filter rejects pod CIDR despite being in the allow
list (nginx proxy changes source IP). Disable IP filter and rely
on Cilium network policies to restrict access to ONLYOFFICE.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:58:52 +02:00
k.rennerandClaude Opus 4.6 6a3fef9478 fix: Disable ONLYOFFICE JWT, use IP filter for security
ONLYOFFICE JWT blocks the WOPI discovery endpoint (403). The oCIS
collaboration service doesn't send JWT for discovery requests.

Security model (same as official oCIS example):
- ONLYOFFICE IP filter: only pod CIDR (10.244.0.0/16) allowed
- WOPI tokens signed by oCIS for browser<->collaboration auth
- Cilium network policies restrict pod-to-pod traffic
- External access only via ingress-nginx with CrowdSec

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:52:09 +02:00
k.rennerandClaude Opus 4.6 b9e8e2770d feat: Enable JWT for ONLYOFFICE WOPI communication
Shared WOPI JWT secret (SOPS encrypted) for both collaboration
service and ONLYOFFICE. IP filter restricted to pod CIDR.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:47:45 +02:00
k.rennerandClaude Opus 4.6 b31043aec1 fix: Restrict ONLYOFFICE IP filter to pod CIDR
Only allow WOPI requests from the pod network (10.244.0.0/16).
External requests to ONLYOFFICE are blocked by the IP filter.

JWT remains disabled (same as official oCIS example) — security
is enforced by network policies and IP filtering instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:42:56 +02:00
k.rennerandClaude Opus 4.6 a607780d97 fix: Use lifecycle hook to set ONLYOFFICE wopi.host and IP filter
ci/woodpecker/cron/security-scan Pipeline was successful
Mounting to local.json or local.dist.json breaks ONLYOFFICE startup.
Instead, use a postStart lifecycle hook to patch the generated
local.json after startup to set wopi.host and IP filter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 19:21:07 +02:00
k.rennerandClaude Opus 4.6 b95c19181e fix: Mount ONLYOFFICE config to local.json directly
local.dist.json gets merged with defaults which overwrites the wopi.host.
Mount directly to local.json which takes final precedence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:49:24 +02:00
k.rennerandClaude Opus 4.6 1dedad0614 fix: Use internal URL for WOPI discovery, public URL via ONLYOFFICE wopi.host
Set COLLABORATION_APP_ADDR to internal ONLYOFFICE Service URL for
backend WOPI discovery. Configure ONLYOFFICE local.json with
wopi.host=https://office.renner.uno so the discovery XML response
contains the public URL for browser iframes.

Revert Cilium socketLB hairpin — no longer needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:02:30 +02:00
k.rennerandClaude Opus 4.6 a174ce9a76 fix: Enable socket LB in pod namespaces for VIP hairpin access
Known Cilium issue: pods can't reach L2 LoadBalancer VIPs.
Setting socketLB.hostNamespaceOnly=false enables socket-level
load balancing in pod network namespaces, allowing pods to
access the LB VIP from within the cluster.

Also removes hostAliases workaround and broken CoreDNS config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:58:17 +02:00
k.rennerandClaude Opus 4.6 8e64b4ee4a fix: Add hostAliases to resolve public hostnames to ingress ClusterIP
Pods can't reach the L2 VIP (10.2.40.80) from inside the cluster
(hairpin issue). Use hostAliases to resolve *.renner.uno hostnames
to the ingress-nginx ClusterIP instead.

Also allow apps→ingress traffic in ingress namespace network policy.

TODO: Replace hardcoded ClusterIP with proper CoreDNS rewrite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:56:01 +02:00
k.rennerandClaude Opus 4.6 d777599df9 fix: Set oCIS pod hostname to 'ocis' for NATS service registration
oCIS registers services in NATS using the pod hostname. In Docker
Compose this was 'ocis'. In K8s it's a random pod name. Setting
hostname: ocis makes the registration consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:47:36 +02:00
k.rennerandClaude Opus 4.6 4280760ec8 fix: Remove OCIS_REVA_GATEWAY - let NATS handle gateway discovery
OCIS_REVA_GATEWAY was being used as a NATS service lookup key, not
a direct address. The gateway is registered in NATS by the oCIS
server and should be discovered automatically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:42:27 +02:00
k.rennerandClaude Opus 4.6 4d4326f3fe fix: Clean up gateway config - remove duplicate GATEWAY_GRPC_ADDR
oCIS server binds gateway to 0.0.0.0:9142. Collaboration service
uses OCIS_REVA_GATEWAY for gateway connection. Removed redundant
GATEWAY_GRPC_ADDR from collaboration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:38:43 +02:00
k.rennerandClaude Opus 4.6 6fdef5c406 fix: Use internal Service URL for COLLABORATION_APP_ADDR
ci/woodpecker/cron/security-scan Pipeline was successful
Cluster-internal communication should stay internal, not go through
the external VIP. ONLYOFFICE WOPI discovery uses the internal
Service URL. The browser iframe URL is handled separately by the
WOPI response and ingress routing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:29:49 +02:00
k.rennerandClaude Opus 4.6 0106cd8d99 fix: Enable Cilium socket LB for pod-to-VIP hairpin access
Pods inside the cluster can't reach the L2 LoadBalancer VIP because
Cilium doesn't handle hairpin traffic by default. Enabling socketLB
allows pods to access LB VIPs from within the cluster.

This fixes the collaboration service failing to reach office.renner.uno
(which resolves to the ingress L2 VIP).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:24:44 +02:00
k.rennerandClaude Opus 4.6 b7306a0766 fix: Add egress rules to apps network policy
Apps need to reach the ingress VIP (for OIDC, WOPI discovery via
public URLs). Allow egress to ingress namespace, DNS, host, and world.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:18:38 +02:00
k.rennerandClaude Opus 4.6 8cc38fb72d fix: Add ONLYOFFICE IP filter config and OCIS_URL for collaboration
ci/woodpecker/cron/security-scan Pipeline was successful
The root cause of the 403 errors: ONLYOFFICE has an IP filter in
local.json that only allows connections from specific hostnames.
Add a permissive filter via ConfigMap.

Also add OCIS_URL to the collaboration service (was in the official
example but missing from our config).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 11:00:42 +02:00
k.rennerandClaude Opus 4.6 508d1bf3a8 fix: Disable K8s service links to prevent env var collision
K8s auto-injects OWNCLOUD_SERVICE_HOST, OWNCLOUD_PORT etc. because
the Service is named 'owncloud'. oCIS parses OWNCLOUD_* env vars
for its own configuration, causing conflicts with NATS registry
and service discovery.

enableServiceLinks: false prevents this injection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:47:22 +02:00
k.rennerandClaude Opus 4.6 0494651363 fix: Add OCIS_REVA_GATEWAY to collaboration service
The collaboration service needs the gateway address to register
with the app provider system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:37:09 +02:00
k.rennerandClaude Opus 4.6 63e8069595 fix: Use public URL for ONLYOFFICE app address
COLLABORATION_APP_ADDR is used in the browser iframe. Must be the
public URL (office.renner.uno), not the internal K8s Service URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 09:58:21 +02:00
k.rennerandClaude Opus 4.6 1ee825a68c fix: Set PROXY_CSP_CONFIG_FILE_LOCATION for oCIS
oCIS needs this env var to read the custom CSP config file.
Without it, it uses built-in defaults that block Authentik OIDC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 09:46:59 +02:00
k.rennerandClaude Opus 4.6 b844b463c8 fix: Update CSP to allow Authentik OIDC and ONLYOFFICE
- connect-src: add auth.renner.uno for OIDC discovery
- font-src: add data: for inline fonts
- script-src: add unsafe-eval for ONLYOFFICE
- default-src: add self

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 09:43:20 +02:00
k.rennerandClaude Opus 4.6 ba3847dc71 fix: Use CephFS (ReadWriteMany) for ownCloud config PVC
Config PVC is shared between oCIS and collaboration pods. RBD
(ReadWriteOnce) can't be attached to multiple nodes. CephFS
supports ReadWriteMany.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 09:27:12 +02:00
k.rennerandClaude Opus 4.6 7ad307a889 fix: Split ownCloud into 3 separate Deployments with Services
ONLYOFFICE WOPI callbacks need resolvable hostnames. Split into:
- owncloud (oCIS server + NATS + gateway)
- ocis-collaboration (WOPI bridge between oCIS and ONLYOFFICE)
- onlyoffice (document server)

Each has its own Service for DNS-based discovery. Communication:
- Collaboration → oCIS via owncloud:9233 (NATS) and owncloud:9142 (gateway)
- Collaboration → ONLYOFFICE via onlyoffice:80 (WOPI discovery)
- ONLYOFFICE → Collaboration via ocis-collaboration:9300 (WOPI callbacks)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:55:00 +02:00
k.rennerandClaude Opus 4.6 c42bfe8575 fix: Point collaboration to localhost ONLYOFFICE (same pod)
Collaboration service tried to reach ONLYOFFICE via the external
URL through the ingress VIP, which is blocked by network policy.
Use localhost:80 since they're in the same pod.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:42:40 +02:00
k.rennerandClaude Opus 4.6 38e704c8cd fix: Add oCIS collaboration as separate sidecar container
The collaboration service is not part of 'ocis server' — it runs
as a separate process. Add it as a third container in the pod
with proper WOPI config pointing to localhost for same-pod
communication with ONLYOFFICE.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:35:28 +02:00
k.rennerandClaude Opus 4.6 94c867be41 feat: Add ONLYOFFICE to ownCloud deployment
Add ONLYOFFICE Document Server as a sidecar container with:
- WOPI integration with oCIS collaboration service
- Separate service and ingress for office.renner.uno
- Cloudflared tunnel route for external access
- JWT disabled (WOPI handles auth)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:24:33 +02:00
k.rennerandClaude Opus 4.6 0e3bbf0539 feat: Remove ownCloud DNS CNAMEs from OpenTofu
ci/woodpecker/push/deploy-infrastructure Pipeline was successful
ci/woodpecker/manual/deploy-infrastructure Pipeline was successful
ci/woodpecker/push/security-scan Pipeline was successful
DNS for owncloud.renner.uno now managed by K8s ExternalDNS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:16:54 +02:00
k.rennerandClaude Opus 4.6 acaa8f7401 fix: Allow ingress-nginx egress to K8s API server
ingress-nginx needs API access for leader election, Ingress
watching, and secret/configmap reading. Add kube-apiserver entity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:10:47 +02:00
k.rennerandClaude Opus 4.6 a23f60ca2a fix: Skip ocis init if config already exists
Init only runs on first boot. Subsequent restarts skip init since
the config is persisted on the PVC.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:03:52 +02:00
k.rennerandClaude Opus 4.6 2d7525c47b fix: Use --insecure yes for ocis init, no OCIS_INSECURE at runtime
ocis init --insecure yes skips the interactive prompt and generates
config without internal TLS (handled by ingress-nginx). The runtime
does NOT use OCIS_INSECURE — all TLS validation is enabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 07:58:30 +02:00
k.rennerandClaude Opus 4.6 4126cc86ec fix: Pass --insecure false to ocis init to skip prompt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 07:54:07 +02:00
k.rennerandClaude Opus 4.6 c74ea9a5b5 fix: Fix ownCloud init - proper command, fsGroup for PVC permissions
Remove shell wrapper, use ocis init directly. Set fsGroup=1000
so PVC mounts are writable by the oCIS user.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 07:46:36 +02:00
k.rennerandClaude Opus 4.6 8c582a31f3 fix: Remove OCIS_INSECURE, use secure init
Let oCIS generate internal certificates. Answer 'no' to the
insecure prompt during init. TLS termination handled by ingress.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 07:43:24 +02:00