types/persist: add AttestationKey (#17281)

Extend Persist with AttestationKey to record a hardware-backed
attestation key for the node's identity.

Add a flag to tailscaled to allow users to control the use of
hardware-backed keys to bind node identity to individual machines.

Updates tailscale/corp#31269


Change-Id: Idcf40d730a448d85f07f1bebf387f086d4c58be3

Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
This commit is contained in:
Patrick O'Doherty
2025-10-10 10:28:36 -07:00
committed by GitHub
parent a2dc517d7d
commit e45557afc0
26 changed files with 370 additions and 42 deletions
+33 -5
View File
@@ -392,6 +392,23 @@ type LocalBackend struct {
//
// See tailscale/corp#29969.
overrideExitNodePolicy bool
// hardwareAttested is whether backend should use a hardware-backed key to
// bind the node identity to this device.
hardwareAttested atomic.Bool
}
// SetHardwareAttested enables hardware attestation key signatures in map
// requests, if supported on this platform. SetHardwareAttested should be called
// before Start.
func (b *LocalBackend) SetHardwareAttested() {
b.hardwareAttested.Store(true)
}
// HardwareAttested reports whether hardware-backed attestation keys should be
// used to bind the node's identity to this device.
func (b *LocalBackend) HardwareAttested() bool {
return b.hardwareAttested.Load()
}
// HealthTracker returns the health tracker for the backend.
@@ -2455,10 +2472,23 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
if b.reconcilePrefsLocked(newPrefs) {
prefsChanged = true
}
// neither UpdatePrefs or reconciliation should change Persist
newPrefs.Persist = b.pm.CurrentPrefs().Persist().AsStruct()
if buildfeatures.HasTPM {
if genKey, ok := feature.HookGenerateAttestationKeyIfEmpty.GetOk(); ok {
newKey, err := genKey(newPrefs.Persist, b.logf)
if err != nil {
b.logf("failed to populate attestation key from TPM: %v", err)
}
if newKey {
prefsChanged = true
}
}
}
if prefsChanged {
// Neither opts.UpdatePrefs nor prefs reconciliation
// is allowed to modify Persist; retain the old value.
newPrefs.Persist = b.pm.CurrentPrefs().Persist().AsStruct()
if err := b.pm.SetPrefs(newPrefs.View(), cn.NetworkProfile()); err != nil {
b.logf("failed to save updated and reconciled prefs: %v", err)
}
@@ -2491,8 +2521,6 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
discoPublic := b.MagicConn().DiscoPublicKey()
var err error
isNetstack := b.sys.IsNetstackRouter()
debugFlags := controlDebugFlags
if isNetstack {