Add SecurityPractice.md, Security Genome record, and deny-escalation lockout
Design doc for hardening qonto-assistant before deployment to railiance01: this is the first fleet service that must be internet-reachable (external harness clients, not just in-cluster jobs) while holding a real bank credential. Covers identity (key-cape in place of the interim bearer token), authorization (finance.qonto.read in flex-auth + tenant-engine capability roles instead of the hardcoded default_tenant_id), network exposure (facade-only internet address), isolation profile, and a Kings Guard mapping (the existing audit stream is already Immune-Observation-shaped; nothing to rebuild later). Ships one concrete, dependency-free piece of that design now: DenyEscalationTracker locks out an actor who repeatedly triggers arg_constraint/credential_exfil denies within a short window, closing the gap where a probing client could retry indefinitely at whatever rate the existing rate limiter otherwise allows. Wired through CapabilityService, on by default, configurable via QONTO_DENY_ESCALATION_* env vars. Ordinary denies (authz_denied, tenant_scope) never count toward it. Also adds specs/security-genome.yaml (kings-guard's genome-record shape, populated now so no rework is needed once a consumer exists). Verified: pytest -> 39 passed (8 new); REST and MCP smoke scripts both pass against fixtures; compileall clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
78eb2a819c
commit
3faf1fed71
9 changed files with 655 additions and 1 deletions
|
|
@ -206,3 +206,16 @@ That consumer-side write remains outside this repo.
|
|||
- The service supports a `bearer` auth mode for future upstream evolution, but
|
||||
the current dogfood path remains `legacy_api_key` because that is the proven
|
||||
BINKY-WP-0005 header mode.
|
||||
|
||||
## Deny-escalation lockout
|
||||
|
||||
On by default (`QONTO_DENY_ESCALATION_ENABLED=true`). An actor who triggers
|
||||
`arg_constraint` or `credential_exfil` policy denials `QONTO_DENY_ESCALATION_THRESHOLD`
|
||||
times (default 3) within `QONTO_DENY_ESCALATION_WINDOW_SECONDS` (default 60s)
|
||||
is locked out for `QONTO_DENY_ESCALATION_LOCKOUT_SECONDS` (default 300s) —
|
||||
every request from that actor is rejected with `actor_locked_out` before the
|
||||
policy kernel is even consulted, regardless of which capability they call
|
||||
next. Ordinary denies (`authz_denied`, `tenant_scope`, `unknown_capability`)
|
||||
never count toward this — only the two reason classes that indicate
|
||||
probing/exfiltration rather than a client mistake. See
|
||||
`docs/SecurityPractice.md` §9.3 and `src/qonto_assistant/security_watch.py`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue