← All field notes
Field note

Gatehub and gatekit: a control plane for fingerprint gates

tlsgate and sshgate began as independent proxies, but operating more than one gate exposed two kinds of duplication: every node needed the same runtime machinery, and every node kept its own view of approved fingerprints. I split those concerns into gatekit and Gatehub.

The node-side spine

gatekit is a Go library, not another service. It provides the shared SQLite fingerprint store, Gatehub synchronization client, per-source rate limiting, a global connection cap, graceful draining, and systemd-aware process lifecycle. Protocol details stay in the gates: SSH and TLS handshakes are different enough that hiding them behind one interface would make the code less clear.

The store keeps protocol-specific observations in a metadata bag, so the synchronization format does not need a schema change for every new fingerprint type. Its legacy migration also preserves approvals, labels, and first-seen history while leaving old columns intact for a binary rollback.

The shared view

Gatehub is the control plane. Gate nodes upload observations and pull approval policy; operators get one place to approve, block, and label fingerprints. Its admin and synchronization listeners are deliberately separate. The admin side belongs behind an internal OIDC-protected proxy, while the public node API exposes only the few paths needed for synchronization and accepts node credentials or mTLS identities.

Gatehub can also correlate privacy-bounded scanner signals with recent TLS observations, but evidence never creates an approval automatically. The original security boundary remains intact: fingerprint gates reduce scanner noise; they do not replace backend authentication.

Source and documentation: Gatehub and gatekit.