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.
Smart TCP Raw Fallback
Raw TCP fallback on a smart_tcp edge entrypoint is disabled by default. Unknown non-HTTP/non-TLS bytes reach a backend only when the entrypoint explicitly sets raw_fallback to a TCP router and the fallback source policy allows the peer.
[entrypoints.edge]
address = ":443"
protocol = "smart_tcp"
raw_fallback = "ssh-fallback"
raw_fallback_trusted_cidrs = ["100.64.0.0/10"]
Use raw_fallback_trusted_cidrs for private raw fallback. Public raw fallback requires an explicit acknowledgement:
[entrypoints.edge]
address = ":443"
protocol = "smart_tcp"
raw_fallback = "public-raw"
allow_public_raw_fallback = true
Security behavior:
- PROXY protocol v1 and v2 prefixes are rejected; Gordon does not trust or parse PROXY headers on smart TCP entrypoints.
trusted_cidrs and raw_fallback_trusted_cidrs use the peer socket IP, not X-Forwarded-For.
- HTTP-looking or TLS-looking malformed traffic is rejected and never bypasses to raw fallback.
- Entry-point-wide
trusted_cidrs applies before sniffing to all protocols; raw fallback has its own narrower policy for private fallback exposure.
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## Smart TCP Raw Fallback
60
61Raw TCP fallback on a `smart_tcp` edge entrypoint is disabled by default. Unknown non-HTTP/non-TLS bytes reach a backend only when the entrypoint explicitly sets `raw_fallback` to a TCP router and the fallback source policy allows the peer.
62
63```toml
64[entrypoints.edge]
65address = ":443"
66protocol = "smart_tcp"
67raw_fallback = "ssh-fallback"
68raw_fallback_trusted_cidrs = ["100.64.0.0/10"]
69```
70
71Use `raw_fallback_trusted_cidrs` for private raw fallback. Public raw fallback requires an explicit acknowledgement:
72
73```toml
74[entrypoints.edge]
75address = ":443"
76protocol = "smart_tcp"
77raw_fallback = "public-raw"
78allow_public_raw_fallback = true
79```
80
81Security behavior:
82
83- PROXY protocol v1 and v2 prefixes are rejected; Gordon does not trust or parse PROXY headers on smart TCP entrypoints.
84- `trusted_cidrs` and `raw_fallback_trusted_cidrs` use the peer socket IP, not `X-Forwarded-For`.
85- HTTP-looking or TLS-looking malformed traffic is rejected and never bypasses to raw fallback.
86- Entry-point-wide `trusted_cidrs` applies before sniffing to all protocols; raw fallback has its own narrower policy for private fallback exposure.
87
88## Docker network isolation
89
90Per-app Docker networks are enabled by default. To block direct external egress from isolated networks, opt into Docker internal networks:
91
92```toml
93[network_isolation]
94enabled = true
95internal = true
96```
97
98`internal = false` remains the compatibility default because some applications and attachments need direct egress during startup.
99
100## Container runtime profile
101
102```toml
103[containers]
104security_profile = "compat" # or "strict"
105```
106
107- `compat` preserves broad image compatibility while retaining `no-new-privileges` and default capability restrictions.
108- `strict` enables a read-only root filesystem, drops all capabilities, and only adds `NET_BIND_SERVICE`.
109
110Use `strict` for images designed to write only to mounted volumes and run without extra Linux capabilities.
111
112## Related
113
114- [Auth](./auth.md)
115- [Images](./images.md)
116- [Network Isolation](./network-isolation.md)
117- [Deploy](./deploy.md)
118- [Volumes](./volumes.md)
119- [Reference](./reference.md)