diff --git a/health/health.go b/health/health.go index d4c319ff8..875509e05 100644 --- a/health/health.go +++ b/health/health.go @@ -70,6 +70,9 @@ const ( // SysDNSManager is the name of the net/dns manager subsystem. SysDNSManager = Subsystem("dns-manager") + + // SysTKA is the name of the tailnet key authority subsystem. + SysTKA = Subsystem("tailnet-lock") ) // NewWarnable returns a new warnable item that the caller can mark @@ -194,6 +197,12 @@ func SetDNSManagerHealth(err error) { setErr(SysDNSManager, err) } // DNSOSHealth returns the net/dns.OSConfigurator error state. func DNSOSHealth() error { return get(SysDNSOS) } +// SetTKAHealth sets the health of the tailnet key authority. +func SetTKAHealth(err error) { setErr(SysTKA, err) } + +// TKAHealth returns the tailnet key authority error state. +func TKAHealth() error { return get(SysTKA) } + // SetLocalLogConfigHealth sets the error state of this client's local log configuration. func SetLocalLogConfigHealth(err error) { mu.Lock() diff --git a/ipn/ipnlocal/network-lock.go b/ipn/ipnlocal/network-lock.go index 850ffc031..8a7d3a466 100644 --- a/ipn/ipnlocal/network-lock.go +++ b/ipn/ipnlocal/network-lock.go @@ -20,6 +20,7 @@ import ( "time" "tailscale.com/envknob" + "tailscale.com/health" "tailscale.com/ipn" "tailscale.com/ipn/ipnstate" "tailscale.com/net/tsaddr" @@ -60,9 +61,11 @@ func (b *LocalBackend) permitTKAInitLocked() bool { func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) { // TODO(tom): Remove this guard for 1.35 and later. if b.tka == nil && !b.permitTKAInitLocked() { + health.SetTKAHealth(nil) return } if b.tka == nil { + health.SetTKAHealth(nil) return // TKA not enabled. } @@ -111,6 +114,13 @@ func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) { } else { b.tka.filtered = nil } + + // Check that we ourselves are not locked out, report a health issue if so. + if nm.SelfNode != nil && b.tka.authority.NodeKeyAuthorized(nm.SelfNode.Key, nm.SelfNode.KeySignature) != nil { + health.SetTKAHealth(errors.New("this node is locked out; it will not have connectivity until it is signed. For more info, see https://tailscale.com/s/locked-out")) + } else { + health.SetTKAHealth(nil) + } } // tkaSyncIfNeeded examines TKA info reported from the control plane, @@ -177,6 +187,7 @@ func (b *LocalBackend) tkaSyncIfNeeded(nm *netmap.NetworkMap, prefs ipn.PrefsVie b.logf("Disablement failed, leaving TKA enabled. Error: %v", err) } else { isEnabled = false + health.SetTKAHealth(nil) } } else { return fmt.Errorf("[bug] unreachable invariant of wantEnabled /w isEnabled")