Per CLAUDE.md MIRROR-EVERYTHING inviolable rule: every chart-hook image reference (pre/post-install Jobs, helper Pods) must use the explicit Harbor proxy-cache form. Fix #158's bitnami → bitnamilegacy swap was a band-aid; the architecturally correct fix is to defeat upstream-deletion blast radius entirely by routing through Harbor. The node-level containerd mirror in infra/hetzner/cloudinit-control- plane.tftpl (line 706) already redirects docker.io/* → harbor.openova.io/proxy-dockerhub/* implicitly, but implicit routing: - Hides the routing from SBOM scans - Bypasses the Kyverno harbor-proxy-pull ClusterPolicy - Means a chart audit (`grep docker.io`) misses a real dependency - Was the proximate cause of prov #27 wedging when Bitnami deleted docker.io/bitnami/kubectl:1.30.4 (Fix #158 had to chase the deletion mid-flight instead of being insulated by Harbor cache) 19 chart-hook image: refs + 5 chart values.yaml repository: defaults now carry the explicit harbor.openova.io/proxy-dockerhub prefix. Application/subchart images (keycloak, postgresql, mongodb in keycloak+litmus subcharts) are intentionally out of scope for this PR — those go through the node-level containerd mirror still. Affected blueprints + chart version bumps: bp-cert-manager 1.2.1 -> 1.2.2 bp-external-secrets-stores 1.0.4 -> 1.0.5 bp-crossplane-claims 1.1.4 -> 1.1.5 bp-flux 1.2.1 -> 1.2.2 bp-guacamole 0.1.16 -> 0.1.17 bp-self-sovereign-cutover 0.1.28 -> 0.1.29 bp-k8s-ws-proxy 0.1.9 -> 0.1.10 bp-harbor 1.2.15 -> 1.2.16 bp-gitea 1.2.5 -> 1.2.6 bp-newapi 1.4.5 -> 1.4.6 bp-wordpress-tenant 0.2.0 -> 0.2.1 catalyst-platform 1.4.138 -> 1.4.139 Co-authored-by: e3mrah <1234567+e3mrah@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
218 lines
10 KiB
YAML
218 lines
10 KiB
YAML
# Catalyst Blueprint values for bp-guacamole.
|
||
#
|
||
# Per docs/INVIOLABLE-PRINCIPLES.md:
|
||
# #1 waterfall — chart ships the full target shape (guacd + web +
|
||
# OIDC + recordings + NetworkPolicy + Keycloak realm-config)
|
||
# on the first cut; no "for now" subset.
|
||
# #4 never hardcode — every operationally-meaningful value is
|
||
# configurable via per-Sovereign overlay.
|
||
# #4a SHA-pinned images; CI fills .tag at promotion time. Empty
|
||
# tag fails fast (see _helpers.tpl).
|
||
# #5 credentials live in K8s Secrets, never in values.yaml.
|
||
#
|
||
# Default-OFF: `enabled: false` per the standard CC3 gate. Operators
|
||
# opt in via per-Sovereign overlay.
|
||
|
||
catalystBlueprint:
|
||
upstream:
|
||
chart: "" # scratch chart — no upstream Helm chart
|
||
version: ""
|
||
repo: ""
|
||
# Top-level enable gate. When false, NO resources render. Verified by
|
||
# `helm template` test in tests/.
|
||
guacamole:
|
||
enabled: false
|
||
# ── guacd: protocol backend ─────────────────────────────────────
|
||
guacd:
|
||
# Resource name. Defaults to `guacd` so the catalyst-api shells/issue
|
||
# handler + qa-loop test matrix (TC-228 / TC-230 / TC-245 / TC-246)
|
||
# can address the Deployment + Service by canonical short name.
|
||
# Override only when running >1 Guacamole in the same namespace
|
||
# (rare; ADR-0001 §11 caps at one Guacamole per Sovereign).
|
||
name: guacd
|
||
image:
|
||
# Mirrored to GHCR by .github/workflows/build-bp-guacamole.yaml so
|
||
# every Sovereign pulls from a registry we own (no Docker Hub rate
|
||
# limits, no upstream availability risk). Bumped automatically by
|
||
# CI when the upstream Apache Guacamole version is rolled.
|
||
repository: ghcr.io/openova-io/openova/guacd
|
||
# SHA-pinned per INVIOLABLE-PRINCIPLES #4a. CI populates this via
|
||
# `yq eval -i ...`. Empty value fails the helm template render
|
||
# (see _helpers.tpl `bp-guacamole.guacdImage`). Initial seed is
|
||
# the upstream-tagged GHCR mirror; CI may pin to a digest tag.
|
||
tag: "1.5.5"
|
||
pullPolicy: IfNotPresent
|
||
replicas: 1
|
||
resources:
|
||
requests:
|
||
cpu: 100m
|
||
memory: 128Mi
|
||
limits:
|
||
memory: 512Mi
|
||
port: 4822
|
||
# ── guacamole webapp: Tomcat front-end ─────────────────────────
|
||
webapp:
|
||
# Resource name. Defaults to `guacamole-server` per the qa-loop test
|
||
# matrix + catalyst-api shells/issue handler.
|
||
name: guacamole-server
|
||
image:
|
||
# GHCR mirror of docker.io/guacamole/guacamole; see guacd.image
|
||
# comment for the mirror rationale.
|
||
repository: ghcr.io/openova-io/openova/guacamole-server
|
||
tag: "1.5.5"
|
||
pullPolicy: IfNotPresent
|
||
# Single replica + 256Mi request: omantel chroot single-node-per-region
|
||
# capacity profile. catalyst-api PVC pins it to one worker (w3 on
|
||
# omantel), and 2× 512Mi guacamole webapp replicas saturated w3 so
|
||
# catalyst-api Pod couldn't reschedule on chart roll. Sovereigns with
|
||
# >1 worker per region can override via values.guacamole.webapp.replicas.
|
||
replicas: 1
|
||
resources:
|
||
requests:
|
||
cpu: 100m
|
||
memory: 256Mi
|
||
limits:
|
||
memory: 768Mi
|
||
port: 8080
|
||
# ── Recording (SeaweedFS PVC) ──────────────────────────────────
|
||
recordings:
|
||
# PVC name. Defaults to `guacamole-recordings`. Override only when
|
||
# multiple Guacamole instances share a namespace.
|
||
pvcName: guacamole-recordings
|
||
pvcSize: 50Gi
|
||
# hcloud-volumes is the canonical Hetzner CSI storageClass per
|
||
# H6 (issue #1118 — `hcloud-volumes` standardisation across
|
||
# Sovereigns). Override per-Sovereign for non-Hetzner clouds.
|
||
storageClass: hcloud-volumes
|
||
mountPath: /recordings
|
||
# qa-loop iter-11 Fix #45 Cluster-A: when an existing PVC is bound
|
||
# to a storageClass different from .storageClass above, the chart's
|
||
# pre-upgrade hook deletes the PVC + bound PV so the new chart-side
|
||
# PVC can be recreated cleanly. PersistentVolumeClaim.spec is K8s-
|
||
# immutable on storageClassName, so without this hook a per-Sovereign
|
||
# overlay flip (e.g. `local-path` → `seaweedfs-storage` after
|
||
# bp-seaweedfs lands) would wedge the bp-guacamole HelmRelease in
|
||
# `Failed to perform remediation: missing target release for rollback`.
|
||
# Default ON because session-recording state on omantel today is
|
||
# ephemeral; flip OFF on Sovereigns with long-lived recording data
|
||
# (operator should snapshot first then re-enable for the upgrade).
|
||
allowMigration: true
|
||
# Image used by the migration hook. The canonical kubectl image
|
||
# surface across OpenOva Sovereigns is docker.io/bitnamilegacy/kubectl
|
||
# (the same one bp-keycloak's realm-config-cli post-deploy Job
|
||
# pulls). Bitnami's 2025-08 secure-images cutover deleted all
|
||
# versioned tags from docker.io/bitnami/kubectl (only :latest +
|
||
# sha256-named tags remain) — bitnamilegacy is the deprecation-
|
||
# fallback path which retains versioned tags AND bash/sh
|
||
# (rancher/kubectl is distroless, would break inline shell). Operator
|
||
# overrides for non-Hetzner Sovereigns by re-mirroring through
|
||
# their own registry (per docs/INVIOLABLE-PRINCIPLES.md #4a — every
|
||
# image traceable to a known-good SHA).
|
||
# Fix #158 (2026-05-11): bumped 1.29.3 -> 1.30.7 to align with
|
||
# k3s 1.30 server version on Hetzner Sovereigns.
|
||
# Fix #163 (2026-05-11, MIRROR-EVERYTHING): explicit
|
||
# harbor.openova.io/proxy-dockerhub prefix per CLAUDE.md inviolable
|
||
# rule.
|
||
migrationImage: harbor.openova.io/proxy-dockerhub/bitnamilegacy/kubectl:1.30.7
|
||
# ── Keycloak OIDC ──────────────────────────────────────────────
|
||
oidc:
|
||
# Issuer URL — render in per-Sovereign overlay as
|
||
# `https://keycloak.<sovereign-fqdn>/realms/catalyst`. Empty
|
||
# value fails the helm template render (see _helpers.tpl
|
||
# `bp-guacamole.oidcIssuer`).
|
||
issuer: ""
|
||
clientId: guacamole
|
||
# Client secret comes from a SealedSecret. The chart materializes
|
||
# the SealedSecret manifest with an empty placeholder; the
|
||
# operator seals the real value via kubeseal.
|
||
clientSecretRef:
|
||
name: guacamole-oidc
|
||
key: client-secret
|
||
# Default-redirect URL — defaults to https://guacamole.<sovereign>/
|
||
# but operator overlay sets the canonical hostname.
|
||
redirectURI: ""
|
||
# Optional groups claim from the IdP — Guacamole reads roles
|
||
# from this claim and maps them to per-connection ACLs.
|
||
groupsClaim: groups
|
||
# ── HTTPRoute (Cilium Gateway) ─────────────────────────────────
|
||
httproute:
|
||
enabled: true
|
||
# Gateway reference. Defaults to the Sovereign's well-known
|
||
# `cilium-gateway` in namespace `gateway-system`; per-Sovereign
|
||
# overlay can rebind.
|
||
parentRef:
|
||
name: cilium-gateway
|
||
namespace: gateway-system
|
||
# Hostname this Guacamole answers on. Empty value fails the
|
||
# helm template render (see _helpers.tpl `bp-guacamole.host`).
|
||
hostname: ""
|
||
# ── NetworkPolicy ─────────────────────────────────────────────
|
||
# When enabled (default), a default-deny baseline is augmented with
|
||
# selective egress to: keycloak (443), k8s-ws-proxy DaemonSet (8080),
|
||
# SeaweedFS S3 endpoint (8333), and the kube-apiserver (443) for
|
||
# the Pod-listing JSP shipped with Guacamole.
|
||
networkPolicy:
|
||
enabled: true
|
||
keycloak:
|
||
namespace: keycloak
|
||
podSelector:
|
||
app: keycloak
|
||
k8sWsProxy:
|
||
namespace: catalyst-system
|
||
podSelector:
|
||
app.kubernetes.io/name: bp-k8s-ws-proxy
|
||
seaweedfs:
|
||
namespace: seaweedfs
|
||
podSelector:
|
||
app: seaweedfs
|
||
component: s3
|
||
# ── NATS audit trail ──────────────────────────────────────────
|
||
audit:
|
||
nats:
|
||
# JetStream subject Guacamole publishes session-open / session-close
|
||
# events to. Consumed by the Sovereign's audit indexer (EPIC-1
|
||
# compliance evaluators) — see canon §3 events bus.
|
||
subject: catalyst.audit
|
||
auditType: guacamole-session
|
||
url: nats://nats-jetstream.nats-jetstream.svc.cluster.local:4222
|
||
# ── Keycloak realm-config integration ─────────────────────────
|
||
# When enabled, the chart emits a ConfigMap that the bp-keycloak
|
||
# post-deploy keycloak-config-cli Job picks up. The ConfigMap
|
||
# patches the `catalyst` realm to add the `guacamole` client +
|
||
# role + group mappings. Operator opt-in to keep
|
||
# bp-guacamole installable in test environments without bp-keycloak.
|
||
realmConfig:
|
||
enabled: true
|
||
# Realm name in Keycloak. Default `catalyst` per existing
|
||
# platform/keycloak realm-config pattern.
|
||
realm: catalyst
|
||
# Namespace where bp-keycloak's keycloak-config-cli post-deploy Job
|
||
# runs. The realm-patch ConfigMap MUST land in this namespace so the
|
||
# Job's label-selector picks it up. Defaults to `keycloak` per the
|
||
# canonical bp-keycloak namespace; override when bp-keycloak runs
|
||
# under a different namespace.
|
||
namespace: keycloak
|
||
# ── Pod-level security context ─────────────────────────────────
|
||
# Both pods run as non-root with read-only root FS — only /tmp
|
||
# and /recordings are writable.
|
||
podSecurityContext:
|
||
runAsNonRoot: true
|
||
runAsUser: 1001
|
||
runAsGroup: 1001
|
||
fsGroup: 1001
|
||
seccompProfile:
|
||
type: RuntimeDefault
|
||
containerSecurityContext:
|
||
allowPrivilegeEscalation: false
|
||
readOnlyRootFilesystem: true
|
||
capabilities:
|
||
drop: [ALL]
|
||
# ── Image pull secret ─────────────────────────────────────────
|
||
# GHCR pull credentials. The catalyst-system namespace's `ghcr-pull`
|
||
# secret is the canonical pull-credential surface across every
|
||
# Sovereign (catalyst-api / catalyst-ui / guacd / guacamole-server /
|
||
# all mount it), so the chart defaults to it. Operator overrides per
|
||
# Sovereign for non-canonical credential names.
|
||
imagePullSecrets:
|
||
- name: ghcr-pull
|