openova/platform/guacamole/blueprint.yaml
e3mrah 639b94fe55
feat(epic-4): K+P+X1+G — k8s-ws-proxy + projector + WebSocket logs + Guacamole chart (#1099) (#1164)
EPIC-4 Slice K+P+X1+G — bundled backend infrastructure for the
"k9s-on-web" Cloud Resources experience:

K1 — core/cmd/k8s-ws-proxy/ — per-node WebSocket exec proxy.
HMAC-signed (X-Catalyst-HMAC: SHA256({timestamp}:{path})) WebSocket
upgrades on /proxy/exec/{ns}/{pod}/{container} bridged to the local
kube-apiserver via in-cluster ServiceAccount. v4.channel.k8s.io
subprotocol echo. Optional TMUX_CASCADE wraps in a shared
catalyst-ops tmux session. Shipped as a DaemonSet + Service with
internalTrafficPolicy=Local in platform/k8s-ws-proxy/chart/.

P1 — core/cmd/projector/ — NATS catalyst.events JetStream → Valkey
KV projector. Canonical key shape:
  cluster:{cluster-id}:kind:{kind}:{namespace}/{name}
Cold-start does a full LIST across DefaultKinds, then catches up on
the 24h replay window. Multi-replica safe (durable consumer queue
group, last-write-wins on namespacedName). Shipped as a default-OFF
Deployment + RBAC under products/catalyst/chart/templates/services/projector/.

X1 — products/catalyst/bootstrap/api/internal/handler/k8s_logs.go —
WebSocket Pod-log streaming endpoint:
  GET /api/v1/sovereigns/{id}/k8s/logs/{ns}/{pod}/{container}
      ?follow&tailLines&since=<rfc3339>&previous
Reads from kubelet via client-go GetLogs().Stream(); each WS frame =
one log line. Supports `since` resume. Reuses RequireSession middleware
+ chroot cluster-id resolver. New k8scache.Factory.CoreClient(id)
accessor exposes the per-cluster typed client without duplicating
kubeconfig parsing.

G1 — platform/guacamole/chart/ — full Apache Guacamole chart:
guacd Deployment + Service, Tomcat webapp Deployment + Service,
Cilium Gateway HTTPRoute, SeaweedFS-PVC for recordings (RWO,
hcloud-volumes), SealedSecret placeholder for Keycloak OIDC client
secret, NetworkPolicy (default-deny + selective egress to KC +
k8s-ws-proxy + SeaweedFS + NATS), and ConfigMap consumed by
keycloak-config-cli post-deploy Job (mirrors platform/keycloak
realm-config pattern). Default-OFF gate; full-ON renders 9
resources. Empty image.tag / hostname / oidc.issuer fail-fast at
helm template time per INVIOLABLE-PRINCIPLES #4a/#5. ONE Guacamole
per Sovereign per ADR-0001 §11. Blueprint manifest uses
v1alpha1 + version "0.1.0" + upgrades.from ["0.x"].

Tests:
- k8s-ws-proxy: HMAC happy/expired-old/expired-future/malformed/
  bad-signature, path-only signature, WS upgrade + protocol echo,
  bad path, bad HMAC, denied namespace via httptest.
- projector: Apply ADD/MOD/DEL/validation, key shape (ns-scoped +
  cluster-scoped), handleOne ack/nak/term routing with fakeMsg,
  cold-start LIST + project + error continuation via dynamicfake.
- X1: parseLogOptions defaults + edge cases + bad query params,
  503/404/400 paths + full WS happy-path with kfake clientset.
- G1: chart/tests/render.sh — default-OFF=0, empty-tag fail-fast,
  full-ON=9 resources, every required kind present, realm-config
  wires OIDC client.
- bp-k8s-ws-proxy chart: chart/tests/render.sh — default-OFF=0,
  empty-tag fail-fast, full-ON=5 resources.

Pre-existing test status: TestPinIssue and TestBootstrapKit/gitea
remain flaky on main per canon §7 — verified not introduced by
this slice.

Co-authored-by: hatiyildiz <hati.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:27:39 +04:00

52 lines
1.5 KiB
YAML

apiVersion: catalyst.openova.io/v1alpha1
kind: Blueprint
metadata:
name: bp-guacamole
labels:
catalyst.openova.io/section: pts-3-1-networking-and-service-mesh
catalyst.openova.io/category: platform
spec:
version: 0.1.0
card:
title: Apache Guacamole
summary: Clientless HTML5 remote-desktop gateway. Browser-based RDP / VNC / SSH and kubectl-exec into Pods, with Keycloak SSO and full session recording to SeaweedFS. One Guacamole per Sovereign per ADR-0001 §11.
icon: guacamole.svg
category: platform
visibility: listed
configSchema:
type: object
properties:
enabled:
type: boolean
default: false
description: Default-OFF gate. Operator opts in via per-Sovereign overlay.
hostname:
type: string
description: Browser-facing hostname (e.g. guacamole.<sovereign-fqdn>). Required when enabled.
oidcIssuer:
type: string
description: Keycloak realm issuer URL. Required when enabled.
recordingsSize:
type: string
default: "50Gi"
description: Per-Sovereign session-recording PVC size.
placementSchema:
modes: [single-region]
minRegions: 1
maxRegions: 1
upgrades:
from: ["0.x"]
manifests:
chart: ./chart
depends:
- blueprint: bp-keycloak
version: ^1
- blueprint: bp-cilium
version: ^1
- blueprint: bp-seaweedfs
version: ^1
- blueprint: bp-sealed-secrets
version: ^1
- blueprint: bp-k8s-ws-proxy
version: ^0