qonto-assistant/specs/security-genome.yaml
tegwick 3faf1fed71 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>
2026-07-23 22:59:06 +02:00

86 lines
3.1 KiB
YAML

# Security Genome record for qonto-assistant.
#
# Schema per kings-guard/specs/NetKingdomImmuneArchitecture.md §9.1
# ("Minimum Genome Record"). Kings Guard does not exist as a running system
# yet — this record is written now so no rework is needed once an admission
# or posture-assessment consumer does exist. See docs/SecurityPractice.md.
security_genome_record:
id: kg:genome:qonto-assistant
version: 0.1.0
ownership:
tenant_id: binky
accountable_owner: bernd.worsch
operational_owner: qonto-assistant
purpose:
intent: >
Sole holder of the company Qonto bank API credential; exposes
read-only finance capabilities (org summary, transactions,
CostRunRate hints) to authorized agent harnesses and operators via a
governed REST + MCP surface, so no client ever holds the bank key
directly.
criticality: high
identities:
workload_identity: "TBD — pending key-cape/workload-identity integration (QONTO-WP-0004)"
deployment_identity: "TBD — pending Railiance placement decision"
capabilities:
provides:
- finance.qonto.read
consumes:
- openbao-secret.read # tenants/binky/qonto-api
- qonto-thirdparty-api.read
communication:
ingress:
- caller: facade-activator # not yet built — see docs/SecurityPractice.md §6
protocol: https
egress:
- destination: openbao
protocol: https
- destination: qonto-thirdparty-api
protocol: https
# No other egress is expected or permitted. Any additional outbound
# destination observed at runtime is, by definition, a deviation from
# this genome.
data:
classifications:
- tenant-confidential
- financial
persistence: ephemeral
export_allowed: false
provenance:
signed_artifact_required: false # not yet implemented fleet-wide
approved_registry: "TBD"
sbom_required: false # not yet implemented; tracked as a gap
reproducible_build_preferred: true
expected_behavior:
max_request_rate: "per QONTO_RATE_LIMIT_REQUESTS / QONTO_RATE_LIMIT_WINDOW_SECONDS (config.py)"
external_network_access: false # beyond the two declared egress destinations
interactive_shell: prohibited
privilege_escalation: prohibited
recovery:
redeployable: true
maximum_recovery_time: PT5M # stateless; cold-start dominated by scale-to-zero wake latency
maximum_data_loss: PT0S # no persisted state
tolerances:
- id: local-dev-shared-secret-auth
description: >
QONTO_ASSISTANT_MCP_TOKEN shared-secret bearer auth is tolerated
only for fixture-backed local development, never for a deployment
holding real Qonto credentials.
expires_at: null # revisit once key-cape integration (QONTO-WP-0004) lands
- id: self-asserted-actor-claims
description: >
X-Actor-* headers are self-asserted, not yet cryptographically
bound to verified identity. Tolerated until key-cape/flex-auth
integration (QONTO-WP-0004) closes this.
expires_at: null