feat: add AssumeRoleActivity for temporary LLM API token grants
Implements AWS AssumeRole-like pattern for Poimen: - User/service requests temporary access with identity + scope - AssumeRoleActivity exchanges credentials with OAuth2 auth server - Returns JWT token valid for limited time (default: 1hr, max: 24hrs) - Token used in all subsequent LLM API calls to api.riotpiao.com Key features: - Credentials from vault/K8s secrets (never hardcoded) - Scope-based access control (llm:read, llm:read llm:write, llm:admin) - Automatic token expiration tracking - Retry support for transient auth failures (2x, 1.5s backoff) - Configurable auth server endpoint Usage pattern: 1. AssumeRoleActivity(identity, scope) → JWT token 2. LLMRouter uses token in LLMAuth config 3. All activity calls validated against token + scopes 4. Workflow optionally refreshes token before expiry Security: - No credentials in code/logs (env or vault only) - Short-lived tokens (1hr default, 24hr max) - Server-enforced scope validation - Token revocation support Activity registered: #10 (authentication category) Knowledge base updated with full activity spec New file: action/assume_role.go (5.2 KB)
This commit is contained in:
@@ -407,10 +407,76 @@
|
||||
"dependencies": [],
|
||||
"notes": "Network-dependent. First activity to run for context-aware routing. Fast timeout."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AssumeRoleActivity",
|
||||
"description": "Request temporary JWT token for accessing LLM APIs (like AWS AssumeRole)",
|
||||
"category": "authentication",
|
||||
"inputs": {
|
||||
"identity": {
|
||||
"type": "string",
|
||||
"description": "User/service identity requesting access",
|
||||
"required": true,
|
||||
"examples": ["[email protected]", "service:poimen-worker"]
|
||||
},
|
||||
"clientId": {
|
||||
"type": "string",
|
||||
"description": "OAuth2 client ID (from vault if not provided)",
|
||||
"required": false
|
||||
},
|
||||
"clientSecret": {
|
||||
"type": "string",
|
||||
"description": "OAuth2 client secret (from vault if not provided)",
|
||||
"required": false
|
||||
},
|
||||
"scope": {
|
||||
"type": "string",
|
||||
"description": "Scope of access (e.g., 'llm:read' or 'llm:read llm:write')",
|
||||
"required": true,
|
||||
"examples": ["llm:read", "llm:read llm:write", "llm:admin"]
|
||||
},
|
||||
"durationSeconds": {
|
||||
"type": "integer",
|
||||
"description": "Token validity duration in seconds (default: 3600, max: 86400)",
|
||||
"required": false,
|
||||
"default": 3600
|
||||
},
|
||||
"authServerUrl": {
|
||||
"type": "string",
|
||||
"description": "Auth server URL (from AUTH_SERVER_URL env if not provided)",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"outputs": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "JWT token for calling api.riotpiao.com"
|
||||
},
|
||||
"expiresAt": {
|
||||
"type": "integer",
|
||||
"description": "Token expiration time (Unix timestamp)"
|
||||
},
|
||||
"expiresIn": {
|
||||
"type": "integer",
|
||||
"description": "Seconds until token expires"
|
||||
},
|
||||
"tokenType": {
|
||||
"type": "string",
|
||||
"description": "Token type (typically 'Bearer')"
|
||||
}
|
||||
},
|
||||
"constraints": {
|
||||
"defaultTimeout": "30s",
|
||||
"isFlaky": false,
|
||||
"recommendedRetries": 2,
|
||||
"retryBackoff": 1.5,
|
||||
"dependencies": [],
|
||||
"notes": "Must run before LLM Router to provide auth token. Call early in workflow."
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"totalActivities": 9,
|
||||
"totalActivities": 10,
|
||||
"lastUpdated": "2025-08-31T00:00:00Z",
|
||||
"categories": {
|
||||
"repository": 1,
|
||||
@@ -421,7 +487,8 @@
|
||||
"notification": 1,
|
||||
"approval": 1,
|
||||
"storage": 1,
|
||||
"memory": 1
|
||||
"memory": 1,
|
||||
"authentication": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user