mirror of
https://github.com/juanfont/headscale.git
synced 2026-11-04 04:34:07 +09:00
state: auto-approve routes after an admin tag change
The new tags may approve announced routes. Approval runs once the policy manager knows the new owner, as after a registration.
This commit is contained in:
1 parent
7343a7d0fc
commit
7e995b1ff9
3 files changed
+38
-8
No files matched your search
@@ -39,10 +39,6 @@ import (
|
||||
var reauthSkipReasons = map[string]string{
|
||||
"owner-routes/r-expired-retag/expire/online": expiredPeerOffline,
|
||||
|
||||
"owner-routes/r-admin/owner/enabled": adminRetagNoApproval,
|
||||
"owner-routes/r-admin/owner/served": adminRetagNoApproval,
|
||||
"owner-routes/r-admin/owner/self-routes": adminRetagNoApproval,
|
||||
|
||||
"identity/w-tagreq-relogin-tags/w-tagreq/owner": keyLoginTagsRefused,
|
||||
"identity/w-tagreq-relogin-tags/w-tagreq/outcome": keyLoginTagsRefused,
|
||||
"identity/w-tagreq-relogin-tags/w-tagreq/node-key": keyLoginTagsRefused,
|
||||
@@ -81,10 +77,6 @@ var reauthSkipReasons = map[string]string{
|
||||
"ephemeral-lifecycle/late-expired/late-exp/legacy-text": refusalText,
|
||||
}
|
||||
|
||||
const (
|
||||
adminRetagNoApproval = "ADMIN_RETAG_NO_APPROVAL: an admin tag change does not auto-approve the routes the new tags may approve; SaaS approves them at once"
|
||||
)
|
||||
|
||||
const (
|
||||
keyLoginTagsRefused = "KEY_LOGIN_TAGS_REFUSED: headscale refuses a user's key login that requests tags the user owns; SaaS tags the device, converting it in place or creating it tagged"
|
||||
taggedKeyOwnedTagRefused = "TAGGED_KEY_OWNED_TAG_REFUSED: headscale refuses a tagged key's login that requests a tag the key's tags own; SaaS gives the device the requested tags"
|
||||
|
||||
@@ -349,3 +349,27 @@ func TestRegistrationDropsWithdrawnAutoApprovals(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []netip.Prefix{kept}, approvedRoutes(t, s, node.ID()))
|
||||
}
|
||||
|
||||
// TestAdminTagChangeApprovesRoutes: an admin tag change runs route
|
||||
// auto-approval for the routes the new tags may approve.
|
||||
func TestAdminTagChangeApprovesRoutes(t *testing.T) {
|
||||
_, s, id := persistTestSetup(t)
|
||||
t.Cleanup(func() { _ = s.Close() })
|
||||
|
||||
_, err := s.SetPolicy([]byte(`{
|
||||
"tagOwners": {"tag:router": ["persist-user@"]},
|
||||
"autoApprovers": {"routes": {"10.0.0.0/16": ["tag:router"]}},
|
||||
"acls": [{"action": "accept", "src": ["*"], "dst": ["*:*"]}]
|
||||
}`))
|
||||
require.NoError(t, err)
|
||||
|
||||
route := netip.MustParsePrefix("10.0.1.0/24")
|
||||
|
||||
announce(t, s, id, route)
|
||||
require.Empty(t, approvedRoutes(t, s, id), "the user may not approve it")
|
||||
|
||||
node, _, err := s.SetNodeTags(id, []string{"tag:router"})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []netip.Prefix{route}, node.ApprovedRoutes().AsSlice())
|
||||
assert.Equal(t, []netip.Prefix{route}, approvedRoutes(t, s, id))
|
||||
}
|
||||
@@ -1150,6 +1150,20 @@ func (s *State) SetNodeTags(nodeID types.NodeID, tags []string) (types.NodeView,
|
||||
// Setting OriginNode ensures the node gets a self-update with the new tags.
|
||||
c.OriginNode = nodeID
|
||||
|
||||
// The new tags may approve announced routes, as on Tailscale SaaS. This
|
||||
// runs after the policy refresh above, which teaches the policy manager
|
||||
// the node's new owner.
|
||||
routesChange, err := s.AutoApproveRoutes(nodeView)
|
||||
c = c.Merge(routesChange)
|
||||
|
||||
if fresh, ok := s.nodeStore.GetNode(nodeID); ok {
|
||||
nodeView = fresh
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nodeView, c, fmt.Errorf("auto approving routes: %w", err)
|
||||
}
|
||||
|
||||
return nodeView, c, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user