From 4c2e978f1e29b530f8b0a05f007c87eb4b2de8cb Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 14 Aug 2024 08:34:53 -0700 Subject: [PATCH] cmd/tailscale/cli: support passing network lock keys via files Fixes tailscale/corp#22356 Change-Id: I959efae716a22bcf582c20d261fb1b57bacf6dd9 Signed-off-by: Brad Fitzpatrick --- cmd/k8s-operator/depaware.txt | 2 +- cmd/tailscale/cli/network-lock.go | 27 +++++++++++++++++++++++---- cmd/tailscale/depaware.txt | 2 +- cmd/tailscaled/depaware.txt | 2 +- ipn/ipnlocal/network-lock.go | 3 ++- tsconst/interface.go | 4 ++++ 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt index a6f7fba01..1454fe5f6 100644 --- a/cmd/k8s-operator/depaware.txt +++ b/cmd/k8s-operator/depaware.txt @@ -747,7 +747,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ tailscale.com/taildrop from tailscale.com/ipn/ipnlocal+ tailscale.com/tempfork/heap from tailscale.com/wgengine/magicsock tailscale.com/tka from tailscale.com/client/tailscale+ - W tailscale.com/tsconst from tailscale.com/net/netmon+ + tailscale.com/tsconst from tailscale.com/net/netmon+ tailscale.com/tsd from tailscale.com/ipn/ipnlocal+ tailscale.com/tsnet from tailscale.com/cmd/k8s-operator+ tailscale.com/tstime from tailscale.com/cmd/k8s-operator+ diff --git a/cmd/tailscale/cli/network-lock.go b/cmd/tailscale/cli/network-lock.go index 42f46e0e1..7bea1f724 100644 --- a/cmd/tailscale/cli/network-lock.go +++ b/cmd/tailscale/cli/network-lock.go @@ -20,6 +20,7 @@ import ( "github.com/peterbourgon/ff/v3/ffcli" "tailscale.com/ipn/ipnstate" "tailscale.com/tka" + "tailscale.com/tsconst" "tailscale.com/types/key" "tailscale.com/types/tkatype" ) @@ -443,15 +444,33 @@ func runNetworkLockModify(ctx context.Context, addArgs, removeArgs []string) err var nlSignCmd = &ffcli.Command{ Name: "sign", - ShortUsage: "tailscale lock sign [] or sign ", + ShortUsage: "tailscale lock sign []\ntailscale lock sign ", ShortHelp: "Signs a node or pre-approved auth key", LongHelp: `Either: - - signs a node key and transmits the signature to the coordination server, or - - signs a pre-approved auth key, printing it in a form that can be used to bring up nodes under tailnet lock`, + - signs a node key and transmits the signature to the coordination + server, or + - signs a pre-approved auth key, printing it in a form that can be + used to bring up nodes under tailnet lock + +If any of the key arguments begin with "file:", the key is retrieved from +the file at the path specified in the argument suffix.`, Exec: runNetworkLockSign, } func runNetworkLockSign(ctx context.Context, args []string) error { + // If any of the arguments start with "file:", replace that argument + // with the contents of the file. We do this early, before the check + // to see if the first argument is an auth key. + for i, arg := range args { + if filename, ok := strings.CutPrefix(arg, "file:"); ok { + b, err := os.ReadFile(filename) + if err != nil { + return err + } + args[i] = strings.TrimSpace(string(b)) + } + } + if len(args) > 0 && strings.HasPrefix(args[0], "tskey-auth-") { return runTskeyWrapCmd(ctx, args) } @@ -476,7 +495,7 @@ func runNetworkLockSign(ctx context.Context, args []string) error { err := localClient.NetworkLockSign(ctx, nodeKey, []byte(rotationKey.Verifier())) // Provide a better help message for when someone clicks through the signing flow // on the wrong device. - if err != nil && strings.Contains(err.Error(), "this node is not trusted by network lock") { + if err != nil && strings.Contains(err.Error(), tsconst.TailnetLockNotTrustedMsg) { fmt.Fprintln(Stderr, "Error: Signing is not available on this device because it does not have a trusted tailnet lock key.") fmt.Fprintln(Stderr) fmt.Fprintln(Stderr, "Try again on a signing device instead. Tailnet admins can see signing devices on the admin panel.") diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index 4bc7a4526..04292cbfe 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -128,7 +128,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/tailcfg from tailscale.com/client/tailscale+ tailscale.com/tempfork/spf13/cobra from tailscale.com/cmd/tailscale/cli/ffcomplete+ tailscale.com/tka from tailscale.com/client/tailscale+ - W tailscale.com/tsconst from tailscale.com/net/netmon+ + tailscale.com/tsconst from tailscale.com/net/netmon+ tailscale.com/tstime from tailscale.com/control/controlhttp+ tailscale.com/tstime/mono from tailscale.com/tstime/rate tailscale.com/tstime/rate from tailscale.com/cmd/tailscale/cli+ diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 3cc9927d8..68bdd8170 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -338,7 +338,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de LD tailscale.com/tempfork/gliderlabs/ssh from tailscale.com/ssh/tailssh tailscale.com/tempfork/heap from tailscale.com/wgengine/magicsock tailscale.com/tka from tailscale.com/client/tailscale+ - W tailscale.com/tsconst from tailscale.com/net/netmon+ + tailscale.com/tsconst from tailscale.com/net/netmon+ tailscale.com/tsd from tailscale.com/cmd/tailscaled+ tailscale.com/tstime from tailscale.com/control/controlclient+ tailscale.com/tstime/mono from tailscale.com/net/tstun+ diff --git a/ipn/ipnlocal/network-lock.go b/ipn/ipnlocal/network-lock.go index 943e652e0..593c5493c 100644 --- a/ipn/ipnlocal/network-lock.go +++ b/ipn/ipnlocal/network-lock.go @@ -27,6 +27,7 @@ import ( "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/tka" + "tailscale.com/tsconst" "tailscale.com/types/key" "tailscale.com/types/logger" "tailscale.com/types/netmap" @@ -716,7 +717,7 @@ func (b *LocalBackend) NetworkLockSign(nodeKey key.NodePublic, rotationPublic [] return key.NodePublic{}, tka.NodeKeySignature{}, errNetworkLockNotActive } if !b.tka.authority.KeyTrusted(nlPriv.KeyID()) { - return key.NodePublic{}, tka.NodeKeySignature{}, errors.New("this node is not trusted by network lock") + return key.NodePublic{}, tka.NodeKeySignature{}, errors.New(tsconst.TailnetLockNotTrustedMsg) } p, err := nodeKey.MarshalBinary() diff --git a/tsconst/interface.go b/tsconst/interface.go index f64e290a9..d17aa356d 100644 --- a/tsconst/interface.go +++ b/tsconst/interface.go @@ -9,3 +9,7 @@ package tsconst // interfaces on Windows. This is set by the WinTun driver. const WintunInterfaceDesc = "Tailscale Tunnel" const WintunInterfaceDesc0_14 = "Wintun Userspace Tunnel" + +// TailnetLockNotTrustedMsg is the error message used by network lock +// and sniffed (via substring) out of an error sent over the network. +const TailnetLockNotTrustedMsg = "this node is not trusted by network lock"