ProofedMesh/deploy/dummy-sink/README.md

116 lines
4.2 KiB
Markdown
Raw Permalink Normal View History

# dummy-sink — deployment
Kubernetes manifests for the ADR-0007 dummy-sink in the `agent-trust`
namespace. The namespace itself is created by
[`deploy/trillian/00-namespace.yaml`](../trillian/00-namespace.yaml);
this directory assumes that file (or an equivalent) is already applied.
## Layout
```
deploy/dummy-sink/
├── 00-serviceaccount.yaml — ServiceAccount (auto-mount off, projected token used)
├── 10-pvc.yaml — PVC dummy-sink-data (1Gi, longhorn, RWO)
├── 11-secret-dev.example.yaml — TEMPLATE for the dev-mode Secret
├── 20-deployment.yaml — Deployment (non-root, read-only rootfs, distroless)
├── 30-service.yaml — ClusterIP Service on :8083
├── 40-networkpolicy.yaml — ingress from testagent-transform,
│ egress to verification-service / signing-service / transparency-log
└── README.md — this file
```
## Apply order
```bash
kubectl apply -f deploy/trillian/00-namespace.yaml # if not yet applied
kubectl apply -f deploy/dummy-sink/00-serviceaccount.yaml
kubectl apply -f deploy/dummy-sink/10-pvc.yaml
# Create the dev Secret separately (see "Secret convention" below) — DO NOT
# commit the real values. The .example file is a template, not a secret.
kubectl apply -f deploy/dummy-sink/20-deployment.yaml
kubectl apply -f deploy/dummy-sink/30-service.yaml
kubectl apply -f deploy/dummy-sink/40-networkpolicy.yaml
```
Reach the sink in-cluster at:
```
http://dummy-sink.agent-trust.svc.cluster.local:8083
```
Health check (also used by Deployment probes):
```
GET /healthz → 200 {"status":"ok"}
```
Deliver endpoint (per ADR-0007 / DEV-611):
```
POST /api/v1/sink/dummy/deliver
Content-Type: application/json
```
## PVC
`dummy-sink-data` is a 1 Gi Longhorn RWO claim mounted at
`/data/dummy-sink`. The Deployment uses `strategy.type: Recreate`
because the PVC is `ReadWriteOnce` — a rolling update would try to
schedule a second pod against the same volume. Scaling past a single
replica requires an RWX storage class or per-pod PVCs; neither is in
Phase-1 scope.
## K8s secret convention
The dummy-sink reads one Secret, `dummy-sink-dev` (or
`dummy-sink-prod` for production), with the Pocket-ID client
credentials. Shape:
| Env key | Purpose |
| ------------------------- | ---------------------------------------------- |
| `POCKET_ID_ISSUER` | Pocket-ID OIDC issuer URL |
| `POCKET_ID_CLIENT_ID` | Pocket-ID client id for this agent |
| `POCKET_ID_CLIENT_SECRET` | Pocket-ID client secret for this agent |
| `POCKET_ID_AUDIENCE` | Expected `aud` claim (default `trust-api`) |
The second half of the double-identity contract (the projected
ServiceAccount token at `/var/run/secrets/tokens/trust-api`) is wired
by the Deployment's `projected` volume and does not require a Secret.
For the GitOps path, convert the created Secret to a SealedSecret and
commit the sealed form under the same filename as the example:
```bash
kubectl create secret generic dummy-sink-dev -n agent-trust \
--from-literal="POCKET_ID_ISSUER=https://auth.basicstack.de" \
--from-literal="POCKET_ID_CLIENT_ID=<id>" \
--from-literal="POCKET_ID_CLIENT_SECRET=<secret>" \
--from-literal="POCKET_ID_AUDIENCE=trust-api" \
--dry-run=client -o yaml | \
kubeseal --controller-namespace=sealed-secrets --format=yaml \
> deploy/dummy-sink/11-secret-dev.sealed.yaml
```
## NetworkPolicy
See `40-networkpolicy.yaml`. In short:
- **Ingress:** `testagent-transform` pods only (matched by
`app.kubernetes.io/name`).
- **Egress:** `verification-service` (:8084), `signing-service`
(:8081), `transparency-log` (:8080), external HTTPS/443 for the
Pocket-ID OIDC endpoint, DNS to `kube-dns`.
## Image
Images are built by `.forgejo/workflows/build-images.yml` on every push
to `main` and pushed to:
```
harbor.basicstack.de/basicstack/dummy-sink:<git-sha>
harbor.basicstack.de/basicstack/dummy-sink:main (floating)
```
The Deployment currently references `:dev`; a GitOps apply will pin it
to a `:<git-sha>` once the image build pipeline has produced one.