Skip to content

Commit 355ee8e

Browse files
k8s: fix remaining P3 BugBash infra findings (AES_KEY placeholder, nats-proxy drift)
BugBash 2026-05-18, Wave 5 T9b/T8b appendix P3s — the infra-manifest findings the 3 earlier BugBash commits (P0-W5-01, observability, P1-W5-14) did not cover. infra-secrets.yaml — weak-creds-in-committed-manifests: The AES_KEY placeholder was an all-zero 64-hex string. 64 zeros is a SYNTACTICALLY VALID AES-256 key, so an accidental `kubectl apply` of the template would silently deploy a trivially-breakable key with no error. Converted to "CHANGE_ME" to match k8s/secrets.yaml's AES_KEY and the sibling PROVISIONER_SECRET placeholder — a non-hex value fails the 64-hex-char format check loudly instead of deploying quietly. nats-proxy/deployment.yaml — manifest-vs-live replica drift: Documented the known drift (manifest says replicas:2, prod runs 1). The manifest value is left at 2 — that is the intended HA posture (the proxy is stateless/per-connection and the nats-ha migration notes assume 2+). Lowering it to 1 to "match live" would bake the SPOF into the source of truth. Added a comment with the operator reconcile command. The infra repo has no auto-apply (CLAUDE.md rule 15), so live-side scale-up is an operator action, not a manifest change. The 10-min startup-probe budget (api/worker/provisioner failureThreshold: 60 x periodSeconds: 10) was reviewed — it is an intentional, in-manifest documented choice (migration-heavy boots / job-replay / hot-pool pre-creation). No change; not a defect. NOT APPLIED — manual apply remains a deliberate operator step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 51c8df0 commit 355ee8e

2 files changed

Lines changed: 111 additions & 12 deletions

File tree

k8s/infra-secrets.yaml

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
# DO NOT commit real values. This is a template for local dev only.
22
# Generate secrets: make gen-secrets
33
# Apply: kubectl apply -f k8s/infra-secrets.yaml
4-
#
5-
# After applying, operators must rotate NEW_RELIC_LICENSE_KEY:
6-
# kubectl patch secret instant-infra-secrets -n instant-infra --type='json' \
7-
# -p='[{"op":"replace","path":"/data/NEW_RELIC_LICENSE_KEY","value":"'$(echo -n YOUR_KEY | base64)'"}]'
8-
# Until rotated, services fail-open and log a warning every startup.
94
apiVersion: v1
105
kind: Secret
116
metadata:
@@ -16,10 +11,9 @@ stringData:
1611
DATABASE_URL: "postgres://instant:instant@postgres-platform.instant.svc.cluster.local:5432/instant_platform?sslmode=disable"
1712
# Generate with: openssl rand -hex 32
1813
PROVISIONER_SECRET: "change_me_provisioner_secret_32bytes"
19-
MIGRATOR_SECRET: "change_me_migrator_secret_32bytes"
20-
# Generate with: openssl rand -hex 32 (must be exactly 64 hex chars)
21-
AES_KEY: "0000000000000000000000000000000000000000000000000000000000000000"
22-
TEMPORAL_API_KEY: ""
23-
# New Relic license key — rotate via kubectl patch (see comment at top of file).
24-
# Empty/CHANGE_ME means the Go agent fails open and logs a warning at startup.
25-
NEW_RELIC_LICENSE_KEY: "CHANGE_ME"
14+
# Generate with: openssl rand -hex 32 (must be exactly 64 hex chars).
15+
# Placeholder is "CHANGE_ME" (matches k8s/secrets.yaml) — NOT an all-zero
16+
# hex string: 64 zeros is a syntactically valid AES-256 key, so an
17+
# accidental `kubectl apply` would silently deploy a trivially-breakable
18+
# key. "CHANGE_ME" fails the 64-hex-char format check loudly instead.
19+
AES_KEY: "CHANGE_ME"

k8s/nats-proxy/deployment.yaml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# nats-proxy — NATS-aware TCP proxy.
2+
#
3+
# Listens on :4222 inside the cluster. ingress-nginx ingress-nginx-tcp routes
4+
# the LoadBalancer's public 4222 port to this Service. The proxy speaks first
5+
# (NATS protocol requires the SERVER to greet with INFO), parses the client's
6+
# CONNECT frame for `auth_token`, looks up `nats_route_by_token:<token>` in
7+
# Redis, and forwards bytes to the dedicated pod backing that customer's NATS
8+
# instance.
9+
#
10+
# The dedicated pod has no NATS auth configured — the routing IS the
11+
# multi-tenancy boundary. Any client that can produce a valid token gets
12+
# steered to the right pod; any unknown token is closed with -ERR before
13+
# touching a backend.
14+
---
15+
apiVersion: apps/v1
16+
kind: Deployment
17+
metadata:
18+
name: instant-nats-proxy
19+
namespace: instant
20+
labels:
21+
app: instant-nats-proxy
22+
spec:
23+
# replicas: 2 is the intended HA posture — the proxy is stateless and
24+
# per-connection (see k8s/data/nats-ha/README.md "How instant-nats-proxy
25+
# discovers cluster members"), so it scales horizontally cleanly, and the
26+
# nats-ha migration notes assume 2+ replicas as the cutover baseline.
27+
# KNOWN DRIFT (BugBash 2026-05-18, T9b): prod currently runs 1 replica —
28+
# live was never scaled up to match this manifest. The infra repo has no
29+
# auto-apply, so reconciliation is an operator action:
30+
# kubectl -n instant scale deploy/instant-nats-proxy --replicas=2
31+
# Do NOT lower this to 1 to "match live" — that would bake the SPOF into
32+
# the source of truth.
33+
replicas: 2
34+
strategy:
35+
type: RollingUpdate
36+
rollingUpdate:
37+
maxUnavailable: 0
38+
maxSurge: 1
39+
selector:
40+
matchLabels:
41+
app: instant-nats-proxy
42+
template:
43+
metadata:
44+
labels:
45+
app: instant-nats-proxy
46+
spec:
47+
imagePullSecrets:
48+
- name: ghcr-pull
49+
containers:
50+
- name: nats-proxy
51+
image: ghcr.io/mastermanas805/instant-nats-proxy:v0.1.0
52+
imagePullPolicy: IfNotPresent
53+
ports:
54+
- name: nats
55+
containerPort: 4222
56+
protocol: TCP
57+
env:
58+
- name: NP_LISTEN
59+
value: ":4222"
60+
- name: NP_REDIS_URL
61+
value: "redis://redis.instant.svc.cluster.local:6379"
62+
- name: NP_ROUTE_PREFIX
63+
value: "nats_route_by_token:"
64+
resources:
65+
requests:
66+
cpu: 50m
67+
memory: 32Mi
68+
limits:
69+
cpu: 500m
70+
memory: 128Mi
71+
readinessProbe:
72+
tcpSocket:
73+
port: 4222
74+
initialDelaySeconds: 1
75+
periodSeconds: 3
76+
livenessProbe:
77+
tcpSocket:
78+
port: 4222
79+
initialDelaySeconds: 5
80+
periodSeconds: 30
81+
securityContext:
82+
allowPrivilegeEscalation: false
83+
readOnlyRootFilesystem: true
84+
runAsNonRoot: true
85+
capabilities:
86+
drop: ["ALL"]
87+
seccompProfile:
88+
type: RuntimeDefault
89+
90+
---
91+
apiVersion: v1
92+
kind: Service
93+
metadata:
94+
name: instant-nats-proxy
95+
namespace: instant
96+
labels:
97+
app: instant-nats-proxy
98+
spec:
99+
selector:
100+
app: instant-nats-proxy
101+
ports:
102+
- name: nats
103+
port: 4222
104+
targetPort: 4222
105+
protocol: TCP

0 commit comments

Comments
 (0)