mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 19:56:52 +01:00
Serve print-cert on the info API, with -address and preferring our v2 certificate
A program that verifies certificates against its own CAs, as
nebula-auth-request does, needs the certificate itself rather than the
parsed identity, and it asked the ssh debug server for it. The info API
now serves print-cert, so it can ask there instead.
- print-cert declares Identity: it reads a certificate from the hostmap or our own, and nothing operational
- -address names the vpn addr, with a port accepted and stripped and 4in6 unmapped, as identity takes it; the operand stays, and giving both is refused
- an address of our own answers with our own certificate, and a tunnel without one is not found, a 404 on the API
- with no address the certificate is the one whoami reports, the v2 when both versions are loaded, not the one handshakes start with
- GET /v1/print-cert?address=<addr>&raw=true answers {"pem": ...}; example config, CHANGELOG, surface test, goldens and an e2e check
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e0dc742e17
commit
660a271466
7 files changed
+156
-17
No files matched your search
+30
-5
@@ -64,11 +64,12 @@ func TestIdentityOverTheInfoAPI(t *testing.T) {
|
||||
assertTunnel(t, myVpnIpNet[0].Addr(), theirVpnIpNet[0].Addr(), myControl, theirControl, r)
|
||||
|
||||
type identity struct {
|
||||
Name string `json:"name"`
|
||||
VpnAddrs []netip.Addr `json:"vpnAddrs"`
|
||||
Networks []netip.Prefix `json:"networks"`
|
||||
Groups []string `json:"groups"`
|
||||
Issuer string `json:"issuer"`
|
||||
Name string `json:"name"`
|
||||
VpnAddrs []netip.Addr `json:"vpnAddrs"`
|
||||
Networks []netip.Prefix `json:"networks"`
|
||||
Groups []string `json:"groups"`
|
||||
Issuer string `json:"issuer"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
}
|
||||
|
||||
// A connection's RemoteAddr, port and all, resolves to the peer.
|
||||
@@ -102,6 +103,30 @@ func TestIdentityOverTheInfoAPI(t *testing.T) {
|
||||
assert.Equal(t, http.StatusBadRequest, status)
|
||||
assert.JSONEq(t, `{"error":"The provided vpn addr could not be parsed: "}`, body)
|
||||
|
||||
// The certificate itself, for a program that verifies it against its own CAs: the one
|
||||
// nebula verified when the tunnel came up, as PEM, by the address a connection carries.
|
||||
status, body = test.HTTPGet(t, path, "/v1/print-cert?address="+netip.AddrPortFrom(theirVpnIpNet[0].Addr(), 51234).String()+"&raw=true")
|
||||
require.Equal(t, http.StatusOK, status, body)
|
||||
var raw struct {
|
||||
PEM string `json:"pem"`
|
||||
}
|
||||
require.NoError(t, json.Unmarshal([]byte(body), &raw))
|
||||
theirs, _, err := cert.UnmarshalCertificateFromPEM([]byte(raw.PEM))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "them", theirs.Name())
|
||||
fp, err := theirs.Fingerprint()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, them.Fingerprint, fp, "the same certificate identity reports")
|
||||
|
||||
// Without raw it is the certificate's fields; without an address, our own.
|
||||
status, body = test.HTTPGet(t, path, "/v1/print-cert")
|
||||
require.Equal(t, http.StatusOK, status, body)
|
||||
assert.Contains(t, body, `"name":"me"`)
|
||||
|
||||
status, body = test.HTTPGet(t, path, "/v1/print-cert?address=10.128.0.9")
|
||||
assert.Equal(t, http.StatusNotFound, status)
|
||||
assert.JSONEq(t, `{"error":"Could not find tunnel for vpn addr: 10.128.0.9"}`, body)
|
||||
|
||||
// Nothing else nebula serves is reachable here.
|
||||
status, body = test.HTTPGet(t, path, "/v1/list-hostmap")
|
||||
assert.Equal(t, http.StatusForbidden, status)
|
||||
|
||||
Vendored
+15
-2
@@ -779,7 +779,7 @@ whoami - Prints the certificate identity of this node
|
||||
|
||||
|
||||
$ help -json
|
||||
[{"name":"change-remote","short":"Changes the remote address used in the tunnel for the provided vpn addr","flags":[{"name":"address","usage":"The new remote address, ip:port"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"close-tunnel","short":"Closes a tunnel for the provided vpn addr","flags":[{"name":"local-only","bool":true,"default":"false","usage":"Disables notifying the remote that the tunnel is shutting down"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"create-tunnel","short":"Creates a tunnel for the provided vpn address","help":"The lighthouses will be queried for real addresses but you can provide one as well.","flags":[{"name":"address","usage":"Optionally provide a real remote address, ip:port "},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"device-info","short":"Prints information about the network device.","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"help","short":"prints available commands or help \u003ccommand\u003e for specific usage info","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"identity","short":"Prints the certificate identity of the host owning the provided vpn addr","help":"Identity is what the certificate says: name, vpn addrs, networks, groups, fingerprint, issuer and validity. The address may carry a port, so a connection's remote address can be passed through as is. For this node's own identity use whoami.","flags":[{"name":"address","usage":"The vpn addr to look up, optionally with a port"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"list-hostmap","short":"List all known previously connected hosts","flags":[{"name":"by-index","bool":true,"default":"false","usage":"gets all hosts in the hostmap from the index table"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"list-lighthouse-addrmap","short":"List all lighthouse map entries","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"list-pending-hostmap","short":"List all handshaking hosts","flags":[{"name":"by-index","bool":true,"default":"false","usage":"gets all hosts in the hostmap from the index table"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"log-format","short":"Gets or sets the current log format","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"log-level","short":"Gets or sets the current log level","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"logout","short":"Ends the current session","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"print-cert","short":"Prints the current certificate being used or the certificate for the provided vpn addr","flags":[{"name":"raw","bool":true,"default":"false","usage":"prints the PEM encoded certificate; with -json, an object holding it"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"print-relays","short":"Prints json details about all relay info","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"print-tunnel","short":"Prints json details about a tunnel for the provided vpn addr","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"query-lighthouse","short":"Query the lighthouses for the provided vpn address","help":"This command Line truncated
|
||||
[{"name":"change-remote","short":"Changes the remote address used in the tunnel for the provided vpn addr","flags":[{"name":"address","usage":"The new remote address, ip:port"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"close-tunnel","short":"Closes a tunnel for the provided vpn addr","flags":[{"name":"local-only","bool":true,"default":"false","usage":"Disables notifying the remote that the tunnel is shutting down"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"create-tunnel","short":"Creates a tunnel for the provided vpn address","help":"The lighthouses will be queried for real addresses but you can provide one as well.","flags":[{"name":"address","usage":"Optionally provide a real remote address, ip:port "},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"device-info","short":"Prints information about the network device.","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"help","short":"prints available commands or help \u003ccommand\u003e for specific usage info","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"identity","short":"Prints the certificate identity of the host owning the provided vpn addr","help":"Identity is what the certificate says: name, vpn addrs, networks, groups, fingerprint, issuer and validity. The address may carry a port, so a connection's remote address can be passed through as is. For this node's own identity use whoami.","flags":[{"name":"address","usage":"The vpn addr to look up, optionally with a port"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"list-hostmap","short":"List all known previously connected hosts","flags":[{"name":"by-index","bool":true,"default":"false","usage":"gets all hosts in the hostmap from the index table"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"list-lighthouse-addrmap","short":"List all lighthouse map entries","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"list-pending-hostmap","short":"List all handshaking hosts","flags":[{"name":"by-index","bool":true,"default":"false","usage":"gets all hosts in the hostmap from the index table"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"log-format","short":"Gets or sets the current log format","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"log-level","short":"Gets or sets the current log level","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"logout","short":"Ends the current session","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"print-cert","short":"Prints the current certificate being used or the certificate for the provided vpn addr","help":"The vpn addr is an operand or -address, which may carry a port so a connection's remote address can be passed through as is. For a peer it is the certificate nebula verified when the tunnel came up; with no address it is this node's own, the v2 certificate when both versions are loaded. -raw prints the PEM.","flags":[{"name":"address","usage":"The vpn addr to look up, optionally with a port"},{"name":"raw","bool":true,"default":"false","usage":"prints the PEM encoded certificate; with -json, an object holding it"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]},{"name":"print-relays","short":"Prints json details about all relay info","flags":[{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, aLine truncated
|
||||
|
||||
$ help -pretty
|
||||
[
|
||||
@@ -1034,7 +1034,12 @@ $ help -pretty
|
||||
{
|
||||
"name": "print-cert",
|
||||
"short": "Prints the current certificate being used or the certificate for the provided vpn addr",
|
||||
"help": "The vpn addr is an operand or -address, which may carry a port so a connection's remote address can be passed through as is. For a peer it is the certificate nebula verified when the tunnel came up; with no address it is this node's own, the v2 certificate when both versions are loaded. -raw prints the PEM.",
|
||||
"flags": [
|
||||
{
|
||||
"name": "address",
|
||||
"usage": "The vpn addr to look up, optionally with a port"
|
||||
},
|
||||
{
|
||||
"name": "raw",
|
||||
"bool": true,
|
||||
@@ -1169,6 +1174,9 @@ $ help -pretty
|
||||
|
||||
$ help print-cert
|
||||
print-cert - Prints the current certificate being used or the certificate for the provided vpn addr
|
||||
The vpn addr is an operand or -address, which may carry a port so a connection's remote address can be passed through as is. For a peer it is the certificate nebula verified when the tunnel came up; with no address it is this node's own, the v2 certificate when both versions are loaded. -raw prints the PEM.
|
||||
-address string
|
||||
The vpn addr to look up, optionally with a port
|
||||
-raw
|
||||
prints the PEM encoded certificate; with -json, an object holding it
|
||||
-json
|
||||
@@ -1177,13 +1185,18 @@ print-cert - Prints the current certificate being used or the certificate for th
|
||||
pretty prints json, assumes -json
|
||||
|
||||
$ help -json print-cert
|
||||
{"name":"print-cert","short":"Prints the current certificate being used or the certificate for the provided vpn addr","flags":[{"name":"raw","bool":true,"default":"false","usage":"prints the PEM encoded certificate; with -json, an object holding it"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]}
|
||||
{"name":"print-cert","short":"Prints the current certificate being used or the certificate for the provided vpn addr","help":"The vpn addr is an operand or -address, which may carry a port so a connection's remote address can be passed through as is. For a peer it is the certificate nebula verified when the tunnel came up; with no address it is this node's own, the v2 certificate when both versions are loaded. -raw prints the PEM.","flags":[{"name":"address","usage":"The vpn addr to look up, optionally with a port"},{"name":"raw","bool":true,"default":"false","usage":"prints the PEM encoded certificate; with -json, an object holding it"},{"name":"json","bool":true,"default":"false","usage":"outputs as json"},{"name":"pretty","bool":true,"default":"false","usage":"pretty prints json, assumes -json"}]}
|
||||
|
||||
$ help -pretty print-cert
|
||||
{
|
||||
"name": "print-cert",
|
||||
"short": "Prints the current certificate being used or the certificate for the provided vpn addr",
|
||||
"help": "The vpn addr is an operand or -address, which may carry a port so a connection's remote address can be passed through as is. For a peer it is the certificate nebula verified when the tunnel came up; with no address it is this node's own, the v2 certificate when both versions are loaded. -raw prints the PEM.",
|
||||
"flags": [
|
||||
{
|
||||
"name": "address",
|
||||
"usage": "The vpn addr to look up, optionally with a port"
|
||||
},
|
||||
{
|
||||
"name": "raw",
|
||||
"bool": true,
|
||||
|
||||
Reference in new issue
Block a user