docs/deployment: record security hardening pass + webapp + APNs
Mark roadmap items done (network policies, Traefik middleware, CF Full strict, CF IP UFW restriction, webapp deploy, APNs wired up, admin URL-baking fix, admin probe bug). Update Chapter 4 (firewall rule inventory now shows CF-only :443, no :80), Chapter 6 (request flow walks through TLS on :443 and middleware hops), Chapter 13 (CF SSL mode is Full strict, not Flexible; documents the origin cert install), Chapter 7 (adds the web service section — proxy pattern, 3 replicas, PostHog build-args), and Appendix C (web manifests, CF origin cert paths on disk, APNs .p8 path, updated network-policies applied status). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
|
||||
## Summary
|
||||
|
||||
Four workloads run in the `honeydue` namespace: **api** (Go REST API, 3
|
||||
replicas), **admin** (Next.js panel, 1 replica), **worker** (Go background
|
||||
jobs, 1 replica), and **redis** (cache + job queue, 1 replica, PVC-backed).
|
||||
Five workloads run in the `honeydue` namespace: **api** (Go REST API, 3
|
||||
replicas), **admin** (Next.js admin panel, 1 replica), **web** (Next.js
|
||||
customer-facing app, 3 replicas), **worker** (Go background jobs, 1
|
||||
replica), and **redis** (cache + job queue, 1 replica, PVC-backed).
|
||||
This chapter deep-dives each: container image, resource limits, probes,
|
||||
volumes, and why each knob is set the way it is.
|
||||
|
||||
@@ -14,10 +15,11 @@ volumes, and why each knob is set the way it is.
|
||||
|---|---|---|---|---|
|
||||
| `api` | `gitea.treytartt.com/admin/honeydue-api:<sha>` | 3 | 8000 | HTTP REST API |
|
||||
| `admin` | `gitea.treytartt.com/admin/honeydue-admin:<sha>` | 1 | 3000 | Next.js admin panel |
|
||||
| `web` | `gitea.treytartt.com/admin/honeydue-web:<sha>` | 3 | 3000 | Next.js customer-facing web client at `app.myhoneydue.com` |
|
||||
| `worker` | `gitea.treytartt.com/admin/honeydue-worker:<sha>` | 1 | — | Background job processor |
|
||||
| `redis` | `redis:7-alpine` | 1 | 6379 | Cache + Asynq queue |
|
||||
|
||||
All four are Kubernetes `Deployment` workloads (not StatefulSets, not
|
||||
All five are Kubernetes `Deployment` workloads (not StatefulSets, not
|
||||
DaemonSets). They share:
|
||||
- ServiceAccount with `automountServiceAccountToken: false` (Chapter 5)
|
||||
- `imagePullSecrets: [gitea-credentials]` (Chapter 11)
|
||||
@@ -25,6 +27,66 @@ DaemonSets). They share:
|
||||
- Individual env vars wired to `honeydue-secrets` keys
|
||||
- Read-only root filesystem with `tmp` emptyDir mounted at `/tmp`
|
||||
|
||||
## Service — web (Next.js customer app)
|
||||
|
||||
### What it does
|
||||
|
||||
Lives at `https://app.myhoneydue.com`. Next.js 16 standalone build,
|
||||
served by `node server.js` inside the container. Sibling repo:
|
||||
`/Users/treyt/Desktop/code/honeyDue/honeyDueAPI-Web/`.
|
||||
|
||||
### Architecture: server-side proxy pattern
|
||||
|
||||
Unlike the admin panel (which makes CORS requests directly to
|
||||
`api.myhoneydue.com`), the web app uses a proxy pattern:
|
||||
|
||||
```
|
||||
Browser → https://app.myhoneydue.com/api/proxy/tasks/123/
|
||||
→ Next.js route handler (src/app/api/proxy/[...path]/route.ts)
|
||||
→ reads honeydue-token httpOnly cookie
|
||||
→ attaches Authorization: Token <value>
|
||||
→ https://api.myhoneydue.com/api/tasks/123/ (server-side fetch)
|
||||
→ response flows back
|
||||
```
|
||||
|
||||
**Consequences:**
|
||||
- Browser never makes cross-origin requests. No CORS entry needed on
|
||||
the Go API for `app.myhoneydue.com`.
|
||||
- Auth tokens live in httpOnly cookies, not localStorage. XSS can't
|
||||
exfiltrate them.
|
||||
- The web pod needs outbound HTTPS to `api.myhoneydue.com` — covered
|
||||
in the `allow-egress-from-web` NetworkPolicy (Chapter 5).
|
||||
|
||||
### Env vars
|
||||
|
||||
Build-time (baked into the client bundle by the Dockerfile `ARG`):
|
||||
- `NEXT_PUBLIC_API_URL` — only used as a fallback; baked for safety
|
||||
- `NEXT_PUBLIC_POSTHOG_KEY` — PostHog project API key
|
||||
- `NEXT_PUBLIC_POSTHOG_HOST` — `https://analytics.88oakapps.com`
|
||||
|
||||
Runtime (ConfigMap):
|
||||
- `API_URL=https://api.myhoneydue.com/api` — consumed by the
|
||||
server-side proxy handlers
|
||||
- `PORT=3000`, `HOSTNAME=0.0.0.0`
|
||||
|
||||
### Deployment spec highlights
|
||||
|
||||
- **3 replicas**, same as api — this is a production customer surface
|
||||
- `topologySpreadConstraints` across `kubernetes.io/hostname` —
|
||||
evicting one node at most kills one pod
|
||||
- `readOnlyRootFilesystem: true`; `emptyDir`s at `/app/.next/cache`
|
||||
(Next.js build cache) and `/tmp`
|
||||
- PDB `web-pdb` with `minAvailable: 2`
|
||||
- runAsUser/runAsGroup `1001` (matches the `nextjs` user created in
|
||||
the Dockerfile)
|
||||
|
||||
### Why same availability as api
|
||||
|
||||
The web client is now the primary user-facing surface. Users hitting
|
||||
`app.myhoneydue.com/login` should never see a 502 because a single
|
||||
node went down. 3 replicas × `minAvailable: 2` guarantees at least
|
||||
two pods stay up through any voluntary disruption.
|
||||
|
||||
## Service 1 — api (Go REST API)
|
||||
|
||||
### What it does
|
||||
|
||||
Reference in New Issue
Block a user