android,libtailscale: allow toggling HW attestation via MDM
Previously hardware attestation was enabled on all supported devices. We now gate this functionality behind an MDM setting (whose default value is true) to allow disabling this in deployments where it might cause issues. Updates tailscale/corp#31269 Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
This commit is contained in:
committed by
Jonathan Nobels
parent
3fa2c6cea8
commit
df38cfa5f6
@@ -150,10 +150,12 @@ class App : UninitializedApp(), libtailscale.AppContext, ViewModelStoreOwner {
|
||||
private fun initializeApp() {
|
||||
// Check if a directory URI has already been stored.
|
||||
val storedUri = getStoredDirectoryUri()
|
||||
val rm = getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager
|
||||
val hardwareAttestation = rm.applicationRestrictions.getBoolean(MDMSettings.KEY_HARDWARE_ATTESTATION, false)
|
||||
if (storedUri != null && storedUri.toString().startsWith("content://")) {
|
||||
startLibtailscale(storedUri.toString())
|
||||
startLibtailscale(storedUri.toString(), hardwareAttestation)
|
||||
} else {
|
||||
startLibtailscale(this.filesDir.absolutePath)
|
||||
startLibtailscale(this.filesDir.absolutePath, hardwareAttestation)
|
||||
}
|
||||
healthNotifier = HealthNotifier(Notifier.health, Notifier.state, applicationScope)
|
||||
connectivityManager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
@@ -202,8 +204,8 @@ class App : UninitializedApp(), libtailscale.AppContext, ViewModelStoreOwner {
|
||||
* Called when a SAF directory URI is available (either already stored or chosen). We must restart
|
||||
* Tailscale because directFileRoot must be set before LocalBackend starts being used.
|
||||
*/
|
||||
fun startLibtailscale(directFileRoot: String) {
|
||||
app = Libtailscale.start(this.filesDir.absolutePath, directFileRoot, this)
|
||||
fun startLibtailscale(directFileRoot: String, hardwareAttestation: Boolean) {
|
||||
app = Libtailscale.start(this.filesDir.absolutePath, directFileRoot, hardwareAttestation, this)
|
||||
ShareFileHelper.init(this, app, directFileRoot, applicationScope)
|
||||
Request.setApp(app)
|
||||
Notifier.setApp(app)
|
||||
|
||||
@@ -18,6 +18,9 @@ object MDMSettings {
|
||||
// to the backend.
|
||||
class NoSuchKeyException : Exception("no such key")
|
||||
|
||||
// MDM restriction keys
|
||||
const val KEY_HARDWARE_ATTESTATION = "HardwareAttestation"
|
||||
|
||||
val forceEnabled = BooleanMDMSetting("ForceEnabled", "Force Enabled Connection Toggle")
|
||||
|
||||
// Handled on the backed
|
||||
@@ -115,6 +118,11 @@ object MDMSettings {
|
||||
.map { it.call(MDMSettings) as MDMSetting<*> }
|
||||
}
|
||||
|
||||
val hardwareAttestation = BooleanMDMSetting(
|
||||
KEY_HARDWARE_ATTESTATION,
|
||||
"Use hardware-backed keys to bind node identity to the device",
|
||||
)
|
||||
|
||||
val allSettingsByKey by lazy { allSettings.associateBy { it.key } }
|
||||
|
||||
fun update(app: App, restrictionsManager: RestrictionsManager?) {
|
||||
|
||||
@@ -360,4 +360,8 @@
|
||||
<string name="taildrop_directory_picker_info">What is taildrop?</string>
|
||||
<string name="taildrop_directory_picker_button">Open Directory Picker</string>
|
||||
|
||||
<!-- Strings for Hardware Attestation MDM setting -->
|
||||
<string name="enable_hardware_attestation">Enable hardware attestation</string>
|
||||
<string name="use_hardware_backed_keys_to_bind_node_identity_to_the_device">Use hardware-backed keys to bind node identity to the device</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -148,4 +148,11 @@
|
||||
android:key="OnboardingFlow"
|
||||
android:restrictionType="choice"
|
||||
android:title="@string/onboarding_flow" />
|
||||
</restrictions>
|
||||
|
||||
<restriction
|
||||
android:defaultValue="true"
|
||||
android:description="@string/use_hardware_backed_keys_to_bind_node_identity_to_the_device"
|
||||
android:key="HardwareAttestation"
|
||||
android:restrictionType="bool"
|
||||
android:title="@string/enable_hardware_attestation" />
|
||||
</restrictions>
|
||||
|
||||
@@ -60,7 +60,7 @@ type App struct {
|
||||
backendMu sync.Mutex
|
||||
}
|
||||
|
||||
func start(dataDir, directFileRoot string, appCtx AppContext) Application {
|
||||
func start(dataDir, directFileRoot string, hwAttestationPref bool, appCtx AppContext) Application {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
log.Printf("panic in Start %s: %s", p, debug.Stack())
|
||||
@@ -84,7 +84,7 @@ func start(dataDir, directFileRoot string, appCtx AppContext) Application {
|
||||
os.Setenv("HOME", dataDir)
|
||||
}
|
||||
|
||||
return newApp(dataDir, directFileRoot, appCtx)
|
||||
return newApp(dataDir, directFileRoot, hwAttestationPref, appCtx)
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
@@ -111,7 +111,7 @@ type backend struct {
|
||||
|
||||
type settingsFunc func(*router.Config, *dns.OSConfig) error
|
||||
|
||||
func (a *App) runBackend(ctx context.Context) error {
|
||||
func (a *App) runBackend(ctx context.Context, hardwareAttestation bool) error {
|
||||
paths.AppSharedDir.Store(a.dataDir)
|
||||
hostinfo.SetOSVersion(a.osVersion())
|
||||
hostinfo.SetPackage(a.appCtx.GetInstallSource())
|
||||
@@ -139,6 +139,9 @@ func (a *App) runBackend(ctx context.Context) error {
|
||||
}
|
||||
a.logIDPublicAtomic.Store(&b.logIDPublic)
|
||||
a.backend = b.backend
|
||||
if hardwareAttestation {
|
||||
a.backend.SetHardwareAttested()
|
||||
}
|
||||
defer b.CloseTUNs()
|
||||
|
||||
hc := localapi.HandlerConfig{
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
// Start starts the application, storing state in the given dataDir and using
|
||||
// the given appCtx.
|
||||
func Start(dataDir, directFileRoot string, appCtx AppContext) Application {
|
||||
return start(dataDir, directFileRoot, appCtx)
|
||||
func Start(dataDir, directFileRoot string, hwAttestationPref bool, appCtx AppContext) Application {
|
||||
return start(dataDir, directFileRoot, hwAttestationPref, appCtx)
|
||||
}
|
||||
|
||||
// AppContext provides a context within which the Application is running. This
|
||||
|
||||
@@ -93,3 +93,7 @@ func (k *hardwareAttestationKey) Close() error {
|
||||
func (k *hardwareAttestationKey) Clone() key.HardwareAttestationKey {
|
||||
return &hardwareAttestationKey{appCtx: k.appCtx, id: k.id, public: k.public}
|
||||
}
|
||||
|
||||
func (k* hardwareAttestationKey) IsZero() bool {
|
||||
return k.id == ""
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ const (
|
||||
customLoginServerPrefKey = "customloginserver"
|
||||
)
|
||||
|
||||
func newApp(dataDir, directFileRoot string, appCtx AppContext) Application {
|
||||
func newApp(dataDir, directFileRoot string, hardwareAttestationPref bool, appCtx AppContext) Application {
|
||||
a := &App{
|
||||
directFileRoot: directFileRoot,
|
||||
dataDir: dataDir,
|
||||
@@ -44,7 +44,9 @@ func newApp(dataDir, directFileRoot string, appCtx AppContext) Application {
|
||||
a.policyStore = &syspolicyStore{a: a}
|
||||
netmon.RegisterInterfaceGetter(a.getInterfaces)
|
||||
rsop.RegisterStore("DeviceHandler", setting.DeviceScope, a.policyStore)
|
||||
if appCtx.HardwareAttestationKeySupported() {
|
||||
|
||||
hwAttestEnabled := appCtx.HardwareAttestationKeySupported() && hardwareAttestationPref
|
||||
if hwAttestEnabled {
|
||||
key.RegisterHardwareAttestationKeyFns(
|
||||
func() key.HardwareAttestationKey { return emptyHardwareAttestationKey(appCtx) },
|
||||
func() (key.HardwareAttestationKey, error) { return createHardwareAttestationKey(appCtx) },
|
||||
@@ -63,7 +65,7 @@ func newApp(dataDir, directFileRoot string, appCtx AppContext) Application {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
if err := a.runBackend(ctx); err != nil {
|
||||
if err := a.runBackend(ctx, hwAttestEnabled); err != nil {
|
||||
fatalErr(err)
|
||||
}
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user