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-21'
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.
  evidence:
  - at: '2026-08-20T22:56:00+00:00'
    actor: codex
    kind: auth_path_reconciliation
    result: passed
    details:
    - Live ClusterSecretStore openbao-email-connect uses tokenSecretRef external-secrets/openbao-email-connect-eso-token,
      is namespace-limited to email-connect, and reports Valid.
    - ExternalSecret email-connect-runtime reports SecretSynced. No Secret value was read.
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
