chore(fmt): apply make fmt command

This commit is contained in:
Adrien Raffin-Caboisse 2022-02-14 15:54:51 +01:00
parent 9cedbbafd4
commit d8c4c3163b
No known key found for this signature in database
GPG key ID: 7FB60532DEBEAD6A
8 changed files with 399 additions and 130 deletions

View file

@ -3,8 +3,8 @@
**TBD (TBD):** **TBD (TBD):**
**BREAKING**: **BREAKING**:
- ACLs have been rewritten and the behavior is different from before. It's now more aligned to tailscale's view of the feature. Namespaces are viewed as users and can communicate with each others. Tags should now work correctly and adding a host to Headscale should now reload the rules. The documentation have a [fictional example](docs/acls.md) that should cover some use cases of the ACLs features.
- ACLs have been rewritten and the behavior is different from before. It's now more aligned to tailscale's view of the feature. Namespaces are viewed as users and can communicate with each others. Tags should now work correctly and adding a host to Headscale should now reload the rules. The documentation have a [fictional example](docs/acls.md) that should cover some use cases of the ACLs features.
**0.13.0 (2022-xx-xx):** **0.13.0 (2022-xx-xx):**

35
acls.go
View file

@ -129,7 +129,11 @@ func (h *Headscale) generateACLRules() ([]tailcfg.FilterRule, error) {
return rules, nil return rules, nil
} }
func (h *Headscale) generateACLPolicySrcIP(machines []Machine, aclPolicy ACLPolicy, u string) ([]string, error) { func (h *Headscale) generateACLPolicySrcIP(
machines []Machine,
aclPolicy ACLPolicy,
u string,
) ([]string, error) {
return expandAlias(machines, aclPolicy, u) return expandAlias(machines, aclPolicy, u)
} }
@ -184,7 +188,11 @@ func (h *Headscale) generateACLPolicyDestPorts(
// - a group // - a group
// - a tag // - a tag
// and transform these in IPAddresses. // and transform these in IPAddresses.
func expandAlias(machines []Machine, aclPolicy ACLPolicy, alias string) ([]string, error) { func expandAlias(
machines []Machine,
aclPolicy ACLPolicy,
alias string,
) ([]string, error) {
ips := []string{} ips := []string{}
if alias == "*" { if alias == "*" {
return []string{"*"}, nil return []string{"*"}, nil
@ -267,7 +275,11 @@ func expandAlias(machines []Machine, aclPolicy ACLPolicy, alias string) ([]strin
// excludeCorrectlyTaggedNodes will remove from the list of input nodes the ones // excludeCorrectlyTaggedNodes will remove from the list of input nodes the ones
// that are correctly tagged since they should not be listed as being in the namespace // that are correctly tagged since they should not be listed as being in the namespace
// we assume in this function that we only have nodes from 1 namespace. // we assume in this function that we only have nodes from 1 namespace.
func excludeCorrectlyTaggedNodes(aclPolicy ACLPolicy, nodes []Machine, namespace string) ([]Machine, error) { func excludeCorrectlyTaggedNodes(
aclPolicy ACLPolicy,
nodes []Machine,
namespace string,
) ([]Machine, error) {
out := []Machine{} out := []Machine{}
tags := []string{} tags := []string{}
for tag, ns := range aclPolicy.TagOwners { for tag, ns := range aclPolicy.TagOwners {
@ -362,7 +374,11 @@ func expandTagOwners(aclPolicy ACLPolicy, tag string) ([]string, error) {
var owners []string var owners []string
ows, ok := aclPolicy.TagOwners[tag] ows, ok := aclPolicy.TagOwners[tag]
if !ok { if !ok {
return []string{}, fmt.Errorf("%w. %v isn't owned by a TagOwner. Please add one first. https://tailscale.com/kb/1018/acls/#tag-owners", errInvalidTag, tag) return []string{}, fmt.Errorf(
"%w. %v isn't owned by a TagOwner. Please add one first. https://tailscale.com/kb/1018/acls/#tag-owners",
errInvalidTag,
tag,
)
} }
for _, owner := range ows { for _, owner := range ows {
if strings.HasPrefix(owner, "group:") { if strings.HasPrefix(owner, "group:") {
@ -384,11 +400,18 @@ func expandTagOwners(aclPolicy ACLPolicy, tag string) ([]string, error) {
func expandGroup(aclPolicy ACLPolicy, group string) ([]string, error) { func expandGroup(aclPolicy ACLPolicy, group string) ([]string, error) {
groups, ok := aclPolicy.Groups[group] groups, ok := aclPolicy.Groups[group]
if !ok { if !ok {
return []string{}, fmt.Errorf("group %v isn't registered. %w", group, errInvalidGroup) return []string{}, fmt.Errorf(
"group %v isn't registered. %w",
group,
errInvalidGroup,
)
} }
for _, g := range groups { for _, g := range groups {
if strings.HasPrefix(g, "group:") { if strings.HasPrefix(g, "group:") {
return []string{}, fmt.Errorf("%w. A group cannot be composed of groups. https://tailscale.com/kb/1018/acls/#groups", errInvalidGroup) return []string{}, fmt.Errorf(
"%w. A group cannot be composed of groups. https://tailscale.com/kb/1018/acls/#groups",
errInvalidGroup,
)
} }
} }

View file

@ -72,7 +72,10 @@ func (s *Suite) TestInvalidAction(c *check.C) {
func (s *Suite) TestInvalidGroupInGroup(c *check.C) { func (s *Suite) TestInvalidGroupInGroup(c *check.C) {
// this ACL is wrong because the group in users sections doesn't exist // this ACL is wrong because the group in users sections doesn't exist
app.aclPolicy = &ACLPolicy{ app.aclPolicy = &ACLPolicy{
Groups: Groups{"group:test": []string{"foo"}, "group:error": []string{"foo", "group:test"}}, Groups: Groups{
"group:test": []string{"foo"},
"group:error": []string{"foo", "group:test"},
},
ACLs: []ACL{ ACLs: []ACL{
{Action: "accept", Users: []string{"group:error"}, Ports: []string{"*:*"}}, {Action: "accept", Users: []string{"group:error"}, Ports: []string{"*:*"}},
}, },
@ -104,7 +107,9 @@ func (s *Suite) TestValidExpandTagOwnersInUsers(c *check.C) {
_, err = app.GetMachine("foo", "testmachine") _, err = app.GetMachine("foo", "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
hostInfo := []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}") hostInfo := []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
)
machine := Machine{ machine := Machine{
ID: 0, ID: 0,
MachineKey: "foo", MachineKey: "foo",
@ -146,7 +151,9 @@ func (s *Suite) TestValidExpandTagOwnersInPorts(c *check.C) {
_, err = app.GetMachine("foo", "testmachine") _, err = app.GetMachine("foo", "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
hostInfo := []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}") hostInfo := []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
)
machine := Machine{ machine := Machine{
ID: 1, ID: 1,
MachineKey: "foo", MachineKey: "foo",
@ -188,7 +195,9 @@ func (s *Suite) TestInvalidTagValidNamespace(c *check.C) {
_, err = app.GetMachine("foo", "testmachine") _, err = app.GetMachine("foo", "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
hostInfo := []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:foo\"]}") hostInfo := []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:foo\"]}",
)
machine := Machine{ machine := Machine{
ID: 1, ID: 1,
MachineKey: "foo", MachineKey: "foo",
@ -229,7 +238,9 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
_, err = app.GetMachine("foo", "webserver") _, err = app.GetMachine("foo", "webserver")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
hostInfo := []byte("{\"OS\":\"centos\",\"Hostname\":\"webserver\",\"RequestTags\":[\"tag:webapp\"]}") hostInfo := []byte(
"{\"OS\":\"centos\",\"Hostname\":\"webserver\",\"RequestTags\":[\"tag:webapp\"]}",
)
machine := Machine{ machine := Machine{
ID: 1, ID: 1,
MachineKey: "foo", MachineKey: "foo",
@ -265,7 +276,11 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
app.aclPolicy = &ACLPolicy{ app.aclPolicy = &ACLPolicy{
TagOwners: TagOwners{"tag:webapp": []string{"foo"}}, TagOwners: TagOwners{"tag:webapp": []string{"foo"}},
ACLs: []ACL{ ACLs: []ACL{
{Action: "accept", Users: []string{"foo"}, Ports: []string{"tag:webapp:80,443"}}, {
Action: "accept",
Users: []string{"foo"},
Ports: []string{"tag:webapp:80,443"},
},
}, },
} }
err = app.UpdateACLRules() err = app.UpdateACLRules()
@ -411,7 +426,10 @@ func Test_expandGroup(t *testing.T) {
name: "simple test", name: "simple test",
args: args{ args: args{
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Groups: Groups{"group:test": []string{"g1", "foo", "test"}, "group:foo": []string{"foo", "test"}}, Groups: Groups{
"group:test": []string{"g1", "foo", "test"},
"group:foo": []string{"foo", "test"},
},
}, },
group: "group:test", group: "group:test",
}, },
@ -422,7 +440,10 @@ func Test_expandGroup(t *testing.T) {
name: "InexistantGroup", name: "InexistantGroup",
args: args{ args: args{
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Groups: Groups{"group:test": []string{"g1", "foo", "test"}, "group:foo": []string{"foo", "test"}}, Groups: Groups{
"group:test": []string{"g1", "foo", "test"},
"group:foo": []string{"foo", "test"},
},
}, },
group: "group:bar", group: "group:bar",
}, },
@ -666,7 +687,10 @@ func Test_listMachinesInNamespace(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if got := listMachinesInNamespace(tt.args.machines, tt.args.namespace); !reflect.DeepEqual(got, tt.want) { if got := listMachinesInNamespace(tt.args.machines, tt.args.namespace); !reflect.DeepEqual(
got,
tt.want,
) {
t.Errorf("listMachinesInNamespace() = %v, want %v", got, tt.want) t.Errorf("listMachinesInNamespace() = %v, want %v", got, tt.want)
} }
}) })
@ -691,7 +715,11 @@ func Test_expandAlias(t *testing.T) {
alias: "*", alias: "*",
machines: []Machine{ machines: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}}, {IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}},
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.78.84.227")}}, {
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.78.84.227"),
},
},
}, },
aclPolicy: ACLPolicy{}, aclPolicy: ACLPolicy{},
}, },
@ -703,10 +731,30 @@ func Test_expandAlias(t *testing.T) {
args: args{ args: args{
alias: "group:foo", alias: "group:foo",
machines: []Machine{ machines: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, netaddr.MustParseIP("100.64.0.1"),
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "test"}}, },
Namespace: Namespace{Name: "foo"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.3"),
},
Namespace: Namespace{Name: "bar"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "test"},
},
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Groups: Groups{"group:foo": []string{"foo", "bar"}}, Groups: Groups{"group:foo": []string{"foo", "bar"}},
@ -720,10 +768,30 @@ func Test_expandAlias(t *testing.T) {
args: args{ args: args{
alias: "group:test", alias: "group:test",
machines: []Machine{ machines: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, netaddr.MustParseIP("100.64.0.1"),
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "test"}}, },
Namespace: Namespace{Name: "foo"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.3"),
},
Namespace: Namespace{Name: "bar"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "test"},
},
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Groups: Groups{"group:foo": []string{"foo", "bar"}}, Groups: Groups{"group:foo": []string{"foo", "bar"}},
@ -748,7 +816,9 @@ func Test_expandAlias(t *testing.T) {
alias: "homeNetwork", alias: "homeNetwork",
machines: []Machine{}, machines: []Machine{},
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Hosts: Hosts{"homeNetwork": netaddr.MustParseIPPrefix("192.168.1.0/24")}, Hosts: Hosts{
"homeNetwork": netaddr.MustParseIPPrefix("192.168.1.0/24"),
},
}, },
}, },
want: []string{"192.168.1.0/24"}, want: []string{"192.168.1.0/24"},
@ -779,10 +849,36 @@ func Test_expandAlias(t *testing.T) {
args: args{ args: args{
alias: "tag:test", alias: "tag:test",
machines: []Machine{ machines: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, netaddr.MustParseIP("100.64.0.1"),
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, },
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.3"),
},
Namespace: Namespace{Name: "bar"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "foo"},
},
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
TagOwners: TagOwners{"tag:test": []string{"foo"}}, TagOwners: TagOwners{"tag:test": []string{"foo"}},
@ -796,10 +892,30 @@ func Test_expandAlias(t *testing.T) {
args: args{ args: args{
alias: "tag:foo", alias: "tag:foo",
machines: []Machine{ machines: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, netaddr.MustParseIP("100.64.0.1"),
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "test"}}, },
Namespace: Namespace{Name: "foo"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.3"),
},
Namespace: Namespace{Name: "bar"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "test"},
},
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Groups: Groups{"group:foo": []string{"foo", "bar"}}, Groups: Groups{"group:foo": []string{"foo", "bar"}},
@ -814,10 +930,36 @@ func Test_expandAlias(t *testing.T) {
args: args{ args: args{
alias: "foo", alias: "foo",
machines: []Machine{ machines: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, netaddr.MustParseIP("100.64.0.1"),
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, },
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.3"),
},
Namespace: Namespace{Name: "bar"},
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "foo"},
},
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
TagOwners: TagOwners{"tag:test": []string{"foo"}}, TagOwners: TagOwners{"tag:test": []string{"foo"}},
@ -829,7 +971,11 @@ func Test_expandAlias(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := expandAlias(test.args.machines, test.args.aclPolicy, test.args.alias) got, err := expandAlias(
test.args.machines,
test.args.aclPolicy,
test.args.alias,
)
if (err != nil) != test.wantErr { if (err != nil) != test.wantErr {
t.Errorf("expandAlias() error = %v, wantErr %v", err, test.wantErr) t.Errorf("expandAlias() error = %v, wantErr %v", err, test.wantErr)
@ -861,14 +1007,38 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
TagOwners: TagOwners{"tag:test": []string{"foo"}}, TagOwners: TagOwners{"tag:test": []string{"foo"}},
}, },
nodes: []Machine{ nodes: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, netaddr.MustParseIP("100.64.0.1"),
},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "foo"},
},
}, },
namespace: "foo", namespace: "foo",
}, },
want: []Machine{ want: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, {
IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")},
Namespace: Namespace{Name: "foo"},
},
}, },
wantErr: false, wantErr: false,
}, },
@ -879,25 +1049,69 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
TagOwners: TagOwners{"tag:foo": []string{"foo"}}, TagOwners: TagOwners{"tag:foo": []string{"foo"}},
}, },
nodes: []Machine{ nodes: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, IPAddresses: MachineAddresses{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, netaddr.MustParseIP("100.64.0.1"),
},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.2"),
},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{
netaddr.MustParseIP("100.64.0.4"),
},
Namespace: Namespace{Name: "foo"},
},
}, },
namespace: "foo", namespace: "foo",
}, },
want: []Machine{ want: []Machine{
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, {
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")}, Namespace: Namespace{Name: "foo"}, HostInfo: []byte("{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}")}, IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.1")},
{IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")},
Namespace: Namespace{Name: "foo"},
HostInfo: []byte(
"{\"OS\":\"centos\",\"Hostname\":\"foo\",\"RequestTags\":[\"tag:test\"]}",
),
},
{
IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")},
Namespace: Namespace{Name: "foo"},
},
}, },
wantErr: false, wantErr: false,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got, err := excludeCorrectlyTaggedNodes(test.args.aclPolicy, test.args.nodes, test.args.namespace) got, err := excludeCorrectlyTaggedNodes(
test.args.aclPolicy,
test.args.nodes,
test.args.namespace,
)
if (err != nil) != test.wantErr { if (err != nil) != test.wantErr {
t.Errorf("excludeCorrectlyTaggedNodes() error = %v, wantErr %v", err, test.wantErr) t.Errorf(
"excludeCorrectlyTaggedNodes() error = %v, wantErr %v",
err,
test.wantErr,
)
return return
} }

6
dns.go
View file

@ -165,7 +165,11 @@ func getMapResponseDNSConfig(
dnsConfig.Domains, dnsConfig.Domains,
fmt.Sprintf( fmt.Sprintf(
"%s.%s", "%s.%s",
strings.ReplaceAll(machine.Namespace.Name, "@", "."), // Replace @ with . for valid domain for machine strings.ReplaceAll(
machine.Namespace.Name,
"@",
".",
), // Replace @ with . for valid domain for machine
baseDomain, baseDomain,
), ),
) )

View file

@ -1,4 +1,3 @@
# ACLs use case example # ACLs use case example
Let's build an example use case for a small business (It may be the place where Let's build an example use case for a small business (It may be the place where
@ -46,81 +45,97 @@ Here are the ACL's to implement the same permissions as above:
```json ```json
{ {
// groups are collections of users having a common scope. A user can be in multiple groups // groups are collections of users having a common scope. A user can be in multiple groups
// groups cannot be composed of groups // groups cannot be composed of groups
"groups": { "groups": {
"group:boss": ["boss"], "group:boss": ["boss"],
"group:dev": ["dev1","dev2"], "group:dev": ["dev1", "dev2"],
"group:admin": ["admin1"], "group:admin": ["admin1"],
"group:intern": ["intern1"], "group:intern": ["intern1"]
},
// tagOwners in tailscale is an association between a TAG and the people allowed to set this TAG on a server.
// This is documented [here](https://tailscale.com/kb/1068/acl-tags#defining-a-tag)
// and explained [here](https://tailscale.com/blog/rbac-like-it-was-meant-to-be/)
"tagOwners": {
// the administrators can add servers in production
"tag:prod-databases": ["group:admin"],
"tag:prod-app-servers": ["group:admin"],
// the boss can tag any server as internal
"tag:internal": ["group:boss"],
// dev can add servers for dev purposes as well as admins
"tag:dev-databases": ["group:admin", "group:dev"],
"tag:dev-app-servers": ["group:admin", "group:dev"]
// interns cannot add servers
},
"acls": [
// boss have access to all servers
{
"action": "accept",
"users": ["group:boss"],
"ports": [
"tag:prod-databases:*",
"tag:prod-app-servers:*",
"tag:internal:*",
"tag:dev-databases:*",
"tag:dev-app-servers:*"
]
}, },
// tagOwners in tailscale is an association between a TAG and the people allowed to set this TAG on a server.
// This is documented [here](https://tailscale.com/kb/1068/acl-tags#defining-a-tag)
// and explained [here](https://tailscale.com/blog/rbac-like-it-was-meant-to-be/)
"tagOwners": {
// the administrators can add servers in production
"tag:prod-databases": ["group:admin"],
"tag:prod-app-servers": ["group:admin"],
// the boss can tag any server as internal // admin have only access to administrative ports of the servers
"tag:internal": ["group:boss"], {
"action": "accept",
// dev can add servers for dev purposes as well as admins "users": ["group:admin"],
"tag:dev-databases": ["group:admin","group:dev"], "ports": [
"tag:dev-app-servers": ["group:admin", "group:dev"], "tag:prod-databases:22",
"tag:prod-app-servers:22",
// interns cannot add servers "tag:internal:22",
"tag:dev-databases:22",
"tag:dev-app-servers:22"
]
}, },
"acls": [
// boss have access to all servers
{"action":"accept",
"users":["group:boss"],
"ports":[
"tag:prod-databases:*",
"tag:prod-app-servers:*",
"tag:internal:*",
"tag:dev-databases:*",
"tag:dev-app-servers:*",
]
},
// admin have only access to administrative ports of the servers // developers have access to databases servers and application servers on all ports
{"action":"accept", // they can only view the applications servers in prod and have no access to databases servers in production
"users":["group:admin"], {
"ports":[ "action": "accept",
"tag:prod-databases:22", "users": ["group:dev"],
"tag:prod-app-servers:22", "ports": [
"tag:internal:22", "tag:dev-databases:*",
"tag:dev-databases:22", "tag:dev-app-servers:*",
"tag:dev-app-servers:22", "tag:prod-app-servers:80,443"
] ]
}, },
// developers have access to databases servers and application servers on all ports // servers should be able to talk to database. Database should not be able to initiate connections to
// they can only view the applications servers in prod and have no access to databases servers in production // applications servers
{"action":"accept", "users":["group:dev"], "ports":[ {
"tag:dev-databases:*", "action": "accept",
"tag:dev-app-servers:*", "users": ["tag:dev-app-servers"],
"tag:prod-app-servers:80,443", "ports": ["tag:dev-databases:5432"]
] },
}, {
"action": "accept",
"users": ["tag:prod-app-servers"],
"ports": ["tag:prod-databases:5432"]
},
// servers should be able to talk to database. Database should not be able to initiate connections to // interns have access to dev-app-servers only in reading mode
// applications servers {
{"action":"accept", "users":["tag:dev-app-servers"], "ports":["tag:dev-databases:5432"]}, "action": "accept",
{"action":"accept", "users":["tag:prod-app-servers"], "ports":["tag:prod-databases:5432"]}, "users": ["group:intern"],
"ports": ["tag:dev-app-servers:80,443"]
},
// interns have access to dev-app-servers only in reading mode // We still have to allow internal namespaces communications since nothing guarantees that each user have
{"action":"accept", "users":["group:intern"], "ports":["tag:dev-app-servers:80,443"]}, // their own namespaces.
{ "action": "accept", "users": ["boss"], "ports": ["boss:*"] },
// We still have to allow internal namespaces communications since nothing guarantees that each user have { "action": "accept", "users": ["dev1"], "ports": ["dev1:*"] },
// their own namespaces. { "action": "accept", "users": ["dev2"], "ports": ["dev2:*"] },
{"action":"accept", "users":["boss"], "ports":["boss:*"]}, { "action": "accept", "users": ["admin1"], "ports": ["admin1:*"] },
{"action":"accept", "users":["dev1"], "ports":["dev1:*"]}, { "action": "accept", "users": ["intern1"], "ports": ["intern1:*"] }
{"action":"accept", "users":["dev2"], "ports":["dev2:*"]}, ]
{"action":"accept", "users":["admin1"], "ports":["admin1:*"]},
{"action":"accept", "users":["intern1"], "ports":["intern1:*"]},
]
} }
``` ```

View file

@ -192,7 +192,10 @@ func (h *Headscale) getFilteredByACLPeers(machine *Machine) (Machines, error) {
for _, m := range mMachines { for _, m := range mMachines {
authorizedMachines = append(authorizedMachines, m) authorizedMachines = append(authorizedMachines, m)
} }
sort.Slice(authorizedMachines, func(i, j int) bool { return authorizedMachines[i].ID < authorizedMachines[j].ID }) sort.Slice(
authorizedMachines,
func(i, j int) bool { return authorizedMachines[i].ID < authorizedMachines[j].ID },
)
log.Trace(). log.Trace().
Caller(). Caller().
@ -695,7 +698,11 @@ func (machine Machine) toNode(
hostname = fmt.Sprintf( hostname = fmt.Sprintf(
"%s.%s.%s", "%s.%s.%s",
machine.Name, machine.Name,
strings.ReplaceAll(machine.Namespace.Name, "@", "."), // Replace @ with . for valid domain for machine strings.ReplaceAll(
machine.Namespace.Name,
"@",
".",
), // Replace @ with . for valid domain for machine
baseDomain, baseDomain,
) )
} else { } else {

View file

@ -176,11 +176,13 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
for index := 0; index <= 10; index++ { for index := 0; index <= 10; index++ {
machine := Machine{ machine := Machine{
ID: uint64(index), ID: uint64(index),
MachineKey: "foo" + strconv.Itoa(index), MachineKey: "foo" + strconv.Itoa(index),
NodeKey: "bar" + strconv.Itoa(index), NodeKey: "bar" + strconv.Itoa(index),
DiscoKey: "faa" + strconv.Itoa(index), DiscoKey: "faa" + strconv.Itoa(index),
IPAddresses: MachineAddresses{netaddr.MustParseIP(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1)))}, IPAddresses: MachineAddresses{
netaddr.MustParseIP(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))),
},
Name: "testmachine" + strconv.Itoa(index), Name: "testmachine" + strconv.Itoa(index),
NamespaceID: stor[index%2].namespace.ID, NamespaceID: stor[index%2].namespace.ID,
Registered: true, Registered: true,

View file

@ -97,7 +97,11 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) {
// update ACLRules with peer informations (to update server tags if necessary) // update ACLRules with peer informations (to update server tags if necessary)
err = h.UpdateACLRules() err = h.UpdateACLRules()
if err != nil { if err != nil {
log.Error().Caller().Str("func", "handleAuthKey").Str("machine", machine.Name).Err(err) log.Error().
Caller().
Str("func", "handleAuthKey").
Str("machine", machine.Name).
Err(err)
} }
// From Tailscale client: // From Tailscale client: