all: remove everything related to non-seamless key renewal
Seamless key renewal has been the default in all clients since 1.90. We retained the ability to disable it from the control plane as a precaution, but we haven't seen any issues that require us to disable it. We're now removing all the code for non-seamless key renewal, because we don't expect to turn it on again, and indeed it's been untested in the field for three releases so might contain latent bugs! Updates tailscale/corp#33042 Change-Id: I4b80bf07a3a50298d1c303743484169accc8844b Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
+7
-16
@@ -3571,12 +3571,11 @@ func (b *LocalBackend) setAuthURLLocked(url string) {
|
||||
//
|
||||
// b.mu must be held.
|
||||
func (b *LocalBackend) popBrowserAuthNowLocked(url string, keyExpired bool, recipient ipnauth.Actor) {
|
||||
b.logf("popBrowserAuthNow(%q): url=%v, key-expired=%v, seamless-key-renewal=%v", maybeUsernameOf(recipient), url != "", keyExpired, b.seamlessRenewalEnabled())
|
||||
b.logf("popBrowserAuthNow(%q): url=%v, key-expired=%v", maybeUsernameOf(recipient), url != "", keyExpired)
|
||||
|
||||
// Deconfigure the local network data plane if:
|
||||
// - seamless key renewal is not enabled;
|
||||
// - key is expired (in which case tailnet connectivity is down anyway).
|
||||
if !b.seamlessRenewalEnabled() || keyExpired {
|
||||
// Deconfigure the local network data plane if the key is expired
|
||||
// (in which case tailnet connectivity is down anyway).
|
||||
if keyExpired {
|
||||
b.blockEngineUpdatesLocked(true)
|
||||
b.stopEngineAndWaitLocked()
|
||||
|
||||
@@ -5938,9 +5937,9 @@ func (b *LocalBackend) enterStateLocked(newState ipn.State) {
|
||||
switch newState {
|
||||
case ipn.NeedsLogin:
|
||||
feature.SystemdStatus("Needs login: %s", authURL)
|
||||
// always block updates on NeedsLogin even if seamless renewal is enabled,
|
||||
// to prevent calls to authReconfigLocked from reconfiguring the engine when our
|
||||
// key has expired and we're waiting to authenticate to use the new key.
|
||||
// always block updates on NeedsLogin, to prevent calls to authReconfigLocked
|
||||
// from reconfiguring the engine when our key has expired and we're waiting
|
||||
// to authenticate to use the new key.
|
||||
b.blockEngineUpdatesLocked(true)
|
||||
fallthrough
|
||||
case ipn.Stopped, ipn.NoState:
|
||||
@@ -7598,14 +7597,6 @@ func (b *LocalBackend) ReadRouteInfo() (*appctype.RouteInfo, error) {
|
||||
return b.readRouteInfoLocked()
|
||||
}
|
||||
|
||||
// seamlessRenewalEnabled reports whether seamless key renewals are enabled.
|
||||
//
|
||||
// As of 2025-09-11, this is the default behaviour unless nodes receive
|
||||
// [tailcfg.NodeAttrDisableSeamlessKeyRenewal] in their netmap.
|
||||
func (b *LocalBackend) seamlessRenewalEnabled() bool {
|
||||
return b.ControlKnobs().SeamlessKeyRenewal.Load()
|
||||
}
|
||||
|
||||
var (
|
||||
disallowedAddrs = []netip.Addr{
|
||||
netip.MustParseAddr("::1"),
|
||||
|
||||
+19
-96
@@ -373,14 +373,6 @@ func (b *LocalBackend) nonInteractiveLoginForStateTest() {
|
||||
// predictable, but maybe a bit less thorough. This is more of an overall
|
||||
// state machine test than a test of the wgengine+magicsock integration.
|
||||
func TestStateMachine(t *testing.T) {
|
||||
runTestStateMachine(t, false)
|
||||
}
|
||||
|
||||
func TestStateMachineSeamless(t *testing.T) {
|
||||
runTestStateMachine(t, true)
|
||||
}
|
||||
|
||||
func runTestStateMachine(t *testing.T, seamless bool) {
|
||||
envknob.Setenv("TAILSCALE_USE_WIP_CODE", "1")
|
||||
defer envknob.Setenv("TAILSCALE_USE_WIP_CODE", "")
|
||||
c := qt.New(t)
|
||||
@@ -590,12 +582,6 @@ func runTestStateMachine(t *testing.T, seamless bool) {
|
||||
cc.persist.UserProfile.LoginName = "user1"
|
||||
cc.persist.NodeID = "node1"
|
||||
|
||||
// even if seamless is being enabled by default rather than by policy, this is
|
||||
// the point where it will first get enabled.
|
||||
if seamless {
|
||||
sys.ControlKnobs().SeamlessKeyRenewal.Store(true)
|
||||
}
|
||||
|
||||
cc.send(sendOpt{loginFinished: true, nm: &netmap.NetworkMap{}})
|
||||
{
|
||||
nn := notifies.drain(3)
|
||||
@@ -1480,11 +1466,23 @@ func TestEngineReconfigOnStateChange(t *testing.T) {
|
||||
lb.StartLoginInteractive(context.Background())
|
||||
cc().sendAuthURL(node1)
|
||||
},
|
||||
// Without seamless renewal, even starting a reauth tears down everything:
|
||||
wantState: ipn.Starting,
|
||||
wantCfg: &wgcfg.Config{},
|
||||
wantRouterCfg: &router.Config{},
|
||||
wantDNSCfg: &dns.Config{},
|
||||
// Starting a reauth should leave everything up:
|
||||
wantState: ipn.Starting,
|
||||
wantCfg: &wgcfg.Config{
|
||||
Peers: []wgcfg.Peer{},
|
||||
Addresses: node1.SelfNode.Addresses().AsSlice(),
|
||||
},
|
||||
wantRouterCfg: &router.Config{
|
||||
SNATSubnetRoutes: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
LocalAddrs: node1.SelfNode.Addresses().AsSlice(),
|
||||
Routes: routesWithQuad100(),
|
||||
},
|
||||
wantDNSCfg: &dns.Config{
|
||||
AcceptDNS: true,
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: hostsFor(node1),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Start/Connect/Login/InitReauth/Login",
|
||||
@@ -1518,71 +1516,8 @@ func TestEngineReconfigOnStateChange(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Seamless/Start/Connect/Login/InitReauth",
|
||||
name: "Start/Connect/Login/Expire",
|
||||
steps: func(t *testing.T, lb *LocalBackend, cc func() *mockControl) {
|
||||
lb.ControlKnobs().SeamlessKeyRenewal.Store(true)
|
||||
mustDo(t)(lb.Start(ipn.Options{}))
|
||||
mustDo2(t)(lb.EditPrefs(connect))
|
||||
cc().authenticated(node1)
|
||||
|
||||
// Start the re-auth process:
|
||||
lb.StartLoginInteractive(context.Background())
|
||||
cc().sendAuthURL(node1)
|
||||
},
|
||||
// With seamless renewal, starting a reauth should leave everything up:
|
||||
wantState: ipn.Starting,
|
||||
wantCfg: &wgcfg.Config{
|
||||
Peers: []wgcfg.Peer{},
|
||||
Addresses: node1.SelfNode.Addresses().AsSlice(),
|
||||
},
|
||||
wantRouterCfg: &router.Config{
|
||||
SNATSubnetRoutes: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
LocalAddrs: node1.SelfNode.Addresses().AsSlice(),
|
||||
Routes: routesWithQuad100(),
|
||||
},
|
||||
wantDNSCfg: &dns.Config{
|
||||
AcceptDNS: true,
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: hostsFor(node1),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Seamless/Start/Connect/Login/InitReauth/Login",
|
||||
steps: func(t *testing.T, lb *LocalBackend, cc func() *mockControl) {
|
||||
lb.ControlKnobs().SeamlessKeyRenewal.Store(true)
|
||||
mustDo(t)(lb.Start(ipn.Options{}))
|
||||
mustDo2(t)(lb.EditPrefs(connect))
|
||||
cc().authenticated(node1)
|
||||
|
||||
// Start the re-auth process:
|
||||
lb.StartLoginInteractive(context.Background())
|
||||
cc().sendAuthURL(node1)
|
||||
|
||||
// Complete the re-auth process:
|
||||
cc().authenticated(node1)
|
||||
},
|
||||
wantState: ipn.Starting,
|
||||
wantCfg: &wgcfg.Config{
|
||||
Peers: []wgcfg.Peer{},
|
||||
Addresses: node1.SelfNode.Addresses().AsSlice(),
|
||||
},
|
||||
wantRouterCfg: &router.Config{
|
||||
SNATSubnetRoutes: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
LocalAddrs: node1.SelfNode.Addresses().AsSlice(),
|
||||
Routes: routesWithQuad100(),
|
||||
},
|
||||
wantDNSCfg: &dns.Config{
|
||||
AcceptDNS: true,
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: hostsFor(node1),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Seamless/Start/Connect/Login/Expire",
|
||||
steps: func(t *testing.T, lb *LocalBackend, cc func() *mockControl) {
|
||||
lb.ControlKnobs().SeamlessKeyRenewal.Store(true)
|
||||
mustDo(t)(lb.Start(ipn.Options{}))
|
||||
mustDo2(t)(lb.EditPrefs(connect))
|
||||
cc().authenticated(node1)
|
||||
@@ -1592,7 +1527,7 @@ func TestEngineReconfigOnStateChange(t *testing.T) {
|
||||
}).View(),
|
||||
}})
|
||||
},
|
||||
// Even with seamless, if the key we are using expires, we want to disconnect:
|
||||
// If the key we are using expires, we want to disconnect:
|
||||
wantState: ipn.NeedsLogin,
|
||||
wantCfg: &wgcfg.Config{},
|
||||
wantRouterCfg: &router.Config{},
|
||||
@@ -1641,14 +1576,6 @@ func TestEngineReconfigOnStateChange(t *testing.T) {
|
||||
// TestSendPreservesAuthURL tests that wgengine updates arriving in the middle of
|
||||
// processing an auth URL doesn't result in the auth URL being cleared.
|
||||
func TestSendPreservesAuthURL(t *testing.T) {
|
||||
runTestSendPreservesAuthURL(t, false)
|
||||
}
|
||||
|
||||
func TestSendPreservesAuthURLSeamless(t *testing.T) {
|
||||
runTestSendPreservesAuthURL(t, true)
|
||||
}
|
||||
|
||||
func runTestSendPreservesAuthURL(t *testing.T, seamless bool) {
|
||||
var cc *mockControl
|
||||
b := newLocalBackendWithTestControl(t, true, func(tb testing.TB, opts controlclient.Options) controlclient.Client {
|
||||
cc = newClient(t, opts)
|
||||
@@ -1667,10 +1594,6 @@ func runTestSendPreservesAuthURL(t *testing.T, seamless bool) {
|
||||
cc.persist.UserProfile.LoginName = "user1"
|
||||
cc.persist.NodeID = "node1"
|
||||
|
||||
if seamless {
|
||||
b.sys.ControlKnobs().SeamlessKeyRenewal.Store(true)
|
||||
}
|
||||
|
||||
cc.send(sendOpt{loginFinished: true, nm: &netmap.NetworkMap{
|
||||
SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
|
||||
}})
|
||||
|
||||
Reference in New Issue
Block a user