Step 23 hardens the existing AI Risk Manager path. It does not create a second identity system, risk engine, device table, model registry, or audit sink.
Bearer access tokens are short-lived JWTs. Refresh tokens are rotated and
stored only as SHA-256 digests. Argon2id verifies passwords, including a dummy
hash path for unknown users so login failures do not disclose whether a
username exists. Invalid, expired, wrong-type, and tampered tokens return a
generic 401 response.
The additive role vocabulary is USER, ANALYST, SECURITY_ADMIN,
ML_ADMIN, and SYSTEM_ADMIN. Legacy Step 16 roles remain valid for
compatibility. USER has no administration authority. Model approval,
promotion, and rollback are protected by the model-operator dependency;
ML_ADMIN, SECURITY_ADMIN, and SYSTEM_ADMIN are authorized alongside the
legacy operator roles. User administration and device trust changes are
security-operator operations.
- Login attempts are limited by username/IP, with Redis sharing the window across workers and a bounded local fallback.
- API requests are limited by IP and by a hash of the bearer token. Sensitive
mutations have a separate configurable limit.
429responses includeRetry-After. - Login-event
Idempotency-Keyhandling remains durable in PostgreSQL and returns the original assessment for a valid duplicate. Sensitive operator mutations also reserve explicitIdempotency-Keyor client request IDs in Redis with a TTL; a reuse is rejected as409 Replay detected. - Request IDs are returned in
X-Request-ID. Body size, timestamp, IP, finite-feature, enum, range, and unknown-field validation happen before risk processing. Clients cannot providerisk_score,risk_level, ordecision; those fields are server output and extra fields are rejected. - Failed login, brute-force, credential-stuffing, replay, rate-limit, authorization, invalid-input, model-tamper, MFA, and device-trust signals use bounded Prometheus labels and are written to the existing audit path where a durable request context exists.
The existing devices table now carries the additive server-managed states
KNOWN, NEW, SUSPICIOUS, and BLOCKED. Registration always starts at
NEW; clients cannot set trust state. A security operator can change it with
PATCH /api/v1/devices/{device_id}/trust. Blocked devices are rejected at
login-event ingestion. Risk scores, decisions, and explanations continue to
come from the existing rule, supervised, anomaly, and feature-explanation
pipeline. No client-supplied score is merged into an assessment.
The Step 22 lifecycle registry remains the only source of the active
supervised model. Runtime loading checks lifecycle status, approval,
feature_version, artifact existence, and SHA-256 checksum before use.
Tampered artifacts fail closed and model-management operations are audited.
.env is ignored and must contain deployment-specific secrets. Compose now
requires database and Grafana passwords from that ignored file instead of
shipping credential defaults. The checked-in .env.example contains blank
placeholders only; set database, JWT, Redis, bootstrap, and Grafana credentials
in any shared environment. Application logs and audit metadata redact passwords, tokens,
cookies, API keys, JWT material, and bootstrap secrets. SQL access uses
SQLAlchemy parameter binding.
Local Compose keeps PostgreSQL, Redis, Kafka, Prometheus, Grafana, and the API
bound to loopback by default. Redis supports the optional local
REDIS_PASSWORD Compose setting, is not a public service, and all replay,
abuse, risk-cache, and state keys use explicit TTLs. Before production,
require Redis authentication plus TLS or a private network ACL, disable public
port publishing, rotate credentials, and verify eviction/availability policy.
Local Kafka intentionally remains a single-node PLAINTEXT development broker. Production deployment requires private listener exposure, TLS, SASL or mTLS client authentication, broker ACLs for login/risk/security/dead-letter topics, least-privilege consumer groups, encryption at rest, and monitored retention. Those production controls are documented here without changing the local Docker workflow.
The Grafana security dashboard carries an AI SECURITY OVERVIEW panel and includes login volume/failures, blocked logins, MFA, suspicious devices, rate-limit violations, authorization failures, abuse signals, replay detection, and a bounded security-event timeline. Prometheus exports no user IDs, IPs, tokens, request IDs, model versions, or raw request contents as labels.
The Step 23 regression suite covers unauthenticated 401, wrong-role 403,
authorized role success, 429 rate limiting, invalid input, replay, model
integrity failure, unauthorized promotion, client-decision rejection,
brute-force detection, new-device handling, and blocked-device handling.