Security checklist
Use this before a service takes real traffic. Most items are enforced at startup when you declare
app.require_posture(Posture::AuthenticatedApi). See Secure defaults
for the codes.
Identity
-
auth_provider = "Keycloak"(or your OIDC IdP). MockAuth is for development only. -
issuer,audience, and a non-emptyaccepted_azpare set. -
application_secret_keyandoauth2_client_secretcome from a secret store, never the file. -
cookie_https_only = true,validate_csrf_token = true, and a deliberatecookie_same_site. -
safe_redirect_domainslists only your own front ends.
Authorization
-
[riverbase.casbin] enabled = true, with a policy reviewed like code. - Every mounted command has a policy row (no
CAS-013at startup). - Every custom route is registered with
RouteAccess::Enforcedor is public with a reason and sign-off. - Workers that send commands run with a
CommandPolicy. -
omit_inaccessible_openapi = trueif API documents are exposed to end users.
Data
- Every query resource declares
policy:.public(…)only for data that is truly shared. - Tenant-owned resources rely on
_tenantfiltering and add ascope_policywhere rows need finer restriction. -
tenant_access_policy = "system"only on operator portals. - Deletion semantics (soft, hard, or prohibited) are decided for every aggregate root.
Surface
-
api_zoneis declared, so each deployment registers only its routes. - CORS is configured with explicit origins. No wildcard with credentials.
- Body and upload limits match the largest legitimate request.
-
deny_unknown_fields = truefor public APIs. -
RIVERBASE_INSECURE_ALLOWis absent from production configuration. -
RIVERBASE_DEBUGis unset, or understood to change verbosity only.
Operations
- Logs are
jsonand do not include raw tokens. The framework never logs secrets; keep it that way in custom handlers. - Database credentials are least-privilege, and migrations run with a separate role if your policy requires it.
- Audit retention is configured to your compliance window.
- Outbox consumers are idempotent.