Add YAML support to ACLs
This commit is contained in:
parent
67d6c8f946
commit
8a3a0b6403
2 changed files with 64 additions and 20 deletions
40
acls.go
40
acls.go
|
@ -5,11 +5,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/tailscale/hujson"
|
"github.com/tailscale/hujson"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
@ -53,16 +55,36 @@ func (h *Headscale) LoadACLPolicy(path string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ast, err := hujson.Parse(policyBytes)
|
switch filepath.Ext(path) {
|
||||||
if err != nil {
|
case ".yml", ".yaml":
|
||||||
return err
|
log.Debug().
|
||||||
}
|
Str("path", path).
|
||||||
ast.Standardize()
|
Bytes("file", policyBytes).
|
||||||
policyBytes = ast.Pack()
|
Msg("Loading ACLs from YAML")
|
||||||
err = json.Unmarshal(policyBytes, &policy)
|
|
||||||
if err != nil {
|
err := yaml.Unmarshal(policyBytes, &policy)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace().
|
||||||
|
Interface("policy", policy).
|
||||||
|
Msg("Loaded policy from YAML")
|
||||||
|
|
||||||
|
default:
|
||||||
|
ast, err := hujson.Parse(policyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.Standardize()
|
||||||
|
policyBytes = ast.Pack()
|
||||||
|
err = json.Unmarshal(policyBytes, &policy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if policy.IsZero() {
|
if policy.IsZero() {
|
||||||
return errEmptyPolicy
|
return errEmptyPolicy
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,24 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tailscale/hujson"
|
"github.com/tailscale/hujson"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ACLPolicy represents a Tailscale ACL Policy.
|
// ACLPolicy represents a Tailscale ACL Policy.
|
||||||
type ACLPolicy struct {
|
type ACLPolicy struct {
|
||||||
Groups Groups `json:"Groups"`
|
Groups Groups `json:"Groups" yaml:"Groups"`
|
||||||
Hosts Hosts `json:"Hosts"`
|
Hosts Hosts `json:"Hosts" yaml:"Hosts"`
|
||||||
TagOwners TagOwners `json:"TagOwners"`
|
TagOwners TagOwners `json:"TagOwners" yaml:"TagOwners"`
|
||||||
ACLs []ACL `json:"ACLs"`
|
ACLs []ACL `json:"ACLs" yaml:"ACLs"`
|
||||||
Tests []ACLTest `json:"Tests"`
|
Tests []ACLTest `json:"Tests" yaml:"Tests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACL is a basic rule for the ACL Policy.
|
// ACL is a basic rule for the ACL Policy.
|
||||||
type ACL struct {
|
type ACL struct {
|
||||||
Action string `json:"Action"`
|
Action string `json:"Action" yaml:"Action"`
|
||||||
Users []string `json:"Users"`
|
Users []string `json:"Users" yaml:"Users"`
|
||||||
Ports []string `json:"Ports"`
|
Ports []string `json:"Ports" yaml:"Ports"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Groups references a series of alias in the ACL rules.
|
// Groups references a series of alias in the ACL rules.
|
||||||
|
@ -35,9 +36,9 @@ type TagOwners map[string][]string
|
||||||
|
|
||||||
// ACLTest is not implemented, but should be use to check if a certain rule is allowed.
|
// ACLTest is not implemented, but should be use to check if a certain rule is allowed.
|
||||||
type ACLTest struct {
|
type ACLTest struct {
|
||||||
User string `json:"User"`
|
User string `json:"User" yaml:"User"`
|
||||||
Allow []string `json:"Allow"`
|
Allow []string `json:"Allow" yaml:"Allow"`
|
||||||
Deny []string `json:"Deny,omitempty"`
|
Deny []string `json:"Deny,omitempty" yaml:"Deny,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON allows to parse the Hosts directly into netaddr objects.
|
// UnmarshalJSON allows to parse the Hosts directly into netaddr objects.
|
||||||
|
@ -69,6 +70,27 @@ func (hosts *Hosts) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML allows to parse the Hosts directly into netaddr objects.
|
||||||
|
func (hosts *Hosts) UnmarshalYAML(data []byte) error {
|
||||||
|
newHosts := Hosts{}
|
||||||
|
hostIPPrefixMap := make(map[string]string)
|
||||||
|
|
||||||
|
err := yaml.Unmarshal(data, &hostIPPrefixMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for host, prefixStr := range hostIPPrefixMap {
|
||||||
|
prefix, err := netaddr.ParseIPPrefix(prefixStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newHosts[host] = prefix
|
||||||
|
}
|
||||||
|
*hosts = newHosts
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsZero is perhaps a bit naive here.
|
// IsZero is perhaps a bit naive here.
|
||||||
func (policy ACLPolicy) IsZero() bool {
|
func (policy ACLPolicy) IsZero() bool {
|
||||||
if len(policy.Groups) == 0 && len(policy.Hosts) == 0 && len(policy.ACLs) == 0 {
|
if len(policy.Groups) == 0 && len(policy.Hosts) == 0 && len(policy.ACLs) == 0 {
|
||||||
|
|
Loading…
Reference in a new issue