detached da5dc1a

docs: update security documentation for hardened proxy and auth controls

commit
da5dc1a3b2be84e93c800132055ef7b7d28ec937
author
bnema · · 2026-02-01 14:43 UTC
parent
504de20
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +25 -1
M docs/config/auth.md +4 -0
@@ -161,6 +161,8 @@ gordon auth token generate --subject temp --expiry 30d
161161 enabled = false
162162 ```
163163
164+> **Security Warning:** When authentication is disabled, the admin API is fully accessible without credentials. This includes endpoints to deploy containers, manage secrets, modify routes, and reload configuration. Only disable auth for local development where Gordon is not exposed to the internet.
165+
164166 ## Internal Registry Auth
165167
166168 Gordon generates internal credentials when auth is enabled. These are used for loopback pulls during deploys and are regenerated on each restart.
@@ -173,6 +175,8 @@ To view internal credentials (for troubleshooting):
173175 gordon auth internal
174176 ```
175177
178+> **Note:** Internal credentials are stored with restrictive permissions (0600) in secure runtime directories (XDG_RUNTIME_DIR or ~/.gordon/run) and cleaned up on shutdown.
179+
176180 ## Related
177181
178182 - [Secret Providers](./secrets.md)
@@ -161,6 +161,8 @@ gordon auth token generate --subject temp --expiry 30d
161 enabled = false161 enabled = false
162 ```162 ```
163 163
164+> **Security Warning:** When authentication is disabled, the admin API is fully accessible without credentials. This includes endpoints to deploy containers, manage secrets, modify routes, and reload configuration. Only disable auth for local development where Gordon is not exposed to the internet.
165+
164 ## Internal Registry Auth166 ## Internal Registry Auth
165 167
166 Gordon generates internal credentials when auth is enabled. These are used for loopback pulls during deploys and are regenerated on each restart.168 Gordon generates internal credentials when auth is enabled. These are used for loopback pulls during deploys and are regenerated on each restart.
@@ -173,6 +175,8 @@ To view internal credentials (for troubleshooting):
173 gordon auth internal175 gordon auth internal
174 ```176 ```
175 177
178+> **Note:** Internal credentials are stored with restrictive permissions (0600) in secure runtime directories (XDG_RUNTIME_DIR or ~/.gordon/run) and cleaned up on shutdown.
179+
176 ## Related180 ## Related
177 181
178 - [Secret Providers](./secrets.md)182 - [Secret Providers](./secrets.md)
M docs/config/secrets.md +6 -0
@@ -89,6 +89,11 @@ DB_PASSWORD=${sops:secrets.yaml:database.password}
8989 - YAML/JSON file encryption
9090 - Git-friendly (encrypted files in repo)
9191
92+**Security:**
93+- Absolute paths are rejected to prevent arbitrary file access
94+- Path traversal (`..`) is blocked
95+- Only relative paths from your config directory are allowed
96+
9297 **Route secrets storage:**
9398 - Domain secrets stay in `.env` files
9499 - Use `${sops:...}` syntax to resolve encrypted values
@@ -193,6 +198,7 @@ JWT_SECRET=${sops:secrets.yaml:jwt.secret}
193198 2. **Never commit**: Don't commit unencrypted secrets to git
194199 3. **Rotate regularly**: Regenerate tokens and passwords periodically
195200 4. **Least privilege**: Use separate secrets per environment
201+5. **Path validation**: SOPS provider rejects absolute paths and path traversal attempts for security
196202
197203 ## Related
198204
@@ -89,6 +89,11 @@ DB_PASSWORD=${sops:secrets.yaml:database.password}
89 - YAML/JSON file encryption89 - YAML/JSON file encryption
90 - Git-friendly (encrypted files in repo)90 - Git-friendly (encrypted files in repo)
91 91
92+**Security:**
93+- Absolute paths are rejected to prevent arbitrary file access
94+- Path traversal (`..`) is blocked
95+- Only relative paths from your config directory are allowed
96+
92 **Route secrets storage:**97 **Route secrets storage:**
93 - Domain secrets stay in `.env` files98 - Domain secrets stay in `.env` files
94 - Use `${sops:...}` syntax to resolve encrypted values99 - Use `${sops:...}` syntax to resolve encrypted values
@@ -193,6 +198,7 @@ JWT_SECRET=${sops:secrets.yaml:jwt.secret}
193 2. **Never commit**: Don't commit unencrypted secrets to git198 2. **Never commit**: Don't commit unencrypted secrets to git
194 3. **Rotate regularly**: Regenerate tokens and passwords periodically199 3. **Rotate regularly**: Regenerate tokens and passwords periodically
195 4. **Least privilege**: Use separate secrets per environment200 4. **Least privilege**: Use separate secrets per environment
201+5. **Path validation**: SOPS provider rejects absolute paths and path traversal attempts for security
196 202
197 ## Related203 ## Related
198 204
M wiki/guides/running-in-container.md +12 -0
@@ -352,6 +352,17 @@ ls -la ~/.password-store
352352
353353 ## Security Considerations
354354
355+### Container Port Binding
356+
357+When Gordon manages containers, it binds their ports to `127.0.0.1` (localhost only) by default. This prevents direct network access to containers, forcing all traffic through Gordon's reverse proxy where:
358+
359+- Authentication is enforced
360+- Rate limiting is applied
361+- Security headers are added
362+- Request logging is performed
363+
364+When running Gordon itself in a container, it communicates with managed containers via Docker's internal network (no port publishing needed).
365+
355366 ### Docker Socket Access
356367
357368 Mounting the Docker/Podman socket grants Gordon full access to the container runtime. This is required for Gordon to manage containers but has security implications:
@@ -366,6 +377,7 @@ Mounting the Docker/Podman socket grants Gordon full access to the container run
366377 2. **Limit network exposure**: Only expose ports 80/443 publicly
367378 3. **Use TLS**: Put Gordon behind a reverse proxy with TLS (Cloudflare, Caddy, nginx)
368379 4. **Enable authentication**: Always enable authentication for the registry
380+5. **Container isolation**: Container ports bound to localhost prevent direct access
369381
370382 ## Troubleshooting
371383
@@ -352,6 +352,17 @@ ls -la ~/.password-store
352 352
353 ## Security Considerations353 ## Security Considerations
354 354
355+### Container Port Binding
356+
357+When Gordon manages containers, it binds their ports to `127.0.0.1` (localhost only) by default. This prevents direct network access to containers, forcing all traffic through Gordon's reverse proxy where:
358+
359+- Authentication is enforced
360+- Rate limiting is applied
361+- Security headers are added
362+- Request logging is performed
363+
364+When running Gordon itself in a container, it communicates with managed containers via Docker's internal network (no port publishing needed).
365+
355 ### Docker Socket Access366 ### Docker Socket Access
356 367
357 Mounting the Docker/Podman socket grants Gordon full access to the container runtime. This is required for Gordon to manage containers but has security implications:368 Mounting the Docker/Podman socket grants Gordon full access to the container runtime. This is required for Gordon to manage containers but has security implications:
@@ -366,6 +377,7 @@ Mounting the Docker/Podman socket grants Gordon full access to the container run
366 2. **Limit network exposure**: Only expose ports 80/443 publicly377 2. **Limit network exposure**: Only expose ports 80/443 publicly
367 3. **Use TLS**: Put Gordon behind a reverse proxy with TLS (Cloudflare, Caddy, nginx)378 3. **Use TLS**: Put Gordon behind a reverse proxy with TLS (Cloudflare, Caddy, nginx)
368 4. **Enable authentication**: Always enable authentication for the registry379 4. **Enable authentication**: Always enable authentication for the registry
380+5. **Container isolation**: Container ports bound to localhost prevent direct access
369 381
370 ## Troubleshooting382 ## Troubleshooting
371 383
M wiki/guides/secure-vps-setup.md +3 -1
@@ -244,9 +244,11 @@ cscli decisions list | wc -l
244244 | 22 | TCP | Closed | SSH (use Tailscale instead) |
245245 | 80 | TCP | Open | HTTP (Gordon proxy) |
246246 | 443 | TCP | Open | HTTPS (Gordon proxy via Cloudflare) |
247-| 5000 | TCP | Closed | Registry (proxied through 80/443) |
247+| 5000 | TCP | Closed | Registry (proxied through 80/443, containers bind to 127.0.0.1) |
248248 | 41641 | UDP | Open | Tailscale WireGuard |
249249
250+> **Security Note:** All managed containers bind to `127.0.0.1` by default, preventing direct access to their ports. The only entry point to your applications is Gordon's reverse proxy on ports 80/443, where authentication and rate limiting are enforced.
251+
250252 ---
251253
252254 ## Troubleshooting
@@ -244,9 +244,11 @@ cscli decisions list | wc -l
244 | 22 | TCP | Closed | SSH (use Tailscale instead) |244 | 22 | TCP | Closed | SSH (use Tailscale instead) |
245 | 80 | TCP | Open | HTTP (Gordon proxy) |245 | 80 | TCP | Open | HTTP (Gordon proxy) |
246 | 443 | TCP | Open | HTTPS (Gordon proxy via Cloudflare) |246 | 443 | TCP | Open | HTTPS (Gordon proxy via Cloudflare) |
247-| 5000 | TCP | Closed | Registry (proxied through 80/443) |247+| 5000 | TCP | Closed | Registry (proxied through 80/443, containers bind to 127.0.0.1) |
248 | 41641 | UDP | Open | Tailscale WireGuard |248 | 41641 | UDP | Open | Tailscale WireGuard |
249 249
250+> **Security Note:** All managed containers bind to `127.0.0.1` by default, preventing direct access to their ports. The only entry point to your applications is Gordon's reverse proxy on ports 80/443, where authentication and rate limiting are enforced.
251+
250 ---252 ---
251 253
252 ## Troubleshooting254 ## Troubleshooting

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