Files
sshsignhost/README.md
T
unkin-agent 67426b9e6e
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Add Go implementation of sshsignhost
Puppet's generate() splices stderr into stdout, so the Python helper's
error prints and its absent HTTP timeouts can corrupt a catalog compile or
hang it forever.

- sign SSH host certificates via Vault approle or kubernetes auth
- emit only {"signed_key": ...} on stdout, errors on stderr, non-zero exit
- forward valid_principals to Vault unsplit; bound every call by a timeout
- keep TLS verification skippable via tls_skip_verify (default true)
- package the binary and completions as an RPM; add PR and tag pipelines
2026-09-19 10:35:00 +10:00

2.0 KiB

sshsignhost

Vault-backed SSH host certificate signing helper for Puppet.

Puppet's profiles::ssh::sign class calls the binary server-side during catalog compilation via generate(), then feeds its stdout to parsejson():

/usr/local/bin/sshsignhost --valid_principals "host,fqdn,ip" --ttl 87600h \
  --public_key "ssh-rsa AAAA..." --json

generate() runs with combine: true, so stderr is spliced into stdout. On success the process writes only the JSON document to stdout and nothing at all to stderr; any failure prints a message naming the cause to stderr and exits non-zero, which aborts the compile cleanly instead of yielding a parse error.

Usage

Flag Default Required
--public_key — yes
--valid_principals (comma-separated, forwarded to Vault verbatim) — yes
--ttl 87600h no
--json false no
--config /opt/sshsignhost/config.yaml no

With --json, stdout is exactly:

{"signed_key": "ssh-rsa-cert-v01@openssh.com AAAA..."}

Without it, the raw signed_key value plus a newline.

Configuration

vault:
  addr: 'https://vault.service.consul:8200'
  auth_method: 'approle'        # or 'kubernetes'
  mount_point: 'sshca'
  role_name: 'signhost'
  # auth_method: approle
  role_id: '...'
  approle_path: 'approle'
  # auth_method: kubernetes
  k8s_mount: 'k8s/au/syd1'
  k8s_role: 'puppet_sshsigner'
  jwt_path: '/var/run/secrets/kubernetes.io/serviceaccount/token'
  # optional
  tls_skip_verify: true         # default true
  timeout: '15s'                # default 15s

tls_skip_verify defaults to true to match the Python helper this replaces (verify=False); flip it to false once Vault's listeners present trusted certificates. timeout bounds every Vault call so a black-holed Vault cannot hang a catalog compile forever.

Build

make build          # -> dist/sshsignhost
make test
make rpm            # RPM with bash/zsh/fish completions