12. Rationale
12. Rationale
← Previous: 11. Rollout | Index | Next: 13. Evolution →
12.1 Why Arc-Native
Arc SSH with Entra is already deployed on 13 of 16 Linux hosts, documented, and used daily. It provides the properties Problem 1 needs — named identity, MFA, minutes-lived certificates, IdP-driven revocation — with no broker to operate, which matters for a team of three or four. What it lacks (privilege tiers, JIT, decommissioning hygiene, recording) is supplied here with tooling the estate already runs. The alternatives below were each weighed against the invariants.
12.2 Rejected: Teleport as the Access Broker (RFC-PAM-0001)
Description: Route all human access through a Teleport cluster with a Vault SSH CA, mandatory session recording and built-in JIT requests.
Why It Was Attractive:
- Full keystroke recording, fail-closed (its INV-6) — stronger than anything Arc offers
- Built-in JIT access requests with approval chains
- One broker for SSH, database and Kubernetes access
- Certificate-only SSH with principal mapping
Why It Was Rejected:
- A new, highly available service to build and operate (Teleport, Vault SSH engine, recording storage) for a very small team — the operational cost is the dominant risk
- It was trialled and shelved; the
TeleportSentinelconnector was dormant for 90+ days and decommissioned on 2026-09-11 - Its rationale (§12) never evaluated Azure Arc SSH, which the estate had already adopted; adopting Teleport now would mean running two access designs during a long migration
- Its principal model (developers share the
ubuntulogin) gives weaker per-person file isolation than Arc's per-user accounts - Every PIM/JIT, IdP-revocation and least-privilege goal it set is achievable on Arc (Sections 5–9); only full recording is not, and that is stated (Section 10) rather than hidden
Conclusion: RFC-PAM-0001's goals are carried forward; its broker choice is superseded. If Level-2 recording later proves necessary and pam_tty_audit insufficient, Teleport can be reconsidered as an Evolution item without undoing this design.
12.3 Rejected: Azure Roles Only (User vs. PIM-Admin)
Description: Use only the two Azure roles; no on-host tiers.
Why It Was Attractive:
- Simplest possible design; nothing on the host beyond the extension
Why It Was Rejected:
- Fails the core requirement: no Operator, Editor or Deployer distinction — anyone who must deploy would need Admin (violates G-3, G-5)
- Reproduces today's problem with PIM bolted on
Conclusion: Azure RBAC decides login and root; it cannot express the tiers in between. Those must be built on the host.
12.4 Rejected: sudoers Negation ("ALL except su") for the Operator Tier
Description: Grant Operators ALL and subtract su, sudo -u, and editors.
Why It Was Attractive:
- One line; intuitively matches "sudo for everything except switching users"
Why It Was Rejected:
- Negation is bypassable by design:
sudo bash,sudo vimthen a shell escape,sudo cp /bin/sh …— root is root and cannot be partially subtracted - Violates Invariant 5 (Operator cannot become anyone else) in practice while appearing to satisfy it
Conclusion: only a positive allow-list, Runas root-only, with no shells/editors, plus pam_wheel disabling su for everyone, is enforceable.
12.5 Rejected: Direct Docker Access for Editors
Description: Put the three Editors (who are Admin-eligible anyway) in the docker group; keep the wrapper for Deployers only.
Why It Was Attractive:
- Zero change to daily habits for the three most active engineers
Why It Was Rejected:
- Reintroduces standing root-equivalent for three people, bypassing PIM — Invariants 3 and 4
- Docker operations are not attributable (the daemon's logs do not carry the invoking user) — weaker audit for the highest-impact actions (G-8)
- Re-opens the Platform Lead's original objection to
dockergroup membership
Conclusion: everyone uses pn-deploy; the dc alias removes the friction; raw Docker is available inside a PIM window.
12.6 Rejected: A Central Synchronisation Service
Description: One Azure Function reads Graph and publishes per-class membership; hosts fetch it.
Why It Was Attractive:
- A single identity holds the Graph permission instead of one per host
Why It Was Rejected:
- Adds a component every host depends on (a single point of failure) to hold one small, read-only permission
- The membership data is low-sensitivity; per-host read exposes little
Conclusion: per-host agent with the host's own managed identity (Section 8).
12.7 Rejected: Azure Machine Configuration as the Primary Enforcement
Description: Enforce sudoers/groups declaratively from Azure Policy Guest Configuration.
Why It Was Attractive:
- Azure-native drift enforcement with a portal compliance view
Why It Was Rejected:
- Custom Linux configuration packages are heavy to author and test and duplicate what Ansible already does in ovh-infra
- Does not solve dynamic group membership — the sync agent would still be needed
Conclusion: Ansible for static policy; kept as an optional audit layer (Section 13).
12.8 Rejected: Immediate Account Deletion on Removal
Description: Delete the local account in the same cycle that removes access.
Why It Was Attractive:
- Simplest lifecycle; nothing lingers
Why It Was Rejected:
- Loses reversibility for mistaken removals and forensic material; frees the UID so a new user could inherit leftover file ownership
- Adds no security: the account is inert from minute five (no password, no keys, Arc denied)
Conclusion: lock at ≤5 minutes, archive and remove at 30 days.
Document Navigation
| Previous | Index | Next |
|---|---|---|
| ← 11. Rollout | Table of Contents | 13. Evolution → |
End of Section 12