0395ad8ddc
Co-authored-by: Claude Code <kjh2064@gmail.com> Co-committed-by: Claude Code <kjh2064@gmail.com>
275 lines
11 KiB
Markdown
275 lines
11 KiB
Markdown
# 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)
|
|
|