Access Control Flags
Ghostunnel uses mutual TLS for authentication and access control. Both the client and server present a certificate that the other party verifies.
Server mode
Several flags restrict which clients can connect, based on fields in the client certificate.
When multiple access control flags are specified, they are OR’d together: a client is allowed if at least one flag matches.
--allow-all
Allow all clients with a valid certificate, regardless of the certificate subject. Mutually exclusive with other access control flags.
--allow-cn
Allow clients with the given common name (CN). Can be repeated. Performs an exact string match.
--allow-ou
Allow clients with the given organizational unit (OU). Can be repeated. Performs an exact string match.
--allow-dns
Allow clients with the given DNS subject alternative name (DNS SAN). Can be repeated. Matches the DNS SAN value on the certificate, no DNS lookups are performed.
--allow-uri
Allow clients with the given URI subject alternative name (URI SAN). Can be
repeated. Supports * and ** wildcards.
For example, setting --allow-uri=spiffe://ghostunnel/* would allow clients
with spiffe://ghostunnel/client1 or spiffe://ghostunnel/client2 URI SANs (as
well as other values). See documentation for the wildcard package
for more information.
--allow-policyand--allow-query(OPA bundle support since v1.9.0)
Allow clients where a Rego policy evaluates to true with the given query.
For more information, see the Open Policy Agent section below.
--disable-authentication
Disable client authentication entirely, no client certificate is required. Anyone can connect. Mutually exclusive with other access control flags.
Passing Client Identity to Backends
Ghostunnel verifies client certificates before forwarding connections, but
backends may also need to know the client’s identity for their own access
control, logging, or auditing. Use --proxy-protocol-mode=tls-full (available
since v1.10.0) to forward the client certificate (CN, full DER-encoded cert) to
the backend via PROXY protocol v2 TLV
extensions.
Client mode
In client mode, additional flags can verify properties of the server certificate. Standard hostname verification always runs regardless of which flags are set.
When multiple verification flags are specified, they are OR’d together: a connection is allowed if at least one flag matches (and hostname verification passes).
--override-server-name
Override the server name used for hostname verification and SNI, instead of
using the hostname from --target. See the ServerName field on
tls.Config.
--verify-cn
Verify the common name (CN) of the server certificate, in addition to hostname verification. Can be repeated. Performs an exact string match.
--verify-ou
Verify the organizational unit (OU) of the server certificate, in addition to hostname verification. Can be repeated. Performs an exact string match.
--verify-dns
Verify that a DNS subject alternative name (DNS SAN) is present on the server certificate, in addition to hostname verification. Can be repeated.
--verify-uri
Verify that a URI subject alternative name (URI SAN) is present on the server
certificate, in addition to hostname verification. Supports * and **
wildcards.
For example, setting --verify-uri=spiffe://ghostunnel/* would allow servers
with spiffe://ghostunnel/server1 or spiffe://ghostunnel/server2 URI SANs (as
well as other values). See documentation for the wildcard package
for more information.
--verify-policyand--verify-query(OPA bundle support since v1.9.0)
Verify that a Rego policy evaluates to true with the given query.
For more information, see the Open Policy Agent section below.
--disable-authentication
Disable client authentication, no certificate is sent to the server. Useful when the backend does not require mutual TLS.
Open Policy Agent
Available since v1.7.0, OPA bundle support available since v1.9.0.
Ghostunnel supports Open Policy Agent (OPA) in both server and client
mode. The policy must be an OPA bundle on disk. When using OPA,
we recommend expressing all access control logic in the policy itself and not
combining it with other access control flags. Policy bundles reload at runtime
via --timed-reload or SIGHUP, just like certificates.
To build a bundle from a .rego file, use the opa build command:
opa build policy.rego -o bundle.tar.gz
See the OPA bundle documentation for details on bundle structure and manifest options.
To use it in server mode, specify the --allow-policy and --allow-query flags.
Example:
ghostunnel server [...] --allow-policy=bundle.tar.gz --allow-query=data.policy.allow
To use it in client mode, specify the --verify-policy and --verify-query flags.
Example:
ghostunnel client [...] --verify-policy=bundle.tar.gz --verify-query=data.policy.allow
Inside your policy, the peer’s X.509 certificate is available as
input.certificate. The example below checks whether the client certificate
contains an allowed common name or SPIFFE ID.
You can use the Rego Playground to test and
develop policies. See the documentation for x509.Certificate
for the structure of the input.certificate variable.
Example (Playground):
package policy
import input
default allow := false
allowed_common_names = [
"client1",
"client2",
]
allowed_spiffe_ids = [
"example.com/client1",
"example.com/client1/*",
"example.com/client2",
"example.com/client2/*",
]
allow if {
# Allow if common name matches a pattern in allowed_common_names
some common_name in allowed_common_names
glob.match(common_name, [], input.certificate.Subject.CommonName)
}
allow if {
# Allow if one of the URI SANs matches a pattern in allowed_spiffe_ids
some uri in input.certificate.URIs
some spiffe_id in allowed_spiffe_ids
# Basic sanity checks for the URI SAN before we compare
uri.Scheme == "spiffe"
# User, query, fragment, etc. should not be set in the URI SAN
not uri.User
not uri.Opaque
not uri.RawQuery
not uri.Fragment
not uri.RawFragment
# Match host/path against the pattern
glob.match(spiffe_id, [".", "/"], sprintf("%s%s", [uri.Host, uri.Path]))
}
The corresponding query for this policy is data.policy.allow.
See x509.Certificate for all available fields, and the Rego documentation for the policy language reference.
Notes
- Policy bundles must be local files. There is no built-in support for loading from a remote OPA server. Fetch and store bundles locally using a separate process.
- Passing a raw
.regofile instead of a bundle to--allow-policyor--verify-policystill works for backward compatibility (treated as V0). Using a bundle is recommended so you can set the Rego language version in the bundle manifest. - By OPA convention, a policy is considered “allowed” if the query produces
exactly one result with a single element whose value is
true. - Policy evaluation timeout is the same as the connection timeout. If a policy takes more time to execute than the specified connection timeout, the connection will fail.