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 package cli
import ( import (
"bytes"
"context" "context"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
@ -99,6 +100,18 @@ func runNetworkLockInit(ctx context.Context, args []string) error {
return err 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:") fmt.Println("You are initializing tailnet lock with the following trusted signing keys:")
for _, k := range keys { for _, k := range keys {
fmt.Printf(" - tlpub:%x (%s key)\n", k.Public, k.Kind.String()) 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(fmt.Sprint(k.Votes))
line.WriteString("\t") line.WriteString("\t")
if k.Key == st.PublicKey { if k.Key == st.PublicKey {
line.WriteString("(us)") line.WriteString("(self)")
} }
fmt.Println(line.String()) 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") return errors.New("absent parent must be represented by a nil slice")
} }
for i, sig := range a.Signatures { 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) return fmt.Errorf("signature %d has missing keyID or malformed signature", i)
} }
} }
@ -196,8 +196,13 @@ func (a *AUM) StaticValidate() error {
case AUMNoOp: case AUMNoOp:
default: default:
// TODO(tom): Ignore unknown AUMs for GA. // An AUM with an unknown message kind was received! That means
return fmt.Errorf("unknown AUM kind: %v", a.MessageKind) // 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 return nil

View File

@ -29,9 +29,6 @@ type State struct {
// DisablementSecrets are KDF-derived values which can be used // DisablementSecrets are KDF-derived values which can be used
// to turn off the TKA in the event of a consensus-breaking bug. // 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"` DisablementSecrets [][]byte `cbor:"2,keyasint"`
// Keys are the public keys currently trusted by the TKA. // 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 return out, nil
default: default:
// TODO(tom): Instead of erroring, update lastHash and // An AUM with an unknown message kind was received! That means
// continue (to preserve future compatibility). // that a future version of tailscaled added some feature we don't
return State{}, fmt.Errorf("unhandled message: %v", update.MessageKind) // 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
} }
} }