addons-cm/docs/openspec/changes/security-audit-hardening/specs/infra-hardening/spec.md
2026-08-07 16:46:33 +02:00

61 lines
2.9 KiB
Markdown

## ADDED Requirements
### Requirement: Hardened Odoo configuration
Production `odoo.conf` SHALL set a strong `admin_passwd` (not the default `admin`), `list_db =
False`, a `dbfilter` scoping databases per host, `proxy_mode = True`, `workers > 0`, request/time
limits, `without_demo = True`, and a strong database password (not the literal `odoo`). The
database manager SHALL NOT be reachable publicly.
#### Scenario: Database manager not exposed
- **WHEN** an anonymous client requests `/web/database/manager` on production
- **THEN** it is not served (blocked at the proxy and/or `list_db=False`)
#### Scenario: Real client IP reaches Odoo logs
- **WHEN** a login fails behind the reverse proxy
- **THEN** with `proxy_mode=True` the Odoo log records the real client IP (from `X-Forwarded-For`),
not the proxy IP
### Requirement: Reverse proxy enforces TLS, rate limiting and security headers
The nginx/traefik layer SHALL terminate TLS with strong protocols/ciphers, apply `limit_req` to
`/web/login`, `/web/session/authenticate`, `/jsonrpc` and `/xmlrpc`, and set security headers
(HSTS, X-Frame-Options/CSP, X-Content-Type-Options, Referrer-Policy). The `session_id` cookie
SHALL be `Secure`, `HttpOnly` and `SameSite`.
#### Scenario: Login rate limited
- **WHEN** a client exceeds the configured request rate on `/web/login`
- **THEN** the proxy returns 429 and further attempts are throttled
#### Scenario: Security headers present
- **WHEN** a response is returned from production
- **THEN** it includes HSTS, anti-clickjacking and content-type-options headers, and the session
cookie carries Secure/HttpOnly/SameSite
### Requirement: Brute-force sources banned on web and API
fail2ban SHALL ban source IPs that exceed a failed-authentication threshold, covering both the web
login route and the API authentication routes (`/web/session/authenticate`, `/xmlrpc/2/common`),
using the real client IP.
#### Scenario: Repeated web login failures banned
- **WHEN** a source exceeds the failed-login threshold on `/web/login`
- **THEN** fail2ban bans that IP for the configured duration
#### Scenario: API auth brute force banned
- **WHEN** a source brute-forces `/web/session/authenticate` or `/xmlrpc/2/common`
- **THEN** the same fail2ban jail bans it (attacks via API do not bypass protection)
### Requirement: Secrets and database access hardened
Database and master secrets SHALL be strong and SHALL NOT be committed in plaintext in versioned
files. The PostgreSQL port SHALL NOT be reachable from outside the host/network (firewalled), and
the database user SHALL have least privilege.
#### Scenario: DB port not externally reachable
- **WHEN** an external client attempts to connect to PostgreSQL (5432) on production
- **THEN** the connection is refused/filtered by the firewall
#### Scenario: No plaintext secrets in repo
- **WHEN** the repository is inspected
- **THEN** production database/master passwords are not present in plaintext in versioned files