diff --git a/api.go b/api.go index c7ae122c..36af5a06 100644 --- a/api.go +++ b/api.go @@ -111,7 +111,8 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { // We have the updated key! if m.NodeKey == wgkey.Key(req.NodeKey).HexString() { - // The client sends an Expiry in the past if the client is requesting a logout + // The client sends an Expiry in the past if the client is requesting to expire the key (aka logout) + // https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648 if !req.Expiry.IsZero() && req.Expiry.UTC().Before(now) { log.Info(). Str("handler", "Registration"). @@ -178,7 +179,13 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) { strings.TrimSuffix(h.cfg.ServerURL, "/"), mKey.HexString()) } - m.RequestedExpiry = &req.Expiry // save the requested expiry time for retrieval later in the authentication flow + // When a client connects, it may request a specific expiry time in its + // RegisterRequest (https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L634) + m.RequestedExpiry = &req.Expiry // RequestedExpiry is used to store the clients requested expiry time since the authentication flow is broken + // into two steps (which cant pass arbitrary data between them easily) and needs to be + // retrieved again after the user has authenticated. After the authentication flow + // completes, RequestedExpiry is copied into Expiry. + h.db.Save(&m) respBody, err := encode(resp, &mKey, h.privateKey) diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index 4a598e77..0ba43b28 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -161,14 +161,18 @@ func getHeadscaleApp() (*headscale.Headscale, error) { return nil, err } - // maxMachineRegistrationDuration is the maximum time a client can request for a client registration - maxMachineRegistrationDuration, _ := time.ParseDuration("10h") + // maxMachineRegistrationDuration is the maximum time headscale will allow a client to (optionally) request for + // the machine key expiry time. RegisterRequests with Expiry times that are more than + // maxMachineRegistrationDuration in the future will be clamped to (now + maxMachineRegistrationDuration) + maxMachineRegistrationDuration, _ := time.ParseDuration("10h") // use 10h here because it is the length of a standard business day plus a small amount of leeway if viper.GetDuration("max_machine_registration_duration") >= time.Second { maxMachineRegistrationDuration = viper.GetDuration("max_machine_registration_duration") } - // defaultMachineRegistrationDuration is the default time assigned to a client registration if one is not specified by the client - defaultMachineRegistrationDuration, _ := time.ParseDuration("8h") + // defaultMachineRegistrationDuration is the default time assigned to a machine registration if one is not + // specified by the tailscale client. It is the default amount of time a machine registration is valid for + // (ie the amount of time before the user has to re-authenticate when requesting a connection) + defaultMachineRegistrationDuration, _ := time.ParseDuration("8h") // use 8h here because it's the length of a standard business day if viper.GetDuration("default_machine_registration_duration") >= time.Second { defaultMachineRegistrationDuration = viper.GetDuration("default_machine_registration_duration") } @@ -212,9 +216,8 @@ func getHeadscaleApp() (*headscale.Headscale, error) { ClientSecret: viper.GetString("oidc.client_secret"), }, - MaxMachineRegistrationDuration: maxMachineRegistrationDuration, // the maximum duration a client may request for expiry time - DefaultMachineRegistrationDuration: defaultMachineRegistrationDuration, // if a client does not request a specific expiry time, use this duration - + MaxMachineRegistrationDuration: maxMachineRegistrationDuration, + DefaultMachineRegistrationDuration: defaultMachineRegistrationDuration, } cfg.OIDC.MatchMap = loadOIDCMatchMap() diff --git a/machine.go b/machine.go index a43fa8de..f4ce0afb 100644 --- a/machine.go +++ b/machine.go @@ -36,7 +36,7 @@ type Machine struct { LastSeen *time.Time LastSuccessfulUpdate *time.Time Expiry *time.Time - RequestedExpiry *time.Time // when a client connects, it may request a specific expiry time, use this field to store it + RequestedExpiry *time.Time HostInfo datatypes.JSON Endpoints datatypes.JSON @@ -63,7 +63,9 @@ func (m Machine) isExpired() bool { } // If the Machine is expired, updateMachineExpiry updates the Machine Expiry time to the maximum allowed duration, -// or the default duration if no Expiry time was requested by the client +// or the default duration if no Expiry time was requested by the client. The expiry time here does not (yet) cause +// a client to be disconnected, however they will have to re-auth the machine if they attempt to reconnect after the +// expiry time. func (h *Headscale) updateMachineExpiry(m *Machine) { if m.isExpired() {