.gitbay/wiki/Architecture/09-Controls.org
104 lines · 10386 bytes
Controls matrix
- Architecture (V1)
- Authentication (V2) and session management (V3)
- Access control (V4)
- Input handling and output encoding (V5)
- Cryptography (V6) and data protection (V8)
- Logging (V7)
- Communications and integrations (V9, V10, V12)
- CI and build isolation
- Availability and operations
One row per control an auditor typically asks about. Status: in
place (implemented and cited), partial (implemented with a stated
limit), gap (not implemented; see 10). Categories follow the
chapter names of OWASP ASVS 4.0 where one fits.
Architecture (V1)
| Control | Status | Evidence |
|---|---|---|
| One authorization path for every surface | partial | all surfaces call control.Dispatch (internal/control/control.go); three web toggles write the store directly (#261) |
| No server-side signing key | in place | internal/sig verifies only |
| Least functionality by default | in place | API, web accounts, git://, push and registration default off (internal/config/config.go) |
| No git library; git runs as a subprocess with built argv | in place | internal/gitutil |
Authentication (V2) and session management (V3)
| Control | Status | Evidence |
|---|---|---|
| No passwords anywhere | in place | SSH keys, emailed single-use links, bearer tokens |
| Credentials stored as hashes | in place | SHA-256 of 256-bit random values (internal/store/sessions.go) |
| Brute-force limit on SSH auth | in place | 10 failures a minute per IP (internal/sshd/ratelimit.go) |
| Account enumeration resistance at login | in place | uniform response (internal/control/loginlink.go) |
| Session cookie flags | in place | HttpOnly, SameSite=Lax, Secure with TLS (internal/httpd/accounts.go) |
| Session lifetime | in place | 12 hours idle, 7 days absolute (internal/store/sessions.go) |
| Credential expiry | in place | optional --ttl on API tokens, SSH and deploy keys; checked at auth and per exec |
| 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) |
| 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) |
Access control (V4)
| Control | Status | Evidence |
|---|---|---|
| Deny by default on private data | in place | CanRead requires owner, public or grant (internal/policy/access.go) |
| Private resources indistinguishable from missing | in place | resolveRepo (internal/control/repo.go), runGit, smart HTTP |
| Credential scopes narrow account rights | in place | key and token scopes (control.go, policy/access.go) |
| Server-side write protections | in place | pre-receive CheckPush, signed commits (internal/hookd/hookd.go) |
| Merge gates | in place | MergeGates; ci/* statuses written only by the build subsystem; required contexts |
| Admin functions isolated | in place | admin noun gated in Dispatch; audit admin-only |
| CSRF protection | in place | SameSite=Lax plus checkOrigin (accounts.go) |
| Typed confirmation for destructive web actions | in place | internal/httpd/confirm.go |
Input handling and output encoding (V5)
| Control | Status | Evidence |
|---|---|---|
| User markup sanitised | in place | ugcHTML with bluemonday (internal/httpd/web.go) |
| No script execution in pages | in place | CSP script-src 'none' (internal/httpd/routes.go) |
| Control characters stripped at the terminal | in place | termSafe (internal/control/term.go) |
| No shell in command execution | in place | protocol.Tokenize for SSH argv; git and podman with argv slices |
| Parsers fuzzed | partial | five fuzz targets run briefly by deploy/audit.sh |
Cryptography (V6) and data protection (V8)
| Control | Status | Evidence |
|---|---|---|
| TLS for all authenticated HTTP | in place | ACME or certificate files; HSTS |
| Secrets encrypted at rest | in place | AES-256-GCM, key file outside the database and the main backups (internal/seal) |
| Secrets kept out of argv, logs and output | in place | ReadsStdin, pruned audit argv, write-only secret commands |
| Local backups encrypted | in place | age to [backup] age_recipients (cmd/gitbayd/backup.go); offsite copy by restic |
| Data retention configurable | in place | [retention] (internal/config/config.go) |
| User data export | in place | account export |
Logging (V7)
| Control | Status | Evidence |
|---|---|---|
| Security-relevant writes audited | in place | every successful mutating command (control.go) |
| Authentication failures audited | in place | auth.failed, auth.throttled |
| Denied attempts audited | in place | refused mutating commands and pushes, ten a minute per actor, 600 in all (internal/control/auditrefusal.go) |
| Audit log tamper resistance | partial | hash chain checked by gitbayd admin audit verify; every row the daemon writes copied to its journal; the table is writable by the daemon user, and removing the newest rows (or reusing their ids) shows only by comparing verify's last id and hash with the journal |
Communications and integrations (V9, V10, V12)
| Control | Status | Evidence |
|---|---|---|
| SSRF protection on user-supplied URLs | partial | webhooks at save and connect; mirrors at save and sync, git pinned to the checked address (internal/mirror/mirror.go); repo import --from has no address check (#298) |
| Webhook payload integrity | in place | HMAC-SHA256 header |
| SMTP credentials protected in transit | in place | STARTTLS required for non-local relays, implicit TLS optional (internal/mail/mail.go) |
| Upload size limits | in place | per-owner storage quota at push (internal/sshd/sshd.go); API body 1 MiB |
CI and build isolation
| Control | Status | Evidence |
|---|---|---|
| Untrusted code runs isolated | in place | rootless podman, cgroup limits; untrusted builds get a disposable home (cmd/gitbay-runner/main.go) |
| No secrets for untrusted builds | in place | internal/control/build.go |
| Runner limited to attached repositories | in place | runnerMayBuild (build.go) |
| Build images fixed by the operator | in place | --pull=never |
| Build network egress restricted | partial | host: loopback closed, public 22/80/443 only (gitbay-runner-egress.nft); internet outbound open by decision (#260) |
| Build results reused only across equal trust | in place | SuccessBuildForTree, SuccessBuildFor (internal/store/builds.go) |
Availability and operations
| Control | Status | Evidence |
|---|---|---|
| Rate limits on API and writes | in place | 5. Rate limits |
| Concurrency limit on git pack generation | gap | #262 |
| Service hardening | in place | systemd sandboxing (3) |
| Backups offsite and append-only | in place | restic with append-only credentials (documented) |
| Restore tested | gap | #259 |
| Migrations validated before commit | gap | foreign-key check runs after commit (#261) |
| Signed, reviewed changes to production | in place | signed commits, require-mr, ff-only merges, clean-tree deploys |