mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 19:51:41 +00:00
tailcfg: add CapabilityDebug
Updates tailscale/corp#7948 Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
1e78fc462c
commit
296e712591
@ -778,6 +778,17 @@ func (h *peerAPIHandler) canPutFile() bool {
|
|||||||
// canDebug reports whether h can debug this node (goroutines, metrics,
|
// canDebug reports whether h can debug this node (goroutines, metrics,
|
||||||
// magicsock internal state, etc).
|
// magicsock internal state, etc).
|
||||||
func (h *peerAPIHandler) canDebug() bool {
|
func (h *peerAPIHandler) canDebug() bool {
|
||||||
|
// Reread the selfNode as it may have changed since the peerAPIServer
|
||||||
|
// was created.
|
||||||
|
// TODO(maisem): handle this in other places too.
|
||||||
|
nm := h.ps.b.NetMap()
|
||||||
|
if nm == nil || nm.SelfNode == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !slices.Contains(nm.SelfNode.Capabilities, tailcfg.CapabilityDebug) {
|
||||||
|
// This node does not expose debug info.
|
||||||
|
return false
|
||||||
|
}
|
||||||
return h.isSelf || h.peerHasCap(tailcfg.CapabilityDebugPeer)
|
return h.isSelf || h.peerHasCap(tailcfg.CapabilityDebugPeer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/util/must"
|
"tailscale.com/util/must"
|
||||||
"tailscale.com/wgengine"
|
"tailscale.com/wgengine"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
@ -113,6 +114,7 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
isSelf bool // the peer sending the request is owned by us
|
isSelf bool // the peer sending the request is owned by us
|
||||||
capSharing bool // self node has file sharing capability
|
capSharing bool // self node has file sharing capability
|
||||||
|
debugCap bool // self node has debug capability
|
||||||
omitRoot bool // don't configure
|
omitRoot bool // don't configure
|
||||||
req *http.Request
|
req *http.Request
|
||||||
checks []check
|
checks []check
|
||||||
@ -140,14 +142,23 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "peer_api_goroutines_deny",
|
name: "goroutines/deny-self-no-cap",
|
||||||
isSelf: false,
|
isSelf: true,
|
||||||
|
debugCap: false,
|
||||||
req: httptest.NewRequest("GET", "/v0/goroutines", nil),
|
req: httptest.NewRequest("GET", "/v0/goroutines", nil),
|
||||||
checks: checks(httpStatus(403)),
|
checks: checks(httpStatus(403)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "peer_api_goroutines",
|
name: "goroutines/deny-nonself",
|
||||||
|
isSelf: false,
|
||||||
|
debugCap: true,
|
||||||
|
req: httptest.NewRequest("GET", "/v0/goroutines", nil),
|
||||||
|
checks: checks(httpStatus(403)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "goroutines/accept-self",
|
||||||
isSelf: true,
|
isSelf: true,
|
||||||
|
debugCap: true,
|
||||||
req: httptest.NewRequest("GET", "/v0/goroutines", nil),
|
req: httptest.NewRequest("GET", "/v0/goroutines", nil),
|
||||||
checks: checks(
|
checks: checks(
|
||||||
httpStatus(200),
|
httpStatus(200),
|
||||||
@ -406,6 +417,7 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "host-val/bad-ip",
|
name: "host-val/bad-ip",
|
||||||
isSelf: true,
|
isSelf: true,
|
||||||
|
debugCap: true,
|
||||||
req: httptest.NewRequest("GET", "http://12.23.45.66:1234/v0/env", nil),
|
req: httptest.NewRequest("GET", "http://12.23.45.66:1234/v0/env", nil),
|
||||||
checks: checks(
|
checks: checks(
|
||||||
httpStatus(403),
|
httpStatus(403),
|
||||||
@ -414,6 +426,7 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "host-val/no-port",
|
name: "host-val/no-port",
|
||||||
isSelf: true,
|
isSelf: true,
|
||||||
|
debugCap: true,
|
||||||
req: httptest.NewRequest("GET", "http://100.100.100.101/v0/env", nil),
|
req: httptest.NewRequest("GET", "http://100.100.100.101/v0/env", nil),
|
||||||
checks: checks(
|
checks: checks(
|
||||||
httpStatus(403),
|
httpStatus(403),
|
||||||
@ -422,6 +435,7 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "host-val/peer",
|
name: "host-val/peer",
|
||||||
isSelf: true,
|
isSelf: true,
|
||||||
|
debugCap: true,
|
||||||
req: httptest.NewRequest("GET", "http://peer/v0/env", nil),
|
req: httptest.NewRequest("GET", "http://peer/v0/env", nil),
|
||||||
checks: checks(
|
checks: checks(
|
||||||
httpStatus(200),
|
httpStatus(200),
|
||||||
@ -430,10 +444,16 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
selfNode := &tailcfg.Node{
|
||||||
|
Addresses: []netip.Prefix{
|
||||||
|
netip.MustParsePrefix("100.100.100.101/32"),
|
||||||
|
},
|
||||||
|
}
|
||||||
var e peerAPITestEnv
|
var e peerAPITestEnv
|
||||||
lb := &LocalBackend{
|
lb := &LocalBackend{
|
||||||
logf: e.logBuf.Logf,
|
logf: e.logBuf.Logf,
|
||||||
capFileSharing: tt.capSharing,
|
capFileSharing: tt.capSharing,
|
||||||
|
netMap: &netmap.NetworkMap{SelfNode: selfNode},
|
||||||
}
|
}
|
||||||
e.ph = &peerAPIHandler{
|
e.ph = &peerAPIHandler{
|
||||||
isSelf: tt.isSelf,
|
isSelf: tt.isSelf,
|
||||||
@ -442,13 +462,12 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ps: &peerAPIServer{
|
ps: &peerAPIServer{
|
||||||
b: lb,
|
b: lb,
|
||||||
selfNode: &tailcfg.Node{
|
selfNode: selfNode,
|
||||||
Addresses: []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("100.100.100.101/32"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if tt.debugCap {
|
||||||
|
e.ph.ps.selfNode.Capabilities = append(e.ph.ps.selfNode.Capabilities, tailcfg.CapabilityDebug)
|
||||||
|
}
|
||||||
var rootDir string
|
var rootDir string
|
||||||
if !tt.omitRoot {
|
if !tt.omitRoot {
|
||||||
rootDir = t.TempDir()
|
rootDir = t.TempDir()
|
||||||
|
@ -1654,12 +1654,16 @@ type Oauth2Token struct {
|
|||||||
const (
|
const (
|
||||||
// These are the capabilities that the self node has as listed in
|
// These are the capabilities that the self node has as listed in
|
||||||
// MapResponse.Node.Capabilities.
|
// MapResponse.Node.Capabilities.
|
||||||
|
//
|
||||||
|
// We've since started referring to these as "Node Attributes" ("nodeAttrs"
|
||||||
|
// in the ACL policy file).
|
||||||
|
|
||||||
CapabilityFileSharing = "https://tailscale.com/cap/file-sharing"
|
CapabilityFileSharing = "https://tailscale.com/cap/file-sharing"
|
||||||
CapabilityAdmin = "https://tailscale.com/cap/is-admin"
|
CapabilityAdmin = "https://tailscale.com/cap/is-admin"
|
||||||
CapabilitySSH = "https://tailscale.com/cap/ssh" // feature enabled/available
|
CapabilitySSH = "https://tailscale.com/cap/ssh" // feature enabled/available
|
||||||
CapabilitySSHRuleIn = "https://tailscale.com/cap/ssh-rule-in" // some SSH rule reach this node
|
CapabilitySSHRuleIn = "https://tailscale.com/cap/ssh-rule-in" // some SSH rule reach this node
|
||||||
CapabilityDataPlaneAuditLogs = "https://tailscale.com/cap/data-plane-audit-logs" // feature enabled
|
CapabilityDataPlaneAuditLogs = "https://tailscale.com/cap/data-plane-audit-logs" // feature enabled
|
||||||
|
CapabilityDebug = "https://tailscale.com/cap/debug" // exposes debug endpoints over the PeerAPI
|
||||||
|
|
||||||
// Inter-node capabilities as specified in the MapResponse.PacketFilter[].CapGrants.
|
// Inter-node capabilities as specified in the MapResponse.PacketFilter[].CapGrants.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user