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
+16 -2
View File
@@ -26,6 +26,7 @@ type Persist struct {
UserProfile tailcfg.UserProfile
NetworkLockKey key.NLPrivate
NodeID tailcfg.StableNodeID
AttestationKey key.HardwareAttestationKey `json:",omitempty"`
// DisallowedTKAStateIDs stores the tka.State.StateID values which
// this node will not operate network lock on. This is used to
@@ -84,11 +85,20 @@ func (p *Persist) Equals(p2 *Persist) bool {
return false
}
var pub, p2Pub key.HardwareAttestationPublic
if p.AttestationKey != nil && !p.AttestationKey.IsZero() {
pub = key.HardwareAttestationPublicFromPlatformKey(p.AttestationKey)
}
if p2.AttestationKey != nil && !p2.AttestationKey.IsZero() {
p2Pub = key.HardwareAttestationPublicFromPlatformKey(p2.AttestationKey)
}
return p.PrivateNodeKey.Equal(p2.PrivateNodeKey) &&
p.OldPrivateNodeKey.Equal(p2.OldPrivateNodeKey) &&
p.UserProfile.Equal(&p2.UserProfile) &&
p.NetworkLockKey.Equal(p2.NetworkLockKey) &&
p.NodeID == p2.NodeID &&
pub.Equal(p2Pub) &&
reflect.DeepEqual(nilIfEmpty(p.DisallowedTKAStateIDs), nilIfEmpty(p2.DisallowedTKAStateIDs))
}
@@ -96,12 +106,16 @@ func (p *Persist) Pretty() string {
var (
ok, nk key.NodePublic
)
akString := "-"
if !p.OldPrivateNodeKey.IsZero() {
ok = p.OldPrivateNodeKey.Public()
}
if !p.PrivateNodeKey.IsZero() {
nk = p.PublicNodeKey()
}
return fmt.Sprintf("Persist{o=%v, n=%v u=%#v}",
ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName)
if p.AttestationKey != nil && !p.AttestationKey.IsZero() {
akString = fmt.Sprintf("%v", p.AttestationKey.Public())
}
return fmt.Sprintf("Persist{o=%v, n=%v u=%#v ak=%s}",
ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName, akString)
}