ipn/ipnlocal: add capability for debugging peers over peerapi

The default is still users can debug their own nodes. But like
cd916b728b did, this adds support for admins to grant additional
capabilities with the new tailcfg.CapabilityDebugPeer cap.

Updates #4217

Change-Id: Ifce3d9a1f8e8845797970a4f97b393194663d35f
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2022-04-18 10:06:41 -07:00 committed by Brad Fitzpatrick
parent 945879fa38
commit e96dd00652
2 changed files with 24 additions and 23 deletions

View File

@ -622,21 +622,19 @@ func (f *incomingFile) PartialFile() ipn.PartialFile {
// canPutFile reports whether h can put a file ("Taildrop") to this node. // canPutFile reports whether h can put a file ("Taildrop") to this node.
func (h *peerAPIHandler) canPutFile() bool { func (h *peerAPIHandler) canPutFile() bool {
if h.isSelf { return h.isSelf || h.peerHasCap(tailcfg.CapabilityFileSharingSend)
return true }
}
if h.peerNode == nil { // canDebug reports whether h can debug this node (goroutines, metrics,
// Shouldn't happen, but in case. // magicsock internal state, etc).
return false func (h *peerAPIHandler) canDebug() bool {
} return h.isSelf || h.peerHasCap(tailcfg.CapabilityDebugPeer)
for _, addr := range h.peerNode.Addresses { }
if !addr.IsSingleIP() {
continue func (h *peerAPIHandler) peerHasCap(wantCap string) bool {
} for _, hasCap := range h.ps.b.PeerCaps(h.remoteAddr.IP()) {
for _, cap := range h.ps.b.PeerCaps(addr.IP()) { if hasCap == wantCap {
if cap == tailcfg.CapabilityFileSharingSend { return true
return true
}
} }
} }
return false return false
@ -763,8 +761,8 @@ func approxSize(n int64) string {
} }
func (h *peerAPIHandler) handleServeGoroutines(w http.ResponseWriter, r *http.Request) { func (h *peerAPIHandler) handleServeGoroutines(w http.ResponseWriter, r *http.Request) {
if !h.isSelf { if !h.canDebug() {
http.Error(w, "not owner", http.StatusForbidden) http.Error(w, "denied; no debug access", http.StatusForbidden)
return return
} }
var buf []byte var buf []byte
@ -779,8 +777,8 @@ func (h *peerAPIHandler) handleServeGoroutines(w http.ResponseWriter, r *http.Re
} }
func (h *peerAPIHandler) handleServeEnv(w http.ResponseWriter, r *http.Request) { func (h *peerAPIHandler) handleServeEnv(w http.ResponseWriter, r *http.Request) {
if !h.isSelf { if !h.canDebug() {
http.Error(w, "not owner", http.StatusForbidden) http.Error(w, "denied; no debug access", http.StatusForbidden)
return return
} }
var data struct { var data struct {
@ -799,8 +797,8 @@ func (h *peerAPIHandler) handleServeEnv(w http.ResponseWriter, r *http.Request)
} }
func (h *peerAPIHandler) handleServeMagicsock(w http.ResponseWriter, r *http.Request) { func (h *peerAPIHandler) handleServeMagicsock(w http.ResponseWriter, r *http.Request) {
if !h.isSelf { if !h.canDebug() {
http.Error(w, "not owner", http.StatusForbidden) http.Error(w, "denied; no debug access", http.StatusForbidden)
return return
} }
eng := h.ps.b.e eng := h.ps.b.e
@ -814,8 +812,8 @@ func (h *peerAPIHandler) handleServeMagicsock(w http.ResponseWriter, r *http.Req
} }
func (h *peerAPIHandler) handleServeMetrics(w http.ResponseWriter, r *http.Request) { func (h *peerAPIHandler) handleServeMetrics(w http.ResponseWriter, r *http.Request) {
if !h.isSelf { if !h.canDebug() {
http.Error(w, "not owner", http.StatusForbidden) http.Error(w, "denied; no debug access", http.StatusForbidden)
return return
} }
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")

View File

@ -1587,6 +1587,9 @@ const (
// CapabilityFileSharingSend grants the ability to receive files from a // CapabilityFileSharingSend grants the ability to receive files from a
// node that's owned by a different user. // node that's owned by a different user.
CapabilityFileSharingSend = "https://tailscale.com/cap/file-send" CapabilityFileSharingSend = "https://tailscale.com/cap/file-send"
// CapabilityDebugPeer grants the ability for a peer to read this node's
// goroutines, metrics, magicsock internal state, etc.
CapabilityDebugPeer = "https://tailscale.com/cap/debug-peer"
) )
// SetDNSRequest is a request to add a DNS record. // SetDNSRequest is a request to add a DNS record.