Control Plane Authentication & Authorization¶
Overview¶
The minato control plane supports multiple authentication mechanisms simultaneously. Requests are authenticated via a chain of providers, and authorization is enforced through role-based access control (RBAC).
Authentication Modes¶
All modes can be enabled simultaneously. The system tries each provider in order:
1. API Key (X-API-Key header) → fastest, for services
2. Bearer Token (Authorization header) → OIDC
3. Basic Auth (Authorization header)
Mode: none (Development)¶
No authentication. All requests are treated as anonymous admin.
AUTH_MODE=none
Use case: Local development, testing.
Mode: basic (Simple Setups)¶
Single shared username/password with bcrypt hashing.
AUTH_MODE=basic
AUTH_BASIC_ENABLED=true
AUTH_BASIC_USER=admin
AUTH_BASIC_PASSWORD=secret123 # Plaintext (hashed on startup)
AUTH_BASIC_ROLE=admin # viewer | operator | admin
Use case: Small teams, internal tools, simple deployments.
Security note: Password is hashed with bcrypt cost 10 on first startup. Use AUTH_BASIC_PASSWORD_HASH to provide a pre-hashed value.
Mode: apikey (Service-to-Service)¶
API keys are generated dynamically by authenticated users and stored in Kubernetes Secrets. They are not configured via environment variables.
# Enable API key support
AUTH_MODE=basic,apikey
AUTH_BASIC_ENABLED=true
AUTH_BASIC_USER=admin
AUTH_BASIC_PASSWORD=secret123
AUTH_APIKEY_ENABLED=true
Important: API keys are created via the API, not loaded from env vars.
Generating an API Key¶
# 1. Authenticate as a user (basic or OIDC)
curl -u admin:secret123 \
http://minato-controlplane:8080/api/v1/gameservers
# 2. Generate an API key (inherits your role or specify one)
curl -u admin:secret123 \
-X POST \
-H "Content-Type: application/json" \
-d '{"name": "ci-cd-pipeline", "role": "operator"}' \
http://minato-controlplane:8080/api/v1/apikeys
# Response:
{
"name": "ci-cd-pipeline",
"role": "operator",
"createdAt": "2026-05-27T20:55:00Z",
"key": "minato_a1b2c3d4e5f6...",
"warning": "This key will never be shown again. Store it securely."
}
Security: The key value is displayed exactly once during creation. It cannot be retrieved later.
Using an API Key¶
curl -H "X-API-Key: minato_a1b2c3d4e5f6..." \
http://minato-controlplane:8080/api/v1/gameservers
Listing API Keys¶
curl -u admin:secret123 \
http://minato-controlplane:8080/api/v1/apikeys
# Returns (without actual key values):
[
{
"name": "ci-cd-pipeline",
"userId": "admin",
"username": "admin",
"role": "operator",
"createdAt": "2026-05-27T20:55:00Z"
}
]
Revoking an API Key¶
curl -u admin:secret123 \
-X DELETE \
http://minato-controlplane:8080/api/v1/apikeys/ci-cd-pipeline
Storage¶
API keys are stored as Kubernetes Secrets in the control plane namespace:
apiVersion: v1
kind: Secret
metadata:
name: minato-apikey-ci-cd-pipeline
namespace: minato-system
labels:
minato.io/apikey: "true"
minato.io/created-by: admin
type: Opaque
data:
key: bWluYXRvX2ExYjJjM2Q0ZTVmNi4uLg== # base64 encoded key
metadata: eyJuYW1lIjoiY2ktY2QtcGlwZWxpbmUiLCJyb2xlIjoib3BlcmF0b3IiLi4ufQ==
Use case: CI/CD pipelines, automated tools, service accounts.
Mode: oidc (Enterprise SSO)¶
Generic OIDC-compatible provider (Keycloak, Auth0, Okta, etc.).
AUTH_MODE=oidc
AUTH_OIDC_ENABLED=true
AUTH_OIDC_ISSUER_URL=https://auth.example.com
AUTH_OIDC_CLIENT_ID=minato-controlplane
AUTH_OIDC_ROLE_CLAIM=groups # JWT claim to read roles from
Role mapping: OIDC claim values are mapped to minato roles via RBAC config.
Use case: Enterprise deployments, SSO integration.
Current limitation: Simplified JWKS implementation. For production, implement full RSA key parsing.
Combining Modes¶
Enable multiple modes simultaneously:
AUTH_MODE=basic,apikey,oidc
# Basic auth for human operators
AUTH_BASIC_ENABLED=true
AUTH_BASIC_USER=admin
AUTH_BASIC_PASSWORD=secret123
# API keys for automation (generated via API, not configured)
AUTH_APIKEY_ENABLED=true
# OIDC for enterprise users
AUTH_OIDC_ENABLED=true
AUTH_OIDC_ISSUER_URL=https://auth.example.com
Role-Based Access Control (RBAC)¶
Predefined Roles¶
| Role | Permissions |
|---|---|
| viewer | Read-only access to all resources (GET /gameservers, /profiles, /fleets, etc.) |
| operator | Viewer + execute actions, create snapshots, access console |
| admin | Operator + create/delete servers, manage API keys |
Permission Model¶
Roles use a permission-based system:
type Permission struct {
Resource string // gameservers, profiles, actions, etc.
Verbs []string // get, list, create, delete, execute
Namespaces []string // optional: restrict to specific namespaces
}
Roles can extend other roles (inheritance):
operatorextendsvieweradminextendsoperator
Route-Level Enforcement¶
// Public (no auth required)
GET /healthz
GET /readyz
// Viewer+ can read
GET /api/v1/gameservers
GET /api/v1/profiles
// Operator+ can execute actions
POST /api/v1/gameservers/{ns}/{name}/actions/{action}
// Admin only
POST /api/v1/gameservers/{namespace}
DELETE /api/v1/gameservers/{namespace}/{name}
POST /api/v1/apikeys # Generate API keys
DELETE /api/v1/apikeys/{name} # Revoke API keys
Audit Logging¶
Every request (except health endpoints) is logged as structured JSON:
{
"timestamp": "2026-05-27T16:00:00Z",
"level": "audit",
"user": "alice",
"role": "admin",
"method": "POST",
"path": "/api/v1/gameservers/default/minecraft-smp-1/actions/save-world",
"clientIP": "10.0.0.15",
"userAgent": "minato-ctl/v1.0",
"result": "success"
}
Fields:
timestamp— ISO 8601 timestampuser— Authenticated usernamerole— User's rolemethod— HTTP methodpath— Request pathclientIP— Source IP addressuserAgent— Client user agentresult—successorfailure
Output: JSON to stdout (use log aggregation to collect)
API Usage Examples¶
With Basic Auth¶
curl -u admin:secret123 \
http://minato-controlplane:8080/api/v1/gameservers
With API Key¶
curl -H "X-API-Key: minato_a1b2c3d4e5f6..." \
http://minato-controlplane:8080/api/v1/gameservers
With OIDC Bearer Token¶
curl -H "Authorization: Bearer <oidc-token>" \
http://minato-controlplane:8080/api/v1/gameservers
Implementation Details¶
Architecture¶
┌─────────────────────────────────────────────┐
│ HTTP Request │
│ │
│ Headers: Authorization / X-API-Key │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Auth Middleware │
│ │
│ Skip if /healthz or /readyz │
│ Try providers in order: │
│ 1. API Key (reads from K8s Secrets) │
│ 2. Bearer Token (OIDC) │
│ 3. Basic Auth │
│ │
│ Attach User to context │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Audit Middleware │
│ │
│ Log request with user info │
│ Capture response status │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ RBAC Middleware │
│ │
│ Check role has permission for │
│ resource + verb │
│ │
│ Return 403 if forbidden │
└──────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ API Handler │
│ │
│ User available via context │
│ Perform action, write response │
└─────────────────────────────────────────────┘
Files¶
internal/controlplane/auth/auth.go— Core interfaces, User, context helpersinternal/controlplane/auth/none.go— No-op providerinternal/controlplane/auth/basic.go— Basic auth with bcryptinternal/controlplane/auth/apikey.go— API key validation (reads from K8s Secrets)internal/controlplane/auth/storage.go— API key storage using K8s Secretsinternal/controlplane/auth/oidc.go— OIDC JWT validationinternal/controlplane/rbac/rbac.go— Role definitions, RequireRole middlewareinternal/controlplane/audit/audit.go— Structured audit logging
Security Recommendations¶
For Development¶
AUTH_MODE=none
For Small Teams¶
AUTH_MODE=basic,apikey
AUTH_BASIC_USER=admin
AUTH_BASIC_PASSWORD=<strong-password>
AUTH_APIKEY_ENABLED=true
Note: API keys are generated via the API after authenticating with basic auth.
For Production / Enterprise¶
AUTH_MODE=oidc,apikey
AUTH_OIDC_ISSUER_URL=https://auth.company.com
AUTH_OIDC_CLIENT_ID=minato-production
AUTH_APIKEY_ENABLED=true
Additional measures:
- Use HTTPS/TLS for all traffic
- Rotate API keys regularly
- Implement rate limiting (not yet implemented)
- Enable network policies to restrict control plane access
- Audit log all API key generation and usage
Future Enhancements¶
- [ ] OIDC JWKS — Full RSA key parsing with key rotation support
- [ ] Custom Roles — Config file (
/etc/minato/rbac.yaml) for custom role definitions - [ ] Rate Limiting — Per-user/per-key request throttling
- [ ] Session Management — Cookie-based sessions for browser users
- [ ] Audit Export — Send audit logs to external SIEM (Splunk, ELK, etc.)
Status: Implemented Date: 2026-05-27 Authors: minato Core Team