Add experimental host_query API for local identity lookups

Programs running alongside nebula have no simple way to ask "who is this
vpn address?" when making authorization decisions, e.g. a nebula-aware
webapp that wants to identify an inbound connection by its source
address instead of presenting a login form. The existing surfaces are
the sshd admin interface (not scriptable from app code) and the
lighthouse-only DNS TXT lookup, which returns raw cert JSON over an
awkward transport.

This adds an opt-in `host_query` config section that serves a small
HTTP+JSON API on a unix socket or tcp address, requiring no client
library to consume:

  GET /v1/host?addr=<vpn addr>  identity of the host owning the address
                                (an established peer, or this node).
                                addr may include a port so a server can
                                pass a connection's RemoteAddr through
                                unparsed.
  GET /v1/self                  this node's own identity.

Responses carry the certificate-derived identity only: name, vpn
addresses, networks, unsafe networks, groups, fingerprint, issuer,
validity window, and cert version.

The self-vs-peer lookup logic is shared with the DNS TXT handler via a
new findCertificateForVpnAddr helper, which also swaps the panicking
GetDefaultCertificate call for the nil-returning accessor so a missing
certificate yields an empty answer instead of a crash.

The listener follows the statsServer lifecycle: the whole section is
reloadable via SIGHUP, including moving between socket paths and tcp
addresses. Unix sockets default to mode 0600, stale sockets left by an
unclean exit are removed at bind time, and a non-socket file at the
configured path is never replaced.

https://claude.ai/code/session_01Nibp24Pgk2JMue8VyWHq7o
This commit is contained in:
Claude
2026-06-13 01:46:02 +00:00
committed by JackDoan
parent 7d3166a19d
commit e87ccdc9ea
7 changed files with 962 additions and 22 deletions
+6
View File
@@ -249,6 +249,11 @@ func Main(c *config.C, configTest bool, buildVersion string, l *slog.Logger, dev
return nil, util.ContextualizeIfNeeded("Failed to start stats emitter", err)
}
hostQuery, err := newHostQueryServerFromConfig(ctx, l, pki, hostMap, c)
if err != nil {
return nil, util.ContextualizeIfNeeded("Failed to configure the host query API", err)
}
if configTest {
return nil, nil
}
@@ -266,6 +271,7 @@ func Main(c *config.C, configTest bool, buildVersion string, l *slog.Logger, dev
sshStart: sshStart,
statsStart: stats.Start,
dnsStart: ds.Start,
hostQueryStart: hostQuery.Start,
lighthouseStart: lightHouse.StartUpdateWorker,
connectionManagerStart: connManager.Start,
}, nil