diff --git a/credential-change-requests/CCR-2026-0035-authelia-platform-smtp.yaml b/credential-change-requests/CCR-2026-0035-authelia-platform-smtp.yaml new file mode 100644 index 0000000..7eb24b5 --- /dev/null +++ b/credential-change-requests/CCR-2026-0035-authelia-platform-smtp.yaml @@ -0,0 +1,53 @@ +id: CCR-2026-0035 +kind: credential-change-request +schema_version: 1 +request_type: workload-kv-read +title: Authelia platform SMTP password projection +status: proposed +created: '2026-10-06' +updated: '2026-10-06' +requester: + agent: codex + reason: CSOC-WP-0010 / NK-WP-0047 restore user-requested password reset email; existing + platform mailbox custody. +review: + required: true + required_approvers: + - founder + - railiance-platform-owner + - net-kingdom-owner + comments: [] +target: + domain: infotech + tenant: platform + workload: authelia + environment: production + purpose: Native password-reset notifier; password mounted read-only under /run/secrets/authelia-smtp/password. +openbao: + mount: platform + kv_path: platform/workloads/railiance-telemetry/smtp + fields: + - SMTP_PASSWORD + policy_name: authelia-smtp-eso + auth: + method: kubernetes + mount: kubernetes + role: authelia-smtp-eso + bound_service_account_names: + - authelia-smtp-eso + bound_service_account_namespaces: + - sso + audience: openbao + max_ttl: 15m +delivery: + namespace: sso + service_account: authelia-smtp-eso + secret_store: openbao-authelia-smtp + external_secret: authelia-smtp + target_secret: authelia-smtp + target_key: password +invariants: +- Mailbox credentials/version unchanged +- Telemetry role and Secret unchanged +- No static ESO tokens or credentials in code/logs/chat +- Owner attended admission required; no live activation from this proposal diff --git a/scripts/authelia_smtp_delivery.py b/scripts/authelia_smtp_delivery.py new file mode 100644 index 0000000..1d0741c --- /dev/null +++ b/scripts/authelia_smtp_delivery.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""Silent attended admission of the fixed Authelia SMTP consumer. + +Reuses the owner-verified telemetry mailbox without copying or rotating it. +Only the dedicated sso/authelia-smtp-eso role gains the exact read-only lane. +""" +import argparse +import importlib.util +import json +import os +from pathlib import Path +import sys + +ROOT = Path(__file__).resolve().parent +sys.path.insert(0, str(ROOT)) +spec = importlib.util.spec_from_file_location( + "authelia_smtp_owner_lane", ROOT / "telemetry_smtp_delivery.py", +) +lane = importlib.util.module_from_spec(spec) +spec.loader.exec_module(lane) +lane.LANE = dict(service_account="authelia-smtp-eso", namespace="sso", + role="authelia-smtp-eso", policy="authelia-smtp-eso", + kv_path="platform/data/workloads/railiance-telemetry/smtp") +lane.POLICY = ('path "' + lane.LANE["kv_path"] + '" { capabilities = ["read"] }\n' + 'path "auth/token/lookup-self" { capabilities = ["read"] }\n' + 'path "auth/token/revoke-self" { capabilities = ["update"] }\n') + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--receipt", required=True, type=Path) + args = parser.parse_args() + fd = os.open(args.receipt, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) + receipt = {"schema": "authelia.smtp-delivery.v1", "status": "failed"} + try: + lane.run(receipt) + except Exception as error: + receipt["reason"] = ( + str(error) if isinstance(error, lane.LaneError) else "contained_operation_failed" + ) + finally: + with os.fdopen(fd, "w") as target: + json.dump(receipt, target, indent=2) + target.write("\n") + return 0 if receipt["status"] == "verified" else 1 + + +if __name__ == "__main__": + with open(os.devnull, "w") as sink: + os.dup2(sink.fileno(), 1) + os.dup2(sink.fileno(), 2) + try: + code = main() + except Exception: + code = 1 + sys.exit(code) diff --git a/tests/test_authelia_smtp_delivery.py b/tests/test_authelia_smtp_delivery.py new file mode 100644 index 0000000..eae6f53 --- /dev/null +++ b/tests/test_authelia_smtp_delivery.py @@ -0,0 +1,50 @@ +import importlib.util +import json +from pathlib import Path +import subprocess +import sys +import unittest +from unittest.mock import patch + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / "scripts")) +spec = importlib.util.spec_from_file_location("authelia_delivery", ROOT / "scripts/authelia_smtp_delivery.py") +delivery = importlib.util.module_from_spec(spec) +spec.loader.exec_module(delivery) + + +class AutheliaAdmissionTests(unittest.TestCase): + def test_role_cannot_be_used_by_telemetry_or_another_namespace(self): + role = delivery.lane.role_payload(delivery.lane.LANE) + self.assertEqual(role["bound_service_account_names"], ["authelia-smtp-eso"]) + self.assertEqual(role["bound_service_account_namespaces"], ["sso"]) + self.assertEqual(role["audience"], "openbao") + self.assertEqual(role["token_explicit_max_ttl"], "15m") + self.assertTrue(role["token_no_default_policy"]) + self.assertNotIn("*", delivery.lane.POLICY) + self.assertNotIn('["update"]', delivery.lane.POLICY.split('auth/token')[0]) + + def test_different_role_or_policy_is_not_overwritten(self): + response = subprocess.CompletedProcess([], 0, b'{"data":{"policy":"different"}}', b'') + with patch.object(delivery.lane, "bao", return_value=response) as bao: + with self.assertRaises(delivery.lane.LaneError): + delivery.lane.ensure("policy", {"policy": delivery.lane.POLICY}, + lambda actual: delivery.lane.require(actual["policy"] == delivery.lane.POLICY, "drift")) + self.assertEqual(bao.call_count, 1) + + def test_existing_mailbox_identity_and_password_are_verified(self): + wanted = dict(delivery.lane.FIELDS, SMTP_PASSWORD="synthetic-fixture") + self.assertEqual(delivery.lane.validate_entry({"data": wanted}), "synthetic-fixture") + for field in ["SMTP_USERNAME", "SMTP_HOST", "SMTP_FROM", "SMTP_PASSWORD"]: + bad = dict(wanted, **{field: ""}) + with self.subTest(field=field), self.assertRaises(delivery.lane.LaneError): + delivery.lane.validate_entry({"data": bad}) + + def test_reusing_lane_does_not_change_telemetry_admission(self): + import telemetry_smtp_delivery + self.assertEqual(telemetry_smtp_delivery.LANE["namespace"], "telemetry") + self.assertEqual(telemetry_smtp_delivery.LANE["service_account"], "telemetry-smtp-eso") + + +if __name__ == "__main__": + unittest.main() diff --git a/workplans/RPF-WP-0052-authelia-platform-smtp-admission.md b/workplans/RPF-WP-0052-authelia-platform-smtp-admission.md new file mode 100644 index 0000000..fdf66f4 --- /dev/null +++ b/workplans/RPF-WP-0052-authelia-platform-smtp-admission.md @@ -0,0 +1,54 @@ +--- +id: RPF-WP-0052 +type: workplan +title: "Admit scoped Authelia platform mailbox consumption" +domain: financials +repo: railiance-platform +status: active +owner: codex +topic_slug: railiance-platform +created: "2026-10-06" +updated: "2026-10-06" +--- + +# Purpose and change boundary + +Approve a new consumer of the existing platform@coulomb.social SMTP mailbox, +not a new mailbox, password rotation, shared namespace role or telemetry change. +Related: CSOC-WP-0010, NK-WP-0047, CCR-2026-0035. Prepared review branch only. + +## Prepare fixed attended mailbox-consumer admission + +```task +id: RPF-WP-0052-T01 +status: done +priority: high +``` + +CCR-2026-0035 and scripts/authelia_smtp_delivery.py reuse the tested silent owner lane; exact sso/authelia-smtp-eso ServiceAccount, OpenBao audience, max15m token/no default policy. Preserve SMTP credential/version and telemetry consumer. Verify password/settings privately and SMTP AUTH without mail send; deny coding-agent direct data/metadata access; refuse different existing policy/role. + +## Execute attended owner admission + +```task +id: RPF-WP-0052-T02 +status: wait +priority: high +``` + +Founder exact approval and own interactive OpenBao platform-admin login required. Execute helper from approved owner checkout with a new mode0600 receipt. Success requires verified receipt and Warden actual child-completion outcome, not exit code alone. Never print mailbox fields/password or reuse static ESO token helpers. + +## Verify scoped delivery and owner handoff + +```task +id: RPF-WP-0052-T03 +status: wait +priority: high +``` + +NetKingdom applies dedicated service account/store/projection and checks Ready. Demonstrate correct consumer positive/other-consumer negative boundary, read-only path, credential untouched, actual package SMTP readiness. Record retained role/policy IDs and handoff to NK-WP-0047; do not claim inbox receipt from AUTH alone. + +Prepared evidence: ten SMTP admission tests passed; notifier/password-mount +and password-only ESO projection parsed; server dry-run accepted package +resources. Dedicated SMTP egress is required and drafted. Native runtime +credential validation, admitted consumer and inbox receipt remain pending. +No live activation or mail sent.