save progress
This commit is contained in:
469
docs/flows/17-exception-approval-workflow.md
Normal file
469
docs/flows/17-exception-approval-workflow.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# Exception Approval Workflow
|
||||
|
||||
## Overview
|
||||
|
||||
The Exception Approval Workflow describes how StellaOps handles policy exception requests, from initial submission through multi-level approval, time-limited grants, and expiration tracking. This flow ensures exceptions are documented, justified, and automatically expire.
|
||||
|
||||
**Business Value**: Maintain security governance while allowing controlled exceptions for legitimate business needs, with full audit trail and automatic expiration.
|
||||
|
||||
## Actors
|
||||
|
||||
| Actor | Type | Role |
|
||||
|-------|------|------|
|
||||
| Developer | Human | Requests exception |
|
||||
| Team Lead | Human | First-level approval |
|
||||
| Security Team | Human | Security review and approval |
|
||||
| CISO | Human | Final approval (high severity) |
|
||||
| Policy Engine | Service | Enforces exception |
|
||||
| Scheduler | Service | Tracks expiration |
|
||||
| Notify | Service | Sends alerts |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Policy violation detected
|
||||
- Exception workflow configured
|
||||
- Approval chain defined
|
||||
- Notification channels configured
|
||||
|
||||
## Exception Types
|
||||
|
||||
| Type | Description | Max Duration | Approval Level |
|
||||
|------|-------------|--------------|----------------|
|
||||
| Temporary | Time-limited deferral | 30 days | Team Lead |
|
||||
| Extended | Business justification | 90 days | Security Team |
|
||||
| Permanent | Architectural constraint | Indefinite | CISO |
|
||||
| Emergency | Incident response | 7 days | Security Team |
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Exception Approval Workflow │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌───────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌───────────┐
|
||||
│ Developer │ │ Team Lead│ │ Security │ │ Policy │ │Scheduler│ │ Notify │
|
||||
└─────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ └─────┬─────┘
|
||||
│ │ │ │ │ │
|
||||
│ Request │ │ │ │ │
|
||||
│ exception │ │ │ │ │
|
||||
│───────────────────────────────────────> │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Validate │ │
|
||||
│ │ │ │ request │ │
|
||||
│ │ │ │───┐ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │<──┘ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Notify │ │
|
||||
│ │ │ │ approvers │ │
|
||||
│ │ │ │──────────────────────────>
|
||||
│ │ │ │ │ │
|
||||
│ │ Approval │ │ │ │ Send
|
||||
│ │ request │ │ │ │ email
|
||||
│ │<──────────────────────────────────────────────────
|
||||
│ │ │ │ │ │
|
||||
│ │ Review & │ │ │ │
|
||||
│ │ approve │ │ │ │
|
||||
│ │───────────────────────────> │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ [If high │ │
|
||||
│ │ │ │ severity] │ │
|
||||
│ │ │ │───────────────────────────>
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Approval │ │ │
|
||||
│ │ │ request │ │ │
|
||||
│ │ │<──────────────────────────────────────
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Review & │ │ │
|
||||
│ │ │ approve │ │ │
|
||||
│ │ │───────────>│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Grant │ │
|
||||
│ │ │ │ exception │ │
|
||||
│ │ │ │───┐ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │<──┘ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ Schedule │ │
|
||||
│ │ │ │ expiration│ │
|
||||
│ │ │ │──────────>│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ Schedule │
|
||||
│ │ │ │ │ reminders │
|
||||
│ │ │ │ │───┐ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │ │<──┘ │
|
||||
│ │ │ │ │ │
|
||||
│ Exception │ │ │ │ │
|
||||
│ granted │ │ │ │ │
|
||||
│<───────────────────────────────────────────────────────────────
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │[7d before] │
|
||||
│ │ │ │ │ expiration │
|
||||
│ │ │ │ │────────────>
|
||||
│ │ │ │ │ │
|
||||
│ Expiration │ │ │ │ │ Notify
|
||||
│ warning │ │ │ │ │ owner
|
||||
│<──────────────────────────────────────────────────────────────
|
||||
│ │ │ │ │ │
|
||||
```
|
||||
|
||||
## Step-by-Step
|
||||
|
||||
### 1. Exception Request
|
||||
|
||||
Developer submits exception request:
|
||||
|
||||
```json
|
||||
{
|
||||
"request_id": "exc-req-123",
|
||||
"requester": "developer@acme.com",
|
||||
"created_at": "2024-12-29T10:00:00Z",
|
||||
"finding": {
|
||||
"scan_id": "scan-abc123",
|
||||
"cve": "CVE-2024-1234",
|
||||
"package": "pkg:npm/lodash@4.17.20",
|
||||
"severity": "high",
|
||||
"policy_violation": "no-high-production"
|
||||
},
|
||||
"exception_type": "temporary",
|
||||
"requested_duration": "30d",
|
||||
"justification": {
|
||||
"business_reason": "Upgrading lodash breaks critical authentication flow. Need time to refactor.",
|
||||
"risk_acceptance": "Vulnerability requires prototype pollution which is not exploitable in our usage pattern.",
|
||||
"mitigation_plan": "WAF rule deployed to block exploitation vectors. Ticket JIRA-1234 tracks fix.",
|
||||
"remediation_deadline": "2025-01-28"
|
||||
},
|
||||
"scope": {
|
||||
"images": ["docker.io/myorg/auth-service:*"],
|
||||
"environments": ["production"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Request Validation
|
||||
|
||||
Policy Engine validates the request:
|
||||
|
||||
```json
|
||||
{
|
||||
"validation": {
|
||||
"request_id": "exc-req-123",
|
||||
"valid": true,
|
||||
"checks": [
|
||||
{"check": "cve_exists", "passed": true},
|
||||
{"check": "policy_violation_active", "passed": true},
|
||||
{"check": "requester_authorized", "passed": true},
|
||||
{"check": "scope_valid", "passed": true},
|
||||
{"check": "duration_within_limits", "passed": true}
|
||||
],
|
||||
"required_approvers": [
|
||||
{"role": "team_lead", "required": true},
|
||||
{"role": "security_team", "required": true, "reason": "high_severity"}
|
||||
],
|
||||
"approval_deadline": "2024-12-31T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Approval Chain Notification
|
||||
|
||||
Notify sends approval requests:
|
||||
|
||||
```json
|
||||
{
|
||||
"notification": {
|
||||
"type": "exception_approval_request",
|
||||
"recipients": [
|
||||
{"email": "team-lead@acme.com", "role": "team_lead"},
|
||||
{"channel": "slack", "target": "#security-approvals"}
|
||||
],
|
||||
"content": {
|
||||
"request_id": "exc-req-123",
|
||||
"requester": "developer@acme.com",
|
||||
"cve": "CVE-2024-1234",
|
||||
"severity": "high",
|
||||
"justification_summary": "Upgrading breaks auth flow. WAF mitigation in place.",
|
||||
"approval_url": "https://console.stellaops.local/exceptions/exc-req-123/approve"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. First-Level Approval (Team Lead)
|
||||
|
||||
Team Lead reviews and approves:
|
||||
|
||||
```json
|
||||
{
|
||||
"approval": {
|
||||
"request_id": "exc-req-123",
|
||||
"approver": "team-lead@acme.com",
|
||||
"role": "team_lead",
|
||||
"decision": "approved",
|
||||
"approved_at": "2024-12-29T11:00:00Z",
|
||||
"conditions": [
|
||||
"Must have JIRA ticket for remediation",
|
||||
"Weekly status update required"
|
||||
],
|
||||
"notes": "Verified WAF rule is active. Approve with conditions."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Security Review (Second Level)
|
||||
|
||||
Security team reviews high-severity exceptions:
|
||||
|
||||
```json
|
||||
{
|
||||
"security_review": {
|
||||
"request_id": "exc-req-123",
|
||||
"reviewer": "security-analyst@acme.com",
|
||||
"role": "security_team",
|
||||
"review_date": "2024-12-29T14:00:00Z",
|
||||
"assessment": {
|
||||
"risk_rating": "medium",
|
||||
"exploitation_likelihood": "low",
|
||||
"mitigation_effectiveness": "high",
|
||||
"recommendation": "approve_with_monitoring"
|
||||
},
|
||||
"decision": "approved",
|
||||
"conditions": [
|
||||
"Enable runtime monitoring for auth-service",
|
||||
"Review exception at 15-day mark"
|
||||
],
|
||||
"approved_duration": "30d" // May reduce requested duration
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Exception Grant
|
||||
|
||||
Policy Engine activates the exception:
|
||||
|
||||
```json
|
||||
{
|
||||
"exception": {
|
||||
"exception_id": "exc-456",
|
||||
"request_id": "exc-req-123",
|
||||
"status": "active",
|
||||
"granted_at": "2024-12-29T14:30:00Z",
|
||||
"granted_by": ["team-lead@acme.com", "security-analyst@acme.com"],
|
||||
"finding": {
|
||||
"cve": "CVE-2024-1234",
|
||||
"package": "pkg:npm/lodash@4.17.20"
|
||||
},
|
||||
"scope": {
|
||||
"images": ["docker.io/myorg/auth-service:*"],
|
||||
"policy_rules": ["no-high-production"]
|
||||
},
|
||||
"validity": {
|
||||
"starts_at": "2024-12-29T14:30:00Z",
|
||||
"expires_at": "2025-01-28T14:30:00Z",
|
||||
"duration": "30d"
|
||||
},
|
||||
"conditions": {
|
||||
"require_jira_ticket": true,
|
||||
"weekly_status_update": true,
|
||||
"runtime_monitoring": true,
|
||||
"mid_point_review": "2025-01-13T14:30:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Exception Enforcement
|
||||
|
||||
During policy evaluation, exception is applied:
|
||||
|
||||
```yaml
|
||||
# Policy evaluation with exception
|
||||
finding:
|
||||
cve: CVE-2024-1234
|
||||
package: pkg:npm/lodash@4.17.20
|
||||
severity: high
|
||||
|
||||
exception_check:
|
||||
exception_id: exc-456
|
||||
scope_match: true
|
||||
still_valid: true
|
||||
conditions_met: true
|
||||
|
||||
verdict:
|
||||
original: FAIL
|
||||
with_exception: PASS
|
||||
reason: "Exception exc-456 active until 2025-01-28"
|
||||
```
|
||||
|
||||
### 8. Expiration Tracking
|
||||
|
||||
Scheduler manages exception lifecycle:
|
||||
|
||||
```json
|
||||
{
|
||||
"exception_schedule": {
|
||||
"exception_id": "exc-456",
|
||||
"events": [
|
||||
{
|
||||
"type": "mid_point_review",
|
||||
"scheduled_at": "2025-01-13T14:30:00Z",
|
||||
"notify": ["requester", "approvers"]
|
||||
},
|
||||
{
|
||||
"type": "expiration_warning",
|
||||
"scheduled_at": "2025-01-21T14:30:00Z",
|
||||
"days_before": 7,
|
||||
"notify": ["requester", "team_lead"]
|
||||
},
|
||||
{
|
||||
"type": "expiration_final_warning",
|
||||
"scheduled_at": "2025-01-27T14:30:00Z",
|
||||
"days_before": 1,
|
||||
"notify": ["requester", "team_lead", "security_team"]
|
||||
},
|
||||
{
|
||||
"type": "expiration",
|
||||
"scheduled_at": "2025-01-28T14:30:00Z",
|
||||
"action": "deactivate_exception"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9. Renewal Request (If Needed)
|
||||
|
||||
Before expiration, requester can request renewal:
|
||||
|
||||
```json
|
||||
{
|
||||
"renewal_request": {
|
||||
"exception_id": "exc-456",
|
||||
"requested_extension": "30d",
|
||||
"reason": "Refactoring taking longer than expected. PR in review.",
|
||||
"progress_update": {
|
||||
"jira_ticket": "JIRA-1234",
|
||||
"status": "In Review",
|
||||
"completion_percentage": 75
|
||||
},
|
||||
"new_deadline": "2025-02-27"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Approval Matrix
|
||||
|
||||
| Severity | Exception Type | Required Approvers |
|
||||
|----------|---------------|-------------------|
|
||||
| Low | Temporary | Team Lead |
|
||||
| Medium | Temporary | Team Lead |
|
||||
| High | Temporary | Team Lead + Security |
|
||||
| Critical | Any | Team Lead + Security + CISO |
|
||||
| Any | Extended | Team Lead + Security |
|
||||
| Any | Permanent | Security + CISO |
|
||||
| Any | Emergency | Security (expedited) |
|
||||
|
||||
## Data Contracts
|
||||
|
||||
### Exception Request Schema
|
||||
|
||||
```typescript
|
||||
interface ExceptionRequest {
|
||||
request_id: string;
|
||||
requester: string;
|
||||
created_at: string;
|
||||
finding: {
|
||||
scan_id: string;
|
||||
cve: string;
|
||||
package: string;
|
||||
severity: 'critical' | 'high' | 'medium' | 'low';
|
||||
policy_violation: string;
|
||||
};
|
||||
exception_type: 'temporary' | 'extended' | 'permanent' | 'emergency';
|
||||
requested_duration?: string;
|
||||
justification: {
|
||||
business_reason: string;
|
||||
risk_acceptance: string;
|
||||
mitigation_plan: string;
|
||||
remediation_deadline?: string;
|
||||
};
|
||||
scope: {
|
||||
images?: string[];
|
||||
environments?: string[];
|
||||
tenants?: string[];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Exception Status Schema
|
||||
|
||||
```typescript
|
||||
interface Exception {
|
||||
exception_id: string;
|
||||
request_id: string;
|
||||
status: 'pending' | 'approved' | 'rejected' | 'active' | 'expired' | 'revoked';
|
||||
finding: {
|
||||
cve: string;
|
||||
package: string;
|
||||
};
|
||||
scope: {
|
||||
images: string[];
|
||||
policy_rules: string[];
|
||||
};
|
||||
validity: {
|
||||
starts_at: string;
|
||||
expires_at: string;
|
||||
duration: string;
|
||||
};
|
||||
approvals: Array<{
|
||||
approver: string;
|
||||
role: string;
|
||||
decision: 'approved' | 'rejected';
|
||||
timestamp: string;
|
||||
conditions?: string[];
|
||||
notes?: string;
|
||||
}>;
|
||||
audit_trail: AuditEntry[];
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Recovery |
|
||||
|-------|----------|
|
||||
| Approval timeout | Escalate to next level or reject |
|
||||
| Approver unavailable | Route to backup approver |
|
||||
| Scope too broad | Request scope refinement |
|
||||
| Missing justification | Request additional details |
|
||||
| Exception conflict | Flag for manual review |
|
||||
|
||||
## Observability
|
||||
|
||||
### Metrics
|
||||
|
||||
| Metric | Type | Labels |
|
||||
|--------|------|--------|
|
||||
| `exception_requests_total` | Counter | `type`, `severity` |
|
||||
| `exception_approvals_total` | Counter | `decision`, `approver_role` |
|
||||
| `exception_active_count` | Gauge | `severity` |
|
||||
| `exception_approval_duration_hours` | Histogram | `severity` |
|
||||
| `exception_expiring_7d` | Gauge | - |
|
||||
|
||||
### Key Log Events
|
||||
|
||||
| Event | Level | Fields |
|
||||
|-------|-------|--------|
|
||||
| `exception.requested` | INFO | `request_id`, `cve`, `requester` |
|
||||
| `exception.approved` | INFO | `exception_id`, `approver`, `duration` |
|
||||
| `exception.rejected` | INFO | `request_id`, `approver`, `reason` |
|
||||
| `exception.activated` | INFO | `exception_id`, `scope` |
|
||||
| `exception.expiring` | WARN | `exception_id`, `days_remaining` |
|
||||
| `exception.expired` | INFO | `exception_id` |
|
||||
|
||||
## Related Flows
|
||||
|
||||
- [Policy Evaluation Flow](04-policy-evaluation-flow.md) - Exception enforcement
|
||||
- [Notification Flow](05-notification-flow.md) - Approval notifications
|
||||
- [Multi-Tenant Policy Rollout Flow](14-multi-tenant-policy-rollout-flow.md) - Policy context
|
||||
Reference in New Issue
Block a user