headscale/acls_types.go

146 lines
4.1 KiB
Go
Raw Normal View History

2021-07-03 17:55:32 +08:00
package headscale
import (
2021-11-05 15:24:00 +08:00
"encoding/json"
2022-09-02 06:05:43 +08:00
"net/netip"
2021-07-03 17:55:32 +08:00
"strings"
2021-07-03 23:31:32 +08:00
"github.com/tailscale/hujson"
2022-02-27 16:04:48 +08:00
"gopkg.in/yaml.v3"
2021-07-03 17:55:32 +08:00
)
2021-11-13 16:39:04 +08:00
// ACLPolicy represents a Tailscale ACL Policy.
2021-07-03 17:55:32 +08:00
type ACLPolicy struct {
Groups Groups `json:"groups" yaml:"groups"`
Hosts Hosts `json:"hosts" yaml:"hosts"`
TagOwners TagOwners `json:"tagOwners" yaml:"tagOwners"`
ACLs []ACL `json:"acls" yaml:"acls"`
Tests []ACLTest `json:"tests" yaml:"tests"`
AutoApprovers AutoApprovers `json:"autoApprovers" yaml:"autoApprovers"`
SSHs []SSH `json:"ssh" yaml:"ssh"`
2021-07-03 17:55:32 +08:00
}
2021-11-13 16:39:04 +08:00
// ACL is a basic rule for the ACL Policy.
2021-07-03 17:55:32 +08:00
type ACL struct {
Action string `json:"action" yaml:"action"`
2022-08-04 16:47:00 +08:00
Protocol string `json:"proto" yaml:"proto"`
Sources []string `json:"src" yaml:"src"`
Destinations []string `json:"dst" yaml:"dst"`
2021-07-03 17:55:32 +08:00
}
2021-11-13 16:39:04 +08:00
// Groups references a series of alias in the ACL rules.
2021-07-03 17:55:32 +08:00
type Groups map[string][]string
2021-11-13 16:39:04 +08:00
// Hosts are alias for IP addresses or subnets.
2022-09-02 06:05:43 +08:00
type Hosts map[string]netip.Prefix
2021-07-03 17:55:32 +08:00
// TagOwners specify what users (users?) are allow to use certain tags.
2021-07-03 23:31:32 +08:00
type TagOwners map[string][]string
2021-07-03 17:55:32 +08:00
2021-11-13 16:39:04 +08:00
// ACLTest is not implemented, but should be use to check if a certain rule is allowed.
2021-07-03 17:55:32 +08:00
type ACLTest struct {
2022-08-04 16:47:00 +08:00
Source string `json:"src" yaml:"src"`
Accept []string `json:"accept" yaml:"accept"`
Deny []string `json:"deny,omitempty" yaml:"deny,omitempty"`
2021-07-03 17:55:32 +08:00
}
// AutoApprovers specify which users (users?), groups or tags have their advertised routes
2022-09-05 04:40:08 +08:00
// or exit node status automatically enabled.
type AutoApprovers struct {
Routes map[string][]string `json:"routes" yaml:"routes"`
ExitNode []string `json:"exitNode" yaml:"exitNode"`
}
// SSH controls who can ssh into which machines.
type SSH struct {
Action string `json:"action" yaml:"action"`
Sources []string `json:"src" yaml:"src"`
Destinations []string `json:"dst" yaml:"dst"`
Users []string `json:"users" yaml:"users"`
CheckPeriod string `json:"checkPeriod,omitempty" yaml:"checkPeriod,omitempty"`
}
2022-09-04 05:46:14 +08:00
// UnmarshalJSON allows to parse the Hosts directly into netip objects.
func (hosts *Hosts) UnmarshalJSON(data []byte) error {
newHosts := Hosts{}
hostIPPrefixMap := make(map[string]string)
2021-11-05 15:24:00 +08:00
ast, err := hujson.Parse(data)
if err != nil {
return err
}
ast.Standardize()
data = ast.Pack()
err = json.Unmarshal(data, &hostIPPrefixMap)
2021-07-03 23:31:32 +08:00
if err != nil {
return err
2021-07-03 17:55:32 +08:00
}
for host, prefixStr := range hostIPPrefixMap {
if !strings.Contains(prefixStr, "/") {
prefixStr += "/32"
2021-07-03 17:55:32 +08:00
}
2022-09-02 06:05:43 +08:00
prefix, err := netip.ParsePrefix(prefixStr)
2021-07-03 17:55:32 +08:00
if err != nil {
2021-07-03 23:31:32 +08:00
return err
2021-07-03 17:55:32 +08:00
}
newHosts[host] = prefix
2021-07-03 17:55:32 +08:00
}
*hosts = newHosts
2021-11-14 23:46:09 +08:00
2021-07-03 23:31:32 +08:00
return nil
}
2022-09-04 05:46:14 +08:00
// UnmarshalYAML allows to parse the Hosts directly into netip objects.
2022-02-27 16:04:48 +08:00
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 {
2022-09-02 06:05:43 +08:00
prefix, err := netip.ParsePrefix(prefixStr)
2022-02-27 16:04:48 +08:00
if err != nil {
return err
}
newHosts[host] = prefix
}
*hosts = newHosts
return nil
}
2021-11-13 16:39:04 +08:00
// IsZero is perhaps a bit naive here.
func (policy ACLPolicy) IsZero() bool {
if len(policy.Groups) == 0 && len(policy.Hosts) == 0 && len(policy.ACLs) == 0 {
2021-07-03 23:31:32 +08:00
return true
}
2021-11-14 23:46:09 +08:00
2021-07-03 23:31:32 +08:00
return false
2021-07-03 17:55:32 +08:00
}
// Returns the list of autoApproving users, groups or tags for a given IPPrefix.
func (autoApprovers *AutoApprovers) GetRouteApprovers(
2022-09-05 07:33:53 +08:00
prefix netip.Prefix,
) ([]string, error) {
if prefix.Bits() == 0 {
return autoApprovers.ExitNode, nil // 0.0.0.0/0, ::/0 or equivalent
}
approverAliases := []string{}
for autoApprovedPrefix, autoApproverAliases := range autoApprovers.Routes {
2022-09-05 07:33:53 +08:00
autoApprovedPrefix, err := netip.ParsePrefix(autoApprovedPrefix)
if err != nil {
return nil, err
}
if prefix.Bits() >= autoApprovedPrefix.Bits() &&
2022-09-05 07:33:53 +08:00
autoApprovedPrefix.Contains(prefix.Masked().Addr()) {
approverAliases = append(approverAliases, autoApproverAliases...)
}
}
return approverAliases, nil
}