email-connect/deploy/k8s/railiance
tegwick 04897a149f
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Complete EMAIL-WP-0004 transactional invitation mail delivery.
Ship the railiance01 deploy package (OpenBao/ESO custody, NetworkPolicy,
probes), provider failure classification and suppression, T04 unit and live
proof, and non-secret NK-WP-0024 hand-back evidence. Workplan finished.
2026-08-12 13:32:11 +02:00
..
clustersecretstore.yaml.template Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
configmap.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
deployment.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
externalsecret.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
kustomization.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
namespace.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
networkpolicies.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
openbao-eso-token-apply.sh Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
pvc.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
README.md Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
service.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00
serviceaccount.yaml Complete EMAIL-WP-0004 transactional invitation mail delivery. 2026-08-12 13:32:11 +02:00

email-connect transactional receiver — railiance01

Deploy the narrow invitation/verification HTTP receiver so user-engine can send mail without holding SMTP credentials, and so unrelated workloads cannot reach the send API.

Target cluster: railiance01 only (KUBECONFIG=~/.kube/config-hosteurope).

Stable in-cluster URL after apply:

http://email-connect.email-connect.svc.cluster.local:8080

Ownership split

Concern Owner Where
Package, manifests, probes, NetworkPolicy, rollback email-connect this directory
OpenBao path, ESO role/policy, ClusterSecretStore railiance-platform CCR-2026-0010, openbao/policies/
Credential routing catalog ops-warden email-connect-transactional

Never paste SMTP passwords, ingest tokens, or OpenBao tokens into Git, State Hub, workplans, logs, or chat. Route first:

warden route find "email-connect SMTP transactional" --json
warden route show email-connect-transactional --json

Runtime secrets (OpenBao → ESO)

Item Value
KV path platform/workloads/email-connect/transactional
Fields EMAIL_CONNECT_INGEST_TOKEN, EMAIL_CONNECT_SMTP_USERNAME, EMAIL_CONNECT_SMTP_PASSWORD
Read / ESO policy external-secrets-email-connect (+ workload-kv-read-email-connect-transactional for operator OIDC)
ClusterSecretStore openbao-email-connect (namespace-limited; token auth like activity-core/reuse)
ESO token Secret external-secrets/openbao-email-connect-eso-token (via openbao-eso-token-apply.sh)
ExternalSecret email-connect/email-connect-runtime → Secret email-connect-runtime
ops-warden catalog email-connect-transactional (draft until provisioned)

Non-secret config (host, port, sender, portal URL) lives in ConfigMap email-connect-config.

Operator provision (attended, after CCR approval)

# Values from mode-0600 files only; shred after.
bao kv put platform/workloads/email-connect/transactional \
  EMAIL_CONNECT_INGEST_TOKEN=@/path/to/ingest.token \
  EMAIL_CONNECT_SMTP_USERNAME=@/path/to/smtp.user \
  EMAIL_CONNECT_SMTP_PASSWORD=@/path/to/smtp.pass

user-engine must receive the same ingest token under its own runtime secret path so it can call Authorization: Bearer … without ever seeing SMTP fields.

Network posture

  • Default deny ingress and egress in email-connect.
  • Ingress: only pods labeled app.kubernetes.io/name=user-engine in namespace user-engine, TCP 8080.
  • Egress: kube-system DNS + TCP 587 to the public internet (IONOS STARTTLS). No cluster-lateral egress and no general HTTPS.

Bearer auth on /v1/* is the second gate; NetworkPolicy is the outer gate.

Apply

Prerequisites:

  1. CCR-2026-0010 approved.
  2. KV secret provisioned at platform/workloads/email-connect/transactional (fields non-empty; do not log values).
  3. ESO delivery token + ClusterSecretStore on railiance01 (token pattern matches openbao-activity-core / openbao-reuse, not Kubernetes auth yet).
  4. Image available on the node/registry at the digest pinned in deployment.yaml.
export KUBECONFIG=~/.kube/config-hosteurope

# 1) Policy + limited ESO child token → external-secrets Secret
./deploy/k8s/railiance/openbao-eso-token-apply.sh

# 2) Namespace-scoped ClusterSecretStore (platform add-on copy)
kubectl apply -f ~/railiance-platform/argocd/platform-addons/openbao-secretstore/openbao-email-connect.clustersecretstore.yaml

# 3) Optional: load a freshly built image when the registry is not yet updated
# docker build -f Containerfile -t forgejo.coulomb.social/coulomb/email-connect:local .
# docker save … | ssh railiance01 sudo k3s ctr -n k8s.io images import -

# 4) Package
kubectl apply -k deploy/k8s/railiance
kubectl -n email-connect rollout status deployment/email-connect
kubectl -n email-connect get pods,svc,networkpolicy,externalsecret,secret

Expect ExternalSecret SecretSynced and a Ready pod. If the Secret is missing, do not create a bootstrap Secret with values from chat — fix OpenBao/ESO.

Smoke (no SMTP proof yet)

From a user-engine pod (or a temporary pod in that namespace with the same labels — NetworkPolicy will otherwise drop the packet):

# Health only (no auth)
kubectl -n user-engine exec deploy/user-engine -- \
  wget -qO- http://email-connect.email-connect.svc.cluster.local:8080/healthz

# Auth check: wrong token must be 401; correct token is exercised by T04.

Negative checks:

  • A pod in another namespace cannot reach port 8080 (connection timeout/reset).
  • user-engine runtime must not contain EMAIL_CONNECT_SMTP_* keys.

Rollback

kubectl -n email-connect rollout undo deployment/email-connect
kubectl -n email-connect rollout status deployment/email-connect

revisionHistoryLimit: 5 keeps prior digests. SQLite on the PVC is additive; rolling back does not clear delivery/idempotency rows (by design).

Done criteria (EMAIL-WP-0004-T03)

  • user-engine calls the cluster-local receiver without possessing SMTP credentials
  • Unrelated workloads cannot open TCP 8080 on the receiver
  • SMTP password and ingest token exist only in OpenBao + the scoped K8s Secret
  • Probes green; NetworkPolicy default-deny + SMTP-only egress applied
  • Documented rollback path works against the previous revision