systemd
For a bare-metal server or VPS without Docker. The binary has no runtime
dependencies; the deployment is three files and one unit. The example unit
in
examples/systemd/oidc-ssh-ca.service
applies the strongest process isolation of any deployment in these docs:
DynamicUser, ProtectSystem=strict, and the CA key passed as a systemd
credential visible only to the service.
Install
# The binary
install -m 0755 oidc-ssh-ca /usr/local/bin/oidc-ssh-ca
# Configuration and key
mkdir -p /etc/oidc-ssh-ca
ssh-keygen -t ed25519 -N "" -f /etc/oidc-ssh-ca/ca_key -C "oidc-ssh-ca"
chmod 0600 /etc/oidc-ssh-ca/ca_key
# ... write /etc/oidc-ssh-ca/policy.yaml ...
oidc-ssh-ca check-config /etc/oidc-ssh-ca/policy.yaml
# The unit
cp examples/systemd/oidc-ssh-ca.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now oidc-ssh-ca
The key reaches the process via LoadCredential — it is exposed only to
this service under %d/ca_key, not to other processes of the same user.
systemd presents that credential file as mode 0440, which the default
CA-key permission check (0600 or stricter) would reject, so the unit
passes --skip-key-permission-check. The credential lives in the
service’s private /run/credentials mount and is unreachable by other
users regardless of its mode bits; the flag disables the check for this
path only. Omit it elsewhere — without the flag the server refuses to
start on a CA key file readable by group or other.
TLS
The server speaks plain HTTP on :8080; put any reverse proxy in front for
TLS. If nothing else on the host serves HTTPS yet, Caddy is the least
configuration:
apt install caddy # or your distro's package
/etc/caddy/Caddyfile:
ca.example.com {
reverse_proxy localhost:8080
}
Caddy obtains and renews the certificate automatically. If you already run
nginx or another proxy, a standard proxy_pass http://127.0.0.1:8080;
virtual host works the same way.
If the TLS setup is the part you want to avoid, the Docker Compose deployment bundles Caddy, and Cloud Run removes the host entirely.
Operations
Reload the policy (an invalid file keeps the current policy running):
systemctl reload oidc-ssh-ca
Emergency stop — set disabled: true at the top of policy.yaml and
reload; the server answers 503 to every request. Or
systemctl stop oidc-ssh-ca.
Audit logs — JSON lines on stdout, captured by journald:
journalctl -u oidc-ssh-ca -f