|
|
@ -40,9 +40,17 @@ var netlockCmd = &ffcli.Command{
|
|
|
|
nlDisablementKDFCmd,
|
|
|
|
nlDisablementKDFCmd,
|
|
|
|
nlLogCmd,
|
|
|
|
nlLogCmd,
|
|
|
|
nlLocalDisableCmd,
|
|
|
|
nlLocalDisableCmd,
|
|
|
|
nlTskeyWrapCmd,
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Exec: runNetworkLockStatus,
|
|
|
|
Exec: runNetworkLockNoSubcommand,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func runNetworkLockNoSubcommand(ctx context.Context, args []string) error {
|
|
|
|
|
|
|
|
// Detect & handle the deprecated command 'lock tskey-wrap'.
|
|
|
|
|
|
|
|
if len(args) >= 2 && args[0] == "tskey-wrap" {
|
|
|
|
|
|
|
|
return runTskeyWrapCmd(ctx, args[1:])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return runNetworkLockStatus(ctx, args)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var nlInitArgs struct {
|
|
|
|
var nlInitArgs struct {
|
|
|
@ -427,13 +435,19 @@ func runNetworkLockModify(ctx context.Context, addArgs, removeArgs []string) err
|
|
|
|
|
|
|
|
|
|
|
|
var nlSignCmd = &ffcli.Command{
|
|
|
|
var nlSignCmd = &ffcli.Command{
|
|
|
|
Name: "sign",
|
|
|
|
Name: "sign",
|
|
|
|
ShortUsage: "sign <node-key> [<rotation-key>]",
|
|
|
|
ShortUsage: "sign <node-key> [<rotation-key>] or sign <auth-key>",
|
|
|
|
ShortHelp: "Signs a node key and transmits the signature to the coordination server",
|
|
|
|
ShortHelp: "Signs a node or pre-approved auth key",
|
|
|
|
LongHelp: "Signs a node key and transmits the signature to the coordination server",
|
|
|
|
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`,
|
|
|
|
Exec: runNetworkLockSign,
|
|
|
|
Exec: runNetworkLockSign,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func runNetworkLockSign(ctx context.Context, args []string) error {
|
|
|
|
func runNetworkLockSign(ctx context.Context, args []string) error {
|
|
|
|
|
|
|
|
if len(args) > 0 && strings.HasPrefix(args[0], "tskey-auth-") {
|
|
|
|
|
|
|
|
return runTskeyWrapCmd(ctx, args)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
var (
|
|
|
|
nodeKey key.NodePublic
|
|
|
|
nodeKey key.NodePublic
|
|
|
|
rotationKey key.NLPublic
|
|
|
|
rotationKey key.NLPublic
|
|
|
@ -636,14 +650,6 @@ func runNetworkLockLog(ctx context.Context, args []string) error {
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var nlTskeyWrapCmd = &ffcli.Command{
|
|
|
|
|
|
|
|
Name: "tskey-wrap",
|
|
|
|
|
|
|
|
ShortUsage: "tskey-wrap <tailscale pre-auth key>",
|
|
|
|
|
|
|
|
ShortHelp: "Modifies a pre-auth key from the admin panel to work with tailnet lock",
|
|
|
|
|
|
|
|
LongHelp: "Modifies a pre-auth key from the admin panel to work with tailnet lock",
|
|
|
|
|
|
|
|
Exec: runTskeyWrapCmd,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func runTskeyWrapCmd(ctx context.Context, args []string) error {
|
|
|
|
func runTskeyWrapCmd(ctx context.Context, args []string) error {
|
|
|
|
if len(args) != 1 {
|
|
|
|
if len(args) != 1 {
|
|
|
|
return errors.New("usage: lock tskey-wrap <tailscale pre-auth key>")
|
|
|
|
return errors.New("usage: lock tskey-wrap <tailscale pre-auth key>")
|
|
|
@ -657,21 +663,25 @@ func runTskeyWrapCmd(ctx context.Context, args []string) error {
|
|
|
|
return fixTailscaledConnectError(err)
|
|
|
|
return fixTailscaledConnectError(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return wrapAuthKey(ctx, args[0], st)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func wrapAuthKey(ctx context.Context, keyStr string, status *ipnstate.Status) error {
|
|
|
|
// Generate a separate tailnet-lock key just for the credential signature.
|
|
|
|
// Generate a separate tailnet-lock key just for the credential signature.
|
|
|
|
// We use the free-form meta strings to mark a little bit of metadata about this
|
|
|
|
// We use the free-form meta strings to mark a little bit of metadata about this
|
|
|
|
// key.
|
|
|
|
// key.
|
|
|
|
priv := key.NewNLPrivate()
|
|
|
|
priv := key.NewNLPrivate()
|
|
|
|
m := map[string]string{
|
|
|
|
m := map[string]string{
|
|
|
|
"purpose": "pre-auth key",
|
|
|
|
"purpose": "pre-auth key",
|
|
|
|
"wrapper_stableid": string(st.Self.ID),
|
|
|
|
"wrapper_stableid": string(status.Self.ID),
|
|
|
|
"wrapper_createtime": fmt.Sprint(time.Now().Unix()),
|
|
|
|
"wrapper_createtime": fmt.Sprint(time.Now().Unix()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(args[0], "tskey-auth-") && strings.Index(args[0][len("tskey-auth-"):], "-") > 0 {
|
|
|
|
if strings.HasPrefix(keyStr, "tskey-auth-") && strings.Index(keyStr[len("tskey-auth-"):], "-") > 0 {
|
|
|
|
// We don't want to accidentally embed the nonce part of the authkey in
|
|
|
|
// We don't want to accidentally embed the nonce part of the authkey in
|
|
|
|
// the event the format changes. As such, we make sure its in the format we
|
|
|
|
// the event the format changes. As such, we make sure its in the format we
|
|
|
|
// expect (tskey-auth-<stableID, inc CNTRL suffix>-nonce) before we parse
|
|
|
|
// expect (tskey-auth-<stableID, inc CNTRL suffix>-nonce) before we parse
|
|
|
|
// out and embed the stableID.
|
|
|
|
// out and embed the stableID.
|
|
|
|
s := strings.TrimPrefix(args[0], "tskey-auth-")
|
|
|
|
s := strings.TrimPrefix(keyStr, "tskey-auth-")
|
|
|
|
m["authkey_stableid"] = s[:strings.Index(s, "-")]
|
|
|
|
m["authkey_stableid"] = s[:strings.Index(s, "-")]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
k := tka.Key{
|
|
|
|
k := tka.Key{
|
|
|
@ -681,7 +691,7 @@ func runTskeyWrapCmd(ctx context.Context, args []string) error {
|
|
|
|
Meta: m,
|
|
|
|
Meta: m,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
wrapped, err := localClient.NetworkLockWrapPreauthKey(ctx, args[0], priv)
|
|
|
|
wrapped, err := localClient.NetworkLockWrapPreauthKey(ctx, keyStr, priv)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("wrapping failed: %w", err)
|
|
|
|
return fmt.Errorf("wrapping failed: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|