mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-12 13:48:01 +00:00
all: store NL keys per profile
This moves the NetworkLock key from a dedicated StateKey to be part of the persist.Persist struct. This struct is stored as part for ipn.Prefs and is also the place where we store the NodeKey. It also moves the ChonkDir from "/tka" to "/tka-profile/<profile-id>". The rename was intentional to be able to delete the "/tka" dir if it exists. This means that we will have a unique key per profile, and a unique directory per profile. Note: `tailscale logout` will delete the entire profile, including any keys. It currently does not delete the ChonkDir. Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
@@ -35,6 +35,7 @@ var (
|
||||
)
|
||||
|
||||
type tkaState struct {
|
||||
profile ipn.ProfileID
|
||||
authority *tka.Authority
|
||||
storage *tka.FS
|
||||
}
|
||||
@@ -251,7 +252,7 @@ func (b *LocalBackend) tkaSyncLocked(ourNodeKey key.NodePublic) error {
|
||||
// b.mu must be held & TKA must be initialized.
|
||||
func (b *LocalBackend) tkaApplyDisablementLocked(secret []byte) error {
|
||||
if b.tka.authority.ValidDisablement(secret) {
|
||||
if err := os.RemoveAll(b.chonkPath()); err != nil {
|
||||
if err := os.RemoveAll(b.chonkPathLocked()); err != nil {
|
||||
return err
|
||||
}
|
||||
b.tka = nil
|
||||
@@ -260,10 +261,10 @@ func (b *LocalBackend) tkaApplyDisablementLocked(secret []byte) error {
|
||||
return errors.New("incorrect disablement secret")
|
||||
}
|
||||
|
||||
// chonkPath returns the absolute path to the directory in which TKA
|
||||
// chonkPathLocked returns the absolute path to the directory in which TKA
|
||||
// state (the 'tailchonk') is stored.
|
||||
func (b *LocalBackend) chonkPath() string {
|
||||
return filepath.Join(b.TailscaleVarRoot(), "tka")
|
||||
func (b *LocalBackend) chonkPathLocked() string {
|
||||
return filepath.Join(b.TailscaleVarRoot(), "tka-profiles", string(b.pm.CurrentProfile().ID))
|
||||
}
|
||||
|
||||
// tkaBootstrapFromGenesisLocked initializes the local (on-disk) state of the
|
||||
@@ -280,7 +281,10 @@ func (b *LocalBackend) tkaBootstrapFromGenesisLocked(g tkatype.MarshaledAUM) err
|
||||
return fmt.Errorf("reading genesis: %v", err)
|
||||
}
|
||||
|
||||
chonkDir := b.chonkPath()
|
||||
chonkDir := b.chonkPathLocked()
|
||||
if err := os.Mkdir(filepath.Dir(chonkDir), 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("creating chonk root dir: %v", err)
|
||||
}
|
||||
if err := os.Mkdir(chonkDir, 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("mkdir: %v", err)
|
||||
}
|
||||
@@ -295,6 +299,7 @@ func (b *LocalBackend) tkaBootstrapFromGenesisLocked(g tkatype.MarshaledAUM) err
|
||||
}
|
||||
|
||||
b.tka = &tkaState{
|
||||
profile: b.pm.CurrentProfile().ID,
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
}
|
||||
@@ -329,17 +334,27 @@ func (b *LocalBackend) NetworkLockStatus() *ipnstate.NetworkLockStatus {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
var nodeKey *key.NodePublic
|
||||
var (
|
||||
nodeKey *key.NodePublic
|
||||
nlPriv key.NLPrivate
|
||||
)
|
||||
if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist() != nil && !p.Persist().PrivateNodeKey.IsZero() {
|
||||
nkp := p.Persist().PublicNodeKey()
|
||||
nodeKey = &nkp
|
||||
nlPriv = p.Persist().NetworkLockKey
|
||||
}
|
||||
|
||||
if nlPriv.IsZero() {
|
||||
return &ipnstate.NetworkLockStatus{
|
||||
Enabled: false,
|
||||
NodeKey: nodeKey,
|
||||
}
|
||||
}
|
||||
if b.tka == nil {
|
||||
return &ipnstate.NetworkLockStatus{
|
||||
Enabled: false,
|
||||
PublicKey: b.nlPrivKey.Public(),
|
||||
NodeKey: nodeKey,
|
||||
PublicKey: nlPriv.Public(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,7 +380,7 @@ func (b *LocalBackend) NetworkLockStatus() *ipnstate.NetworkLockStatus {
|
||||
return &ipnstate.NetworkLockStatus{
|
||||
Enabled: true,
|
||||
Head: &head,
|
||||
PublicKey: b.nlPrivKey.Public(),
|
||||
PublicKey: nlPriv.Public(),
|
||||
NodeKey: nodeKey,
|
||||
NodeKeySigned: selfAuthorized,
|
||||
TrustedKeys: outKeys,
|
||||
@@ -387,12 +402,14 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byt
|
||||
}
|
||||
|
||||
var ourNodeKey key.NodePublic
|
||||
var nlPriv key.NLPrivate
|
||||
b.mu.Lock()
|
||||
if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist() != nil && !p.Persist().PrivateNodeKey.IsZero() {
|
||||
ourNodeKey = p.Persist().PublicNodeKey()
|
||||
nlPriv = p.Persist().NetworkLockKey
|
||||
}
|
||||
b.mu.Unlock()
|
||||
if ourNodeKey.IsZero() {
|
||||
if ourNodeKey.IsZero() || nlPriv.IsZero() {
|
||||
return errors.New("no node-key: is tailscale logged in?")
|
||||
}
|
||||
|
||||
@@ -407,7 +424,7 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byt
|
||||
// - DisablementSecret: value needed to disable.
|
||||
// - DisablementValue: the KDF of the disablement secret, a public value.
|
||||
DisablementSecrets: disablementValues,
|
||||
}, b.nlPrivKey)
|
||||
}, nlPriv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tka.Create: %v", err)
|
||||
}
|
||||
@@ -430,7 +447,7 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byt
|
||||
// satisfy network-lock checks.
|
||||
sigs := make(map[tailcfg.NodeID]tkatype.MarshaledSignature, len(initResp.NeedSignatures))
|
||||
for _, nodeInfo := range initResp.NeedSignatures {
|
||||
nks, err := signNodeKey(nodeInfo, b.nlPrivKey)
|
||||
nks, err := signNodeKey(nodeInfo, nlPriv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating signature: %v", err)
|
||||
}
|
||||
@@ -470,10 +487,18 @@ func (b *LocalBackend) NetworkLockSign(nodeKey key.NodePublic, rotationPublic []
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
var nlPriv key.NLPrivate
|
||||
if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist() != nil {
|
||||
nlPriv = p.Persist().NetworkLockKey
|
||||
}
|
||||
if nlPriv.IsZero() {
|
||||
return key.NodePublic{}, tka.NodeKeySignature{}, errMissingNetmap
|
||||
}
|
||||
|
||||
if b.tka == nil {
|
||||
return key.NodePublic{}, tka.NodeKeySignature{}, errNetworkLockNotActive
|
||||
}
|
||||
if !b.tka.authority.KeyTrusted(b.nlPrivKey.KeyID()) {
|
||||
if !b.tka.authority.KeyTrusted(nlPriv.KeyID()) {
|
||||
return key.NodePublic{}, tka.NodeKeySignature{}, errors.New("this node is not trusted by network lock")
|
||||
}
|
||||
|
||||
@@ -483,11 +508,11 @@ func (b *LocalBackend) NetworkLockSign(nodeKey key.NodePublic, rotationPublic []
|
||||
}
|
||||
sig := tka.NodeKeySignature{
|
||||
SigKind: tka.SigDirect,
|
||||
KeyID: b.nlPrivKey.KeyID(),
|
||||
KeyID: nlPriv.KeyID(),
|
||||
Pubkey: p,
|
||||
WrappingPubkey: rotationPublic,
|
||||
}
|
||||
sig.Signature, err = b.nlPrivKey.SignNKS(sig.SigHash())
|
||||
sig.Signature, err = nlPriv.SignNKS(sig.SigHash())
|
||||
if err != nil {
|
||||
return key.NodePublic{}, tka.NodeKeySignature{}, fmt.Errorf("signature failed: %w", err)
|
||||
}
|
||||
@@ -527,11 +552,18 @@ func (b *LocalBackend) NetworkLockModify(addKeys, removeKeys []tka.Key) (err err
|
||||
if err := b.CanSupportNetworkLock(); err != nil {
|
||||
return err
|
||||
}
|
||||
var nlPriv key.NLPrivate
|
||||
if p := b.pm.CurrentPrefs(); p.Valid() && p.Persist() != nil {
|
||||
nlPriv = p.Persist().NetworkLockKey
|
||||
}
|
||||
if nlPriv.IsZero() {
|
||||
return errMissingNetmap
|
||||
}
|
||||
if b.tka == nil {
|
||||
return errNetworkLockNotActive
|
||||
}
|
||||
|
||||
updater := b.tka.authority.NewUpdater(b.nlPrivKey)
|
||||
updater := b.tka.authority.NewUpdater(nlPriv)
|
||||
|
||||
for _, addKey := range addKeys {
|
||||
if err := updater.AddKey(addKey); err != nil {
|
||||
|
Reference in New Issue
Block a user