Files

88 lines
6.4 KiB
Markdown

# platform/
Cluster-wide **platform services**, Flux-managed (**R-PLAT-01**, **R-GITOPS-01/02/03**). Reconciled
by the `platform` Flux Kustomization defined in [`clusters/base/platform.yaml`](../clusters/base/platform.yaml),
**before** `apps/`.
Governing spec: [`docs/05-gitops-and-delivery.md`](../../home-network-k3s/docs/05-gitops-and-delivery.md),
[`docs/01-architecture-overview.md`](../../home-network-k3s/docs/01-architecture-overview.md).
> **Phase 0 scaffolding only.** Every component here is a structurally-correct **stub** — a Flux
> HelmRelease and/or Kustomization with a values placeholder, a README citing the governing ADR/spec,
> and TODOs for the phase that fills it in. **No cluster exists**; nothing reconciles yet. Do not add
> working config, secrets, or provisioning under Phase 0 (spec `AGENTS.md` §1/§5/§6, `roadmap/phases.md`).
## Reconciliation flow (how a change lands)
```
git (source of truth)
│ operator PR → CI (lint · schema · Kyverno L0 · Chainsaw) → merge to tracked branch
▼
Flux GitRepository (clusters/base/flux-system.yaml)
▼
Flux Kustomization "platform" → ./platform (this dir) ── substituteFrom cluster-vars ──┐
│ prune=true (drift correction, R-GITOPS-03) · wait=true │ R-ENV-02
▼ │
Flux Kustomization "apps" → ./apps (dependsOn platform) ─ substituteFrom cluster-vars ──┘
```
Git is authoritative; the cluster conforms to git and drift is auto-corrected (R-GITOPS-01/03).
Manual `kubectl apply` of platform state is prohibited (spec `AGENTS.md` §5).
## The dev ↔ prod overlay model (R-ENV-02)
Platform manifests are authored **once**. Every value that legitimately differs between environments
is a `${TOKEN}` resolved from the `cluster-vars` ConfigMap via Flux `postBuild.substituteFrom`. The
`clusters/dev` and `clusters/prod` overlays differ **only** by the values they patch into
`cluster-vars` (issuer, replica counts, storage sizes, retention). See
[`clusters/README.md`](../clusters/README.md). Base manifests are **never forked per environment**.
## Components (one directory each)
| Dir | Component | Governing ADR / spec | Serves |
|---|---|---|---|
| `cilium/` | CNI + kube-proxy replacement + Gateway API + Egress Gateway + Hubble | [ADR-0002](../../home-network-k3s/decisions/adr-0002-cni-cilium.md), docs/03 | R-NET-* |
| `longhorn/` | Replicated block storage; 3-replica default StorageClass + bulk tier | [ADR-0003](../../home-network-k3s/decisions/adr-0003-storage-longhorn.md), docs/04 | R-STATE-* |
| `cert-manager/` | TLS via Let's Encrypt DNS-01 (Cloudflare); staging + prod ClusterIssuers | [ADR-0006](../../home-network-k3s/decisions/adr-0006-tls-cert-manager-letsencrypt.md), docs/08 | R-TLS-* |
| `externaldns/` | Automatic DNS records for public services (Cloudflare) | docs/09 | R-DNS-* |
| `gateway/` | Gateway API GatewayClass + shared HTTPS Gateway + wildcard cert | [ADR-0002](../../home-network-k3s/decisions/adr-0002-cni-cilium.md)/[ADR-0006](../../home-network-k3s/decisions/adr-0006-tls-cert-manager-letsencrypt.md), docs/09 | R-DNS-01, R-TLS-01 |
| `monitoring/` | kube-prometheus-stack + Loki + Grafana Alloy + Alertmanager | docs/10 | R-OBS-* |
| `velero/` | Off-cluster backup/DR of volumes + resource state | [ADR-0003](../../home-network-k3s/decisions/adr-0003-storage-longhorn.md), docs/04 | R-STATE-03 |
| `kubevirt/` | KubeVirt + CDI (IaaS: application VMs on the same K8s surface) | [ADR-0005](../../home-network-k3s/decisions/adr-0005-vm-workloads-kubevirt.md), docs/06 | R-PLAT-03 |
| `image-automation/` | Flux image-update-automation (hands-off image tag advance) | [ADR-0009](../../home-network-k3s/decisions/adr-0009-automated-image-updates.md), docs/11 | R-UPD-02 |
| `keycloak/` | Platform IdP (OIDC + SAML), config-as-code, PostgreSQL on Longhorn | [ADR-0014](../../home-network-k3s/decisions/adr-0014-idp-keycloak.md), docs/15 | R-IDP-* |
| `oauth2-proxy/` | Forward-auth at the Gateway for non-OIDC apps → Keycloak | [ADR-0014](../../home-network-k3s/decisions/adr-0014-idp-keycloak.md), docs/15 | R-IDP-* |
| `kyverno/` | **L0 policy-as-code gate — OWNED BY THE POLICY ENGINEER (WS-TEST).** | [ADR-0011](../../home-network-k3s/decisions/adr-0011-test-tooling-kyverno-chainsaw.md), docs/14 | R-TEST-* |
## ⚠️ INTEGRATION TODO(PM): wire kyverno into the platform kustomization
`platform/kyverno/` is authored by a **different agent** (the policy engineer, WS-TEST). This
workstream did **not** create any files under `platform/kyverno/` and must not.
[`platform/kustomization.yaml`](kustomization.yaml) intentionally **omits `- kyverno`**. Once the
policy engineer's files land, the **PM** must add `- kyverno` to that list (recommended first, so
policies are present before other components reconcile). The line is present as a commented TODO in
the kustomization.
## Secrets
Every secret referenced below (Cloudflare API token, Velero backup-target creds, Keycloak admin/DB,
oauth2-proxy cookie/client secrets) is referenced **by name only** and will be committed
**SOPS-encrypted** (WS-SEC, [ADR-0007](../../home-network-k3s/decisions/adr-0007-secrets-sops-age.md)).
**No plaintext secret appears anywhere in this tree.**
## Cross-workstream contracts surfaced by these stubs
- **cilium (WS-NET ↔ WS-INFRA):** Cilium's *initial* CNI install is done by Ansible at cluster
bootstrap (docs/02, Phase 1). The HelmRelease here manages Cilium *config* thereafter; its Helm
values MUST match the Ansible bootstrap values (kubeProxyReplacement, k8sServiceHost/Port, API
server host) or reconciliation will fight the bootstrap. Contract owner: WS-NET + WS-INFRA.
- **gateway + cert-manager + externaldns (WS-NET + WS-SEC):** the shared Gateway listener, the
wildcard `*.home.keithjackson.dev` cert, and the ExternalDNS source all reference each other; they
form the "Issuer + Gateway TLS" interface in `roadmap/workstreams.md`.
- **image-automation (WS-UPDATE):** this dir holds only the *cluster-wide* ImageUpdateAutomation +
git write-back. Per-service `ImageRepository`/`ImagePolicy` are rendered from each
ServiceDefinition's `update` block (WS-GITOPS/WS-UPDATE), living with `apps/`.
- **keycloak/oauth2-proxy (WS-SEC):** the SSO/auth contract (`auth` block → Keycloak client /
oauth2-proxy protection) is owned by WS-SEC; these are placeholders pending that contract.