release orchestrator pivot, architecture and planning
This commit is contained in:
305
docs/modules/release-orchestrator/security/auth.md
Normal file
305
docs/modules/release-orchestrator/security/auth.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# Authentication & Authorization
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
### OAuth 2.0 for Human Users
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OAUTH 2.0 AUTHORIZATION CODE FLOW │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────────┐ │
|
||||
│ │ Browser │ │ Authority │ │
|
||||
│ └────┬─────┘ └──────┬───────┘ │
|
||||
│ │ │ │
|
||||
│ │ 1. Login request │ │
|
||||
│ │ ────────────────────────────────────► │ │
|
||||
│ │ │ │
|
||||
│ │ 2. Redirect to IdP │ │
|
||||
│ │ ◄──────────────────────────────────── │ │
|
||||
│ │ │ │
|
||||
│ │ 3. User authenticates at IdP │ │
|
||||
│ │ ─────────────────────────────────► │ │
|
||||
│ │ │ │
|
||||
│ │ 4. IdP callback with code │ │
|
||||
│ │ ◄──────────────────────────────────── │ │
|
||||
│ │ │ │
|
||||
│ │ 5. Exchange code for tokens │ │
|
||||
│ │ ────────────────────────────────────► │ │
|
||||
│ │ │ │
|
||||
│ │ 6. Access token + refresh token │ │
|
||||
│ │ ◄──────────────────────────────────── │ │
|
||||
│ │ │ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### mTLS for Agents
|
||||
|
||||
Agents authenticate using mutual TLS with certificates issued by Stella's internal CA.
|
||||
|
||||
**Registration Flow:**
|
||||
1. Admin generates one-time registration token
|
||||
2. Agent starts with registration token
|
||||
3. Agent submits CSR (Certificate Signing Request)
|
||||
4. Authority issues certificate signed by Stella CA
|
||||
5. Agent uses certificate for all subsequent requests
|
||||
|
||||
### API Keys for Service-to-Service
|
||||
|
||||
External services can use API keys for programmatic access:
|
||||
- Keys are tenant-scoped
|
||||
- Keys can have restricted permissions
|
||||
- Keys can have expiration dates
|
||||
- Key usage is audited
|
||||
|
||||
## JWT Token Structure
|
||||
|
||||
### Access Token Claims
|
||||
|
||||
```typescript
|
||||
interface AccessTokenClaims {
|
||||
// Standard claims
|
||||
iss: string; // "https://authority.stella.local"
|
||||
sub: string; // User ID
|
||||
aud: string[]; // ["stella-api"]
|
||||
exp: number; // Expiration timestamp
|
||||
iat: number; // Issued at timestamp
|
||||
jti: string; // Unique token ID
|
||||
|
||||
// Custom claims
|
||||
tenant_id: string;
|
||||
roles: string[];
|
||||
permissions: Permission[];
|
||||
email?: string;
|
||||
name?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Token Lifetimes
|
||||
|
||||
| Token Type | Lifetime | Refresh |
|
||||
|------------|----------|---------|
|
||||
| Access Token | 15 minutes | Via refresh token |
|
||||
| Refresh Token | 7 days | Rotated on use |
|
||||
| Agent Token | 1 hour | Via mTLS connection |
|
||||
| API Key | Configurable | Not refreshed |
|
||||
|
||||
## Authorization Model
|
||||
|
||||
### Resource Types
|
||||
|
||||
```typescript
|
||||
type ResourceType =
|
||||
| "environment"
|
||||
| "release"
|
||||
| "promotion"
|
||||
| "target"
|
||||
| "agent"
|
||||
| "workflow"
|
||||
| "plugin"
|
||||
| "integration"
|
||||
| "evidence";
|
||||
```
|
||||
|
||||
### Action Types
|
||||
|
||||
```typescript
|
||||
type ActionType =
|
||||
| "create"
|
||||
| "read"
|
||||
| "update"
|
||||
| "delete"
|
||||
| "execute"
|
||||
| "approve"
|
||||
| "deploy"
|
||||
| "rollback";
|
||||
```
|
||||
|
||||
### Permission Structure
|
||||
|
||||
```typescript
|
||||
interface Permission {
|
||||
resource: ResourceType;
|
||||
action: ActionType;
|
||||
scope?: PermissionScope;
|
||||
conditions?: Condition[];
|
||||
}
|
||||
|
||||
type PermissionScope =
|
||||
| "*" // All resources
|
||||
| { environmentId: UUID } // Specific environment
|
||||
| { labels: Record<string, string> }; // Label-based
|
||||
```
|
||||
|
||||
### Built-in Roles
|
||||
|
||||
| Role | Description | Key Permissions |
|
||||
|------|-------------|-----------------|
|
||||
| `admin` | Full access | All permissions |
|
||||
| `release_manager` | Manage releases and promotions | Create releases, request promotions |
|
||||
| `deployer` | Execute deployments | Approve promotions (where allowed), view releases |
|
||||
| `approver` | Approve promotions | Approve promotions (SoD respected) |
|
||||
| `viewer` | Read-only access | Read all resources |
|
||||
| `agent` | Agent service account | Execute deployment tasks |
|
||||
|
||||
### Role Definitions
|
||||
|
||||
```typescript
|
||||
const roles = {
|
||||
admin: {
|
||||
permissions: [
|
||||
{ resource: "*", action: "*" }
|
||||
]
|
||||
},
|
||||
release_manager: {
|
||||
permissions: [
|
||||
{ resource: "release", action: "create" },
|
||||
{ resource: "release", action: "read" },
|
||||
{ resource: "release", action: "update" },
|
||||
{ resource: "promotion", action: "create" },
|
||||
{ resource: "promotion", action: "read" },
|
||||
{ resource: "environment", action: "read" },
|
||||
{ resource: "workflow", action: "read" },
|
||||
{ resource: "workflow", action: "execute" }
|
||||
]
|
||||
},
|
||||
deployer: {
|
||||
permissions: [
|
||||
{ resource: "release", action: "read" },
|
||||
{ resource: "promotion", action: "read" },
|
||||
{ resource: "promotion", action: "approve" },
|
||||
{ resource: "environment", action: "read" },
|
||||
{ resource: "target", action: "read" },
|
||||
{ resource: "agent", action: "read" }
|
||||
]
|
||||
},
|
||||
approver: {
|
||||
permissions: [
|
||||
{ resource: "promotion", action: "read" },
|
||||
{ resource: "promotion", action: "approve" },
|
||||
{ resource: "release", action: "read" },
|
||||
{ resource: "environment", action: "read" }
|
||||
]
|
||||
},
|
||||
viewer: {
|
||||
permissions: [
|
||||
{ resource: "*", action: "read" }
|
||||
]
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Environment-Scoped Permissions
|
||||
|
||||
Permissions can be scoped to specific environments:
|
||||
|
||||
```typescript
|
||||
// User can approve promotions only to staging
|
||||
{
|
||||
resource: "promotion",
|
||||
action: "approve",
|
||||
scope: { environmentId: "staging-env-id" }
|
||||
}
|
||||
|
||||
// User can deploy only to targets with specific labels
|
||||
{
|
||||
resource: "target",
|
||||
action: "deploy",
|
||||
scope: { labels: { "tier": "frontend" } }
|
||||
}
|
||||
```
|
||||
|
||||
## Separation of Duties (SoD)
|
||||
|
||||
When SoD is enabled for an environment:
|
||||
- The user who requested a promotion cannot approve it
|
||||
- The user who created a release cannot be the sole approver
|
||||
- Approval records include SoD verification status
|
||||
|
||||
```typescript
|
||||
interface ApprovalValidation {
|
||||
promotionId: UUID;
|
||||
approverId: UUID;
|
||||
requesterId: UUID;
|
||||
sodRequired: boolean;
|
||||
sodSatisfied: boolean;
|
||||
validationResult: "valid" | "self_approval_denied" | "sod_violation";
|
||||
}
|
||||
```
|
||||
|
||||
## Permission Checking Algorithm
|
||||
|
||||
```typescript
|
||||
async function checkPermission(
|
||||
userId: UUID,
|
||||
resource: ResourceType,
|
||||
action: ActionType,
|
||||
resourceId?: UUID
|
||||
): Promise<boolean> {
|
||||
// 1. Get user's roles and direct permissions
|
||||
const userRoles = await getUserRoles(userId);
|
||||
const userPermissions = await getUserPermissions(userId);
|
||||
|
||||
// 2. Expand role permissions
|
||||
const rolePermissions = userRoles.flatMap(r => roles[r].permissions);
|
||||
const allPermissions = [...rolePermissions, ...userPermissions];
|
||||
|
||||
// 3. Check for matching permission
|
||||
for (const perm of allPermissions) {
|
||||
if (matchesResource(perm.resource, resource) &&
|
||||
matchesAction(perm.action, action) &&
|
||||
matchesScope(perm.scope, resourceId) &&
|
||||
evaluateConditions(perm.conditions)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function matchesResource(pattern: string, resource: string): boolean {
|
||||
return pattern === "*" || pattern === resource;
|
||||
}
|
||||
|
||||
function matchesAction(pattern: string, action: string): boolean {
|
||||
return pattern === "*" || pattern === action;
|
||||
}
|
||||
```
|
||||
|
||||
## API Authorization Headers
|
||||
|
||||
All API requests require:
|
||||
```http
|
||||
Authorization: Bearer <access_token>
|
||||
```
|
||||
|
||||
For agent requests (over mTLS):
|
||||
```http
|
||||
X-Agent-Id: <agent_id>
|
||||
Authorization: Bearer <agent_token>
|
||||
```
|
||||
|
||||
## Permission Denied Response
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "PERMISSION_DENIED",
|
||||
"message": "User does not have permission to approve promotions to production",
|
||||
"details": {
|
||||
"resource": "promotion",
|
||||
"action": "approve",
|
||||
"scope": { "environmentId": "prod-env-id" },
|
||||
"requiredRoles": ["admin", "approver"],
|
||||
"userRoles": ["viewer"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Security Overview](overview.md)
|
||||
- [Agent Security](agent-security.md)
|
||||
- [Authority Module](../../../authority/architecture.md)
|
||||
Reference in New Issue
Block a user