# 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=" \ --from-literal="POCKET_ID_CLIENT_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: harbor.basicstack.de/basicstack/dummy-sink:main (floating) ``` The Deployment currently references `:dev`; a GitOps apply will pin it to a `:` once the image build pipeline has produced one.