mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-27 12:05:26 +00:00
initial implementation of autoApprovers support
This commit is contained in:
parent
cc0bec15ef
commit
004ebcaba1
@ -11,11 +11,12 @@ import (
|
|||||||
|
|
||||||
// ACLPolicy represents a Tailscale ACL Policy.
|
// ACLPolicy represents a Tailscale ACL Policy.
|
||||||
type ACLPolicy struct {
|
type ACLPolicy struct {
|
||||||
Groups Groups `json:"groups" yaml:"groups"`
|
Groups Groups `json:"groups" yaml:"groups"`
|
||||||
Hosts Hosts `json:"hosts" yaml:"hosts"`
|
Hosts Hosts `json:"hosts" yaml:"hosts"`
|
||||||
TagOwners TagOwners `json:"tagOwners" yaml:"tagOwners"`
|
TagOwners TagOwners `json:"tagOwners" yaml:"tagOwners"`
|
||||||
ACLs []ACL `json:"acls" yaml:"acls"`
|
ACLs []ACL `json:"acls" yaml:"acls"`
|
||||||
Tests []ACLTest `json:"tests" yaml:"tests"`
|
Tests []ACLTest `json:"tests" yaml:"tests"`
|
||||||
|
AutoApprovers AutoApprovers `json:"autoApprovers" yaml:"autoApprovers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACL is a basic rule for the ACL Policy.
|
// ACL is a basic rule for the ACL Policy.
|
||||||
@ -42,6 +43,13 @@ type ACLTest struct {
|
|||||||
Deny []string `json:"deny,omitempty" yaml:"deny,omitempty"`
|
Deny []string `json:"deny,omitempty" yaml:"deny,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutoApprovers specify which users (namespaces?), groups or tags have their advertised routes
|
||||||
|
// or exit node status automatically enabled
|
||||||
|
type AutoApprovers struct {
|
||||||
|
Routes map[string][]string `json:"routes" yaml:"routes"`
|
||||||
|
ExitNode []string `json:"exitNode" yaml:"exitNode"`
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON allows to parse the Hosts directly into netaddr objects.
|
// UnmarshalJSON allows to parse the Hosts directly into netaddr objects.
|
||||||
func (hosts *Hosts) UnmarshalJSON(data []byte) error {
|
func (hosts *Hosts) UnmarshalJSON(data []byte) error {
|
||||||
newHosts := Hosts{}
|
newHosts := Hosts{}
|
||||||
|
75
machine.go
75
machine.go
@ -930,6 +930,81 @@ func (h *Headscale) EnableRoutes(machine *Machine, routeStrs ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enabled any routes advertised by a machine that match the ACL autoApprovers policy
|
||||||
|
// TODO simplify by expanding only for current machine, and by checking if approvedIPs contains machine.IPs[0]
|
||||||
|
func (h *Headscale) EnableAutoApprovedRoutes(machine *Machine) error {
|
||||||
|
approvedRoutes := make([]netaddr.IPPrefix, 0, len(machine.HostInfo.RoutableIPs))
|
||||||
|
machines, err := h.ListMachines()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, advertisedRoute := range machine.HostInfo.RoutableIPs {
|
||||||
|
log.Debug().
|
||||||
|
Uint64("machine", machine.ID).
|
||||||
|
Str("advertisedRoute", advertisedRoute.String()).
|
||||||
|
Msg("Client requested to advertise route")
|
||||||
|
|
||||||
|
approved := false
|
||||||
|
routeApprovers := h.aclPolicy.AutoApprovers.Routes[advertisedRoute.String()]
|
||||||
|
|
||||||
|
if advertisedRoute.Bits() == 0 {
|
||||||
|
routeApprovers = h.aclPolicy.AutoApprovers.ExitNode
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(routeApprovers) > 0 {
|
||||||
|
for _, approvedAlias := range routeApprovers {
|
||||||
|
|
||||||
|
approvedIps, err := expandAlias(machines, *h.aclPolicy, approvedAlias, h.cfg.OIDC.StripEmaildomain)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).
|
||||||
|
Str("alias", approvedAlias).
|
||||||
|
Msg("Failed to expand alias when processing autoApprovers policy")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, machineIp := range machine.IPAddresses {
|
||||||
|
for _, approvedIp := range approvedIps {
|
||||||
|
approved = machineIp.String() == approvedIp
|
||||||
|
|
||||||
|
if approved {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if approved {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Debug().
|
||||||
|
Uint64("client", machine.ID).
|
||||||
|
Str("advertisedRoute", advertisedRoute.String()).
|
||||||
|
Msg("Advertised route is not automatically approved")
|
||||||
|
}
|
||||||
|
|
||||||
|
if approved {
|
||||||
|
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, approvedRoute := range approvedRoutes {
|
||||||
|
if !contains(machine.EnabledRoutes, approvedRoute) {
|
||||||
|
log.Info().
|
||||||
|
Str("route", approvedRoute.String()).
|
||||||
|
Uint64("client", machine.ID).
|
||||||
|
Msg("Enabling autoApproved route for client")
|
||||||
|
machine.EnabledRoutes = append(machine.EnabledRoutes, approvedRoute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (machine *Machine) RoutesToProto() *v1.Routes {
|
func (machine *Machine) RoutesToProto() *v1.Routes {
|
||||||
availableRoutes := machine.GetAdvertisedRoutes()
|
availableRoutes := machine.GetAdvertisedRoutes()
|
||||||
|
|
||||||
|
@ -42,7 +42,14 @@ func (h *Headscale) handlePollCommon(
|
|||||||
Str("machine", machine.Hostname).
|
Str("machine", machine.Hostname).
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update routes with peer information
|
||||||
|
err = h.EnableAutoApprovedRoutes(machine)
|
||||||
|
if err != nil {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// From Tailscale client:
|
// From Tailscale client:
|
||||||
//
|
//
|
||||||
// ReadOnly is whether the client just wants to fetch the MapResponse,
|
// ReadOnly is whether the client just wants to fetch the MapResponse,
|
||||||
|
Loading…
Reference in New Issue
Block a user