.gitbay/wiki/Architecture/09-Controls.org

1ed9fb9399b21da8e6cf45be8389792aac82d5bc
gitbay/.gitbay/wiki/Architecture/09-Controls.org rendered · source · history · blame · raw

104 lines · 9918 bytes

  1#+title: Controls matrix
  2
  3One row per control an auditor typically asks about. *Status*: =in
  4place= (implemented and cited), =partial= (implemented with a stated
  5limit), =gap= (not implemented; see [[file:10-Known-Gaps.org][10]]). Categories follow the
  6chapter names of OWASP ASVS 4.0 where one fits.
  7
  8** Architecture (V1)
  9
 10| Control                                     | Status   | Evidence                                                         |
 11|---------------------------------------------+----------+------------------------------------------------------------------|
 12| One authorization path for every surface     | partial  | all surfaces call =control.Dispatch= (=internal/control/control.go=); three web toggles write the store directly (#261) |
 13| No server-side signing key                  | in place | =internal/sig= verifies only                                     |
 14| Least functionality by default              | in place | API, web accounts, git://, push and registration default off (=internal/config/config.go=) |
 15| No git library; git runs as a subprocess with built argv | in place | =internal/gitutil=                                     |
 16
 17** Authentication (V2) and session management (V3)
 18
 19| Control                                     | Status   | Evidence                                                         |
 20|---------------------------------------------+----------+------------------------------------------------------------------|
 21| No passwords anywhere                       | in place | SSH keys, emailed single-use links, bearer tokens                |
 22| Credentials stored as hashes                | in place | SHA-256 of 256-bit random values (=internal/store/sessions.go=)  |
 23| Brute-force limit on SSH auth               | in place | 10 failures a minute per IP (=internal/sshd/ratelimit.go=)       |
 24| Account enumeration resistance at login     | in place | uniform response (=internal/control/loginlink.go=)         |
 25| Session cookie flags                        | in place | HttpOnly, SameSite=Lax, Secure with TLS (=internal/httpd/accounts.go=) |
 26| Session lifetime                            | partial  | 7 days absolute, no idle timeout (#276)                                  |
 27| Credential expiry                           | in place | optional =--ttl= on API tokens, SSH and deploy keys; checked at auth and per exec |
 28| Revocation takes effect immediately         | in place | removing a key or disabling an account closes its connections; every exec re-reads its key (=internal/sshd/sshd.go=) |
 29| Delegation bounded by the delegating credential | partial | expiring tokens refused on =MintsCredential= commands; credentials record their creating token (=internal/control/control.go=); a web session can still mint credentials that outlive it (#297) |
 30
 31** Access control (V4)
 32
 33| Control                                     | Status   | Evidence                                                         |
 34|---------------------------------------------+----------+------------------------------------------------------------------|
 35| Deny by default on private data             | in place | =CanRead= requires owner, public or grant (=internal/policy/access.go=) |
 36| Private resources indistinguishable from missing | in place | =resolveRepo= (=internal/control/repo.go=), =runGit=, smart HTTP |
 37| Credential scopes narrow account rights     | in place | key and token scopes (=control.go=, =policy/access.go=) |
 38| Server-side write protections              | in place | pre-receive =CheckPush=, signed commits (=internal/hookd/hookd.go=) |
 39| Merge gates                                 | partial  | =MergeGates=; any writer can post a =ci/*= status (#258)         |
 40| Admin functions isolated                    | in place | =admin= noun gated in =Dispatch=; =audit= admin-only             |
 41| CSRF protection                             | in place | SameSite=Lax plus =checkOrigin= (=accounts.go=)               |
 42| Typed confirmation for destructive web actions | in place | =internal/httpd/confirm.go=                                  |
 43
 44** Input handling and output encoding (V5)
 45
 46| Control                                     | Status   | Evidence                                                         |
 47|---------------------------------------------+----------+------------------------------------------------------------------|
 48| User markup sanitised                       | in place | =ugcHTML= with bluemonday (=internal/httpd/web.go=)         |
 49| No script execution in pages                | in place | CSP =script-src 'none'= (=internal/httpd/routes.go=)         |
 50| Control characters stripped at the terminal | in place | =termSafe= (=internal/control/term.go=)                    |
 51| No shell in command execution               | in place | =protocol.Tokenize= for SSH argv; git and podman with argv slices |
 52| Parsers fuzzed                              | partial  | five fuzz targets run briefly by =deploy/audit.sh=               |
 53
 54** Cryptography (V6) and data protection (V8)
 55
 56| Control                                     | Status   | Evidence                                                         |
 57|---------------------------------------------+----------+------------------------------------------------------------------|
 58| TLS for all authenticated HTTP              | in place | ACME or certificate files; HSTS                                  |
 59| Secrets encrypted at rest                   | gap      | CI secrets, webhook secrets, mirror tokens stored in clear (#273) |
 60| Secrets kept out of argv, logs and output   | in place | =ReadsStdin=, pruned audit argv, write-only secret commands      |
 61| Local backups encrypted                     | gap      | tar.gz in clear; offsite copy encrypted by restic (#274)                |
 62| Data retention configurable                 | in place | =[retention]= (=internal/config/config.go=)              |
 63| User data export                            | in place | =account export=                                                 |
 64
 65** Logging (V7)
 66
 67| Control                                     | Status   | Evidence                                                         |
 68|---------------------------------------------+----------+------------------------------------------------------------------|
 69| Security-relevant writes audited            | in place | every successful mutating command (=control.go=)         |
 70| Authentication failures audited             | in place | =auth.failed=, =auth.throttled=                                  |
 71| Denied attempts audited                     | gap      | refused commands are not recorded (#275)                                |
 72| Audit log tamper resistance                 | gap      | same database, writable by the daemon user (#275)                       |
 73
 74** Communications and integrations (V9, V10, V12)
 75
 76| Control                                     | Status   | Evidence                                                         |
 77|---------------------------------------------+----------+------------------------------------------------------------------|
 78| SSRF protection on user-supplied URLs       | partial  | webhooks at save and connect; mirrors at save only (#279)               |
 79| Webhook payload integrity                   | in place | HMAC-SHA256 header                                               |
 80| SMTP credentials protected in transit       | partial  | STARTTLS opportunistic (#280); Go refuses PLAIN auth without TLS to a remote host |
 81| Upload size limits                          | in place | per-owner storage quota at push (=internal/sshd/sshd.go=); API body 1 MiB |
 82
 83** CI and build isolation
 84
 85| Control                                     | Status   | Evidence                                                         |
 86|---------------------------------------------+----------+------------------------------------------------------------------|
 87| Untrusted code runs isolated                | partial  | rootless podman, cgroup limits; shared build home per repository (#255) |
 88| No secrets for untrusted builds             | in place | =internal/control/build.go=                                  |
 89| Runner limited to attached repositories     | in place | =runnerMayBuild= (=build.go=)                            |
 90| Build images fixed by the operator          | in place | =--pull=never=                                                   |
 91| Build network egress restricted             | gap      | #260                                                             |
 92| Build results reused only across equal trust | gap     | tree reuse ignores trust and image (#258)                        |
 93
 94** Availability and operations
 95
 96| Control                                     | Status   | Evidence                                                         |
 97|---------------------------------------------+----------+------------------------------------------------------------------|
 98| Rate limits on API and writes               | in place | [[file:05-Identity-and-Access.org][5. Rate limits]]                         |
 99| Concurrency limit on git pack generation    | gap      | #262                                                             |
100| Service hardening                           | in place | systemd sandboxing ([[file:03-Deployment.org][3]])                                     |
101| Backups offsite and append-only             | in place | restic with append-only credentials (documented)                 |
102| Restore tested                              | gap      | #259                                                             |
103| Migrations validated before commit          | gap      | foreign-key check runs after commit (#261)                       |
104| Signed, reviewed changes to production      | in place | signed commits, =require-mr=, ff-only merges, clean-tree deploys |