# VS-01: Identity Access Control (IAC) & Role-Based Access **Vertical Slice:** VS-01 (Identity & Authorization) **Version:** 1.0 DRAFT **Date:** 2026-08-07 **Owner:** Security & Identity Architecture **Status:** 📋 DRAFT (Specification Ready for Contract Review) --- ## 📋 User Story **As a** platform security architect **I want to** establish identity, MFA, RBAC role hierarchy, and maker-checker approval boundaries **So that** all downstream slices (VS-02 through VS-08) can enforce consistent access control and segregation of duties **Acceptance Criteria:** - 📋 Identity contract defined (user/role/permission schema) - 📋 MFA policy specified (2FA/TOTP/WebAuthn tiers) - 📋 RBAC role hierarchy formalized (Guest/User/Operator/Admin/SuperAdmin + domain-specific roles) - 📋 Maker-checker approval boundaries documented (for critical operations like model promotion, dataset freeze) - 📋 Permission matrix mapped (read/write/delete/audit per role) --- ## 🎯 Non-Goals - ❌ Implement UI/API endpoints (belongs to BE/FE slices) - ❌ Integrate with external identity provider (OIDC/Kerberos setup deferred) - ❌ Build MFA enforcement engine (belongs to separate AUTH_ENFORCEMENT slice) - ❌ Execute permission checks (belongs to handler/middleware slices) - ❌ Seed production user data (deferred to operations) --- ## 🔄 State Transitions ### Identity Lifecycle ``` [UNDEFINED] ↓ (user registered) [ACTIVE] ↓ (MFA required but not set) [REQUIRES_MFA_SETUP] ↓ (MFA device registered) [MFA_CONFIGURED] ↓ (temporary disable during password reset) [MFA_SUSPENDED] ↓ (re-enable) [MFA_CONFIGURED] ↓ (admin deactivation) [INACTIVE] ↓ (security breach) [REVOKED] ``` ### Role Assignment Workflow (Maker-Checker) ``` User requests elevated role (e.g., OPERATOR → ADMIN) ↓ [PENDING_APPROVAL] ← Role request created (requester_id, requested_role, reason) ↓ Admin receives notification (role.required_approver_count = 2) ↓ Approver-1 reviews & approves/rejects ↓ [APPROVED_BY_1] or [REJECTED] ↓ (if approved by 1, awaits Approver-2) [APPROVED_BY_2] ↓ [ACTIVE] (role_assignment.effective_at set, correlation_id = approval_request.id) ↓ [EXPIRED] (optional: time-bound roles like "Quarterly Reviewer") ``` --- ## 🔐 RBAC Constraints ### Core Role Hierarchy | Role | Description | Can Access | Can Modify | Can Approve | Maker-Checker Approval Required | |------|-------------|-----------|-----------|-------------|--------| | **GUEST** | Anonymous/public | Public resources (GDP compliant) | ❌ | ❌ | N/A | | **USER** | Authenticated individual | Own data + shared workspace | Own data | ❌ | N/A | | **OPERATOR** | Operations team (data ops, risk team) | All non-sensitive data | Configurations | MODEL_ACTIVATION (1 more) | MODEL_ACTIVATION, DATASET_FREEZE | | **ADMIN** | Platform administrator | All data (except audit logs) | All (soft delete) | All (except critical) | CRITICAL_CONFIG, USER_REVOCATION | | **SUPER_ADMIN** | Super administrator | All (including audit logs) | All (hard delete) | All | N/A (can self-approve in emergency) | ### Domain-Specific Roles (Optional, for Future Slices) - **QUANT_ENGINEER** — Can read market data, backtest code; cannot modify live models - **RISK_MANAGER** — Can read risk dashboards, flag models; cannot freeze or promote - **COMPLIANCE_OFFICER** — Can audit all; cannot modify data - **MODEL_REVIEWER** — Can read model cards, evidence; approves promotion via maker-checker ### MFA Tiers | Tier | Requirement | Impact | Users | |------|-------------|--------|-------| | **NO_MFA** | None (legacy) | Guest/public read | Public API consumers | | **TOTP_OPTIONAL** | Google Authenticator / Authy (optional) | USER tier | General staff | | **TOTP_REQUIRED** | TOTP mandatory | OPERATOR+ tier | Operations, Risk, Compliance | | **HARDWARE_KEY** | YubiKey / FIDO2 (required) | SUPER_ADMIN tier | Executives, DBAs | --- ## 📊 Data Contract (v1.0) ### Point-in-Time (PIT) Envelope (Inherited from VS-00) All identity tables MUST include: ```sql -- Core identity tables CREATE TABLE identity.users ( id UUID PRIMARY KEY, email VARCHAR(255) NOT NULL UNIQUE, display_name VARCHAR(255), mfa_status VARCHAR(50) NOT NULL DEFAULT 'REQUIRES_MFA_SETUP', -- ACTIVE, REQUIRES_MFA_SETUP, MFA_CONFIGURED, INACTIVE, REVOKED mfa_method VARCHAR(50), -- TOTP, HARDWARE_KEY, none created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL ); CREATE TABLE identity.roles ( id UUID PRIMARY KEY, name VARCHAR(100) NOT NULL UNIQUE, -- GUEST, USER, OPERATOR, ADMIN, SUPER_ADMIN description TEXT, required_approver_count INT DEFAULT 1, -- How many approvers needed for elevation to this role published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL ); CREATE TABLE identity.user_roles ( id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES identity.users(id), role_id UUID NOT NULL REFERENCES identity.roles(id), assigned_by_user_id UUID, -- Who assigned this role effective_at TIMESTAMPTZ NOT NULL, expires_at TIMESTAMPTZ, -- Optional: time-bound roles is_active BOOLEAN DEFAULT TRUE, published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL ); CREATE TABLE identity.role_approval_requests ( id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES identity.users(id), requested_role_id UUID NOT NULL REFERENCES identity.roles(id), reason TEXT, status VARCHAR(50) NOT NULL DEFAULT 'PENDING_APPROVAL', -- PENDING_APPROVAL, APPROVED_BY_1, APPROVED_BY_2, REJECTED, WITHDRAWN approver_count_required INT NOT NULL, approvers JSONB NOT NULL DEFAULT '[]'::JSONB, -- [{ "approver_id": UUID, "approved_at": TIMESTAMPTZ, "reason": "" }] created_at TIMESTAMPTZ NOT NULL, published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL ); CREATE TABLE identity.mfa_devices ( id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES identity.users(id), device_type VARCHAR(50) NOT NULL, -- TOTP, HARDWARE_KEY secret_hash VARCHAR(255), -- Hashed TOTP secret (never store plaintext) device_name VARCHAR(255), -- User-friendly name ("My YubiKey", "Work Phone") registered_at TIMESTAMPTZ NOT NULL, last_used_at TIMESTAMPTZ, is_backup_device BOOLEAN DEFAULT FALSE, published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL ); CREATE TABLE identity.permissions ( id UUID PRIMARY KEY, role_id UUID NOT NULL REFERENCES identity.roles(id), resource VARCHAR(255) NOT NULL, -- "model_activation", "dataset_freeze", "user_management" action VARCHAR(50) NOT NULL, -- READ, WRITE, DELETE, AUDIT constraints JSONB, -- Optional: { "requires_approval_count": 2, "requires_evidence": ["model_card"] } published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), revision INT NOT NULL DEFAULT 1, correlation_id UUID NOT NULL, UNIQUE(role_id, resource, action) ); ``` ### Data Quality Rules - ✅ No direct password storage (use bcrypt + salt) - ✅ MFA secrets never logged or exposed in HTTP responses - ✅ All role changes tracked in `user_roles` append-only (no soft deletes) - ✅ Approval requests immutable once APPROVED_BY_1 or REJECTED - ✅ PIT envelope strictly enforced: `published_at <= cutoff` for all reads - ✅ `correlation_id` links all related tables for audit trail --- ## 🛡️ Governance Gates ### Pre-Merge Gates - [ ] **RBAC Matrix Approved:** Security team signs off on role hierarchy and permission matrix - [ ] **MFA Tier Mapping:** Confirm mapping between role tiers and MFA requirements - [ ] **Maker-Checker Thresholds:** Define approval_count per critical operation (e.g., model promotion = 2 approvers) - [ ] **Audit Log Design:** Confirm all authorization decisions (grant/deny/revoke) are logged with `correlation_id` - [ ] **Identity Provider Integration Plan:** Document OIDC/Kerberos provider (if applicable) ### Post-Merge Validation - [ ] **Schema Tests:** User/role/MFA creation tests pass (40+ scenarios) - [ ] **RBAC Policy Tests:** Permission matrix matches code (cross-checked vs ADR-SEC-001) - [ ] **PIT Query Tests:** All reads include `WHERE published_at <= @cutoff` --- ## 📋 Source / Assumptions / Unknown ### Source - **ADR-SEC-001:** OIDC/JWT/DevelopmentHeader authentication tiers (approved 2026-08-04) - **Existing RBAC:** VS-00-SLICE_SPEC (base governance, roles table exists) - **Maker-Checker Pattern:** Standard 2-approver workflow from compliance requirements ### Assumptions - ✅ OIDC identity provider will be integrated later (separate slice); VS-01 is schema + policy only - ✅ MFA enforcement (checking device before operation) happens in middleware/handler layer (not here) - ✅ Audit logging of permission checks is already handled by OutboxPollerJob + SerilogCorrelation - ✅ All users are human; no service-account roles yet (may expand in future) ### Unknown - ❓ **OIDC Provider Identity:** Which OIDC provider (Keycloak, Auth0, Azure AD)? Deferred to separate architecture decision. - ❓ **Hardware Key Vendor:** YubiKey vs other FIDO2 vendors? Deferred to procurement. - ❓ **Approval SLA:** How long can role requests stay in PENDING_APPROVAL before escalation alert? (Assumed 5 business days; confirm with ops) - ❓ **Audit Retention:** How long to retain `role_approval_requests` history? (Assumed 7 years for compliance; confirm with legal) - ❓ **Domain-Specific Roles:** Should QUANT_ENGINEER/RISK_MANAGER/COMPLIANCE roles be predefined, or dynamically created per organization? (Deferred to VS-03+) --- ## ✅ Compliance & Traceability **Governance:** AGENTS.md v16.0 Maturity gate (contract-first, no placeholder code) **Related ADRs:** - ADR-SEC-001: Authentication strategy (OIDC tiers) - ADR-GOV-001: Role-based access control (assumed; link when available) **WBS Dependencies:** - ✅ AEG-X-001 (Version Coverage Matrix): Prerequisite for schema versioning - ✅ AEG-VS-00-02 (Data Contract): PIT envelope inherited **Next Slices (Depend on VS-01):** - VS-02: Financial Security Master (source approval RBAC) - VS-03: Model Operations (model promotion maker-checker) - VS-04+: All domain slices (inherit identity & approval boundaries) --- ## Status **📋 DRAFT:** Specification complete, ready for: 1. Security team approval (RBAC matrix + MFA tiers) 2. Compliance team approval (maker-checker SLA + audit retention) 3. Architecture review (schema + PIT readiness) 4. Next: Implementation (separate PR for schema migration + tests)