Access control
Two independent, per-tunnel controls, both enforced at the edge before a request or connection ever reaches your local app: HTTP basic auth gates ngstone port tunnels, and source-IP allowlisting gates both ngstone port and ngstone tcp.
HTTP basic auth#
Require a username and password before the edge forwards anything:
$ ngstone port 3000 --basic-auth alice:secrethttps://amber-fox-42.example.com (basic auth: 1 credential)Repeat the flag for multiple valid credentials — any one of them succeeds:
$ ngstone port 3000 --basic-auth alice:secret --basic-auth bob:hunter2Load credentials from a file instead — one user:pass pair per line, blank lines and lines starting with # ignored:
# staging credentialsalice:secretbob:hunter2$ chmod 600 creds.txt$ ngstone port 3000 --basic-auth-file creds.txtOr set NGSTONE_BASIC_AUTH, one credential per line, same as the file format:
$ export NGSTONE_BASIC_AUTH=$'alice:secret\nbob:hunter2'$ ngstone port 3000user:pass. Repeatable for multiple credentials.user:pass credential per line.user:pass credential per line.Credential precedence#
Only one source is used — they don't merge. The first one present wins:
--basic-auth was never passed.IP allowlisting#
Restrict a tunnel to a set of source CIDRs — works for both HTTP and raw TCP tunnels:
$ ngstone tcp 22 --allow-cidr 203.0.113.0/24tcp://amber-fox-42.example.com:14201 -> 127.0.0.1:22Comma-separate multiple ranges:
$ ngstone port 3000 --allow-cidr 203.0.113.0/24,198.51.100.42/32A connection from outside every listed range is rejected before it reaches your app: 403 Forbidden for HTTP, a closed connection for TCP.
Combining both#
Both controls can apply to the same HTTP tunnel at once. The edge checks the source IP first, then basic auth — a request that fails the allowlist never gets a chance to present credentials:
$ ngstone port 3000 --allow-cidr 203.0.113.0/24 --basic-auth alice:secretngstone tcp accepts --allow-cidr but rejects --basic-authat bind time — there's no HTTP request to attach credentials to inside a raw TCP stream.Security notes#
Prefer the file or the env var over the flag
ps or /proc/<pid>/cmdline on Linux. On a shared or multi-tenant machine, --basic-auth leaks your credentials to anyone who can run ps auxww. Use --basic-auth-file (mode 0600) or NGSTONE_BASIC_AUTH instead.Credentials never cross the wire in plaintext. The agent hashes each user:pass pair with SHA-256 before sending it in the Bind message, and the edge stores and compares only that digest — it never sees or stores your password.
Digests are unsalted
user:pass combinations. Use strong, unique passwords, not a reused low-entropy one.--allow-cidrtrusts whatever the edge believes is the connection's source IP. Behind a front proxy with -proxy-protocol, that means trusting the PROXY header the proxy attaches — and the edge must be told which peers are allowed to send one, with -proxy-protocol-trusted <CIDRs> on ngstoned. Without that, or without firewalling the public port to the proxy alone, a direct client can open a raw connection, forge its own PROXY header, and spoof an allowed source IP straight past the allowlist. See Behind an existing reverse proxy.
Once the edge has verified basic auth for a request, it deletes the Authorization header before forwarding — your local app and the request inspector never see the credential. If no basic auth is configured for that tunnel, Authorization passes through untouched, exactly like every other header.
Requires protocol v2#
Access control is carried in wire protocol v2. If an agent requests --basic-auth or --allow-cidr and the edge only negotiates v1, the agent refuses to bind — it fails closed rather than silently opening an unprotected tunnel:
ngstone: edge does not support access control (negotiated protocol v1); upgrade ngstoned to use --basic-auth/--allow-cidrUpgrade ngstoned to a version that offers protocol 2 to use either flag. See Versioning in the wire protocol reference.