Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
856a5b1
Add cgo build tags to fix CGO_ENABLED=0 cross-compilation
csstaub Apr 21, 2026
d646d56
Add --eventlog flag for Windows Event Log support
csstaub Apr 21, 2026
c696448
Add additional tests for system logger methods
csstaub Apr 22, 2026
23bc8a4
Organize docs into sections
claude Apr 23, 2026
39c8772
Add native Windows Service Control Manager support
bdudley-cw Apr 21, 2026
29fbee8
Fix minor nits in Windows service code
csstaub Apr 23, 2026
c119b3c
Add Windows service docs, reorganize systemd/launchd docs
csstaub Apr 23, 2026
5af9ec6
Proof-read and improve documentation
csstaub Apr 24, 2026
48b10b5
Add integration tests for Windows SCM
csstaub Apr 24, 2026
b4267c3
Improve integration test harness and coverage calculation
csstaub Apr 24, 2026
20dc5f4
Update tests to reflect changes in coverage instrumentation
csstaub Apr 25, 2026
025e438
Add a few more tests for Windows SCM
csstaub Apr 25, 2026
3093137
Add note about Windows SCM in README, availability in docs
csstaub Apr 25, 2026
066edde
Detect and report service start failure in service install/start
bdudley-cw Apr 27, 2026
58c5344
Improvements for readiness polling for Windows SCM
csstaub Apr 28, 2026
6c50014
Implement notify-ready functionality, generalize from the systemd fun…
csstaub Apr 28, 2026
094477f
Better Windows SCM tracking for running status
csstaub Apr 29, 2026
8a2f642
Document service subcommands in flags reference
csstaub Apr 29, 2026
dcc4a1f
Update CONTRIBUTING.md integration test coverage description
csstaub Apr 29, 2026
2d2e286
Expand launchd docs with KeepAlive, reload, and shutdown notes
csstaub Apr 29, 2026
385e1f8
Better wording for new docs
csstaub Apr 29, 2026
843d09e
Mention that v1.11 is the next release
csstaub Apr 29, 2026
4677fcc
Add Docker link in menu, add icons
csstaub Apr 29, 2026
115f214
Merge branch 'next'
csstaub Apr 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ ghostunnel
ghostunnel.man
mage-bin
ghostunnel.exe
ghostunnel.test
ghostunnel.cover
ghostunnel.certstore
ghostunnel-*
__pycache__
Expand Down
10 changes: 7 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ GHOSTUNNEL_TEST_PARALLEL=4 go tool mage test:integration # control parallelism
Integration tests run in parallel by default (up to `NumCPU`, capped at 16).
Set `GHOSTUNNEL_TEST_PARALLEL` to control the number of concurrent tests (may exceed the default cap).

The integration test runner first builds a coverage-instrumented test binary
(`go test -c`), then runs each `tests/test-*.py` script against that binary.
Each Python test starts a ghostunnel process, exercises it, and verifies behavior.
The integration test runner first builds a coverage-instrumented binary with
`go build -cover -tags coverage`. Each Python test starts that binary with
`GOCOVERDIR` pointing at a per-run directory; the `coverage` build tag (see
`coverage_enabled.go`) flushes counters on exit so data survives
signal-triggered shutdowns. After the run, `go tool covdata textfmt` converts
the binary coverage data to a text profile, which is then merged with the
unit-test profile.

## Architecture Overview

Expand Down
6 changes: 5 additions & 1 deletion Dockerfile-test
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ FROM golang:${GO_VERSION}
RUN apt-get update && \
apt-get install -y build-essential python3-minimal netcat-traditional softhsm2 rsyslog git openssl default-jre-headless </dev/null && \
mkdir -p /etc/softhsm /var/lib/softhsm/tokens /go/src/github.com/ghostunnel/ghostunnel && \
go install github.com/wadey/gocovmerge@latest && \
go install golang.org/x/tools/cmd/cover@latest && \
go install github.com/magefile/mage@latest

WORKDIR /go/src/github.com/ghostunnel/ghostunnel

# Mark workspace as safe for git — the volume mount at runtime may have
# different ownership than the container user, which causes git (and
# therefore go build with VCS stamping) to fail.
RUN git config --global --add safe.directory /go/src/github.com/ghostunnel/ghostunnel

ENV GO111MODULE=on

# Copy source code
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Linux, Landlock sandboxing is enabled by default to limit process privileges.
and Prometheus metrics endpoints, plus optional pprof profiling.

Ghostunnel also supports UNIX domain sockets, PROXY protocol v2,
systemd/launchd socket activation, and more.
systemd/launchd socket activation, Windows service management (SCM), and more.

Getting Started
===============
Expand Down
2 changes: 1 addition & 1 deletion certloader/certstore_disabled.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !darwin && !windows
//go:build !cgo || (!darwin && !windows)

/*-
* Copyright 2018 Square Inc.
Expand Down
2 changes: 1 addition & 1 deletion certloader/certstore_enabled.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build darwin || windows
//go:build cgo && (darwin || windows)

/*-
* Copyright 2018 Square Inc.
Expand Down
2 changes: 1 addition & 1 deletion certloader/certstore_enabled_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build darwin || windows
//go:build cgo && (darwin || windows)

package certloader

Expand Down
2 changes: 1 addition & 1 deletion certloader/certstore_reload_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build darwin || windows
//go:build cgo && (darwin || windows)

package certloader

Expand Down
2 changes: 2 additions & 0 deletions certstore/certstore_linux.go → certstore/certstore_other.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !cgo || (!darwin && !windows)

package certstore

import (
Expand Down
2 changes: 1 addition & 1 deletion certstore/certstore_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !linux
//go:build cgo && (darwin || windows)

package certstore

Expand Down
2 changes: 1 addition & 1 deletion certstore/errors_darwin_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build darwin
//go:build darwin && cgo

package certstore

Expand Down
2 changes: 1 addition & 1 deletion certstore/main_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !linux
//go:build cgo && (darwin || windows)

package certstore

Expand Down
2 changes: 1 addition & 1 deletion certstore/testca_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !linux
//go:build cgo && (darwin || windows)

package certstore

Expand Down
27 changes: 27 additions & 0 deletions coverage_enabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build coverage

package main

import (
"os"
"runtime/coverage"
)

func init() {
// Wrap exitFunc to flush coverage counters before exiting.
// os.Exit does not run atexit handlers, so without this the
// coverage data written by go build -cover would be lost.
wrapped := exitFunc
exitFunc = func(code int) {
if dir := os.Getenv("GOCOVERDIR"); dir != "" {
coverage.WriteCountersDir(dir)
}
wrapped(code)
}

// Register GOCOVERDIR as an extra RW path for landlock, so that
// coverage counters can be written on Linux even with sandboxing.
if dir := os.Getenv("GOCOVERDIR"); dir != "" {
extraRWPaths = append(extraRWPaths, dir)
}
}
2 changes: 1 addition & 1 deletion docs/certificates/acme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ stapling.

To enable ACME, use the `--auto-acme-cert` flag with the FQDN to obtain a
certificate for. You must also specify an email address with
`--auto-acme-email` (for CA notifications about certificate lifecycle events)
`--auto-acme-email` (used by the CA for expiration and renewal notices)
and agree to the CA's Terms of Service with `--auto-acme-agree-to-tos`:

```bash
Expand Down
5 changes: 2 additions & 3 deletions docs/certificates/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ bytes, so you don't need to specify it explicitly.
| PEM (combined) | `.pem` | `--keystore` | Single file with cert chain and private key |
| PKCS#12 | `.p12`, `.pfx` | `--keystore` | Binary bundle; optional `--storepass` for password |
| JCEKS | `.jceks`, `.jks` | `--keystore` | Java keystore; requires `--storepass` |
| DER | `.der` | `--keystore` | Raw X.509 or PKCS#7; less common |

These options are mutually exclusive with each other and with `--use-workload-api`,
`--keychain-identity`, and PKCS#11 flags.
Expand Down Expand Up @@ -134,9 +133,9 @@ cat root-ca.pem intermediate-ca.pem > cacert.pem
Ghostunnel detects the format in this order:

1. **File extension**: `.pem`/`.crt` → PEM, `.p12`/`.pfx` → PKCS#12,
`.jceks`/`.jks` → JCEKS, `.der` → DER.
`.jceks`/`.jks` → JCEKS.
2. **Magic bytes**: if the extension is ambiguous, the first bytes of the file
are inspected (e.g. `-----BEGIN` → PEM, ASN.1 sequence → PKCS#12 or DER).
are inspected (e.g. `-----BEGIN` → PEM, ASN.1 sequence → PKCS#12).

In practice, just use the right file extension and Ghostunnel will do the
right thing.
Expand Down
38 changes: 16 additions & 22 deletions docs/certificates/hsm-pkcs11.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ aliases:
- /docs/hsm-pkcs11/
---

Ghostunnel has support for loading private keys from [PKCS#11][pkcs11-spec]
modules, which should work with any hardware security module that exposes a
PKCS#11 interface.
An easy way to test the PKCS#11 interface for development purposes is with
[SoftHSM][softhsm]. Note that CGO is required in order for PKCS#11 support to
work.
Ghostunnel can load private keys from any hardware security module that
exposes a [PKCS#11][pkcs11-spec] interface. CGO is required for PKCS#11
support. [SoftHSM][softhsm] is an easy way to test without real hardware.

[softhsm]: https://github.com/opendnssec/SoftHSMv2

Expand Down Expand Up @@ -46,16 +43,15 @@ ghostunnel server \
--allow-cn client
```

The `--pkcs11-module`, `--pkcs11-token-label` and `--pkcs11-pin` flags can be
used to select the private key to be used from the PKCS#11 module. It's also possible
to use environment variables to set PKCS#11 options instead of flags (via
`PKCS11_MODULE`, `PKCS11_TOKEN_LABEL` and `PKCS11_PIN`), useful if you don't want to show the PIN on the command line.
The `--pkcs11-module`, `--pkcs11-token-label`, and `--pkcs11-pin` flags
select the private key from the PKCS#11 module. You can also set these via
environment variables (`PKCS11_MODULE`, `PKCS11_TOKEN_LABEL`, `PKCS11_PIN`)
to keep the PIN off the command line.

Note that `--cert` needs to point to the certificate chain that corresponds
to the private key in the PKCS#11 module, with the leaf certificate being the
first certificate in the chain (see
[Certificate Formats]({{< ref "formats.md" >}})). Ghostunnel currently
cannot read the certificate chain directly from the module.
Note: `--cert` must point to the certificate chain matching the private key in
the PKCS#11 module, with the leaf certificate first (see [Certificate
Formats]({{< ref "formats.md" >}})). Ghostunnel cannot read the certificate
chain from the module directly.

## Using a YubiKey

Expand Down Expand Up @@ -145,7 +141,7 @@ ghostunnel server \
--pkcs11-pin 123456 \
--listen localhost:8443 \
--target localhost:8080 \
--cacert ca-cert.pem \
--cacert cacert.pem \
--allow-cn client
```

Expand Down Expand Up @@ -181,19 +177,17 @@ pkcs11-tool --module /path/to/libykcs11.dylib -O
## Certificate Hotswapping

When using PKCS#11, certificate hotswapping (via `SIGHUP`/`SIGUSR1` or
`--timed-reload`) reloads only the certificate from disk. The private key
in the HSM stays put, so the new certificate still needs to match the key
that was loaded from the HSM.
`--timed-reload`) reloads only the certificate from disk. The private key in
the HSM is not reloaded, so the new certificate must still match it.

Note that Landlock sandboxing is automatically disabled when PKCS#11 is used,
as PKCS#11 modules are opaque shared libraries that may need access to
arbitrary files and sockets.

## Inspecting PKCS#11 State

If you need to inspect the state of a PKCS#11 module/token, we recommend the
[`pkcs11-tool`][pkcs11-tool] utility from OpenSC. For example, it can be used
to list slots or read certificate(s) from a module:
Use the [`pkcs11-tool`][pkcs11-tool] utility from OpenSC to inspect PKCS#11
module/token state. For example:

```bash
# List slots on a module
Expand Down
2 changes: 1 addition & 1 deletion docs/certificates/keychain.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ ghostunnel server \
--listen localhost:8443 \
--target localhost:8080 \
--cacert cacert.pem \
--allow-ou=client
--allow-ou client
```

This flag is only available on macOS.
Expand Down
9 changes: 5 additions & 4 deletions docs/certificates/spiffe-workload-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ X.509 roots. Peers are expected to present SPIFFE
[X509-SVIDs](https://github.com/spiffe/spiffe/blob/main/standards/X509-SVID.md),
which are verified using SPIFFE authentication.

To enable workload API support, use the `--use-workload-api` flag. By default,
the location of the SPIFFE Workload API socket is picked up from the
`SPIFFE_ENDPOINT_SOCKET` environment variable. If you prefer to specify this via
flag, the `--use-workload-api-addr` flag can be used to explicitly set the address.
To enable workload API support, set the `SPIFFE_ENDPOINT_SOCKET` environment
variable or pass the `--use-workload-api-addr` flag. Either of these implicitly
enables `--use-workload-api`, so the explicit flag is not required when the
address is provided. You can also pass `--use-workload-api` on its own if the
environment variable is already set.

On UNIX systems (Linux, macOS):

Expand Down
4 changes: 2 additions & 2 deletions docs/deployment/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ description: Running Ghostunnel as a container or as a supervised system service
weight: 50
---

Published container images and integration with systemd for running Ghostunnel
as a long-lived service.
Container images and service manager integration (systemd, launchd, Windows
SCM) for running Ghostunnel as a long-lived service.
Loading
Loading