Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 278674@bnt-lap001 Assistant-Session: 64827407-e196-4ce3-b70c-76e7b537493f
14 KiB
| id | demand_source | consumer_repo | credential_type | status | approved_by | approved_at | created | updated |
|---|---|---|---|---|---|---|---|---|
| mas-tem-relay-smtp | mail-address-semantics/workplans/MAS-WP-0003-T03 | mail-address-semantics | openbao-kv-founder-provision | reviewed | null | null | 2026-10-18 | 2026-10-18 |
Construction plan: MAS live-test TEM SMTP relay credential
1. Demand
MAS-WP-0003-T03 runs a temporary live-test MX (mas/mas-mx) on
railiance01. It sends service replies through Scaleway Transactional Email
at [smtp.tem.scaleway.com]:587, because outbound port 25 is blocked on the
node. The MX needs one SMTP credential: username (the Scaleway project ID,
which is not secret) and password (a Scaleway API secret key). The founder
types the value into the OpenBao UI. ops-mason builds an empty home and a
read path into namespace mas, delivered as Secret mas-relay, which the MX
mounts optionally at /etc/mas-relay. The lane is temporary: it is removed
with the mas namespace when MAS-WP-0003 closes.
Requested by hub message 14bdd217 (2026-10-18). The request suggested
kv/mas/tem-relay; it is placed at platform/suppliers/scaleway/mas-tem-relay
instead (supplier convention). It also asked for a ClusterSecretStore openbao-mas and an ESO token.
This plan keeps the shape but adapts it to the current conventions (§3).
2. Existing-structure survey
Generated by scripts/plan-survey.py at 2026-10-18T10:13:55Z against BAO_ADDR=http://127.0.0.1:18200, token display_name token-claude-MASON-WP-0014-T02 (policies: default, ops-mason-survey). Metadata only: no kv get and no */data/* read was issued; policy bodies were read with bao policy read for name-matched candidates only.
Demand: KV path platform/suppliers/scaleway/mas-tem-relay, proposed policy workload-kv-read-mas-tem-relay, AppRole -, Kubernetes role external-secrets-mas-tem-relay, consumer mail-address-semantics. Match terms: mail-address-semantics, external-secrets-mas-tem-relay, tem, smtp, mas, suppliers, scaleway, mas-tem-relay.
bao secrets list (10 mounts, 1 relevant)
platform/ kv version=2
bao auth list (6 auth mounts, 2 relevant)
approle/ approle
kubernetes/ kubernetes
bao policy list (94 policies, 5 relevant)
authelia-smtp-eso matches: smtp
operator-kv-scaleway-bootstrap matches: scaleway
ops-mason-construct matches: mas
ops-mason-survey matches: mas
telemetry-smtp-eso matches: smtp
bao list auth/approle/role (approle) (14 roles, 0 relevant)
(no relevant entries)
bao list auth/kubernetes/role (kubernetes) (35 roles, 2 relevant)
authelia-smtp-eso matches: smtp
token_policies=['authelia-smtp-eso']
token_ttl=900
token_max_ttl=900
token_num_uses=0
bound_service_account_names=['authelia-smtp-eso']
bound_service_account_namespaces=['sso']
audience=openbao
telemetry-smtp-eso matches: smtp
token_policies=['telemetry-smtp-eso']
token_ttl=900
token_max_ttl=900
token_num_uses=0
bound_service_account_names=['telemetry-smtp-eso']
bound_service_account_namespaces=['telemetry']
audience=openbao
bao policy read of name-matched candidates (target platform/data/suppliers/scaleway/mas-tem-relay)
authelia-smtp-eso: no stanza covers platform/data/suppliers/scaleway/mas-tem-relay
operator-kv-scaleway-bootstrap: no stanza covers platform/data/suppliers/scaleway/mas-tem-relay
ops-mason-construct: path "platform/data/suppliers/*" capabilities=['create']
ops-mason-construct: path "platform/metadata/suppliers/*" capabilities=['create', 'read', 'update', 'delete', 'list']
ops-mason-construct: path "platform/metadata/*" capabilities=['read', 'list']
ops-mason-construct: path "platform/data/*" capabilities=['deny']
ops-mason-survey: not permitted by ops-mason-survey
telemetry-smtp-eso: no stanza covers platform/data/suppliers/scaleway/mas-tem-relay
bao kv metadata get / bao kv list (metadata only)
platform/suppliers/scaleway/mas-tem-relay: exists, current_version=2, created=2026-10-18, updated=2026-10-18
owner: railiance-platform
platform/suppliers/scaleway/: backup, bootstrap, mas-tem-relay
ops-warden routing catalog /home/worsch/ops-warden/registry/routing/catalog.yaml (48 entries, 10 relevant)
state-hub-forge-derivation-read owner=ops-mason status=active matches: mas
path_template: platform/workloads/state-hub/forge-derivation (field FORGE_READ_TOKEN)
auth_method: Kubernetes auth (role state-hub-forge-derivation, ServiceAccount state-hub/state-hub) from the in-cluster state-hub workload
object-storage-sts owner=net-kingdom status=draft matches: tem
rein-openweights-openrouter-approle owner=ops-mason status=active matches: mas
path_template: reins/rein-openweights/openrouter
auth_method: AppRole login role=rein-openweights (role_id+secret_id via REIN_OPENWEIGHTS_APPROLE_DIR)
inbound-library-imap-approle owner=ops-mason status=active matches: mas
path_template: platform/workloads/inbound-library/imap
auth_method: AppRole login role=inbound-library (role_id+secret_id in ~/.local/inbound-library/approle, config/library.json credential.approle_dir)
audit-core-senders owner=ops-mason status=active matches: mas
path_template: platform/workloads/audit-core/senders
policy_ref: external-secrets-audit-core
auth_method: OpenBao KV v2 custody; audit-core reads via ESO (policy external-secrets-audit-core, token auth). Operators and agents never read the registry; a sender gets its own exact-path projection.
email-connect-transactional owner=railiance-platform status=active matches: smtp
path_template: platform/workloads/email-connect/transactional
policy_ref: flex-auth check secret.read:email-connect
auth_method: caller's own OpenBao token (operator OIDC, or ESO child token openbao-email-connect-eso-token)
scaleway-bootstrap owner=railiance-platform status=draft matches: mas, scaleway
path_template: platform/workloads/railiance/scaleway/bootstrap
auth_method: caller's own OpenBao token (founder / operator workstation)
openbao-structure-survey owner=ops-mason status=active matches: mas
auth_method: founder-minted scoped grant: ops-mason scripts/bao-session.sh grant <task> (policy ops-mason-survey, 45m, display_name claude-<task>)
platform-supplier-credentials owner=railiance-platform status=active matches: suppliers
path_template: platform/suppliers/<supplier>/<account>
auth_method: railiance-platform delegated credential change (CCR); founder-attended provision from a mode-0600 file
fluid-telegram-operator owner=ops-mason status=draft matches: mas
path_template: platform/workloads/coulomb/fluid-telegram/hall-of-helix/{operator-app,operator-session,bot-token,redaction-salt}
auth_method: bao login -method=oidc -path=netkingdom role=fluid-telegram-hall-of-helix-workload-kv (members of fluid-telegram-operators, aal2, 15m token)
Does an existing lane already satisfy this demand?
Decision (review 2026-10-18): no. Edited from the generated "partial".
- The KV path exists because ops-mason created the placeholder (v1, 10:03Z), and the founder wrote the TEM value as v2 (10:11Z). That is the home this plan builds, not an existing lane.
- No policy or role reads
platform/data/suppliers/scaleway/mas-tem-relay. The only name-matched policy that touches the path isops-mason-construct, which has create-only access and cannot read. - The two SMTP ESO lanes,
authelia-smtp-esoandtelemetry-smtp-eso, both readplatform/data/workloads/railiance-telemetry/smtp, which is the IONOS mailboxplatform@coulomb.social(CCR-2026-0035). That is a different supplier and belongs to production senders, so it is not reused. - Repo sources (checked earlier the same day): no catalog entry or CCR for
masor TEM.openbao-email-connectis a separate production sender. - Not detected by design: a policy with an unrelated name covering the path.
3. Proposed changes
SEC-DSM §37:
- Q1 Can the operation use identity directly? No. TEM SMTP authenticates only with username/password.
- Q2 Can the target accept federated identity? No. TEM SMTP has no federation.
- Q3 Can the target issue an ephemeral credential? Not viably. Scaleway
API keys can carry an expiry, but adding an issuer for a temporary test
lane would be issuance for show (
DSM-TRANS-003). Instead the founder sets the key's own Scaleway expiry to the end of MAS-WP-0003. - Q4 Can an existing static credential be rotated automatically? No automated rotation for a lane this short-lived.
- Q5 Must a persistent static credential exist? Yes, for the life of MAS-WP-0003 only. This is §5 level "vaulted static secret".
Credential facts:
| Field | Value |
|---|---|
| Owner | founder (Scaleway IAM) |
| Consumer | mas/mas-mx |
| Authority | Scaleway IAM API key on a dedicated application with only the Transactional Email permission set, on the TEM project |
| Delivery | ESO → Secret mas/mas-relay |
| Copies | OpenBao KV, plus one Kubernetes Secret (a delivery copy, not the authority) |
| Rotation | Replace the KV version; ESO refreshes |
| Revocation | Delete the API key in Scaleway, then tear down (rows 6–7 below) |
| Detection | TEM sending logs and the OpenBao audit log for reads of the path |
| What would eliminate it | Removing the MX, or an MTA that relays through email-connect's API instead of SMTP |
| # | Action | Object | Reuse-vs-new rationale |
|---|---|---|---|
| 1 | create | KV v2 platform/suppliers/scaleway/mas-tem-relay, fields username, password (placeholder xxx) |
No existing home (§2). Supplier account path platform/suppliers/<supplier>/<account> (founder decision 2026-10-08, ops-warden platform-supplier-credentials); credential-change.py accepts it |
| 2 | create | policy workload-kv-read-mas-tem-relay: read on platform/data/suppliers/scaleway/mas-tem-relay, plus token lookup-self and revoke-self (CCR-2026-0051 policy file, used verbatim) |
Single-path ESO reader; no metadata read needed |
| 3 | create | Kubernetes auth role external-secrets-mas-tem-relay: SA mas-tem-relay-eso, ns mas, audience openbao, ttl/max 15m, token_no_default_policy |
Current pattern (CCR-2026-0050), with no static ESO token to deliver or expire |
| 4 | create (consumer repo) | ServiceAccount mas-tem-relay-eso, namespaced SecretStore openbao-mas-tem-relay, ExternalSecret mas-relay (keys username, password), all in ns mas |
Namespaced instead of a ClusterSecretStore, so the store is deleted with the namespace |
| 5 | reuse (railiance-platform) | CCR-2026-0051 (railiance-platform@4398f89), with policy file openbao/policies/workload-kv-read-mas-tem-relay.hcl |
Platform's record of the lane. ops-mason applies rows 2–3 under ops-mason-construct after approval and records evidence against the CCR |
| 6 | tear-down (at MAS-WP-0003 close) | auth role, policy, KV path (metadata delete) |
Cluster-scoped OpenBao objects do not go away with the namespace |
| 7 | tear-down (founder) | Scaleway API key | Revokes the authority itself |
No catalog entry: the lane is temporary and has a single consumer.
4. Review notes
- Naming:
mas-tem-relayis used for the supplier account segment, policy, role, SA and store, so one grep finds every object to retire. Secretmas-relaykeeps the name the consumer asked for. - TTL/scoping: 15m role TTL matches CCR-2026-0050. The policy covers one data path and no metadata. Binding is to exact SA and namespace claims.
- Redundancy: does not reuse the
email-connectsender key (§2). - Deviation from the request: it asked for a ClusterSecretStore
openbao-masand an ESO token. Both are replaced, by Kubernetes auth (DSM-K8S-001, projected identity before a broker token) and by a namespaced store (easier to retire). The consumer applies rows 4 itself. - Secret values: ops-mason neither reads nor writes them. The policy
grants
readonly to the ESO role. - Naming vs existing SMTP lanes:
authelia-smtp-esoandtelemetry-smtp-esouse one name for role, policy and SA. This lane keeps theexternal-secrets-*/workload-kv-read-*shape, which is whatops-mason-constructmay build (MASON-IN-0005). - Build path: after approval, ops-mason applies rows 2–3 itself under
bao-session.sh build. Row 1 is done: the placeholder came first and the founder wrote the value on 2026-10-18. - CCR: CCR-2026-0051 (approvers: founder, railiance-platform-owner, mail-address-semantics-owner). The post-build check compares the written policy with its policy file.
- Open: founder approval;
bound_claims_confirmedafter the SA exists.
5. Executive summary
One-line ask: let the temporary MAS test mail server read its TEM SMTP login from OpenBao, and nothing else, until MAS-WP-0003 ends.
Who gets access: the External Secrets reader in namespace mas, and
only when it signs in as ServiceAccount mas-tem-relay-eso. No person, no
agent, no other namespace.
To what: read on platform/suppliers/scaleway/mas-tem-relay
(username, password), delivered as Secret mas/mas-relay to the mas-mx
container at /etc/mas-relay.
For how long: 15-minute OpenBao sessions, renewed by ESO, until teardown at MAS-WP-0003 close. The Scaleway key's own expiry is the hard stop.
Blast radius if the credential leaks: someone can send mail as your TEM project, which risks reputation, quota and cost, until you revoke the key in the Scaleway console. If the key is TEM-only it gives no other Scaleway access.
Cost to reverse: low. Delete the role, the policy and the KV path, then revoke the key. Nothing else depends on it.
Decision: pending.