cmd/tailscale,tka: implement compat for TKA messages, minor UX tweaks

Signed-off-by: Tom DNetto <tom@tailscale.com>
This commit is contained in:
Tom DNetto 2022-12-13 09:33:13 -08:00 committed by Tom
parent c4e262a0fc
commit 8724aa254f
3 changed files with 31 additions and 10 deletions

View File

@ -5,6 +5,7 @@
package cli
import (
"bytes"
"context"
"crypto/rand"
"encoding/hex"
@ -99,6 +100,18 @@ func runNetworkLockInit(ctx context.Context, args []string) error {
return err
}
// Common mistake: Not specifying the current node's key as one of the trusted keys.
foundSelfKey := false
for _, k := range keys {
if bytes.Equal(k.ID(), st.PublicKey.KeyID()) {
foundSelfKey = true
break
}
}
if !foundSelfKey {
return errors.New("the tailnet lock key of the current node must be one of the trusted keys during initialization")
}
fmt.Println("You are initializing tailnet lock with the following trusted signing keys:")
for _, k := range keys {
fmt.Printf(" - tlpub:%x (%s key)\n", k.Public, k.Kind.String())
@ -196,7 +209,7 @@ func runNetworkLockStatus(ctx context.Context, args []string) error {
line.WriteString(fmt.Sprint(k.Votes))
line.WriteString("\t")
if k.Key == st.PublicKey {
line.WriteString("(us)")
line.WriteString("(self)")
}
fmt.Println(line.String())
}

View File

@ -150,7 +150,7 @@ func (a *AUM) StaticValidate() error {
return errors.New("absent parent must be represented by a nil slice")
}
for i, sig := range a.Signatures {
if len(sig.KeyID) == 0 || len(sig.Signature) != ed25519.SignatureSize {
if len(sig.KeyID) != 32 || len(sig.Signature) != ed25519.SignatureSize {
return fmt.Errorf("signature %d has missing keyID or malformed signature", i)
}
}
@ -196,8 +196,13 @@ func (a *AUM) StaticValidate() error {
case AUMNoOp:
default:
// TODO(tom): Ignore unknown AUMs for GA.
return fmt.Errorf("unknown AUM kind: %v", a.MessageKind)
// An AUM with an unknown message kind was received! That means
// that a future version of tailscaled added some feature we don't
// understand.
//
// The future-compatibility contract for AUM message types is that
// they must only add new features, not change the semantics of existing
// mechanisms or features. As such, old clients can safely ignore them.
}
return nil

View File

@ -29,9 +29,6 @@ type State struct {
// DisablementSecrets are KDF-derived values which can be used
// to turn off the TKA in the event of a consensus-breaking bug.
//
// TODO(tom): This is an alpha feature, remove this mechanism once
// we have confidence in our implementation.
DisablementSecrets [][]byte `cbor:"2,keyasint"`
// Keys are the public keys currently trusted by the TKA.
@ -217,9 +214,15 @@ func (s State) applyVerifiedAUM(update AUM) (State, error) {
return out, nil
default:
// TODO(tom): Instead of erroring, update lastHash and
// continue (to preserve future compatibility).
return State{}, fmt.Errorf("unhandled message: %v", update.MessageKind)
// An AUM with an unknown message kind was received! That means
// that a future version of tailscaled added some feature we don't
// understand.
//
// The future-compatibility contract for AUM message types is that
// they must only add new features, not change the semantics of existing
// mechanisms or features. As such, old clients can safely ignore them.
out := s.cloneForUpdate(&update)
return out, nil
}
}