mirror of
https://github.com/juanfont/headscale.git
synced 2025-09-11 17:53:10 +02:00
Allow setting ForcedTags using the acls.hujson config file
This patch introduces a declarative way to set ForcedTags for machines. If a "forcedTags" field is set in the acls.hujson file, the ForcedTags of machines will be overriden in the database based on the tags defined in the config file. ```json { "hosts": { "a": "fd7a:115c:a1e0::1", "b": "fd7a:115c:a1e0::2" }, "forcedTags": { "tag:some-tag": [ "a", "tag:some-other-tag" ], "tag:some-other-tag": [ "b" ] } } ```
This commit is contained in:
parent
b01f1f1867
commit
1dd7f193c9
@ -119,9 +119,82 @@ func (h *Headscale) LoadACLPolicyFromBytes(acl []byte, format string) error {
|
||||
|
||||
h.aclPolicy = &policy
|
||||
|
||||
machines, err := h.ListMachines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if h.aclPolicy.ForcedTags != nil {
|
||||
forcedTagsByIp := make(map[netip.Addr][]string)
|
||||
|
||||
for tag, _ := range h.aclPolicy.ForcedTags {
|
||||
var expandedHosts []string
|
||||
|
||||
err := expandNestedTagsToHosts(h.aclPolicy.ForcedTags, tag, &expandedHosts, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, expandedHost := range expandedHosts {
|
||||
ipForExpandedHost := h.aclPolicy.Hosts[expandedHost].Addr()
|
||||
|
||||
forcedTags, _ := forcedTagsByIp[ipForExpandedHost]
|
||||
|
||||
forcedTagsByIp[ipForExpandedHost] = append(forcedTags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
for _, machine := range machines {
|
||||
machine, err := h.GetMachineByID(machine.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
machine.ForcedTags = []string{}
|
||||
|
||||
for _, ip := range machine.IPAddresses {
|
||||
forcedTags, ok := forcedTagsByIp[ip]
|
||||
|
||||
if ok {
|
||||
log.Info().
|
||||
Str("machine", machine.String()).
|
||||
Strs("forcedTags", forcedTags).
|
||||
Msg("Setting forced tags")
|
||||
|
||||
machine.ForcedTags = forcedTags
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.db.Save(machine).Error; err != nil {
|
||||
return fmt.Errorf("failed to update tags for machine in the database: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
h.setLastStateChangeToNow()
|
||||
}
|
||||
|
||||
return h.UpdateACLRules()
|
||||
}
|
||||
|
||||
func expandNestedTagsToHosts(forcedTags ForcedTags, tag string, into *[]string, depth int) error {
|
||||
if depth > 5 {
|
||||
log.Error().
|
||||
Msgf("Recursed too deeply trying to expand %s, expanded %v so far", tag, *into)
|
||||
|
||||
return fmt.Errorf("Recursed too deeply")
|
||||
}
|
||||
|
||||
for _, hostOrTag := range forcedTags[tag] {
|
||||
if !strings.HasPrefix(hostOrTag, "tag:") {
|
||||
*into = append(*into, hostOrTag)
|
||||
} else {
|
||||
expandNestedTagsToHosts(forcedTags, hostOrTag, into, depth + 1)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Headscale) UpdateACLRules() error {
|
||||
machines, err := h.ListMachines()
|
||||
if err != nil {
|
||||
|
@ -14,6 +14,7 @@ type ACLPolicy struct {
|
||||
Groups Groups `json:"groups" yaml:"groups"`
|
||||
Hosts Hosts `json:"hosts" yaml:"hosts"`
|
||||
TagOwners TagOwners `json:"tagOwners" yaml:"tagOwners"`
|
||||
ForcedTags ForcedTags `json:"forcedTags" yaml:"forcedTags"`
|
||||
ACLs []ACL `json:"acls" yaml:"acls"`
|
||||
Tests []ACLTest `json:"tests" yaml:"tests"`
|
||||
AutoApprovers AutoApprovers `json:"autoApprovers" yaml:"autoApprovers"`
|
||||
@ -28,6 +29,9 @@ type ACL struct {
|
||||
Destinations []string `json:"dst" yaml:"dst"`
|
||||
}
|
||||
|
||||
// ForcedTags specifies which tags are applied to which hosts by the server
|
||||
type ForcedTags map[string][]string
|
||||
|
||||
// Groups references a series of alias in the ACL rules.
|
||||
type Groups map[string][]string
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user