mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	Merge pull request #373 from restanrm/feat-email-in-acls
This commit is contained in:
		
						commit
						dec4ee5f73
					
				| @ -10,6 +10,7 @@ | ||||
| **Features**: | ||||
| 
 | ||||
| - Add support for writing ACL files with YAML [#359](https://github.com/juanfont/headscale/pull/359) | ||||
| - Users can now use emails in ACL's groups [#372](https://github.com/juanfont/headscale/issues/372) | ||||
| 
 | ||||
| **Changes**: | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										46
									
								
								acls.go
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								acls.go
									
									
									
									
									
								
							| @ -160,7 +160,7 @@ func (h *Headscale) generateACLPolicySrcIP( | ||||
| 	aclPolicy ACLPolicy, | ||||
| 	u string, | ||||
| ) ([]string, error) { | ||||
| 	return expandAlias(machines, aclPolicy, u) | ||||
| 	return expandAlias(machines, aclPolicy, u, h.cfg.OIDC.StripEmaildomain) | ||||
| } | ||||
| 
 | ||||
| func (h *Headscale) generateACLPolicyDestPorts( | ||||
| @ -186,7 +186,12 @@ func (h *Headscale) generateACLPolicyDestPorts( | ||||
| 		alias = fmt.Sprintf("%s:%s", tokens[0], tokens[1]) | ||||
| 	} | ||||
| 
 | ||||
| 	expanded, err := expandAlias(machines, aclPolicy, alias) | ||||
| 	expanded, err := expandAlias( | ||||
| 		machines, | ||||
| 		aclPolicy, | ||||
| 		alias, | ||||
| 		h.cfg.OIDC.StripEmaildomain, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -218,6 +223,7 @@ func expandAlias( | ||||
| 	machines []Machine, | ||||
| 	aclPolicy ACLPolicy, | ||||
| 	alias string, | ||||
| 	stripEmailDomain bool, | ||||
| ) ([]string, error) { | ||||
| 	ips := []string{} | ||||
| 	if alias == "*" { | ||||
| @ -225,7 +231,7 @@ func expandAlias( | ||||
| 	} | ||||
| 
 | ||||
| 	if strings.HasPrefix(alias, "group:") { | ||||
| 		namespaces, err := expandGroup(aclPolicy, alias) | ||||
| 		namespaces, err := expandGroup(aclPolicy, alias, stripEmailDomain) | ||||
| 		if err != nil { | ||||
| 			return ips, err | ||||
| 		} | ||||
| @ -240,7 +246,7 @@ func expandAlias( | ||||
| 	} | ||||
| 
 | ||||
| 	if strings.HasPrefix(alias, "tag:") { | ||||
| 		owners, err := expandTagOwners(aclPolicy, alias) | ||||
| 		owners, err := expandTagOwners(aclPolicy, alias, stripEmailDomain) | ||||
| 		if err != nil { | ||||
| 			return ips, err | ||||
| 		} | ||||
| @ -396,7 +402,11 @@ func filterMachinesByNamespace(machines []Machine, namespace string) []Machine { | ||||
| 
 | ||||
| // expandTagOwners will return a list of namespace. An owner can be either a namespace or a group
 | ||||
| // a group cannot be composed of groups.
 | ||||
| func expandTagOwners(aclPolicy ACLPolicy, tag string) ([]string, error) { | ||||
| func expandTagOwners( | ||||
| 	aclPolicy ACLPolicy, | ||||
| 	tag string, | ||||
| 	stripEmailDomain bool, | ||||
| ) ([]string, error) { | ||||
| 	var owners []string | ||||
| 	ows, ok := aclPolicy.TagOwners[tag] | ||||
| 	if !ok { | ||||
| @ -408,7 +418,7 @@ func expandTagOwners(aclPolicy ACLPolicy, tag string) ([]string, error) { | ||||
| 	} | ||||
| 	for _, owner := range ows { | ||||
| 		if strings.HasPrefix(owner, "group:") { | ||||
| 			gs, err := expandGroup(aclPolicy, owner) | ||||
| 			gs, err := expandGroup(aclPolicy, owner, stripEmailDomain) | ||||
| 			if err != nil { | ||||
| 				return []string{}, err | ||||
| 			} | ||||
| @ -423,8 +433,13 @@ func expandTagOwners(aclPolicy ACLPolicy, tag string) ([]string, error) { | ||||
| 
 | ||||
| // expandGroup will return the list of namespace inside the group
 | ||||
| // after some validation.
 | ||||
| func expandGroup(aclPolicy ACLPolicy, group string) ([]string, error) { | ||||
| 	groups, ok := aclPolicy.Groups[group] | ||||
| func expandGroup( | ||||
| 	aclPolicy ACLPolicy, | ||||
| 	group string, | ||||
| 	stripEmailDomain bool, | ||||
| ) ([]string, error) { | ||||
| 	outGroups := []string{} | ||||
| 	aclGroups, ok := aclPolicy.Groups[group] | ||||
| 	if !ok { | ||||
| 		return []string{}, fmt.Errorf( | ||||
| 			"group %v isn't registered. %w", | ||||
| @ -432,14 +447,23 @@ func expandGroup(aclPolicy ACLPolicy, group string) ([]string, error) { | ||||
| 			errInvalidGroup, | ||||
| 		) | ||||
| 	} | ||||
| 	for _, g := range groups { | ||||
| 		if strings.HasPrefix(g, "group:") { | ||||
| 	for _, group := range aclGroups { | ||||
| 		if strings.HasPrefix(group, "group:") { | ||||
| 			return []string{}, fmt.Errorf( | ||||
| 				"%w. A group cannot be composed of groups. https://tailscale.com/kb/1018/acls/#groups", | ||||
| 				errInvalidGroup, | ||||
| 			) | ||||
| 		} | ||||
| 		grp, err := NormalizeNamespaceName(group, stripEmailDomain) | ||||
| 		if err != nil { | ||||
| 			return []string{}, fmt.Errorf( | ||||
| 				"failed to normalize group %q, err: %w", | ||||
| 				group, | ||||
| 				errInvalidGroup, | ||||
| 			) | ||||
| 		} | ||||
| 		outGroups = append(outGroups, grp) | ||||
| 	} | ||||
| 
 | ||||
| 	return groups, nil | ||||
| 	return outGroups, nil | ||||
| } | ||||
|  | ||||
							
								
								
									
										67
									
								
								acls_test.go
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								acls_test.go
									
									
									
									
									
								
							| @ -432,6 +432,7 @@ func Test_expandGroup(t *testing.T) { | ||||
| 	type args struct { | ||||
| 		aclPolicy        ACLPolicy | ||||
| 		group            string | ||||
| 		stripEmailDomain bool | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| @ -449,6 +450,7 @@ func Test_expandGroup(t *testing.T) { | ||||
| 					}, | ||||
| 				}, | ||||
| 				group:            "group:test", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"user1", "user2", "user3"}, | ||||
| 			wantErr: false, | ||||
| @ -463,14 +465,53 @@ func Test_expandGroup(t *testing.T) { | ||||
| 					}, | ||||
| 				}, | ||||
| 				group:            "group:undefined", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{}, | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Expand emails in group", | ||||
| 			args: args{ | ||||
| 				aclPolicy: ACLPolicy{ | ||||
| 					Groups: Groups{ | ||||
| 						"group:admin": []string{ | ||||
| 							"joe.bar@gmail.com", | ||||
| 							"john.doe@yahoo.fr", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				group:            "group:admin", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"joe.bar", "john.doe"}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Expand emails in group", | ||||
| 			args: args{ | ||||
| 				aclPolicy: ACLPolicy{ | ||||
| 					Groups: Groups{ | ||||
| 						"group:admin": []string{ | ||||
| 							"joe.bar@gmail.com", | ||||
| 							"john.doe@yahoo.fr", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				group:            "group:admin", | ||||
| 				stripEmailDomain: false, | ||||
| 			}, | ||||
| 			want:    []string{"joe.bar.gmail.com", "john.doe.yahoo.fr"}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, test := range tests { | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			got, err := expandGroup(test.args.aclPolicy, test.args.group) | ||||
| 			got, err := expandGroup( | ||||
| 				test.args.aclPolicy, | ||||
| 				test.args.group, | ||||
| 				test.args.stripEmailDomain, | ||||
| 			) | ||||
| 			if (err != nil) != test.wantErr { | ||||
| 				t.Errorf("expandGroup() error = %v, wantErr %v", err, test.wantErr) | ||||
| 
 | ||||
| @ -487,6 +528,7 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 	type args struct { | ||||
| 		aclPolicy        ACLPolicy | ||||
| 		tag              string | ||||
| 		stripEmailDomain bool | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| @ -501,6 +543,7 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 					TagOwners: TagOwners{"tag:test": []string{"user1"}}, | ||||
| 				}, | ||||
| 				tag:              "tag:test", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"user1"}, | ||||
| 			wantErr: false, | ||||
| @ -513,6 +556,7 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 					TagOwners: TagOwners{"tag:test": []string{"group:foo"}}, | ||||
| 				}, | ||||
| 				tag:              "tag:test", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"user1", "user2"}, | ||||
| 			wantErr: false, | ||||
| @ -525,6 +569,7 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 					TagOwners: TagOwners{"tag:test": []string{"group:foo", "user3"}}, | ||||
| 				}, | ||||
| 				tag:              "tag:test", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"user1", "user2", "user3"}, | ||||
| 			wantErr: false, | ||||
| @ -536,6 +581,7 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 					TagOwners: TagOwners{"tag:foo": []string{"group:foo", "user1"}}, | ||||
| 				}, | ||||
| 				tag:              "tag:test", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{}, | ||||
| 			wantErr: true, | ||||
| @ -548,6 +594,7 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 					TagOwners: TagOwners{"tag:test": []string{"group:foo", "user2"}}, | ||||
| 				}, | ||||
| 				tag:              "tag:test", | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{}, | ||||
| 			wantErr: true, | ||||
| @ -555,7 +602,11 @@ func Test_expandTagOwners(t *testing.T) { | ||||
| 	} | ||||
| 	for _, test := range tests { | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			got, err := expandTagOwners(test.args.aclPolicy, test.args.tag) | ||||
| 			got, err := expandTagOwners( | ||||
| 				test.args.aclPolicy, | ||||
| 				test.args.tag, | ||||
| 				test.args.stripEmailDomain, | ||||
| 			) | ||||
| 			if (err != nil) != test.wantErr { | ||||
| 				t.Errorf("expandTagOwners() error = %v, wantErr %v", err, test.wantErr) | ||||
| 
 | ||||
| @ -720,6 +771,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 		machines         []Machine | ||||
| 		aclPolicy        ACLPolicy | ||||
| 		alias            string | ||||
| 		stripEmailDomain bool | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| @ -740,6 +792,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 					}, | ||||
| 				}, | ||||
| 				aclPolicy:        ACLPolicy{}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"*"}, | ||||
| 			wantErr: false, | ||||
| @ -777,6 +830,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				aclPolicy: ACLPolicy{ | ||||
| 					Groups: Groups{"group:accountant": []string{"joe", "marc"}}, | ||||
| 				}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"100.64.0.1", "100.64.0.2", "100.64.0.3"}, | ||||
| 			wantErr: false, | ||||
| @ -814,6 +868,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				aclPolicy: ACLPolicy{ | ||||
| 					Groups: Groups{"group:accountant": []string{"joe", "marc"}}, | ||||
| 				}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{}, | ||||
| 			wantErr: true, | ||||
| @ -824,6 +879,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				alias:            "10.0.0.3", | ||||
| 				machines:         []Machine{}, | ||||
| 				aclPolicy:        ACLPolicy{}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"10.0.0.3"}, | ||||
| 			wantErr: false, | ||||
| @ -838,6 +894,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 						"homeNetwork": netaddr.MustParseIPPrefix("192.168.1.0/24"), | ||||
| 					}, | ||||
| 				}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"192.168.1.0/24"}, | ||||
| 			wantErr: false, | ||||
| @ -848,6 +905,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				alias:            "10.0.0.1", | ||||
| 				machines:         []Machine{}, | ||||
| 				aclPolicy:        ACLPolicy{}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"10.0.0.1"}, | ||||
| 			wantErr: false, | ||||
| @ -858,6 +916,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				alias:            "10.0.0.0/16", | ||||
| 				machines:         []Machine{}, | ||||
| 				aclPolicy:        ACLPolicy{}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"10.0.0.0/16"}, | ||||
| 			wantErr: false, | ||||
| @ -901,6 +960,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				aclPolicy: ACLPolicy{ | ||||
| 					TagOwners: TagOwners{"tag:hr-webserver": []string{"joe"}}, | ||||
| 				}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"100.64.0.1", "100.64.0.2"}, | ||||
| 			wantErr: false, | ||||
| @ -941,6 +1001,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 						"tag:accountant-webserver": []string{"group:accountant"}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{}, | ||||
| 			wantErr: true, | ||||
| @ -984,6 +1045,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				aclPolicy: ACLPolicy{ | ||||
| 					TagOwners: TagOwners{"tag:accountant-webserver": []string{"joe"}}, | ||||
| 				}, | ||||
| 				stripEmailDomain: true, | ||||
| 			}, | ||||
| 			want:    []string{"100.64.0.4"}, | ||||
| 			wantErr: false, | ||||
| @ -995,6 +1057,7 @@ func Test_expandAlias(t *testing.T) { | ||||
| 				test.args.machines, | ||||
| 				test.args.aclPolicy, | ||||
| 				test.args.alias, | ||||
| 				test.args.stripEmailDomain, | ||||
| 			) | ||||
| 			if (err != nil) != test.wantErr { | ||||
| 				t.Errorf("expandAlias() error = %v, wantErr %v", err, test.wantErr) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user