Skip to content

authn-revokd

An agent that fetches signed KRLs and CRLs, keeps only the lists that verify, writes them where sshd and TLS servers read them, and fails closed when one lapses.

OpenSSH has no way to distribute a KRL, and nothing in a KRL says it is stale. sshd reads a file that stopped updating months ago as the current list. authn-revokd closes both gaps for the lists authn-bridge publishes: it fetches each list, keeps it only if it verifies, writes it where sshd or a TLS server reads it, and, when a list lapses, writes one that revokes the CA itself. Pure Go, CGO_ENABLED=0, one binary. These pages describe v0.6.4.

$ go install github.com/go-authn/revocation/cmd/authn-revokd@v0.6.4
$ authn-revokd -version
authn-revokd v0.6.4
$ authn-revokd -help
Usage of authn-revokd:
  -config string
    	the configuration file (default "/etc/authn-revokd/revokd.hcl")
  -once
    	sync once and exit: 1 when a list is not current, or could not be fetched
  -version
    	print the version and exit

-help exits 0; before v0.6.2 it exited 2.

Before v0.6.0 the command was revokd, and read /etc/revokd.hcl by default. Nothing reads that file any more; when it is there and the new default is not, the error names both paths.

What it does, in one run

Against a test authn-bridge on loopback, with a KRL source and a CRL source:

$ authn-revokd -config revokd.hcl -once
bridge-ssh: version 0, issued 2026-10-11T09:50:24Z, expires 2026-10-11T10:50:24Z
bridge-x509: version 1791712224691, issued 2026-10-11T09:50:24Z, expires 2026-10-11T10:50:24Z
output sshd: wrote /tmp/authn/revokd/out/sshd.krl
output tls: wrote /tmp/authn/revokd/out/bridge.crl
$ ssh-keygen -Q -l -f out/sshd.krl
# KRL version 0
# Generated at 20261011T115024
# Comment: authn-revokd sshd

A second run with nothing new prints nothing and exits 0: an output is rewritten only when its content changes.

Why the transport does not matter

Every list authenticates itself: a KRL by a detached SSHSIG signature by the CA’s own key, a CRL by its CA’s signature. Every list says when it stops being current. So a list may come over HTTPS, plain HTTP inside a cluster, a mirror, or a file. The transport decides how fast a change arrives, never whether a forged or stale list is taken.

KRLCRL
authenticSSHSIG by the SSH CA key, namespace krl@go-authn.github.iosigned by its CA
currentexpires@go-authn.github.io, which sshd ignoresnextUpdate
never backwardskrl_version, then generation dateCRL Number, then thisUpdate
fail closedauthn-revokd writes a KRL that revokes the CA keyOpenSSL refuses an expired CRL by itself

Where to go next

Installing itthe daemon, or -once on a timer; wiring sshd and nginx
The configurationsources, outputs, the mirror, and what is refused
How a list is verifiedsignature, dates, and never older than the list held, across restarts
When a list lapsesthe KRL that revokes the CA itself

What it does not do

A revocation reaches a server no faster than authn-revokd polls (refresh), plus the issuer’s delay in issuing again. While the issuer is down, its certificates are refused from the list’s expiry on. Whoever holds a CA’s key can sign any list, as they can sign any certificate.

Licence

BSD-3-Clause.

Created on by tannevaled

Modified on by tannevaled