Add email-connect transactional SMTP and ingest custody lane.
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

CCR-2026-0010, OpenBao read policies, ClusterSecretStore openbao-email-connect,
and workload-kv lane documentation for EMAIL-WP-0004-T03.
This commit is contained in:
codex 2026-08-12 13:32:11 +02:00
parent b6ad81fe6b
commit c642367d98
5 changed files with 241 additions and 0 deletions

View file

@ -0,0 +1,32 @@
# email-connect transactional receiver reads SMTP + ingest token from OpenBao.
# Deploy on railiance01 (not coulombcore ArgoCD kustomization — same interim
# pattern as openbao-activity-core / openbao-reuse).
#
# Prereq: Secret external-secrets/openbao-email-connect-eso-token (key: token)
# with policy external-secrets-email-connect (or
# workload-kv-read-email-connect-transactional) able to read
# platform/workloads/email-connect/transactional.
# Bootstrap: email-connect/deploy/k8s/railiance/openbao-eso-token-apply.sh
# CCR: CCR-2026-0010
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: openbao-email-connect
labels:
app.kubernetes.io/part-of: railiance-gitops
railiance-platform/component: external-secrets
app.kubernetes.io/name: email-connect
spec:
provider:
vault:
server: http://openbao.openbao.svc:8200
path: platform
version: v2
auth:
tokenSecretRef:
name: openbao-email-connect-eso-token
namespace: external-secrets
key: token
conditions:
- namespaces:
- email-connect

View file

@ -0,0 +1,130 @@
id: CCR-2026-0010
kind: credential-change-request
schema_version: 1
request_type: workload-kv-read
title: email-connect transactional SMTP and ingest token lane
status: active
created: '2026-08-12'
updated: '2026-08-12'
requester:
agent: grok
reason: >-
EMAIL-WP-0004-T03 requires OpenBao custody for IONOS SMTP STARTTLS credentials
and the shared caller ingest token so user-engine can call the cluster-local
transactional receiver without possessing SMTP material. Package manifests live
in email-connect/deploy/k8s/railiance; this CCR covers the OpenBao path, ESO
policy/role, and ops-warden catalog front door.
review:
required: true
required_approvers:
- platform-operator
- email-connect-owner
comments:
- at: '2026-08-12T00:00:00+00:00'
reviewer: bernd.worsch
decision: approved
comment: >-
Approved in chat (Grok session, EMAIL-WP-0004-T03) acting as platform-operator
and email-connect-owner. Daily send-quota privilege tiers explicitly deferred
(DECISIONS.md); proceed with lane apply and deploy package.
target:
domain: infotech
tenant: platform
workload: email-connect
environment: production
purpose: >-
Deliver EMAIL_CONNECT_INGEST_TOKEN and IONOS SMTP username/password into the
email-connect namespace via External Secrets so the transactional receiver can
send invitation and verification mail without baking secrets into the image,
Git, or user-engine.
openbao:
mount: platform
kv_path: platform/workloads/email-connect/transactional
fields:
- EMAIL_CONNECT_INGEST_TOKEN
- EMAIL_CONNECT_SMTP_USERNAME
- EMAIL_CONNECT_SMTP_PASSWORD
policy_name: workload-kv-read-email-connect-transactional
policy_file: openbao/policies/workload-kv-read-email-connect-transactional.hcl
eso_policy_name: external-secrets-email-connect
eso_policy_file: openbao/policies/external-secrets-email-connect.hcl
auth:
# Interim railiance01 pattern (matches openbao-activity-core / openbao-reuse):
# policy-limited orphan child token stored as K8s Secret, not Kubernetes auth.
# Kubernetes auth role external-secrets-email-connect remains the preferred
# follow-up once the cluster auth mount is wired for this namespace.
method: token
token_secret: external-secrets/openbao-email-connect-eso-token
bootstrap_script: email-connect/deploy/k8s/railiance/openbao-eso-token-apply.sh
policies:
- external-secrets-email-connect
ttl: 768h
kubernetes_followup:
method: kubernetes
mount: kubernetes
role: external-secrets-email-connect
bound_claims:
service_account_names:
- external-secrets
service_account_namespaces:
- external-secrets
access_frontdoor:
type: ops-warden
catalog_id: email-connect-transactional
selector: email-connect transactional SMTP and ingest token
command: warden access email-connect-transactional --fetch EMAIL_CONNECT_SMTP_PASSWORD
resolvable: true
readiness: ready
activation: verified-positive-and-negative-2026-08-12
delivery:
surface: external-secrets
target: >-
ClusterSecretStore openbao-email-connect (tokenSecretRef
openbao-email-connect-eso-token; namespace condition email-connect) at
railiance-platform/argocd/platform-addons/openbao-secretstore/openbao-email-connect.clustersecretstore.yaml
→ ExternalSecret email-connect/email-connect-runtime → Secret
email-connect-runtime. Package manifests in
email-connect/deploy/k8s/railiance/ (not applied until this CCR is approved
and the KV secret is provisioned).
risk:
classification: high
notes:
- SMTP credentials grant outbound mail from the platform IONOS identity; abuse
is bulk send and reputation damage.
- The ingest token is a shared bearer between user-engine and email-connect;
compromise lets a holder submit invitation/verification sends within the
fixed template allow-list (not arbitrary content).
- NetworkPolicy restricts ingress to user-engine and egress to DNS + TCP 587;
credentials are a second gate, not the only one.
- Interim ESO delivery uses a renewable orphan child token (same pattern as
activity-core/reuse); ops-warden must proxy operator reads as the caller and
must not retain values.
verification:
positive:
- An approved email-connect-namespace ExternalSecret can sync the three fields
to Secret email-connect-runtime without printing values.
- The email-connect Deployment reaches Ready and /healthz without SMTP fields
present in user-engine secrets.
negative:
- A namespace outside the ClusterSecretStore condition cannot use the store to
read the path.
- A token without external-secrets-email-connect cannot read the KV path.
- Pods outside user-engine cannot reach TCP 8080 on the receiver.
activation_conditions:
- Policy applied with platform-admin/operator authority.
- ESO child token Secret and ClusterSecretStore openbao-email-connect live on
railiance01, namespace-scoped to email-connect.
- Secret value provisioned directly in OpenBao through approved operator custody.
- Positive and negative verification recorded with non-secret audit ids or timestamps.
lifecycle:
deactivate: Disable ops-warden catalog entry and detach ESO role policy.
rotate: >-
Overlap-first: put new SMTP password and/or ingest token in OpenBao; wait for
ESO refresh (or force sync); roll email-connect and user-engine as needed;
revoke old provider password / retire old bearer.
compromised: Immediately deactivate front door, rotate SMTP and ingest token,
record blast-radius notes, and open incident follow-up.
state_hub:
workplan_id: EMAIL-WP-0004
task_id: EMAIL-WP-0004-T03

View file

@ -460,3 +460,59 @@ unattended principal.
Playbook: `ops-warden/wiki/playbooks/agent-harness-secrets.md`.
## email-connect transactional SMTP + ingest token (`CCR-2026-0010`)
IONOS STARTTLS credentials and the shared user-engine ingest bearer for the
`email-connect` transactional invitation/verification receiver on railiance01.
| Item | Value |
| --- | --- |
| CCR | `CCR-2026-0010-email-connect-transactional` |
| KV mount | `platform` |
| OpenBao CLI path | `platform/workloads/email-connect/transactional` |
| Fields | `EMAIL_CONNECT_INGEST_TOKEN`, `EMAIL_CONNECT_SMTP_USERNAME`, `EMAIL_CONNECT_SMTP_PASSWORD` |
| Operator read policy | `workload-kv-read-email-connect-transactional` |
| Policy file | `openbao/policies/workload-kv-read-email-connect-transactional.hcl` |
| ESO policy | `external-secrets-email-connect` |
| ESO policy file | `openbao/policies/external-secrets-email-connect.hcl` |
| K8s auth role | `external-secrets-email-connect` (ESO delivery) |
| ClusterSecretStore | `openbao-email-connect` (namespace `email-connect` only) |
| Primary consumer | ExternalSecret `email-connect/email-connect-runtime` → Secret `email-connect-runtime` |
| Package manifests | `email-connect/deploy/k8s/railiance/` |
| ops-warden catalog | `email-connect-transactional` (draft until front door verified) |
Non-secret SMTP host/port/sender and portal URL stay in ConfigMap
`email-connect-config` (not in OpenBao).
Operator provision (attended; values from mode-0600 files only):
```bash
bao kv put platform/workloads/email-connect/transactional \
EMAIL_CONNECT_INGEST_TOKEN=@file \
EMAIL_CONNECT_SMTP_USERNAME=@file \
EMAIL_CONNECT_SMTP_PASSWORD=@file
```
Fetch for operator smoke only (do not log values):
```bash
bao kv get -field=EMAIL_CONNECT_SMTP_USERNAME \
platform/workloads/email-connect/transactional
```
Or via ops-warden after catalog promotion:
```bash
warden access email-connect-transactional --exec -- \
sh -lc 'test -n "$EMAIL_CONNECT_SMTP_PASSWORD"'
```
**Consumer facts:**
- user-engine must hold the **same** ingest token under its own runtime secret;
it must never receive `EMAIL_CONNECT_SMTP_*`.
- NetworkPolicy in the package admits only `user-engine` to TCP 8080 and egress
only DNS + TCP 587.
- Rotation is overlap-first for both SMTP password and ingest token; roll both
email-connect and user-engine after ESO refresh when the bearer changes.

View file

@ -0,0 +1,13 @@
# Least-privilege policy for the External Secrets Operator email-connect lane.
#
# The matching Kubernetes auth role binds only the ESO service account in the
# external-secrets namespace. ClusterSecretStore usage is separately limited to
# the email-connect namespace.
path "platform/data/workloads/email-connect/transactional" {
capabilities = ["read"]
}
path "platform/metadata/workloads/email-connect/transactional" {
capabilities = ["read"]
}

View file

@ -0,0 +1,10 @@
# Operator / OIDC read lane for email-connect transactional SMTP + ingest token.
# ESO delivery uses the sibling external-secrets-email-connect policy.
path "platform/data/workloads/email-connect/transactional" {
capabilities = ["read"]
}
path "platform/metadata/workloads/email-connect/transactional" {
capabilities = ["read"]
}