diff --git a/machine.go b/machine.go index 43ec4720..099f7fac 100644 --- a/machine.go +++ b/machine.go @@ -945,9 +945,9 @@ func (h *Headscale) EnableAutoApprovedRoutes(machine *Machine) error { continue // Skip routes that are already enabled for the node } - approved := false - routeApprovers, err := h.aclPolicy.AutoApprovers.GetRouteApprovers(advertisedRoute) - + routeApprovers, err := h.aclPolicy.AutoApprovers.GetRouteApprovers( + advertisedRoute, + ) if err != nil { log.Err(err). Str("advertisedRoute", advertisedRoute.String()). @@ -957,26 +957,22 @@ func (h *Headscale) EnableAutoApprovedRoutes(machine *Machine) error { } for _, approvedAlias := range routeApprovers { + if approvedAlias == machine.Namespace.Name { + approvedRoutes = append(approvedRoutes, advertisedRoute) + } else { + approvedIps, err := expandAlias(thisMachine, *h.aclPolicy, approvedAlias, h.cfg.OIDC.StripEmaildomain) + if err != nil { + log.Err(err). + Str("alias", approvedAlias). + Msg("Failed to expand alias when processing autoApprovers policy") + return err + } - approvedIps, err := expandAlias(thisMachine, *h.aclPolicy, approvedAlias, h.cfg.OIDC.StripEmaildomain) - - if err != nil { - log.Err(err). - Str("alias", approvedAlias). - Msg("Failed to expand alias when processing autoApprovers policy") - return err + // approvedIPs should contain all of machine's IPs if it matches the rule, so check for first + if contains(approvedIps, machine.IPAddresses[0].String()) { + approvedRoutes = append(approvedRoutes, advertisedRoute) + } } - - // approvedIPs should contain all of machine's IPs if it matches the rule, so check for first - approved = contains(approvedIps, machine.IPAddresses[0].String()) - - if approved { - break - } - } - - if approved { - approvedRoutes = append(approvedRoutes, advertisedRoute) } } diff --git a/machine_test.go b/machine_test.go index 5da0906f..2c0c91d6 100644 --- a/machine_test.go +++ b/machine_test.go @@ -1051,3 +1051,44 @@ func TestHeadscale_GenerateGivenName(t *testing.T) { }) } } + +func (s *Suite) TestAutoApproveRoutes(c *check.C) { + err := app.LoadACLPolicy("./tests/acls/acl_policy_autoapprovers.hujson") + c.Assert(err, check.IsNil) + + namespace, err := app.CreateNamespace("test") + c.Assert(err, check.IsNil) + + pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil) + c.Assert(err, check.IsNil) + + nodeKey := key.NewNode() + + defaultRoute := netaddr.MustParseIPPrefix("0.0.0.0/0") + route1 := netaddr.MustParseIPPrefix("10.10.0.0/16") + route2 := netaddr.MustParseIPPrefix("10.11.0.0/16") + + machine := Machine{ + ID: 0, + MachineKey: "foo", + NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()), + DiscoKey: "faa", + Hostname: "test", + NamespaceID: namespace.ID, + RegisterMethod: RegisterMethodAuthKey, + AuthKeyID: uint(pak.ID), + HostInfo: HostInfo{ + RequestTags: []string{"tag:exit"}, + RoutableIPs: []netaddr.IPPrefix{defaultRoute, route1, route2}, + }, + IPAddresses: []netaddr.IP{netaddr.MustParseIP("100.64.0.1")}, + } + + app.db.Save(&machine) + + machine0ByID, err := app.GetMachineByID(0) + c.Assert(err, check.IsNil) + + app.EnableAutoApprovedRoutes(machine0ByID) + c.Assert(machine0ByID.GetEnabledRoutes(), check.HasLen, 3) +} diff --git a/protocol_common_poll.go b/protocol_common_poll.go index d6a8fff2..37e2dbc7 100644 --- a/protocol_common_poll.go +++ b/protocol_common_poll.go @@ -44,10 +44,7 @@ func (h *Headscale) handlePollCommon( } // update routes with peer information - err = h.EnableAutoApprovedRoutes(machine) - if err != nil { - //TODO - } + h.EnableAutoApprovedRoutes(machine) } // From Tailscale client: diff --git a/tests/acls/acl_policy_autoapprovers.hujson b/tests/acls/acl_policy_autoapprovers.hujson new file mode 100644 index 00000000..bf564d88 --- /dev/null +++ b/tests/acls/acl_policy_autoapprovers.hujson @@ -0,0 +1,24 @@ +// This ACL validates autoApprovers support for +// exit nodes and advertised routes + +{ + "tagOwners": { + "tag:exit": ["test"], + }, + + "groups": { + "group:test": ["test"] + }, + + "acls": [ + {"action": "accept", "users": ["*"], "ports": ["*:*"]}, + ], + + "autoApprovers": { + "exitNode": ["tag:exit"], + "routes": { + "10.10.0.0/16": ["group:test"], + "10.11.0.0/16": ["test"], + } + } +} \ No newline at end of file