rdev/docs/api/authentication.md
jordan 72d16929ca feat: Implement hexagonal architecture with services, webhooks, queue, and telemetry
Major refactoring to hexagonal (ports & adapters) architecture:

- Add service layer (apikey_service, project_service) for business logic
- Add webhook system with dispatcher and delivery tracking
- Add command queue with priority-based processing
- Add rate limiting with sliding window algorithm
- Add audit logging for command execution
- Add OpenTelemetry integration (traces, metrics, spans)
- Add circuit breaker for fault tolerance
- Add cached repository wrapper for performance
- Add comprehensive validation package
- Add Kubernetes client integration for pod management
- Add database migrations (allowed_ips, audit_log, rate_limiting, queue, webhooks)
- Add network policy and PodDisruptionBudget for k8s
- Remove legacy executor and projects/registry packages
- Untrack secrets.yaml (now managed via envault)
- Add coverage.out to .gitignore
- Add e2e test infrastructure with docker-compose
- Add comprehensive documentation (API, architecture, operations, plans)
- Add golangci-lint config and pre-commit hook

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:57:46 -07:00

258 lines
4.5 KiB
Markdown

# Authentication Guide
rdev uses API keys for authentication. This guide covers how to authenticate requests and manage API keys.
## API Key Format
API keys follow this format:
```
rdev_<32 random characters>
```
Example:
```
rdev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
```
## Authenticating Requests
### Using X-API-Key Header
```bash
curl https://rdev.example.com/projects \
-H "X-API-Key: rdev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
```
### Using Authorization Header
```bash
curl https://rdev.example.com/projects \
-H "Authorization: Bearer rdev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
```
## Scopes
API keys have scopes that limit what actions they can perform:
| Scope | Description |
|-------|-------------|
| `projects:read` | List and view projects |
| `projects:execute` | Execute commands in projects |
| `keys:read` | List API keys |
| `keys:write` | Create and revoke API keys |
| `admin` | Full access to all operations |
### Scope Inheritance
- `admin` scope includes all other scopes
- Command execution requires `projects:execute`
- Reading projects requires `projects:read` or `projects:execute`
## Managing API Keys
### List Keys
```bash
curl https://rdev.example.com/keys \
-H "X-API-Key: your-admin-key"
```
Response:
```json
{
"data": [
{
"id": "key-001",
"name": "production-key",
"key_prefix": "rdev_a1b2",
"scopes": ["projects:read", "projects:execute"],
"created_at": "2024-01-01T00:00:00Z",
"last_used_at": "2024-01-15T10:30:00Z"
}
]
}
```
### Create Key
```bash
curl -X POST https://rdev.example.com/keys \
-H "X-API-Key: your-admin-key" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-pipeline",
"scopes": ["projects:execute"],
"expires_in": "30d",
"allowed_ips": ["10.0.0.0/8"]
}'
```
Request body:
```json
{
"name": "ci-pipeline",
"scopes": ["projects:read", "projects:execute"],
"expires_in": "30d",
"allowed_ips": ["10.0.0.0/8", "192.168.1.0/24"]
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | yes | Human-readable key name |
| `scopes` | array | yes | Permission scopes |
| `expires_in` | string | no | Expiration duration (e.g., "30d", "24h") |
| `allowed_ips` | array | no | IP allowlist in CIDR notation |
Response:
```json
{
"data": {
"id": "key-002",
"name": "ci-pipeline",
"key": "rdev_x1y2z3...",
"scopes": ["projects:execute"],
"created_at": "2024-01-15T10:30:00Z",
"expires_at": "2024-02-14T10:30:00Z"
}
}
```
> **Important**: The full key is only returned once at creation time. Store it securely!
### Revoke Key
```bash
curl -X DELETE https://rdev.example.com/keys/key-002 \
-H "X-API-Key: your-admin-key"
```
## IP Allowlisting
Keys can be restricted to specific IP addresses:
```json
{
"name": "restricted-key",
"scopes": ["projects:execute"],
"allowed_ips": [
"10.0.0.0/8",
"192.168.1.100/32"
]
}
```
If `allowed_ips` is empty or not set, all IPs are allowed.
## Key Expiration
Keys can have an expiration time:
- Set at creation with `expires_in`
- Cannot be extended after creation
- Expired keys return `KEY_EXPIRED` error
## Best Practices
### 1. Use Least Privilege
Create keys with only the scopes needed:
```json
{
"name": "read-only-dashboard",
"scopes": ["projects:read"]
}
```
### 2. Set Expiration
For temporary access, set expiration:
```json
{
"name": "contractor-access",
"scopes": ["projects:execute"],
"expires_in": "7d"
}
```
### 3. Use IP Restrictions
For CI/CD pipelines with known IPs:
```json
{
"name": "github-actions",
"scopes": ["projects:execute"],
"allowed_ips": ["192.30.252.0/22"]
}
```
### 4. Rotate Keys Regularly
Create new keys and revoke old ones periodically.
### 5. Use Descriptive Names
Name keys by their purpose:
- `ci-github-actions`
- `dev-jordan-laptop`
- `prod-monitoring`
## Error Responses
### 401 Unauthorized
Missing or invalid API key:
```json
{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing API key"
}
}
```
### 401 Key Revoked
```json
{
"error": {
"code": "KEY_REVOKED",
"message": "API key has been revoked"
}
}
```
### 401 Key Expired
```json
{
"error": {
"code": "KEY_EXPIRED",
"message": "API key has expired"
}
}
```
### 403 IP Not Allowed
```json
{
"error": {
"code": "IP_NOT_ALLOWED",
"message": "IP address not allowed for this API key"
}
}
```
### 403 Forbidden
Insufficient scopes:
```json
{
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions. Required: projects:execute"
}
}
```