Add email-connect transactional SMTP and ingest custody lane.
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:
parent
b6ad81fe6b
commit
c642367d98
5 changed files with 241 additions and 0 deletions
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
13
openbao/policies/external-secrets-email-connect.hcl
Normal file
13
openbao/policies/external-secrets-email-connect.hcl
Normal 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"]
|
||||
}
|
||||
|
|
@ -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"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue