42 lines
2.4 KiB
Markdown
42 lines
2.4 KiB
Markdown
# 7.4 — `/db/*` read surfaces (GREEN)
|
|||
|
|
|
||
|
|
Phase: 7 — Additional capability prefixes
|
||
|
|
Stage: GREEN
|
||
|
|
Depends on: [6.5](6.5-cutover.md)
|
||
|
|
|
||
|
|
The most dangerous prefix in this phase. G2 says the gateway holds no cluster
|
||
|
|
credentials — so it cannot be the thing that authenticates to CloudNativePG, MinIO or
|
||
|
|
Prometheus on a caller's behalf. If designing this route makes you want to give the
|
||
|
|
gateway a secret, the design is wrong: put the credential-holding logic in a service
|
||
|
|
behind the gateway and proxy to that.
|
||
|
|
|
||
|
|
- [ ] `/db/*` on `api.riotpiao.com` exposes read surfaces backed by CloudNativePG, MinIO and monitoring
|
||
|
|
- [ ] The gateway holds no database password, no MinIO access key and no cluster credential of any kind (G2). Credentials, if any are needed, live in the service being proxied to
|
||
|
|
- [ ] Exposed operations are read-only. There is no write, no delete and no schema-changing path on this prefix
|
||
|
|
- [ ] Which sub-paths reach which upstream is enumerated explicitly in configuration. No catch-all, no pass-through of arbitrary query text
|
||
|
|
- [ ] Timeouts and body caps are explicit per sub-route, with no silent defaults (G6)
|
||
|
|
- [ ] The route requires authentication and the token is checked for a distinct read capability
|
||
|
|
- [ ] Result sets are paginated with a bounded page size; an unbounded read cannot be requested
|
||
|
|
- [ ] The NetworkPolicy is extended only to the specific upstreams reached. Note `prometheus-operated.monitoring` is headless with ClusterIP `None`, so it needs a pod selector, not a ClusterIP
|
||
|
|
- [ ] `/v1/*` behaviour is unchanged before and after
|
||
|
|
- [ ] Metrics and rejection counters cover this route with its own route label
|
||
|
|
|
||
|
|
## Verify
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -o /dev/null -w '%{http_code}\n' https://api.riotpiao.com/db/healthz
|
||
|
|
# expected: 401 without a token
|
||
|
|
|
||
|
|
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE -H "authorization: Bearer $DB_READ_TOKEN" \
|
||
|
|
https://api.riotpiao.com/db/anything
|
||
|
|
# expected: 405 or 404 — no mutating method is routable on this prefix
|
||
|
|
|
||
|
|
kubectl -n api get pod -l app=homelab-frontend -o jsonpath='{range .items[0].spec.containers[0].env[*]}{.name}{"\n"}{end}' \
|
||
|
|
| grep -Ei 'password|secret|access_key'
|
||
|
|
# expected: no output — the gateway carries no database or object-store credentials
|
||
|
|
|
||
|
|
curl -s -H "authorization: Bearer $DB_READ_TOKEN" 'https://api.riotpiao.com/db/...?limit=100000' \
|
||
|
|
| python3 -c "import json,sys;d=json.load(sys.stdin);print(len(d['items']))"
|
||
|
|
# expected: capped at the configured maximum page size, not 100000
|
||
|
|
```
|