client/tailscale,ipn/ipn{local,server},util/syspolicy: implement the AlwaysOn.OverrideWithReason policy setting

In this PR, we update client/tailscale.LocalClient to allow sending requests with an optional X-Tailscale-Reason
header. We then update ipn/ipnserver.{actor,Server} to retrieve this reason, if specified, and use it to determine
whether ipnauth.Disconnect is allowed when the AlwaysOn.OverrideWithReason policy setting is enabled.
For now, we log the reason, along with the profile and OS username, to the backend log.

Finally, we update LocalBackend to remember when a disconnect was permitted and do not reconnect automatically
unless the policy changes.

Updates tailscale/corp#26146

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl
2025-01-31 16:14:13 -06:00
committed by Nick Khyl
parent 2c02f712d1
commit d832467461
7 changed files with 125 additions and 17 deletions

View File

@@ -34,7 +34,13 @@ const (
// Warning: This policy setting is experimental and may change or be removed in the future.
// It may also not be fully supported by all Tailscale clients until it is out of experimental status.
// See tailscale/corp#26247, tailscale/corp#26248 and tailscale/corp#26249 for more information.
AlwaysOn Key = "AlwaysOn"
AlwaysOn Key = "AlwaysOn.Enabled"
// AlwaysOnOverrideWithReason is a boolean key that alters the behavior
// of [AlwaysOn]. When true, the user is allowed to disconnect Tailscale
// by providing a reason. The reason is logged and sent to the control
// for auditing purposes. It has no effect when [AlwaysOn] is false.
AlwaysOnOverrideWithReason Key = "AlwaysOn.OverrideWithReason"
// ExitNodeID is the exit node's node id. default ""; if blank, no exit node is forced.
// Exit node ID takes precedence over exit node IP.
@@ -150,6 +156,7 @@ var implicitDefinitions = []*setting.Definition{
// Device policy settings (can only be configured on a per-device basis):
setting.NewDefinition(AllowedSuggestedExitNodes, setting.DeviceSetting, setting.StringListValue),
setting.NewDefinition(AlwaysOn, setting.DeviceSetting, setting.BooleanValue),
setting.NewDefinition(AlwaysOnOverrideWithReason, setting.DeviceSetting, setting.BooleanValue),
setting.NewDefinition(ApplyUpdates, setting.DeviceSetting, setting.PreferenceOptionValue),
setting.NewDefinition(AuthKey, setting.DeviceSetting, setting.StringValue),
setting.NewDefinition(CheckUpdates, setting.DeviceSetting, setting.PreferenceOptionValue),