From d8c4c3163b6fe9bba05fa2dd2566910ebf749c31 Mon Sep 17 00:00:00 2001 From: Adrien Raffin-Caboisse Date: Mon, 14 Feb 2022 15:54:51 +0100 Subject: [PATCH] chore(fmt): apply make fmt command --- CHANGELOG.md | 2 +- acls.go | 35 +++++- acls_test.go | 302 +++++++++++++++++++++++++++++++++++++++++------- dns.go | 6 +- docs/acls.md | 155 ++++++++++++++----------- machine.go | 11 +- machine_test.go | 12 +- poll.go | 6 +- 8 files changed, 399 insertions(+), 130 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16427017..62808b84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,8 @@ **TBD (TBD):** **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):** diff --git a/acls.go b/acls.go index 3d6b1945..d5d39889 100644 --- a/acls.go +++ b/acls.go @@ -129,7 +129,11 @@ func (h *Headscale) generateACLRules() ([]tailcfg.FilterRule, error) { 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) } @@ -184,7 +188,11 @@ func (h *Headscale) generateACLPolicyDestPorts( // - a group // - a tag // 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{} if alias == "*" { 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 // 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. -func excludeCorrectlyTaggedNodes(aclPolicy ACLPolicy, nodes []Machine, namespace string) ([]Machine, error) { +func excludeCorrectlyTaggedNodes( + aclPolicy ACLPolicy, + nodes []Machine, + namespace string, +) ([]Machine, error) { out := []Machine{} tags := []string{} for tag, ns := range aclPolicy.TagOwners { @@ -362,7 +374,11 @@ func expandTagOwners(aclPolicy ACLPolicy, tag string) ([]string, error) { var owners []string ows, ok := aclPolicy.TagOwners[tag] 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 { 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) { groups, ok := aclPolicy.Groups[group] 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 { 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, + ) } } diff --git a/acls_test.go b/acls_test.go index 786de0fc..f8407d42 100644 --- a/acls_test.go +++ b/acls_test.go @@ -72,7 +72,10 @@ func (s *Suite) TestInvalidAction(c *check.C) { func (s *Suite) TestInvalidGroupInGroup(c *check.C) { // this ACL is wrong because the group in users sections doesn't exist 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{ {Action: "accept", Users: []string{"group:error"}, Ports: []string{"*:*"}}, }, @@ -104,7 +107,9 @@ func (s *Suite) TestValidExpandTagOwnersInUsers(c *check.C) { _, err = app.GetMachine("foo", "testmachine") 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{ ID: 0, MachineKey: "foo", @@ -146,7 +151,9 @@ func (s *Suite) TestValidExpandTagOwnersInPorts(c *check.C) { _, err = app.GetMachine("foo", "testmachine") 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{ ID: 1, MachineKey: "foo", @@ -188,7 +195,9 @@ func (s *Suite) TestInvalidTagValidNamespace(c *check.C) { _, err = app.GetMachine("foo", "testmachine") 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{ ID: 1, MachineKey: "foo", @@ -229,7 +238,9 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) { _, err = app.GetMachine("foo", "webserver") 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{ ID: 1, MachineKey: "foo", @@ -265,7 +276,11 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) { app.aclPolicy = &ACLPolicy{ TagOwners: TagOwners{"tag:webapp": []string{"foo"}}, 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() @@ -411,7 +426,10 @@ func Test_expandGroup(t *testing.T) { name: "simple test", args: args{ 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", }, @@ -422,7 +440,10 @@ func Test_expandGroup(t *testing.T) { name: "InexistantGroup", args: args{ 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", }, @@ -666,7 +687,10 @@ func Test_listMachinesInNamespace(t *testing.T) { } for _, tt := range tests { 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) } }) @@ -691,7 +715,11 @@ func Test_expandAlias(t *testing.T) { alias: "*", machines: []Machine{ {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{}, }, @@ -703,10 +731,30 @@ func Test_expandAlias(t *testing.T) { args: args{ alias: "group:foo", 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{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, - {IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "test"}}, + { + 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{ + netaddr.MustParseIP("100.64.0.3"), + }, + Namespace: Namespace{Name: "bar"}, + }, + { + IPAddresses: MachineAddresses{ + netaddr.MustParseIP("100.64.0.4"), + }, + Namespace: Namespace{Name: "test"}, + }, }, aclPolicy: ACLPolicy{ Groups: Groups{"group:foo": []string{"foo", "bar"}}, @@ -720,10 +768,30 @@ func Test_expandAlias(t *testing.T) { args: args{ alias: "group:test", 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{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, - {IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "test"}}, + { + 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{ + netaddr.MustParseIP("100.64.0.3"), + }, + Namespace: Namespace{Name: "bar"}, + }, + { + IPAddresses: MachineAddresses{ + netaddr.MustParseIP("100.64.0.4"), + }, + Namespace: Namespace{Name: "test"}, + }, }, aclPolicy: ACLPolicy{ Groups: Groups{"group:foo": []string{"foo", "bar"}}, @@ -748,7 +816,9 @@ func Test_expandAlias(t *testing.T) { alias: "homeNetwork", machines: []Machine{}, 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"}, @@ -779,10 +849,36 @@ func Test_expandAlias(t *testing.T) { args: args{ alias: "tag:test", 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{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, - {IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, + { + 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.3"), + }, + Namespace: Namespace{Name: "bar"}, + }, + { + IPAddresses: MachineAddresses{ + netaddr.MustParseIP("100.64.0.4"), + }, + Namespace: Namespace{Name: "foo"}, + }, }, aclPolicy: ACLPolicy{ TagOwners: TagOwners{"tag:test": []string{"foo"}}, @@ -796,10 +892,30 @@ func Test_expandAlias(t *testing.T) { args: args{ alias: "tag:foo", 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{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, - {IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "test"}}, + { + 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{ + netaddr.MustParseIP("100.64.0.3"), + }, + Namespace: Namespace{Name: "bar"}, + }, + { + IPAddresses: MachineAddresses{ + netaddr.MustParseIP("100.64.0.4"), + }, + Namespace: Namespace{Name: "test"}, + }, }, aclPolicy: ACLPolicy{ Groups: Groups{"group:foo": []string{"foo", "bar"}}, @@ -814,10 +930,36 @@ func Test_expandAlias(t *testing.T) { args: args{ alias: "foo", 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{netaddr.MustParseIP("100.64.0.3")}, Namespace: Namespace{Name: "bar"}}, - {IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, + { + 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.3"), + }, + Namespace: Namespace{Name: "bar"}, + }, + { + IPAddresses: MachineAddresses{ + netaddr.MustParseIP("100.64.0.4"), + }, + Namespace: Namespace{Name: "foo"}, + }, }, aclPolicy: ACLPolicy{ TagOwners: TagOwners{"tag:test": []string{"foo"}}, @@ -829,7 +971,11 @@ func Test_expandAlias(t *testing.T) { } for _, test := range tests { 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 { 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"}}, }, 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{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, + { + 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.4"), + }, + Namespace: Namespace{Name: "foo"}, + }, }, namespace: "foo", }, 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, }, @@ -879,25 +1049,69 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) { TagOwners: TagOwners{"tag:foo": []string{"foo"}}, }, 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{netaddr.MustParseIP("100.64.0.4")}, Namespace: Namespace{Name: "foo"}}, + { + 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.4"), + }, + Namespace: Namespace{Name: "foo"}, + }, }, namespace: "foo", }, 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.4")}, Namespace: Namespace{Name: "foo"}}, + { + 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.4")}, + Namespace: Namespace{Name: "foo"}, + }, }, wantErr: false, }, } for _, test := range tests { 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 { - t.Errorf("excludeCorrectlyTaggedNodes() error = %v, wantErr %v", err, test.wantErr) + t.Errorf( + "excludeCorrectlyTaggedNodes() error = %v, wantErr %v", + err, + test.wantErr, + ) return } diff --git a/dns.go b/dns.go index 085a14e2..be6238f8 100644 --- a/dns.go +++ b/dns.go @@ -165,7 +165,11 @@ func getMapResponseDNSConfig( dnsConfig.Domains, fmt.Sprintf( "%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, ), ) diff --git a/docs/acls.md b/docs/acls.md index 89e8b557..63e7c6b8 100644 --- a/docs/acls.md +++ b/docs/acls.md @@ -1,4 +1,3 @@ - # ACLs use case example 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 { - // groups are collections of users having a common scope. A user can be in multiple groups - // groups cannot be composed of groups - "groups": { - "group:boss": ["boss"], - "group:dev": ["dev1","dev2"], - "group:admin": ["admin1"], - "group:intern": ["intern1"], + // groups are collections of users having a common scope. A user can be in multiple groups + // groups cannot be composed of groups + "groups": { + "group:boss": ["boss"], + "group:dev": ["dev1", "dev2"], + "group:admin": ["admin1"], + "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 - "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 + // admin have only access to administrative ports of the servers + { + "action": "accept", + "users": ["group:admin"], + "ports": [ + "tag:prod-databases:22", + "tag:prod-app-servers:22", + "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 - {"action":"accept", - "users":["group:admin"], - "ports":[ - "tag:prod-databases:22", - "tag:prod-app-servers:22", - "tag:internal:22", - "tag:dev-databases:22", - "tag:dev-app-servers:22", - ] - }, + // developers have access to databases servers and application servers on all ports + // they can only view the applications servers in prod and have no access to databases servers in production + { + "action": "accept", + "users": ["group:dev"], + "ports": [ + "tag:dev-databases:*", + "tag:dev-app-servers:*", + "tag:prod-app-servers:80,443" + ] + }, - // developers have access to databases servers and application servers on all ports - // they can only view the applications servers in prod and have no access to databases servers in production - {"action":"accept", "users":["group:dev"], "ports":[ - "tag:dev-databases:*", - "tag:dev-app-servers:*", - "tag:prod-app-servers:80,443", - ] - }, + // servers should be able to talk to database. Database should not be able to initiate connections to + // applications servers + { + "action": "accept", + "users": ["tag:dev-app-servers"], + "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 - // applications servers - {"action":"accept", "users":["tag:dev-app-servers"], "ports":["tag:dev-databases:5432"]}, - {"action":"accept", "users":["tag:prod-app-servers"], "ports":["tag:prod-databases:5432"]}, + // interns have access to dev-app-servers only in reading mode + { + "action": "accept", + "users": ["group:intern"], + "ports": ["tag:dev-app-servers:80,443"] + }, - // interns have access to dev-app-servers only in reading mode - {"action":"accept", "users":["group:intern"], "ports":["tag:dev-app-servers:80,443"]}, - - // We still have to allow internal namespaces communications since nothing guarantees that each user have - // their own namespaces. - {"action":"accept", "users":["boss"], "ports":["boss:*"]}, - {"action":"accept", "users":["dev1"], "ports":["dev1:*"]}, - {"action":"accept", "users":["dev2"], "ports":["dev2:*"]}, - {"action":"accept", "users":["admin1"], "ports":["admin1:*"]}, - {"action":"accept", "users":["intern1"], "ports":["intern1:*"]}, - ] + // We still have to allow internal namespaces communications since nothing guarantees that each user have + // their own namespaces. + { "action": "accept", "users": ["boss"], "ports": ["boss:*"] }, + { "action": "accept", "users": ["dev1"], "ports": ["dev1:*"] }, + { "action": "accept", "users": ["dev2"], "ports": ["dev2:*"] }, + { "action": "accept", "users": ["admin1"], "ports": ["admin1:*"] }, + { "action": "accept", "users": ["intern1"], "ports": ["intern1:*"] } + ] } ``` - diff --git a/machine.go b/machine.go index cb70bf12..ba677f15 100644 --- a/machine.go +++ b/machine.go @@ -192,7 +192,10 @@ func (h *Headscale) getFilteredByACLPeers(machine *Machine) (Machines, error) { for _, m := range mMachines { 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(). Caller(). @@ -695,7 +698,11 @@ func (machine Machine) toNode( hostname = fmt.Sprintf( "%s.%s.%s", 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, ) } else { diff --git a/machine_test.go b/machine_test.go index df00067b..f9e58be9 100644 --- a/machine_test.go +++ b/machine_test.go @@ -176,11 +176,13 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) { for index := 0; index <= 10; index++ { machine := Machine{ - ID: uint64(index), - MachineKey: "foo" + strconv.Itoa(index), - NodeKey: "bar" + strconv.Itoa(index), - DiscoKey: "faa" + strconv.Itoa(index), - IPAddresses: MachineAddresses{netaddr.MustParseIP(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1)))}, + ID: uint64(index), + MachineKey: "foo" + strconv.Itoa(index), + NodeKey: "bar" + strconv.Itoa(index), + DiscoKey: "faa" + strconv.Itoa(index), + IPAddresses: MachineAddresses{ + netaddr.MustParseIP(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))), + }, Name: "testmachine" + strconv.Itoa(index), NamespaceID: stor[index%2].namespace.ID, Registered: true, diff --git a/poll.go b/poll.go index f00f7484..96db43f2 100644 --- a/poll.go +++ b/poll.go @@ -97,7 +97,11 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) { // update ACLRules with peer informations (to update server tags if necessary) err = h.UpdateACLRules() 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: