Commit Graph

4 Commits

Author SHA1 Message Date
jordan
0a861d9144 k8s(cluster): close the unauthenticated metrics and peer plane to foreign pods
Before this, ANY pod in the k3s cluster could read tidalDB's :9091 metrics -
corpus size, seqnos, leader identity, all unauthenticated - and reach the peer
gRPC plane. Measured, not assumed: scraping tidaldb-0:9091 from gitea-0 in
namespace threesix returned metrics, and returns "connection refused" after this.
NetworkPolicy enforcement on this k3s is therefore confirmed, not presumed.

Ingress only. Egress is left unrestricted deliberately - the WAL-archival/S3 and
peer dial-out surfaces are not fully enumerated, and a wrong egress rule
partitions the cluster instead of merely blocking a scrape.

:9500 stays open, and the file records why. All three probes (startup, readiness,
liveness) target it, probes come from the NODE rather than a pod, and node-to-pod
handling is CNI-specific - a wrong rule there fails liveness at 6x10s and restarts
every pod. The exposure that would have closed is /cluster/status, which is
unauthenticated by design. That is an engine defect and gets fixed in
tidal-server, not worked around at the network layer.

Verified after apply: scraper still collects 353 tidaldb_ series, a quorum-acked
write through the public ingress returns 201, and all three regions report
applied=13322229 lag=0 reachable partitioned=false with zero new restarts.
2026-08-22 00:23:55 -06:00
jordan
087b83154a k8s(cluster): publish the client surface over public TLS, data routes only
tidaldb.threesix.ai now serves the cluster's data surface over a Let's Encrypt
cert, verified end-to-end from the internet: 401 without a bearer, 401 with a
wrong one, 200 with the real key, and a quorum-acked write returning 201 on all
three node IPs.

Three things this had to get right, each of which failed first:

* The backend is HTTPS, not HTTP. Pods serve :9500 over TLS with the internal
  cluster CA whenever grpc_tls is configured, so a plaintext backend dial answers
  500. Added a ServersTransport that VERIFIES that hop - every pod mounts the same
  tidaldb-cluster-tls leaf and its SANs include the client-Service DNS name, so
  serverName pinning validates it without insecureSkipVerify.

* `service.*` annotations are read from the Service, not the Ingress. Putting
  serversscheme/serverstransport on the Ingress is silently ignored and presents
  exactly as a broken backend.

* http01 cannot be used behind any gateway gate that rejects unknown callers,
  because it rejects the ACME challenge too. Uses the Cloudflare dns01 solver.

Deliberately unpublished: /cluster/* (every mutating admin verb shares the SAME
single bearer as the data routes, so a client key could remove members or transfer
shards), /cluster/status (unauthenticated - leaks leader, membership, seqnos),
/openapi.json (unauthenticated, enumerates the admin routes), and /metrics (only
on the headless peers Service, unreachable here).

Documents two controls that are NOT available and why: an IP allowlist cannot work
while the shared Traefik Service runs externalTrafficPolicy=Cluster (svclb SNATs
the client address), and Traefik basicAuth cannot stack in front of the bearer
because both occupy the Authorization header.
2026-08-21 23:14:55 -06:00
jx12n
6651c14adc feat(m11): cluster security (m11p7) + perf instrumentation floor
m11p7 — secure the cluster, all opt-in (pre-m11p7 byte-for-byte):
- gRPC replication mTLS by default via a custom tokio-rustls acceptor +
  DynamicCertResolver; zero-drop content-hash cert rotation (k8s ..data swap,
  no pod restart, no inotify)
- inter-node HTTP TLS sharing the same resolver (one rotation, both planes) +
  per-node keyed-BLAKE3 signed x-tidal-node-token; marker-without-token -> 403
- admin audit log (operator-leg only) + per-principal rate limit (engine
  RateLimiter; sibling nodes exempt)
- k8s cert-manager manifest (certs.yaml) + scripts/gen-cluster-certs.sh fallback;
  secret.example.yaml gains TIDAL_CLUSTER_KEY (file-mounted, hot-rotatable)
- exit gate verified real: mtls.rs (gRPC foreign-pod), cluster_security.rs
  (HTTP foreign + zero-drop rotation under load), 7 security unit tests

perf — instrument floor (sweep Wave 1):
- new tidal/benches/wal.rs + tidal-server/benches/scatter.rs
- p99->mean honesty relabel; sweep manifest at docs/reviews/perf-sweep-2026-06-13.md
- add @tidal-performance agent (Martin Thompson)

new: cluster/{audit,http_tls,security}.rs, tests/cluster_security.rs,
docs/planning/milestone-11/phase-7.md
2026-06-13 01:25:35 -06:00
jx12n
bf57be18e1 feat(m11): membership, snapshot install, and reseed (m11p5) 2026-06-12 19:55:54 -06:00