Skip to content

Commit

Permalink
Merge pull request #1 from hopleus/features/authorized-node
Browse files Browse the repository at this point in the history
Features/authorized node
  • Loading branch information
hopleus authored Oct 7, 2024
2 parents e7a3726 + 4f0ac6d commit c2dde39
Show file tree
Hide file tree
Showing 36 changed files with 1,451 additions and 740 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

- Improved compatibilty of built-in DERP server with clients connecting over WebSocket.
- Allow nodes to use SSH agent forwarding [#2145](https://github.com/juanfont/headscale/pull/2145)
- Node Approval. Manually approve new nodes before they access the network.

## [FORK] 0.23.0-241005
### Changes
Expand Down
62 changes: 62 additions & 0 deletions cmd/headscale/cli/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ func init() {
}
nodeCmd.AddCommand(registerNodeCmd)

approveNodeCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
err = approveNodeCmd.MarkFlagRequired("identifier")
if err != nil {
log.Fatalf(err.Error())
}
nodeCmd.AddCommand(approveNodeCmd)

expireNodeCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
err = expireNodeCmd.MarkFlagRequired("identifier")
if err != nil {
Expand Down Expand Up @@ -206,6 +213,50 @@ var listNodesCmd = &cobra.Command{
},
}

var approveNodeCmd = &cobra.Command{
Use: "approve",
Short: "Approve a node in your network",
Aliases: []string{"a"},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")

identifier, err := cmd.Flags().GetUint64("identifier")
if err != nil {
ErrorOutput(
err,
fmt.Sprintf("Error converting ID to integer: %s", err),
output,
)

return
}

ctx, client, conn, cancel := newHeadscaleCLIWithConfig()
defer cancel()
defer conn.Close()

request := &v1.ApproveNodeRequest{
NodeId: identifier,
}

response, err := client.ApproveNode(ctx, request)
if err != nil {
ErrorOutput(
err,
fmt.Sprintf(
"Cannot expire node: %s\n",
status.Convert(err).Message(),
),
output,
)

return
}

SuccessOutput(response.GetNode(), "Node approved", output)
},
}

var expireNodeCmd = &cobra.Command{
Use: "expire",
Short: "Expire (log out) a node in your network",
Expand Down Expand Up @@ -529,6 +580,7 @@ func nodesToPtables(
"Ephemeral",
"Last seen",
"Expiration",
"Authorized",
"Connected",
"Expired",
}
Expand Down Expand Up @@ -563,6 +615,15 @@ func nodesToPtables(
expiryTime = "N/A"
}

var authorized time.Time
var authorizedTime string
if node.GetAuthorized() != nil {
authorized = node.GetAuthorized().AsTime()
authorizedTime = authorized.Format("2006-01-02 15:04:05")
} else {
authorizedTime = "N/A"
}

var machineKey key.MachinePublic
err := machineKey.UnmarshalText(
[]byte(node.GetMachineKey()),
Expand Down Expand Up @@ -642,6 +703,7 @@ func nodesToPtables(
strconv.FormatBool(ephemeral),
lastSeenTime,
expiryTime,
authorizedTime,
online,
expired,
}
Expand Down
14 changes: 10 additions & 4 deletions cmd/headscale/cli/preauthkeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func init() {
Bool("ephemeral", false, "Preauthkey for ephemeral nodes")
createPreAuthKeyCmd.Flags().
StringP("expiration", "e", DefaultPreAuthKeyExpiry, "Human-readable expiration of the key (e.g. 30m, 24h)")
createPreAuthKeyCmd.PersistentFlags().
Bool("preauthorized", false, "Nodes authenticated by this key will be automatically approved.")
createPreAuthKeyCmd.Flags().
StringSlice("tags", []string{}, "Tags to automatically assign to node")
}
Expand Down Expand Up @@ -93,6 +95,7 @@ var listPreAuthKeys = &cobra.Command{
"Ephemeral",
"Used",
"Expiration",
"Preauthorized",
"Created",
"Tags",
},
Expand All @@ -118,6 +121,7 @@ var listPreAuthKeys = &cobra.Command{
strconv.FormatBool(key.GetEphemeral()),
strconv.FormatBool(key.GetUsed()),
expiration,
strconv.FormatBool(key.GetPreauthorized()),
key.GetCreatedAt().AsTime().Format("2006-01-02 15:04:05"),
aclTags,
})
Expand Down Expand Up @@ -149,12 +153,14 @@ var createPreAuthKeyCmd = &cobra.Command{
reusable, _ := cmd.Flags().GetBool("reusable")
ephemeral, _ := cmd.Flags().GetBool("ephemeral")
tags, _ := cmd.Flags().GetStringSlice("tags")
preauthorized, _ := cmd.Flags().GetBool("preauthorized")

request := &v1.CreatePreAuthKeyRequest{
User: user,
Reusable: reusable,
Ephemeral: ephemeral,
AclTags: tags,
User: user,
Reusable: reusable,
Ephemeral: ephemeral,
Preauthorized: preauthorized,
AclTags: tags,
}

durationStr, _ := cmd.Flags().GetString("expiration")
Expand Down
9 changes: 9 additions & 0 deletions config-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,12 @@ routes:
platformConfig: false
# Disabling routes for Swagger
swagger: false

## NodeManagement
node_management:
# Require new nodes to be approved by admins before they can access the network.
manual_approve_new_node: false

# The amount of time from a node can stay logged in to HeadScale before it needs to re-authenticate.
# Setting the value to "0" will mean no expiry.
key_expiry: 0
Loading

0 comments on commit c2dde39

Please sign in to comment.