v2.31.0-dev14 3751047

security-hardening.md RawHistoryFolder

Security Hardening Controls

This page summarizes Gordon's security-related configuration knobs and the defaults operators should know before exposing an instance.

Registry upload quotas

Registry blob uploads are bounded by two limits under [server]:

[server]
max_blob_chunk_size = "95MB"
max_blob_size = "1GB"
  • max_blob_chunk_size limits a single upload chunk.
  • max_blob_size limits the cumulative blob/layer upload size.
  • Exceeding either limit returns an OCI-compatible size error and the failed upload is cleaned up.

Admin logs permission

Container and deploy logs can include environment-derived output. Gordon gates log access behind a dedicated scope:

gordon auth token generate --subject ops --scopes "admin:logs:read" --expiry 30d
  • /admin/logs and deploy failure logs require admin:logs:read.
  • admin:status:read does not grant log access.
  • Common secret patterns are redacted before logs are returned.

Volume pruning scope

Volume pruning only removes unused Docker volumes explicitly managed by Gordon (gordon.managed=true). It ignores unrelated Docker volumes even if they are unused.

Use dedicated admin scopes:

  • admin:volumes:read for listing volumes.
  • admin:volumes:write for prune operations.

Pass migration plaintext handling

When Gordon migrates legacy plaintext .env files into pass, it removes the plaintext source after a successful migration and does not leave .env.migrated copies by default. If pass entries already exist, migration fails closed and leaves the plaintext file in place for manual operator review rather than deleting potentially unique values.

External image registries

Gordon's configured registry is always allowed. Explicit external registries must be allowlisted:

[images]
allowed_registries = ["docker.io", "ghcr.io", "registry.example.com:5000"]
require_digest = true
  • Empty allowed_registries rejects explicit external registries.
  • localhost, loopback, private, link-local, unspecified, and metadata-style registries are rejected.
  • require_digest = true requires allowlisted external images to use @sha256:<64 hex chars>.
  • Include ports in allowlist entries when the registry uses a non-default port.

Docker network isolation

Per-app Docker networks are enabled by default. To block direct external egress from isolated networks, opt into Docker internal networks:

[network_isolation]
enabled = true
internal = true

internal = false remains the compatibility default because some applications and attachments need direct egress during startup.

Container runtime profile

[containers]
security_profile = "compat" # or "strict"
  • compat preserves broad image compatibility while retaining no-new-privileges and default capability restrictions.
  • strict enables a read-only root filesystem, drops all capabilities, and only adds NET_BIND_SERVICE.

Use strict for images designed to write only to mounted volumes and run without extra Linux capabilities.

source
1# Security Hardening Controls
2
3This page summarizes Gordon's security-related configuration knobs and the defaults operators should know before exposing an instance.
4
5## Registry upload quotas
6
7Registry blob uploads are bounded by two limits under `[server]`:
8
9```toml
10[server]
11max_blob_chunk_size = "95MB"
12max_blob_size = "1GB"
13```
14
15- `max_blob_chunk_size` limits a single upload chunk.
16- `max_blob_size` limits the cumulative blob/layer upload size.
17- Exceeding either limit returns an OCI-compatible size error and the failed upload is cleaned up.
18
19## Admin logs permission
20
21Container and deploy logs can include environment-derived output. Gordon gates log access behind a dedicated scope:
22
23```bash
24gordon auth token generate --subject ops --scopes "admin:logs:read" --expiry 30d
25```
26
27- `/admin/logs` and deploy failure logs require `admin:logs:read`.
28- `admin:status:read` does not grant log access.
29- Common secret patterns are redacted before logs are returned.
30
31## Volume pruning scope
32
33Volume pruning only removes unused Docker volumes explicitly managed by Gordon (`gordon.managed=true`). It ignores unrelated Docker volumes even if they are unused.
34
35Use dedicated admin scopes:
36
37- `admin:volumes:read` for listing volumes.
38- `admin:volumes:write` for prune operations.
39
40## Pass migration plaintext handling
41
42When Gordon migrates legacy plaintext `.env` files into `pass`, it removes the plaintext source after a successful migration and does not leave `.env.migrated` copies by default. If pass entries already exist, migration fails closed and leaves the plaintext file in place for manual operator review rather than deleting potentially unique values.
43
44## External image registries
45
46Gordon's configured registry is always allowed. Explicit external registries must be allowlisted:
47
48```toml
49[images]
50allowed_registries = ["docker.io", "ghcr.io", "registry.example.com:5000"]
51require_digest = true
52```
53
54- Empty `allowed_registries` rejects explicit external registries.
55- `localhost`, loopback, private, link-local, unspecified, and metadata-style registries are rejected.
56- `require_digest = true` requires allowlisted external images to use `@sha256:<64 hex chars>`.
57- Include ports in allowlist entries when the registry uses a non-default port.
58
59## Docker network isolation
60
61Per-app Docker networks are enabled by default. To block direct external egress from isolated networks, opt into Docker internal networks:
62
63```toml
64[network_isolation]
65enabled = true
66internal = true
67```
68
69`internal = false` remains the compatibility default because some applications and attachments need direct egress during startup.
70
71## Container runtime profile
72
73```toml
74[containers]
75security_profile = "compat" # or "strict"
76```
77
78- `compat` preserves broad image compatibility while retaining `no-new-privileges` and default capability restrictions.
79- `strict` enables a read-only root filesystem, drops all capabilities, and only adds `NET_BIND_SERVICE`.
80
81Use `strict` for images designed to write only to mounted volumes and run without extra Linux capabilities.
82
83## Related
84
85- [Auth](./auth.md)
86- [Images](./images.md)
87- [Network Isolation](./network-isolation.md)
88- [Deploy](./deploy.md)
89- [Volumes](./volumes.md)
90- [Reference](./reference.md)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close