mirror of
https://github.com/juanfont/headscale.git
synced 2024-12-24 21:25:52 -05:00
chore(fmt): apply make fmt command
This commit is contained in:
parent
9cedbbafd4
commit
d8c4c3163b
@ -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
35
acls.go
@ -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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
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
6
dns.go
@ -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,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
43
docs/acls.md
43
docs/acls.md
@ -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
|
||||||
@ -52,7 +51,7 @@ Here are the ACL's to implement the same permissions as above:
|
|||||||
"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.
|
// 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)
|
// This is documented [here](https://tailscale.com/kb/1068/acl-tags#defining-a-tag)
|
||||||
@ -67,51 +66,68 @@ Here are the ACL's to implement the same permissions as above:
|
|||||||
|
|
||||||
// dev can add servers for dev purposes as well as admins
|
// dev can add servers for dev purposes as well as admins
|
||||||
"tag:dev-databases": ["group:admin", "group:dev"],
|
"tag:dev-databases": ["group:admin", "group:dev"],
|
||||||
"tag:dev-app-servers": ["group:admin", "group:dev"],
|
"tag:dev-app-servers": ["group:admin", "group:dev"]
|
||||||
|
|
||||||
// interns cannot add servers
|
// interns cannot add servers
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
// boss have access to all servers
|
// boss have access to all servers
|
||||||
{"action":"accept",
|
{
|
||||||
|
"action": "accept",
|
||||||
"users": ["group:boss"],
|
"users": ["group:boss"],
|
||||||
"ports": [
|
"ports": [
|
||||||
"tag:prod-databases:*",
|
"tag:prod-databases:*",
|
||||||
"tag:prod-app-servers:*",
|
"tag:prod-app-servers:*",
|
||||||
"tag:internal:*",
|
"tag:internal:*",
|
||||||
"tag:dev-databases:*",
|
"tag:dev-databases:*",
|
||||||
"tag:dev-app-servers:*",
|
"tag:dev-app-servers:*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// admin have only access to administrative ports of the servers
|
// admin have only access to administrative ports of the servers
|
||||||
{"action":"accept",
|
{
|
||||||
|
"action": "accept",
|
||||||
"users": ["group:admin"],
|
"users": ["group:admin"],
|
||||||
"ports": [
|
"ports": [
|
||||||
"tag:prod-databases:22",
|
"tag:prod-databases:22",
|
||||||
"tag:prod-app-servers:22",
|
"tag:prod-app-servers:22",
|
||||||
"tag:internal:22",
|
"tag:internal:22",
|
||||||
"tag:dev-databases:22",
|
"tag:dev-databases:22",
|
||||||
"tag:dev-app-servers:22",
|
"tag:dev-app-servers:22"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// developers have access to databases servers and application servers on all ports
|
// 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
|
// they can only view the applications servers in prod and have no access to databases servers in production
|
||||||
{"action":"accept", "users":["group:dev"], "ports":[
|
{
|
||||||
|
"action": "accept",
|
||||||
|
"users": ["group:dev"],
|
||||||
|
"ports": [
|
||||||
"tag:dev-databases:*",
|
"tag:dev-databases:*",
|
||||||
"tag:dev-app-servers:*",
|
"tag:dev-app-servers:*",
|
||||||
"tag:prod-app-servers:80,443",
|
"tag:prod-app-servers:80,443"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// servers should be able to talk to database. Database should not be able to initiate connections to
|
// servers should be able to talk to database. Database should not be able to initiate connections to
|
||||||
// applications servers
|
// 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"]},
|
"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
|
// interns have access to dev-app-servers only in reading mode
|
||||||
{"action":"accept", "users":["group:intern"], "ports":["tag:dev-app-servers:80,443"]},
|
{
|
||||||
|
"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
|
// We still have to allow internal namespaces communications since nothing guarantees that each user have
|
||||||
// their own namespaces.
|
// their own namespaces.
|
||||||
@ -119,8 +135,7 @@ Here are the ACL's to implement the same permissions as above:
|
|||||||
{ "action": "accept", "users": ["dev1"], "ports": ["dev1:*"] },
|
{ "action": "accept", "users": ["dev1"], "ports": ["dev1:*"] },
|
||||||
{ "action": "accept", "users": ["dev2"], "ports": ["dev2:*"] },
|
{ "action": "accept", "users": ["dev2"], "ports": ["dev2:*"] },
|
||||||
{ "action": "accept", "users": ["admin1"], "ports": ["admin1:*"] },
|
{ "action": "accept", "users": ["admin1"], "ports": ["admin1:*"] },
|
||||||
{"action":"accept", "users":["intern1"], "ports":["intern1:*"]},
|
{ "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 {
|
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 {
|
||||||
|
@ -180,7 +180,9 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
|
|||||||
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,
|
||||||
|
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)
|
// 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:
|
||||||
|
Loading…
Reference in New Issue
Block a user