Skip to content

Commit fb0d8a9

Browse files
authored
Merge pull request ghostunnel#734 from ghostunnel/cs/local-restrictions-docs
Improve the security and deployment docs
2 parents 546012a + c8b3353 commit fb0d8a9

3 files changed

Lines changed: 107 additions & 68 deletions

File tree

docs/deployment/launchd.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,40 @@ Both `SockType` and `SockFamily` must be defined for each socket. If the
8282
family is omitted, launchd opens two sockets (IPv4 and IPv6) for each key,
8383
which Ghostunnel does not currently support.
8484

85+
## UNIX Socket Activation
86+
87+
To restrict access to a specific local user (see
88+
[Security]({{< ref "general.md#restricting-to-specific-local-users" >}})),
89+
have launchd create a UNIX domain socket with the desired ownership and mode
90+
instead of binding to TCP:
91+
92+
```xml
93+
<key>Sockets</key>
94+
<dict>
95+
<key>Listener</key>
96+
<dict>
97+
<key>SockPathName</key>
98+
<string>/var/run/ghostunnel.sock</string>
99+
<key>SockPathMode</key>
100+
<integer>384</integer>
101+
<key>SockPathOwner</key>
102+
<integer>0</integer>
103+
<key>SockPathGroup</key>
104+
<integer>0</integer>
105+
<key>SockType</key>
106+
<string>stream</string>
107+
</dict>
108+
</dict>
109+
```
110+
111+
`SockPathMode` is a **decimal** integer in plist XML, not octal. `384` is
112+
`0600` (owner read/write only); `416` is `0640`; `432` is `0660`. Combined
113+
with `SockPathOwner`/`SockPathGroup`, this lets launchd enforce per-user
114+
access at socket creation time, without any firewall rules.
115+
116+
The full list of `Sockets` keys is documented in `launchd.plist(5)`
117+
(`man launchd.plist`).
118+
85119
## Installing
86120

87121
```bash

docs/deployment/systemd.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,27 @@ The `FileDescriptorName` in `ghostunnel.socket` must match the name passed to
140140
`--listen`. If multiple sockets are needed (e.g. for a status port), use the
141141
name to distinguish them.
142142

143+
### UNIX Socket Variant
144+
145+
To restrict access to a specific local user (see
146+
[Security]({{< ref "general.md#restricting-to-specific-local-users" >}})),
147+
have systemd create a UNIX domain socket with the desired ownership and mode
148+
instead of binding to TCP:
149+
150+
```ini
151+
[Socket]
152+
FileDescriptorName=ghostunnel
153+
ListenStream=/run/ghostunnel.sock
154+
SocketUser=root
155+
SocketGroup=root
156+
SocketMode=0600
157+
```
158+
159+
systemd applies `SocketUser`/`SocketGroup`/`SocketMode` at socket creation
160+
time, so only the intended user can `connect(2)` to it; no firewall rules
161+
required. See [systemd.socket(5)][systemd-socket] for the full list of
162+
options.
163+
143164
### Installing
144165

145166
```bash
@@ -162,10 +183,15 @@ the privileges it needs:
162183

163184
```ini
164185
[Service]
165-
# Run as a dedicated unprivileged user
186+
# Dedicated unprivileged user. Use User=ghostunnel if you need persistent
187+
# state or specific file ownership instead.
166188
DynamicUser=yes
167189

168-
# Filesystem restrictions
190+
# Filesystem: most of the system becomes read-only outside /dev, /proc, /sys.
191+
# Ghostunnel only needs read access to certs, which still works from standard
192+
# readable locations such as /etc. Note that ProtectHome=yes makes /home and
193+
# /root inaccessible, so certs should not be stored there unless you relax
194+
# ProtectHome or add an explicit exception with ReadOnlyPaths=.
169195
ProtectSystem=strict
170196
ProtectHome=yes
171197
PrivateTmp=yes
@@ -176,11 +202,11 @@ ProtectKernelLogs=yes
176202
ProtectControlGroups=yes
177203
ProtectProc=invisible
178204

179-
# Network: only allow AF_INET/AF_INET6 (and AF_UNIX for syslog/notify)
205+
# Network: only allow AF_INET/AF_INET6/AF_UNIX
180206
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
181207

182-
# Capabilities: drop everything, Ghostunnel doesn't need any
183-
# (use socket activation or listen on ports > 1024)
208+
# Capabilities: drop everything. Add CAP_NET_BIND_SERVICE if binding to a
209+
# privileged port (< 1024) without socket activation.
184210
CapabilityBoundingSet=
185211
NoNewPrivileges=yes
186212

@@ -196,23 +222,8 @@ RemoveIPC=yes
196222
UMask=0077
197223
```
198224

199-
### Notes
200-
201-
* **`DynamicUser=yes`** allocates a transient user at runtime. If you need
202-
persistent state or specific file ownership, use a static `User=ghostunnel`
203-
instead.
204-
* **`CapabilityBoundingSet=`** (empty) drops all capabilities. If you need to
205-
bind to a privileged port (< 1024) without socket activation, add
206-
`CAP_NET_BIND_SERVICE` instead.
207-
* **`ProtectSystem=strict`** makes the entire filesystem read-only except
208-
`/dev`, `/proc`, and `/sys`. Ghostunnel only needs to read certificate
209-
files, so this is safe. If your certificates live outside the default
210-
paths, no extra configuration is needed — they are already readable.
211-
* These settings work alongside Ghostunnel's own Landlock sandboxing
212-
(enabled by default on Linux). The two layers are complementary — systemd
213-
restricts at the process level, Landlock restricts within the process.
214-
* Run `systemd-analyze security ghostunnel.service` to audit the effective
215-
security posture of your unit file.
225+
Run `systemd-analyze security ghostunnel.service` to audit the effective
226+
security posture of your unit file.
216227

217228
[sd-notify]: https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
218229
[systemd-service]: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html

docs/security/general.md

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,29 @@
11
---
2-
title: Landlock & TLS
2+
title: General Security
33
description: Landlock sandboxing, TLS protocol settings, cipher suites, address restrictions.
44
weight: 10
55
---
66

7-
Ghostunnel's TLS settings and Landlock sandboxing.
7+
Ghostunnel's TLS settings, address restrictions, and Landlock sandboxing.
88

9-
## TLS Configuration
9+
## TLS Settings
1010

11-
Ghostunnel enforces a minimum TLS version of **TLS 1.2**. Earlier versions are
12-
not supported. TLS 1.3 is supported and will be negotiated when both sides
13-
support it.
11+
Ghostunnel enforces a minimum TLS version of TLS 1.2, and TLS 1.3 is supported
12+
and will be negotiated when both sides support it. Earlier versions of TLS are
13+
not supported.
1414

1515
### Cipher Suites
1616

17-
The following cipher suites are enabled by default, in order of preference:
18-
19-
**AES-GCM:**
20-
- `TLS_AES_128_GCM_SHA256` (TLS 1.3)
21-
- `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`
22-
- `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`
23-
- `TLS_AES_256_GCM_SHA384` (TLS 1.3)
24-
- `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`
25-
- `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`
26-
27-
**ChaCha20-Poly1305:**
28-
- `TLS_CHACHA20_POLY1305_SHA256` (TLS 1.3)
29-
- `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305`
30-
- `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305`
31-
32-
All suites use authenticated encryption (AEAD). CBC-mode ciphers are not
33-
enabled. ECDSA suites are listed before RSA to prefer ECDSA when both
34-
certificate types are available.
35-
36-
To check which cipher suite and protocol version were negotiated for a
37-
connection:
38-
39-
```bash
40-
openssl s_client -connect localhost:8443 \
41-
-cert client-cert.pem -key client-key.pem -CAfile cacert.pem \
42-
</dev/null 2>/dev/null | grep -E 'Protocol|Cipher'
43-
```
44-
4517
In TLS 1.3, cipher suite selection is handled by Go's [`crypto/tls`][crypto-tls]
46-
and cannot be configured by the application. The TLS 1.3 suites listed above are always
47-
available when TLS 1.3 is negotiated. The configurable cipher suite list only
48-
affects TLS 1.2 connections.
49-
50-
### Curve Preferences
51-
52-
In server mode, key exchange prefers the following elliptic curves:
53-
54-
1. **X25519**: fast, constant-time, widely supported
55-
2. **P-256 (secp256r1)**: hardware-accelerated on most platforms
18+
and cannot be configured by the application. For TLS 1.2, the configured cipher
19+
suites all use authenticated encryption (AEAD). Older CBC-mode ciphers are not
20+
enabled.
5621

5722
### Client Authentication
5823

5924
In server mode, Ghostunnel requires and verifies client certificates by
60-
default (`RequireAndVerifyClientCert`). This can be disabled with
61-
`--disable-authentication`, in which case no client certificate is requested.
25+
default. This can be disabled with `--disable-authentication`, in which case no
26+
client certificate is requested.
6227

6328
The status port (`--status`) is optional and does not require client
6429
certificates. It is typically consumed by monitoring systems that may not
@@ -96,6 +61,34 @@ To accept connections from remote hosts, pass `--unsafe-listen`. The listen
9661
side of client mode accepts plaintext connections, so exposing it beyond
9762
localhost risks unauthorized access to the proxied service.
9863

64+
### Restricting to specific local users
65+
66+
Binding to `localhost` (or `127.0.0.1` / `[::1]`) blocks the network, but on a
67+
shared host any local user can still connect to the port. If you need to
68+
restrict access to a specific UID (for example, only `root` may reach the
69+
plaintext side of a tunnel), bind to a UNIX domain socket and use
70+
filesystem permissions:
71+
72+
```bash
73+
ghostunnel client \
74+
--listen=unix:/var/run/ghostunnel/client.sock \
75+
--target=backend.example.com:8443 \
76+
...
77+
```
78+
79+
Set the socket's owner and mode so only the intended user can `connect(2)` to
80+
it. With socket activation, the service manager creates the socket and applies
81+
the permissions for you; see [Systemd]({{< ref "systemd.md" >}}) and
82+
[Launchd]({{< ref "launchd.md" >}}). Otherwise, ensure the socket's parent
83+
directory is `chmod 0700` and `chown` it to the intended user, since the path
84+
must be traversable to connect.
85+
86+
Firewall-based UID filtering exists but is fragile. On Linux, `iptables`
87+
supports `-m owner --uid-owner` and `nftables` supports `skuid`. On macOS, `pf`
88+
accepts `user =` rules, but Apple has formally stated that `pf` is not a stable
89+
API; see [TN3165: Packet Filter is not API][tn3165]. Prefer UNIX socket
90+
permissions, which are kernel-enforced via VFS and survive OS upgrades.
91+
9992
## Landlock sandboxing
10093

10194
*Available since v1.8.0. Enabled by default since v1.9.0.*
@@ -133,3 +126,4 @@ libraries that may require access to arbitrary files and sockets.
133126

134127
[crypto-tls]: https://pkg.go.dev/crypto/tls
135128
[landlock]: https://docs.kernel.org/userspace-api/landlock.html
129+
[tn3165]: https://developer.apple.com/documentation/technotes/tn3165-packet-filter-is-not-api

0 commit comments

Comments
 (0)