mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-26 00:06:53 +09:00
policy/v2: keep the live policy when SetPolicy fails to compile
SetPolicy assigned the new policy before compiling it, so a compile that failed partway left the rejected filter live while the stored policy stayed old.
This commit is contained in:
1 parent
3417e4cb77
commit
9ce160ed5b
2 files changed
+61
-1
No files matched your search
@@ -577,9 +577,24 @@ func (pm *PolicyManager) SetPolicy(polB []byte) (bool, error) {
|
|||||||
Int("tests.count", len(pol.Tests)).
|
Int("tests.count", len(pol.Tests)).
|
||||||
Msg("Policy parsed successfully")
|
Msg("Policy parsed successfully")
|
||||||
|
|
||||||
|
prev := pm.pol
|
||||||
pm.pol = pol
|
pm.pol = pol
|
||||||
|
|
||||||
return pm.updateLocked()
|
changed, err := pm.updateLocked()
|
||||||
|
if err != nil {
|
||||||
|
// updateLocked stops partway, so the rejected policy's filter may
|
||||||
|
// already be live; recompile the previous one.
|
||||||
|
pm.pol = prev
|
||||||
|
|
||||||
|
_, rerr := pm.updateLocked()
|
||||||
|
if rerr != nil {
|
||||||
|
log.Error().Err(rerr).Msg("restoring previous policy after rejected SetPolicy")
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter returns the current filter rules for the entire tailnet and the associated matchers.
|
// Filter returns the current filter rules for the entire tailnet and the associated matchers.
|
||||||
|
|||||||
@@ -85,6 +85,44 @@ func TestPolicyManager(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSetPolicyRejectedKeepsLiveFilter pins that a policy SetPolicy rejects
|
||||||
|
// does not take effect. A nodeAttrs target naming no user passes validation
|
||||||
|
// but fails to compile after the filter is already compiled; keeping that
|
||||||
|
// filter would run the rejected policy while the stored one is unchanged.
|
||||||
|
func TestSetPolicyRejectedKeepsLiveFilter(t *testing.T) {
|
||||||
|
// IDs are assigned after construction so the test also builds where
|
||||||
|
// types.User embeds gorm.Model.
|
||||||
|
users := types.Users{{Name: "user1"}, {Name: "user2"}}
|
||||||
|
users[0].ID, users[1].ID = 1, 2
|
||||||
|
nodes := types.Nodes{
|
||||||
|
node("n1", "100.64.0.1", "fd7a:115c:a1e0::1", users[0]),
|
||||||
|
node("n2", "100.64.0.2", "fd7a:115c:a1e0::2", users[1]),
|
||||||
|
}
|
||||||
|
nodes[0].ID, nodes[1].ID = 1, 2
|
||||||
|
|
||||||
|
pm, err := NewPolicyManager([]byte(`{
|
||||||
|
"acls": [{"action": "accept", "src": ["user1@"], "dst": ["user1@:*"]}]
|
||||||
|
}`), users, nodes.ViewSlice())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
before, _ := pm.Filter()
|
||||||
|
beforeRules, err := pm.FilterForNode(nodes[1].View())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = pm.SetPolicy([]byte(`{
|
||||||
|
"acls": [{"action": "accept", "src": ["*"], "dst": ["*:*"]}],
|
||||||
|
"nodeAttrs": [{"target": ["ghost@"], "attr": ["randomize-client-port"]}]
|
||||||
|
}`))
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
after, _ := pm.Filter()
|
||||||
|
require.Equal(t, before, after, "a rejected policy must not replace the live filter")
|
||||||
|
|
||||||
|
afterRules, err := pm.FilterForNode(nodes[1].View())
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, beforeRules, afterRules)
|
||||||
|
}
|
||||||
|
|
||||||
func TestInvalidateAutogroupSelfCache(t *testing.T) {
|
func TestInvalidateAutogroupSelfCache(t *testing.T) {
|
||||||
users := types.Users{
|
users := types.Users{
|
||||||
{ID: 1, Name: "user1", Email: "user1@headscale.net"},
|
{ID: 1, Name: "user1", Email: "user1@headscale.net"},
|
||||||
@@ -2420,6 +2458,13 @@ func TestValidateUserReferences_AllSites(t *testing.T) {
|
|||||||
"tagOwners": {"tag:ssh": ["alice@"]},
|
"tagOwners": {"tag:ssh": ["alice@"]},
|
||||||
"acls": [{"action":"accept","src":["*"],"dst":["*:*"]}],
|
"acls": [{"action":"accept","src":["*"],"dst":["*:*"]}],
|
||||||
"ssh": [{"action":"accept","src":["dup@"],"dst":["tag:ssh"],"users":["root"]}]
|
"ssh": [{"action":"accept","src":["dup@"],"dst":["tag:ssh"],"users":["root"]}]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nodeAttrs.target",
|
||||||
|
pol: `{
|
||||||
|
"acls": [{"action":"accept","src":["*"],"dst":["*:*"]}],
|
||||||
|
"nodeAttrs": [{"target":["dup@"],"attr":["randomize-client-port"]}]
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user