3.2 KiB
Security Standards
Philosophy
Defense in depth, least privilege, fail closed. Authentication verifies who; authorization verifies what they can do. Centralize both — never duplicate permission checks across handlers.
RBAC Enforcement
All protected routes use RequirePermission middleware attached at registration time:
// In router/routers.go
hostsGroup.GET("", RequirePermission("host:view"), handler)
hostsGroup.POST("/control", RequirePermission("host:control"), handler)
RequirePermission in controllers/rbac_check.go resolves the user from the JWT, looks up their effective permissions (including inherited role permissions), and aborts with 403 if the required permission is absent.
cluster_admin bypasses all permission checks via early return — do not add new bypass paths outside this single mechanism.
Permission String Format
"action:scope" — e.g., "job:submit", "host:view", "queue:manage".
Scopes: all (unrestricted), self (own resources), cluster, hostgroup, self_ug, self_hg.
Permissions are defined in config/rbac.yaml. Roles support inheritance via includes: — resolution is recursive. Add new permissions to the YAML first, then wire them onto routes.
JWT Authentication
Token flow:
POST /auth/logon→ validates credentials via configured auth backend → issues JWT with{username, IP, expiry}claims- Every subsequent request:
Authorization: Bearer <token>header middleware/validatehandler.gostrips the prefix, parses with golang-jwt, validates the IP claim against the request IP
IP-bound tokens prevent token theft across network boundaries. Do not remove the IP validation.
Token secret is loaded from config/auth.yaml at startup. It must never appear in source code or logs.
Auth Backends
Backend selection is controlled by config/auth.yaml. Supported: configfile, ldap, oauth2, pam. All backends implement the same interface — adding a new backend means implementing that interface, not modifying middleware.
Input Validation
Validate at the API boundary inside preCheck{Resource}Request() helpers — before any service or store access. Return 400 with a clear message on validation failure. Do not pass unvalidated input to downstream layers.
Secrets
- JWT secret key:
config/auth.yaml(file-system protected, chmod 0600) - LDAP bind credentials:
config/auth.yaml - Never log tokens, passwords, secret keys, or full request bodies containing credentials
- Validate all required config at startup; fail fast with a clear error if missing
Rate Limiting and IP Whitelist
Rate limiting (middleware/rate_limit.go) and IP whitelist (middleware/ip_whitelist.go) are applied before JWT validation in the middleware chain. They use ctx.ClientIP() and abort with 429 / 403 respectively. Both are configured in config/ YAML — do not hardcode thresholds.
Transport
All daemon-to-daemon communication is over TCP. Production deployments add TLS at the network layer (not handled in application code). The WAL and replication wire format uses Cap'n Proto — schema files in src/schema/. Do not add unvalidated deserialization paths for external input.