mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-26 08:53:05 +00:00
chore(fmt): apply make fmt command
This commit is contained in:
parent
9cedbbafd4
commit
d8c4c3163b
8 changed files with 399 additions and 130 deletions
|
@ -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):**
|
||||
|
||||
|
|
35
acls.go
35
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
302
acls_test.go
302
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
|
||||
}
|
||||
|
|
6
dns.go
6
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,
|
||||
),
|
||||
)
|
||||
|
|
155
docs/acls.md
155
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:*"] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
|
11
machine.go
11
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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
6
poll.go
6
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:
|
||||
|
|
Loading…
Reference in a new issue