From e8ca30a5c7df80c327eaa29d0ab7f97c52bc6dde Mon Sep 17 00:00:00 2001 From: Andrea Gottardo Date: Fri, 14 Jun 2024 10:59:40 -0700 Subject: [PATCH] xcode/iOS: support serial number collection via MDM on iOS (#11429) Fixes tailscale/corp#18366. This PR provides serial number collection on iOS, by allowing system administrators to pass a `DeviceSerialNumber` MDM key which can be read by the `posture` package in Go. Signed-off-by: Andrea Gottardo --- posture/serialnumber_ios.go | 25 +++++++++++++++++++++++++ posture/serialnumber_stub.go | 3 +-- tailcfg/tailcfg.go | 3 ++- util/syspolicy/policy_keys.go | 4 ++++ 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 posture/serialnumber_ios.go diff --git a/posture/serialnumber_ios.go b/posture/serialnumber_ios.go new file mode 100644 index 000000000..b5aa09056 --- /dev/null +++ b/posture/serialnumber_ios.go @@ -0,0 +1,25 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package posture + +import ( + "fmt" + + "tailscale.com/types/logger" + "tailscale.com/util/syspolicy" +) + +// GetSerialNumbers returns the serial number of the iOS/tvOS device as reported by an +// MDM solution. It requires configuration via the DeviceSerialNumber system policy. +// This is the only way to gather serial numbers on iOS and tvOS. +func GetSerialNumbers(_ logger.Logf) ([]string, error) { + s, err := syspolicy.GetString("DeviceSerialNumber", "") + if err != nil { + return nil, fmt.Errorf("failed to get serial number from MDM: %v", err) + } + if s != "" { + return []string{s}, nil + } + return nil, nil +} diff --git a/posture/serialnumber_stub.go b/posture/serialnumber_stub.go index f1f6d4694..cdabf03e5 100644 --- a/posture/serialnumber_stub.go +++ b/posture/serialnumber_stub.go @@ -1,14 +1,13 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -// ios: Apple does not allow getting serials on iOS // android: not implemented // js: not implemented // plan9: not implemented // solaris: currently unsupported by go-smbios: // https://github.com/digitalocean/go-smbios/pull/21 -//go:build ios || android || solaris || plan9 || js || wasm || (darwin && !cgo) || tamago || aix +//go:build android || solaris || plan9 || js || wasm || tamago || aix || (darwin && !cgo && !ios) package posture diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 21fddf020..be3abeb2e 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -138,7 +138,8 @@ type CapabilityVersion int // - 95: 2024-05-06: Client uses NodeAttrUserDialUseRoutes to change DNS dialing behavior. // - 96: 2024-05-29: Client understands NodeAttrSSHBehaviorV1 // - 97: 2024-06-06: Client understands NodeAttrDisableSplitDNSWhenNoCustomResolvers -const CurrentCapabilityVersion CapabilityVersion = 97 +// - 98: 2024-06-13: iOS/tvOS clients may provide serial number as part of posture information +const CurrentCapabilityVersion CapabilityVersion = 98 type StableID string diff --git a/util/syspolicy/policy_keys.go b/util/syspolicy/policy_keys.go index 209356486..ef0cfed8f 100644 --- a/util/syspolicy/policy_keys.go +++ b/util/syspolicy/policy_keys.go @@ -76,6 +76,10 @@ const ( // Key is a string value that specifies an option: "always", "never", "user-decides". // The default is "user-decides" unless otherwise stated. PostureChecking Key = "PostureChecking" + // DeviceSerialNumber is the serial number of the device that is running Tailscale. + // This is used on iOS/tvOS to allow IT administrators to manually give us a serial number via MDM. + // We are unable to programmatically get the serial number from IOKit due to sandboxing restrictions. + DeviceSerialNumber Key = "DeviceSerialNumber" // ManagedByOrganizationName indicates the name of the organization managing the Tailscale // install. It is displayed inside the client UI in a prominent location.