mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	inline old acl hujson tests
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
		
							parent
							
								
									f2c1d1b8f9
								
							
						
					
					
						commit
						2d365c8c9c
					
				@ -59,8 +59,8 @@ const (
 | 
			
		||||
 | 
			
		||||
var featureEnableSSH = envknob.RegisterBool("HEADSCALE_EXPERIMENTAL_FEATURE_SSH")
 | 
			
		||||
 | 
			
		||||
// LoadACLPolicy loads the ACL policy from the specify path, and generates the ACL rules.
 | 
			
		||||
func (h *Headscale) LoadACLPolicy(path string) error {
 | 
			
		||||
// LoadACLPolicyFromPath loads the ACL policy from the specify path, and generates the ACL rules.
 | 
			
		||||
func (h *Headscale) LoadACLPolicyFromPath(path string) error {
 | 
			
		||||
	log.Debug().
 | 
			
		||||
		Str("func", "LoadACLPolicy").
 | 
			
		||||
		Str("path", path).
 | 
			
		||||
@ -72,37 +72,42 @@ func (h *Headscale) LoadACLPolicy(path string) error {
 | 
			
		||||
	}
 | 
			
		||||
	defer policyFile.Close()
 | 
			
		||||
 | 
			
		||||
	var policy ACLPolicy
 | 
			
		||||
	policyBytes, err := io.ReadAll(policyFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch filepath.Ext(path) {
 | 
			
		||||
	case ".yml", ".yaml":
 | 
			
		||||
	log.Debug().
 | 
			
		||||
		Str("path", path).
 | 
			
		||||
		Bytes("file", policyBytes).
 | 
			
		||||
			Msg("Loading ACLs from YAML")
 | 
			
		||||
		Msg("Loading ACLs")
 | 
			
		||||
 | 
			
		||||
		err := yaml.Unmarshal(policyBytes, &policy)
 | 
			
		||||
	switch filepath.Ext(path) {
 | 
			
		||||
	case ".yml", ".yaml":
 | 
			
		||||
		return h.LoadACLPolicyFromBytes(policyBytes, "yaml")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return h.LoadACLPolicyFromBytes(policyBytes, "hujson")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Headscale) LoadACLPolicyFromBytes(acl []byte, format string) error {
 | 
			
		||||
	var policy ACLPolicy
 | 
			
		||||
	switch format {
 | 
			
		||||
	case "yaml":
 | 
			
		||||
		err := yaml.Unmarshal(acl, &policy)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Trace().
 | 
			
		||||
			Interface("policy", policy).
 | 
			
		||||
			Msg("Loaded policy from YAML")
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		ast, err := hujson.Parse(policyBytes)
 | 
			
		||||
		ast, err := hujson.Parse(acl)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ast.Standardize()
 | 
			
		||||
		policyBytes = ast.Pack()
 | 
			
		||||
		err = json.Unmarshal(policyBytes, &policy)
 | 
			
		||||
		acl = ast.Pack()
 | 
			
		||||
		err = json.Unmarshal(acl, &policy)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -15,17 +15,26 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestWrongPath(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("asdfg")
 | 
			
		||||
	err := app.LoadACLPolicyFromPath("asdfg")
 | 
			
		||||
	c.Assert(err, check.NotNil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestBrokenHuJson(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/broken.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.NotNil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestInvalidPolicyHuson(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/invalid.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "valid_json": true,
 | 
			
		||||
    "but_a_policy_though": false
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.NotNil)
 | 
			
		||||
	c.Assert(err, check.Equals, errEmptyPolicy)
 | 
			
		||||
}
 | 
			
		||||
@ -49,12 +58,161 @@ func (s *Suite) TestParseInvalidCIDR(c *check.C) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestRuleInvalidGeneration(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_invalid.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    // Declare static groups of users beyond those in the identity service.
 | 
			
		||||
    "groups": {
 | 
			
		||||
        "group:example": [
 | 
			
		||||
            "user1@example.com",
 | 
			
		||||
            "user2@example.com",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    // Declare hostname aliases to use in place of IP addresses or subnets.
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "example-host-1": "100.100.100.100",
 | 
			
		||||
        "example-host-2": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
    // Define who is allowed to use which tags.
 | 
			
		||||
    "tagOwners": {
 | 
			
		||||
        // Everyone in the montreal-admins or global-admins group are
 | 
			
		||||
        // allowed to tag servers as montreal-webserver.
 | 
			
		||||
        "tag:montreal-webserver": [
 | 
			
		||||
            "group:montreal-admins",
 | 
			
		||||
            "group:global-admins",
 | 
			
		||||
        ],
 | 
			
		||||
        // Only a few admins are allowed to create API servers.
 | 
			
		||||
        "tag:api-server": [
 | 
			
		||||
            "group:global-admins",
 | 
			
		||||
            "example-host-1",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    // Access control lists.
 | 
			
		||||
    "acls": [
 | 
			
		||||
        // Engineering users, plus the president, can access port 22 (ssh)
 | 
			
		||||
        // and port 3389 (remote desktop protocol) on all servers, and all
 | 
			
		||||
        // ports on git-server or ci-server.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:engineering",
 | 
			
		||||
                "president@example.com"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:22,3389",
 | 
			
		||||
                "git-server:*",
 | 
			
		||||
                "ci-server:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow engineer users to access any port on a device tagged with
 | 
			
		||||
        // tag:production.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:engineers"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:production:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow servers in the my-subnet host and 192.168.1.0/24 to access hosts
 | 
			
		||||
        // on both networks.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "my-subnet",
 | 
			
		||||
                "192.168.1.0/24"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "my-subnet:*",
 | 
			
		||||
                "192.168.1.0/24:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow every user of your network to access anything on the network.
 | 
			
		||||
        // Comment out this section if you want to define specific ACL
 | 
			
		||||
        // restrictions above.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // All users in Montreal are allowed to access the Montreal web
 | 
			
		||||
        // servers.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:montreal-users"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:montreal-webserver:80,443"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Montreal web servers are allowed to make outgoing connections to
 | 
			
		||||
        // the API servers, but only on https port 443.
 | 
			
		||||
        // In contrast, this doesn't grant API servers the right to initiate
 | 
			
		||||
        // any connections.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "tag:montreal-webserver"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:api-server:443"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
    // Declare tests to check functionality of ACL rules
 | 
			
		||||
    "tests": [
 | 
			
		||||
        {
 | 
			
		||||
            "src": "user1@example.com",
 | 
			
		||||
            "accept": [
 | 
			
		||||
                "example-host-1:22",
 | 
			
		||||
                "example-host-2:80"
 | 
			
		||||
            ],
 | 
			
		||||
            "deny": [
 | 
			
		||||
                "exapmle-host-2:100"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "src": "user2@example.com",
 | 
			
		||||
            "accept": [
 | 
			
		||||
                "100.60.3.4:22"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.NotNil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestBasicRule(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_1.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "subnet-1",
 | 
			
		||||
                "192.168.1.0/24"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:22,3389",
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
 | 
			
		||||
@ -411,7 +569,27 @@ func (s *Suite) TestValidTagInvalidUser(c *check.C) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestPortRange(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_range.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "subnet-1",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:5400-5500",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
 | 
			
		||||
@ -425,7 +603,48 @@ func (s *Suite) TestPortRange(c *check.C) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestProtocolParsing(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_protocols.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "proto": "tcp",
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "proto": "udp",
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:53",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "proto": "icmp",
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
 | 
			
		||||
@ -439,7 +658,27 @@ func (s *Suite) TestProtocolParsing(c *check.C) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestPortWildcard(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_wildcards.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
 | 
			
		||||
@ -455,7 +694,19 @@ func (s *Suite) TestPortWildcard(c *check.C) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestPortWildcardYAML(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_wildcards.yaml")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
---
 | 
			
		||||
hosts:
 | 
			
		||||
  host-1: 100.100.100.100/32
 | 
			
		||||
  subnet-1: 100.100.101.100/24
 | 
			
		||||
acls:
 | 
			
		||||
  - action: accept
 | 
			
		||||
    src:
 | 
			
		||||
      - "*"
 | 
			
		||||
    dst:
 | 
			
		||||
      - host-1:*
 | 
			
		||||
`)
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "yaml")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
 | 
			
		||||
@ -493,9 +744,27 @@ func (s *Suite) TestPortUser(c *check.C) {
 | 
			
		||||
	}
 | 
			
		||||
	app.db.Save(&machine)
 | 
			
		||||
 | 
			
		||||
	err = app.LoadACLPolicy(
 | 
			
		||||
		"./tests/acls/acl_policy_basic_user_as_user.hujson",
 | 
			
		||||
	)
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "testuser",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err = app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	machines, err := app.ListMachines()
 | 
			
		||||
@ -538,7 +807,33 @@ func (s *Suite) TestPortGroup(c *check.C) {
 | 
			
		||||
	}
 | 
			
		||||
	app.db.Save(&machine)
 | 
			
		||||
 | 
			
		||||
	err = app.LoadACLPolicy("./tests/acls/acl_policy_basic_groups.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "groups": {
 | 
			
		||||
        "group:example": [
 | 
			
		||||
            "testuser",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:example",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
	err = app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	machines, err := app.ListMachines()
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ import (
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
	grpcMiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
 | 
			
		||||
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
 | 
			
		||||
	"github.com/juanfont/headscale"
 | 
			
		||||
	v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
 | 
			
		||||
	"github.com/patrickmn/go-cache"
 | 
			
		||||
	zerolog "github.com/philip-bui/grpc-zerolog"
 | 
			
		||||
@ -507,8 +508,10 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router {
 | 
			
		||||
	router.HandleFunc("/windows", h.WindowsConfigMessage).Methods(http.MethodGet)
 | 
			
		||||
	router.HandleFunc("/windows/tailscale.reg", h.WindowsRegConfig).
 | 
			
		||||
		Methods(http.MethodGet)
 | 
			
		||||
	router.HandleFunc("/swagger", SwaggerUI).Methods(http.MethodGet)
 | 
			
		||||
	router.HandleFunc("/swagger/v1/openapiv2.json", SwaggerAPIv1).
 | 
			
		||||
 | 
			
		||||
	// TODO(kristoffer): move swagger into a package
 | 
			
		||||
	router.HandleFunc("/swagger", headscale.SwaggerUI).Methods(http.MethodGet)
 | 
			
		||||
	router.HandleFunc("/swagger/v1/openapiv2.json", headscale.SwaggerAPIv1).
 | 
			
		||||
		Methods(http.MethodGet)
 | 
			
		||||
 | 
			
		||||
	if h.cfg.DERP.ServerEnabled {
 | 
			
		||||
@ -758,7 +761,7 @@ func (h *Headscale) Serve() error {
 | 
			
		||||
 | 
			
		||||
				if h.cfg.ACL.PolicyPath != "" {
 | 
			
		||||
					aclPath := AbsolutePathFromConfigPath(h.cfg.ACL.PolicyPath)
 | 
			
		||||
					err := h.LoadACLPolicy(aclPath)
 | 
			
		||||
					err := h.LoadACLPolicyFromPath(aclPath)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						log.Error().Err(err).Msg("Failed to reload ACL policy")
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
@ -1212,7 +1212,31 @@ func TestHeadscale_generateGivenName(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Suite) TestAutoApproveRoutes(c *check.C) {
 | 
			
		||||
	err := app.LoadACLPolicy("./tests/acls/acl_policy_autoapprovers.hujson")
 | 
			
		||||
	acl := []byte(`
 | 
			
		||||
{
 | 
			
		||||
    "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"],
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
	`)
 | 
			
		||||
 | 
			
		||||
	err := app.LoadACLPolicyFromBytes(acl, "hujson")
 | 
			
		||||
	c.Assert(err, check.IsNil)
 | 
			
		||||
 | 
			
		||||
	user, err := app.CreateUser("test")
 | 
			
		||||
 | 
			
		||||
@ -1,127 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    // Declare static groups of users beyond those in the identity service.
 | 
			
		||||
    "groups": {
 | 
			
		||||
        "group:example": [
 | 
			
		||||
            "user1@example.com",
 | 
			
		||||
            "user2@example.com",
 | 
			
		||||
        ],
 | 
			
		||||
        "group:example2": [
 | 
			
		||||
            "user1@example.com",
 | 
			
		||||
            "user2@example.com",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    // Declare hostname aliases to use in place of IP addresses or subnets.
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "example-host-1": "100.100.100.100",
 | 
			
		||||
        "example-host-2": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
    // Define who is allowed to use which tags.
 | 
			
		||||
    "tagOwners": {
 | 
			
		||||
        // Everyone in the montreal-admins or global-admins group are
 | 
			
		||||
        // allowed to tag servers as montreal-webserver.
 | 
			
		||||
        "tag:montreal-webserver": [
 | 
			
		||||
            "group:example",
 | 
			
		||||
        ],
 | 
			
		||||
        // Only a few admins are allowed to create API servers.
 | 
			
		||||
        "tag:production": [
 | 
			
		||||
            "group:example",
 | 
			
		||||
            "president@example.com",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    // Access control lists.
 | 
			
		||||
    "acls": [
 | 
			
		||||
        // Engineering users, plus the president, can access port 22 (ssh)
 | 
			
		||||
        // and port 3389 (remote desktop protocol) on all servers, and all
 | 
			
		||||
        // ports on git-server or ci-server.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:example2",
 | 
			
		||||
                "192.168.1.0/24"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:22,3389",
 | 
			
		||||
                "git-server:*",
 | 
			
		||||
                "ci-server:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow engineer users to access any port on a device tagged with
 | 
			
		||||
        // tag:production.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:example"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:production:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow servers in the my-subnet host and 192.168.1.0/24 to access hosts
 | 
			
		||||
        // on both networks.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "example-host-2", 
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "example-host-1:*",
 | 
			
		||||
                "192.168.1.0/24:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow every user of your network to access anything on the network.
 | 
			
		||||
        // Comment out this section if you want to define specific ACL
 | 
			
		||||
        // restrictions above.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // All users in Montreal are allowed to access the Montreal web
 | 
			
		||||
        // servers.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "example-host-1"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:montreal-webserver:80,443"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Montreal web servers are allowed to make outgoing connections to
 | 
			
		||||
        // the API servers, but only on https port 443.
 | 
			
		||||
        // In contrast, this doesn't grant API servers the right to initiate
 | 
			
		||||
        // any connections.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "tag:montreal-webserver"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:api-server:443"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
    // Declare tests to check functionality of ACL rules
 | 
			
		||||
    "tests": [
 | 
			
		||||
        {
 | 
			
		||||
            "src": "user1@example.com",
 | 
			
		||||
            "accept": [
 | 
			
		||||
                "example-host-1:22",
 | 
			
		||||
                "example-host-2:80"
 | 
			
		||||
            ],
 | 
			
		||||
            "deny": [
 | 
			
		||||
                "exapmle-host-2:100"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "src": "user2@example.com",
 | 
			
		||||
            "accept": [
 | 
			
		||||
                "100.60.3.4:22"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
// 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"],
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
// This ACL is a very basic example to validate the 
 | 
			
		||||
// expansion of hosts
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "subnet-1",
 | 
			
		||||
                "192.168.1.0/24"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:22,3389",
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,26 +0,0 @@
 | 
			
		||||
// This ACL is used to test group expansion
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "groups": {
 | 
			
		||||
        "group:example": [
 | 
			
		||||
            "testuser",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:example",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
// This ACL is used to test wildcards
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "proto": "tcp",
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "proto": "udp",
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:53",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "proto": "icmp",
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
// This ACL is used to test the port range expansion
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "subnet-1",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:5400-5500",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
// This ACL is used to test namespace expansion
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "testuser",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
// This ACL is used to test wildcards
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "host-1": "100.100.100.100",
 | 
			
		||||
        "subnet-1": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "acls": [
 | 
			
		||||
        {
 | 
			
		||||
            "Action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*",
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "host-1:*",
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
hosts:
 | 
			
		||||
  host-1: 100.100.100.100/32
 | 
			
		||||
  subnet-1: 100.100.101.100/24
 | 
			
		||||
acls:
 | 
			
		||||
  - action: accept
 | 
			
		||||
    src:
 | 
			
		||||
      - "*"
 | 
			
		||||
    dst:
 | 
			
		||||
      - host-1:*
 | 
			
		||||
@ -1,125 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    // Declare static groups of users beyond those in the identity service.
 | 
			
		||||
    "groups": {
 | 
			
		||||
        "group:example": [
 | 
			
		||||
            "user1@example.com",
 | 
			
		||||
            "user2@example.com",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    // Declare hostname aliases to use in place of IP addresses or subnets.
 | 
			
		||||
    "hosts": {
 | 
			
		||||
        "example-host-1": "100.100.100.100",
 | 
			
		||||
        "example-host-2": "100.100.101.100/24",
 | 
			
		||||
    },
 | 
			
		||||
    // Define who is allowed to use which tags.
 | 
			
		||||
    "tagOwners": {
 | 
			
		||||
        // Everyone in the montreal-admins or global-admins group are
 | 
			
		||||
        // allowed to tag servers as montreal-webserver.
 | 
			
		||||
        "tag:montreal-webserver": [
 | 
			
		||||
            "group:montreal-admins",
 | 
			
		||||
            "group:global-admins",
 | 
			
		||||
        ],
 | 
			
		||||
        // Only a few admins are allowed to create API servers.
 | 
			
		||||
        "tag:api-server": [
 | 
			
		||||
            "group:global-admins",
 | 
			
		||||
            "example-host-1",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    // Access control lists.
 | 
			
		||||
    "acls": [
 | 
			
		||||
        // Engineering users, plus the president, can access port 22 (ssh)
 | 
			
		||||
        // and port 3389 (remote desktop protocol) on all servers, and all
 | 
			
		||||
        // ports on git-server or ci-server.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:engineering",
 | 
			
		||||
                "president@example.com"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:22,3389",
 | 
			
		||||
                "git-server:*",
 | 
			
		||||
                "ci-server:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow engineer users to access any port on a device tagged with
 | 
			
		||||
        // tag:production.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:engineers"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:production:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow servers in the my-subnet host and 192.168.1.0/24 to access hosts
 | 
			
		||||
        // on both networks.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "my-subnet",
 | 
			
		||||
                "192.168.1.0/24"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "my-subnet:*",
 | 
			
		||||
                "192.168.1.0/24:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Allow every user of your network to access anything on the network.
 | 
			
		||||
        // Comment out this section if you want to define specific ACL
 | 
			
		||||
        // restrictions above.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "*"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "*:*"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // All users in Montreal are allowed to access the Montreal web
 | 
			
		||||
        // servers.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "group:montreal-users"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:montreal-webserver:80,443"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        // Montreal web servers are allowed to make outgoing connections to
 | 
			
		||||
        // the API servers, but only on https port 443.
 | 
			
		||||
        // In contrast, this doesn't grant API servers the right to initiate
 | 
			
		||||
        // any connections.
 | 
			
		||||
        {
 | 
			
		||||
            "action": "accept",
 | 
			
		||||
            "src": [
 | 
			
		||||
                "tag:montreal-webserver"
 | 
			
		||||
            ],
 | 
			
		||||
            "dst": [
 | 
			
		||||
                "tag:api-server:443"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
    // Declare tests to check functionality of ACL rules
 | 
			
		||||
    "tests": [
 | 
			
		||||
        {
 | 
			
		||||
            "src": "user1@example.com",
 | 
			
		||||
            "accept": [
 | 
			
		||||
                "example-host-1:22",
 | 
			
		||||
                "example-host-2:80"
 | 
			
		||||
            ],
 | 
			
		||||
            "deny": [
 | 
			
		||||
                "exapmle-host-2:100"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "src": "user2@example.com",
 | 
			
		||||
            "accept": [
 | 
			
		||||
                "100.60.3.4:22"
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
@ -1,4 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "valid_json": true,
 | 
			
		||||
    "but_a_policy_though": false
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user