2023-05-21 16:37:59 +00:00
package policy
2021-07-03 09:55:32 +00:00
import (
2021-07-04 10:35:18 +00:00
"encoding/json"
2022-04-15 16:01:13 +00:00
"errors"
2021-07-03 15:31:32 +00:00
"fmt"
2021-07-03 09:55:32 +00:00
"io"
2022-09-03 21:46:14 +00:00
"net/netip"
2021-07-03 09:55:32 +00:00
"os"
2024-10-02 07:06:09 +00:00
"slices"
2021-07-04 10:35:18 +00:00
"strconv"
2021-07-03 15:31:32 +00:00
"strings"
2022-09-30 18:44:23 +00:00
"time"
2021-07-03 09:55:32 +00:00
2024-07-22 06:56:00 +00:00
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/util"
2021-08-05 17:18:18 +00:00
"github.com/rs/zerolog/log"
2021-07-03 09:55:32 +00:00
"github.com/tailscale/hujson"
2023-04-28 14:11:02 +00:00
"go4.org/netipx"
2024-10-02 07:06:09 +00:00
"tailscale.com/net/tsaddr"
2021-07-03 15:31:32 +00:00
"tailscale.com/tailcfg"
2021-07-03 09:55:32 +00:00
)
2023-05-11 07:09:18 +00:00
var (
2023-05-21 16:37:59 +00:00
ErrEmptyPolicy = errors . New ( "empty policy" )
ErrInvalidAction = errors . New ( "invalid action" )
ErrInvalidGroup = errors . New ( "invalid group" )
ErrInvalidTag = errors . New ( "invalid tag" )
ErrInvalidPortFormat = errors . New ( "invalid port format" )
ErrWildcardIsNeeded = errors . New ( "wildcard as port is required for the protocol" )
2021-11-04 22:16:56 +00:00
)
2021-07-03 09:55:32 +00:00
2021-11-14 17:31:51 +00:00
const (
2021-11-15 17:24:24 +00:00
portRangeBegin = 0
portRangeEnd = 65535
expectedTokenItems = 2
2021-11-14 17:31:51 +00:00
)
2024-04-30 05:23:16 +00:00
var theInternetSet * netipx . IPSet
// theInternet returns the IPSet for the Internet.
// https://www.youtube.com/watch?v=iDbyYGrswtg
func theInternet ( ) * netipx . IPSet {
if theInternetSet != nil {
return theInternetSet
}
var internetBuilder netipx . IPSetBuilder
internetBuilder . AddPrefix ( netip . MustParsePrefix ( "2000::/3" ) )
2024-10-02 07:06:09 +00:00
internetBuilder . AddPrefix ( tsaddr . AllIPv4 ( ) )
2024-04-30 05:23:16 +00:00
// Delete Private network addresses
// https://datatracker.ietf.org/doc/html/rfc1918
internetBuilder . RemovePrefix ( netip . MustParsePrefix ( "fc00::/7" ) )
internetBuilder . RemovePrefix ( netip . MustParsePrefix ( "10.0.0.0/8" ) )
internetBuilder . RemovePrefix ( netip . MustParsePrefix ( "172.16.0.0/12" ) )
internetBuilder . RemovePrefix ( netip . MustParsePrefix ( "192.168.0.0/16" ) )
// Delete Tailscale networks
2024-10-02 07:06:09 +00:00
internetBuilder . RemovePrefix ( tsaddr . TailscaleULARange ( ) )
internetBuilder . RemovePrefix ( tsaddr . CGNATRange ( ) )
2024-04-30 05:23:16 +00:00
// Delete "cant find DHCP networks"
internetBuilder . RemovePrefix ( netip . MustParsePrefix ( "fe80::/10" ) ) // link-loca
internetBuilder . RemovePrefix ( netip . MustParsePrefix ( "169.254.0.0/16" ) )
theInternetSet , _ := internetBuilder . IPSet ( )
return theInternetSet
}
2022-06-26 09:43:17 +00:00
// For some reason golang.org/x/net/internal/iana is an internal package.
2022-06-11 12:09:08 +00:00
const (
protocolICMP = 1 // Internet Control Message
protocolIGMP = 2 // Internet Group Management
protocolIPv4 = 4 // IPv4 encapsulation
protocolTCP = 6 // Transmission Control
protocolEGP = 8 // Exterior Gateway Protocol
protocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP)
protocolUDP = 17 // User Datagram
protocolGRE = 47 // Generic Routing Encapsulation
protocolESP = 50 // Encap Security Payload
protocolAH = 51 // Authentication Header
protocolIPv6ICMP = 58 // ICMP for IPv6
protocolSCTP = 132 // Stream Control Transmission Protocol
ProtocolFC = 133 // Fibre Channel
)
2023-05-10 08:19:16 +00:00
// LoadACLPolicyFromPath loads the ACL policy from the specify path, and generates the ACL rules.
2023-05-21 16:37:59 +00:00
func LoadACLPolicyFromPath ( path string ) ( * ACLPolicy , error ) {
2021-12-01 19:02:00 +00:00
log . Debug ( ) .
Str ( "func" , "LoadACLPolicy" ) .
Str ( "path" , path ) .
Msg ( "Loading ACL policy from path" )
2021-07-03 09:55:32 +00:00
policyFile , err := os . Open ( path )
if err != nil {
2023-05-21 16:37:59 +00:00
return nil , err
2021-07-03 09:55:32 +00:00
}
defer policyFile . Close ( )
2021-11-14 19:32:03 +00:00
policyBytes , err := io . ReadAll ( policyFile )
2021-07-03 09:55:32 +00:00
if err != nil {
2023-05-21 16:37:59 +00:00
return nil , err
2021-07-03 09:55:32 +00:00
}
2021-11-05 07:24:00 +00:00
2023-05-10 08:19:16 +00:00
log . Debug ( ) .
Str ( "path" , path ) .
Bytes ( "file" , policyBytes ) .
Msg ( "Loading ACLs" )
2024-07-18 05:38:25 +00:00
return LoadACLPolicyFromBytes ( policyBytes )
2023-05-10 08:19:16 +00:00
}
2024-07-18 05:38:25 +00:00
func LoadACLPolicyFromBytes ( acl [ ] byte ) ( * ACLPolicy , error ) {
2023-05-10 08:19:16 +00:00
var policy ACLPolicy
2022-02-27 08:04:48 +00:00
2024-07-18 05:38:25 +00:00
ast , err := hujson . Parse ( acl )
if err != nil {
return nil , fmt . Errorf ( "parsing hujson, err: %w" , err )
}
2022-02-27 08:04:48 +00:00
2024-07-18 05:38:25 +00:00
ast . Standardize ( )
acl = ast . Pack ( )
if err := json . Unmarshal ( acl , & policy ) ; err != nil {
return nil , fmt . Errorf ( "unmarshalling policy, err: %w" , err )
2021-07-04 11:33:00 +00:00
}
2022-02-27 08:04:48 +00:00
2021-07-03 09:55:32 +00:00
if policy . IsZero ( ) {
2023-05-21 16:37:59 +00:00
return nil , ErrEmptyPolicy
2021-07-03 09:55:32 +00:00
}
2023-05-21 16:37:59 +00:00
return & policy , nil
2022-02-03 19:00:41 +00:00
}
2024-02-23 09:59:24 +00:00
func GenerateFilterAndSSHRulesForTests (
2023-05-21 16:37:59 +00:00
policy * ACLPolicy ,
2023-09-24 11:42:05 +00:00
node * types . Node ,
peers types . Nodes ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2023-05-21 16:37:59 +00:00
) ( [ ] tailcfg . FilterRule , * tailcfg . SSHPolicy , error ) {
2023-05-31 16:45:04 +00:00
// If there is no policy defined, we default to allow all
2023-05-21 16:37:59 +00:00
if policy == nil {
2023-05-31 16:45:04 +00:00
return tailcfg . FilterAllowAll , & tailcfg . SSHPolicy { } , nil
2022-11-30 23:37:58 +00:00
}
2024-10-21 17:58:59 +00:00
rules , err := policy . CompileFilterRules ( users , append ( peers , node ) )
2021-07-04 11:24:05 +00:00
if err != nil {
2023-05-21 16:37:59 +00:00
return [ ] tailcfg . FilterRule { } , & tailcfg . SSHPolicy { } , err
2021-07-04 11:24:05 +00:00
}
2023-04-26 15:27:51 +00:00
2023-09-24 11:42:05 +00:00
log . Trace ( ) . Interface ( "ACL" , rules ) . Str ( "node" , node . GivenName ) . Msg ( "ACL rules" )
2022-02-14 14:26:54 +00:00
2024-10-21 17:58:59 +00:00
sshPolicy , err := policy . CompileSSHPolicy ( node , users , peers )
2023-06-08 17:10:09 +00:00
if err != nil {
return [ ] tailcfg . FilterRule { } , & tailcfg . SSHPolicy { } , err
}
2023-06-16 14:42:30 +00:00
2023-05-21 16:37:59 +00:00
return rules , sshPolicy , nil
2021-07-03 15:31:32 +00:00
}
2024-02-23 09:59:24 +00:00
// CompileFilterRules takes a set of nodes and an ACLPolicy and generates a
2023-04-26 09:19:47 +00:00
// set of Tailscale compatible FilterRules used to allow traffic on clients.
2024-02-23 09:59:24 +00:00
func ( pol * ACLPolicy ) CompileFilterRules (
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2024-02-23 09:59:24 +00:00
nodes types . Nodes ,
2023-01-30 08:39:27 +00:00
) ( [ ] tailcfg . FilterRule , error ) {
2024-02-23 09:59:24 +00:00
if pol == nil {
return tailcfg . FilterAllowAll , nil
}
2024-06-23 20:06:50 +00:00
var rules [ ] tailcfg . FilterRule
2021-07-03 15:31:32 +00:00
2023-04-26 09:19:47 +00:00
for index , acl := range pol . ACLs {
2021-11-14 19:32:03 +00:00
if acl . Action != "accept" {
2023-05-21 16:37:59 +00:00
return nil , ErrInvalidAction
2021-07-03 15:31:32 +00:00
}
2024-06-23 20:06:50 +00:00
var srcIPs [ ] string
2023-04-26 09:19:47 +00:00
for srcIndex , src := range acl . Sources {
2024-10-21 17:58:59 +00:00
srcs , err := pol . expandSource ( src , users , nodes )
2021-07-03 15:31:32 +00:00
if err != nil {
2024-10-21 17:58:59 +00:00
return nil , fmt . Errorf (
"parsing policy, acl index: %d->%d: %w" ,
index ,
srcIndex ,
err ,
)
2021-07-03 15:31:32 +00:00
}
2021-11-04 22:16:56 +00:00
srcIPs = append ( srcIPs , srcs ... )
2021-07-03 15:31:32 +00:00
}
2023-06-13 08:03:22 +00:00
protocols , isWildcard , err := parseProtocol ( acl . Protocol )
2022-06-08 15:43:59 +00:00
if err != nil {
2024-04-12 13:57:43 +00:00
return nil , fmt . Errorf ( "parsing policy, protocol err: %w " , err )
2022-06-08 15:43:59 +00:00
}
2021-07-04 10:35:18 +00:00
destPorts := [ ] tailcfg . NetPortRange { }
2023-06-13 08:03:22 +00:00
for _ , dest := range acl . Destinations {
alias , port , err := parseDestination ( dest )
if err != nil {
return nil , err
}
expanded , err := pol . ExpandAlias (
2023-09-24 11:42:05 +00:00
nodes ,
2024-10-21 17:58:59 +00:00
users ,
2023-06-13 08:03:22 +00:00
alias ,
2022-08-04 08:47:00 +00:00
)
2021-07-04 10:35:18 +00:00
if err != nil {
2023-06-13 08:03:22 +00:00
return nil , err
}
2021-11-14 15:46:09 +00:00
2023-06-13 08:03:22 +00:00
ports , err := expandPorts ( port , isWildcard )
if err != nil {
2021-07-04 10:35:18 +00:00
return nil , err
}
2023-06-13 08:03:22 +00:00
2024-06-23 20:06:50 +00:00
var dests [ ] tailcfg . NetPortRange
2023-06-13 08:03:22 +00:00
for _ , dest := range expanded . Prefixes ( ) {
for _ , port := range * ports {
pr := tailcfg . NetPortRange {
IP : dest . String ( ) ,
Ports : port ,
}
dests = append ( dests , pr )
}
}
2021-11-04 22:16:56 +00:00
destPorts = append ( destPorts , dests ... )
2021-07-04 10:35:18 +00:00
}
rules = append ( rules , tailcfg . FilterRule {
SrcIPs : srcIPs ,
DstPorts : destPorts ,
2022-06-08 15:43:59 +00:00
IPProto : protocols ,
2021-07-04 10:35:18 +00:00
} )
2021-07-03 15:31:32 +00:00
}
2021-11-04 22:16:56 +00:00
return rules , nil
2021-07-03 15:31:32 +00:00
}
2023-09-24 11:42:05 +00:00
// ReduceFilterRules takes a node and a set of rules and removes all rules and destinations
2023-06-16 14:42:30 +00:00
// that are not relevant to that particular node.
2023-09-24 11:42:05 +00:00
func ReduceFilterRules ( node * types . Node , rules [ ] tailcfg . FilterRule ) [ ] tailcfg . FilterRule {
2023-06-16 14:42:30 +00:00
ret := [ ] tailcfg . FilterRule { }
for _ , rule := range rules {
2023-09-24 11:42:05 +00:00
// record if the rule is actually relevant for the given node.
2024-06-23 20:06:50 +00:00
var dests [ ] tailcfg . NetPortRange
2024-04-30 05:23:16 +00:00
DEST_LOOP :
2023-06-16 14:42:30 +00:00
for _ , dest := range rule . DstPorts {
expanded , err := util . ParseIPSet ( dest . IP , nil )
// Fail closed, if we cant parse it, then we should not allow
// access.
if err != nil {
2024-04-30 05:23:16 +00:00
continue DEST_LOOP
2023-06-16 14:42:30 +00:00
}
2024-04-17 05:03:06 +00:00
if node . InIPSet ( expanded ) {
2023-06-16 14:42:30 +00:00
dests = append ( dests , dest )
2024-04-30 05:23:16 +00:00
continue DEST_LOOP
2023-06-16 14:42:30 +00:00
}
2024-01-18 16:30:25 +00:00
// If the node exposes routes, ensure they are note removed
// when the filters are reduced.
if node . Hostinfo != nil {
if len ( node . Hostinfo . RoutableIPs ) > 0 {
for _ , routableIP := range node . Hostinfo . RoutableIPs {
2024-04-30 05:23:16 +00:00
if expanded . OverlapsPrefix ( routableIP ) {
2024-01-18 16:30:25 +00:00
dests = append ( dests , dest )
2024-04-30 05:23:16 +00:00
continue DEST_LOOP
2024-01-18 16:30:25 +00:00
}
}
}
}
2023-06-16 14:42:30 +00:00
}
if len ( dests ) > 0 {
ret = append ( ret , tailcfg . FilterRule {
SrcIPs : rule . SrcIPs ,
DstPorts : dests ,
IPProto : rule . IPProto ,
} )
}
}
return ret
}
2024-02-23 09:59:24 +00:00
func ( pol * ACLPolicy ) CompileSSHPolicy (
2023-09-24 11:42:05 +00:00
node * types . Node ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2023-09-24 11:42:05 +00:00
peers types . Nodes ,
2024-02-23 09:59:24 +00:00
) ( * tailcfg . SSHPolicy , error ) {
if pol == nil {
return nil , nil
}
2024-06-23 20:06:50 +00:00
var rules [ ] * tailcfg . SSHRule
2022-09-30 18:44:23 +00:00
acceptAction := tailcfg . SSHAction {
Message : "" ,
Reject : false ,
Accept : true ,
SessionDuration : 0 ,
2024-09-23 09:59:16 +00:00
AllowAgentForwarding : true ,
2022-09-30 18:44:23 +00:00
HoldAndDelegate : "" ,
AllowLocalPortForwarding : true ,
}
rejectAction := tailcfg . SSHAction {
Message : "" ,
Reject : true ,
Accept : false ,
SessionDuration : 0 ,
AllowAgentForwarding : false ,
HoldAndDelegate : "" ,
AllowLocalPortForwarding : false ,
}
2023-06-08 17:50:59 +00:00
for index , sshACL := range pol . SSHs {
var dest netipx . IPSetBuilder
for _ , src := range sshACL . Destinations {
2024-10-21 17:58:59 +00:00
expanded , err := pol . ExpandAlias ( append ( peers , node ) , users , src )
2023-06-08 17:50:59 +00:00
if err != nil {
return nil , err
}
dest . AddSet ( expanded )
}
destSet , err := dest . IPSet ( )
if err != nil {
return nil , err
}
2024-04-17 05:03:06 +00:00
if ! node . InIPSet ( destSet ) {
2023-06-08 17:50:59 +00:00
continue
}
2022-09-30 18:44:23 +00:00
action := rejectAction
switch sshACL . Action {
case "accept" :
action = acceptAction
case "check" :
checkAction , err := sshCheckAction ( sshACL . CheckPeriod )
if err != nil {
2024-10-21 17:58:59 +00:00
return nil , fmt . Errorf (
"parsing SSH policy, parsing check duration, index: %d: %w" ,
index ,
err ,
)
2022-09-30 18:44:23 +00:00
} else {
action = * checkAction
}
default :
2024-10-21 17:58:59 +00:00
return nil , fmt . Errorf (
"parsing SSH policy, unknown action %q, index: %d: %w" ,
sshACL . Action ,
index ,
err ,
)
2022-09-30 18:44:23 +00:00
}
principals := make ( [ ] * tailcfg . SSHPrincipal , 0 , len ( sshACL . Sources ) )
for innerIndex , rawSrc := range sshACL . Sources {
2023-04-28 14:11:02 +00:00
if isWildcard ( rawSrc ) {
2022-09-30 18:44:23 +00:00
principals = append ( principals , & tailcfg . SSHPrincipal {
2023-04-28 14:11:02 +00:00
Any : true ,
2022-09-30 18:44:23 +00:00
} )
2023-04-28 14:11:02 +00:00
} else if isGroup ( rawSrc ) {
2023-06-19 07:17:50 +00:00
users , err := pol . expandUsersFromGroup ( rawSrc )
2023-04-28 14:11:02 +00:00
if err != nil {
2024-04-12 13:57:43 +00:00
return nil , fmt . Errorf ( "parsing SSH policy, expanding user from group, index: %d->%d: %w" , index , innerIndex , err )
2023-04-28 14:11:02 +00:00
}
for _ , user := range users {
principals = append ( principals , & tailcfg . SSHPrincipal {
UserLogin : user ,
} )
}
} else {
2023-06-08 17:50:59 +00:00
expandedSrcs , err := pol . ExpandAlias (
peers ,
2024-10-21 17:58:59 +00:00
users ,
2023-04-28 14:11:02 +00:00
rawSrc ,
)
if err != nil {
2024-04-12 13:57:43 +00:00
return nil , fmt . Errorf ( "parsing SSH policy, expanding alias, index: %d->%d: %w" , index , innerIndex , err )
2023-04-28 14:11:02 +00:00
}
for _ , expandedSrc := range expandedSrcs . Prefixes ( ) {
principals = append ( principals , & tailcfg . SSHPrincipal {
NodeIP : expandedSrc . Addr ( ) . String ( ) ,
} )
}
2022-09-30 18:44:23 +00:00
}
}
userMap := make ( map [ string ] string , len ( sshACL . Users ) )
for _ , user := range sshACL . Users {
userMap [ user ] = "="
}
rules = append ( rules , & tailcfg . SSHRule {
2023-04-28 14:11:02 +00:00
Principals : principals ,
SSHUsers : userMap ,
Action : & action ,
2022-09-30 18:44:23 +00:00
} )
}
2024-02-23 09:59:24 +00:00
return & tailcfg . SSHPolicy {
Rules : rules ,
} , nil
2022-09-30 18:44:23 +00:00
}
func sshCheckAction ( duration string ) ( * tailcfg . SSHAction , error ) {
sessionLength , err := time . ParseDuration ( duration )
if err != nil {
return nil , err
}
return & tailcfg . SSHAction {
Message : "" ,
Reject : false ,
Accept : true ,
SessionDuration : sessionLength ,
2024-09-23 09:59:16 +00:00
AllowAgentForwarding : true ,
2022-09-30 18:44:23 +00:00
HoldAndDelegate : "" ,
AllowLocalPortForwarding : true ,
} , nil
}
2023-06-12 13:59:05 +00:00
func parseDestination ( dest string ) ( string , string , error ) {
var tokens [ ] string
2023-04-16 10:26:35 +00:00
// Check if there is a IPv4/6:Port combination, IPv6 has more than
// three ":".
tokens = strings . Split ( dest , ":" )
2021-11-15 17:24:24 +00:00
if len ( tokens ) < expectedTokenItems || len ( tokens ) > 3 {
2023-04-16 10:26:35 +00:00
port := tokens [ len ( tokens ) - 1 ]
maybeIPv6Str := strings . TrimSuffix ( dest , ":" + port )
log . Trace ( ) . Str ( "maybeIPv6Str" , maybeIPv6Str ) . Msg ( "" )
2023-05-20 09:53:01 +00:00
filteredMaybeIPv6Str := maybeIPv6Str
if strings . Contains ( maybeIPv6Str , "/" ) {
networkParts := strings . Split ( maybeIPv6Str , "/" )
filteredMaybeIPv6Str = networkParts [ 0 ]
}
if maybeIPv6 , err := netip . ParseAddr ( filteredMaybeIPv6Str ) ; err != nil && ! maybeIPv6 . Is6 ( ) {
2023-04-16 10:26:35 +00:00
log . Trace ( ) . Err ( err ) . Msg ( "trying to parse as IPv6" )
2023-06-12 13:59:05 +00:00
return "" , "" , fmt . Errorf (
2023-04-16 10:26:35 +00:00
"failed to parse destination, tokens %v: %w" ,
tokens ,
2023-05-21 16:37:59 +00:00
ErrInvalidPortFormat ,
2023-04-16 10:26:35 +00:00
)
} else {
tokens = [ ] string { maybeIPv6Str , port }
}
2021-07-04 10:35:18 +00:00
}
var alias string
// We can have here stuff like:
// git-server:*
// 192.168.1.0/24:22
2023-04-16 10:26:35 +00:00
// fd7a:115c:a1e0::2:22
// fd7a:115c:a1e0::2/128:22
2021-07-04 10:35:18 +00:00
// tag:montreal-webserver:80,443
// tag:api-server:443
// example-host-1:*
2021-11-15 17:24:24 +00:00
if len ( tokens ) == expectedTokenItems {
2021-07-04 10:35:18 +00:00
alias = tokens [ 0 ]
} else {
alias = fmt . Sprintf ( "%s:%s" , tokens [ 0 ] , tokens [ 1 ] )
}
2023-06-12 13:59:05 +00:00
return alias , tokens [ len ( tokens ) - 1 ] , nil
2021-07-04 10:35:18 +00:00
}
2022-06-08 15:43:59 +00:00
// parseProtocol reads the proto field of the ACL and generates a list of
// protocols that will be allowed, following the IANA IP protocol number
// https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
//
// If the ACL proto field is empty, it allows ICMPv4, ICMPv6, TCP, and UDP,
// as per Tailscale behaviour (see tailcfg.FilterRule).
//
// Also returns a boolean indicating if the protocol
// requires all the destinations to use wildcard as port number (only TCP,
// UDP and SCTP support specifying ports).
func parseProtocol ( protocol string ) ( [ ] int , bool , error ) {
switch protocol {
case "" :
2022-12-05 19:12:33 +00:00
return nil , false , nil
2022-06-08 15:43:59 +00:00
case "igmp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolIGMP } , true , nil
2022-06-08 15:43:59 +00:00
case "ipv4" , "ip-in-ip" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolIPv4 } , true , nil
2022-06-08 15:43:59 +00:00
case "tcp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolTCP } , false , nil
2022-06-08 15:43:59 +00:00
case "egp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolEGP } , true , nil
2022-06-08 15:43:59 +00:00
case "igp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolIGP } , true , nil
2022-06-08 15:43:59 +00:00
case "udp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolUDP } , false , nil
2022-06-08 15:43:59 +00:00
case "gre" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolGRE } , true , nil
2022-06-08 15:43:59 +00:00
case "esp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolESP } , true , nil
2022-06-08 15:43:59 +00:00
case "ah" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolAH } , true , nil
2022-06-08 15:43:59 +00:00
case "sctp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolSCTP } , false , nil
2022-06-08 15:43:59 +00:00
case "icmp" :
2022-06-11 12:09:08 +00:00
return [ ] int { protocolICMP , protocolIPv6ICMP } , true , nil
2022-06-08 15:43:59 +00:00
default :
protocolNumber , err := strconv . Atoi ( protocol )
if err != nil {
2024-04-12 13:57:43 +00:00
return nil , false , fmt . Errorf ( "parsing protocol number: %w" , err )
2022-06-08 15:43:59 +00:00
}
2022-08-04 08:47:00 +00:00
needsWildcard := protocolNumber != protocolTCP &&
protocolNumber != protocolUDP &&
protocolNumber != protocolSCTP
2022-06-08 15:43:59 +00:00
return [ ] int { protocolNumber } , needsWildcard , nil
}
}
2023-06-19 07:17:50 +00:00
// expandSource returns a set of Source IPs that would be associated
// with the given src alias.
func ( pol * ACLPolicy ) expandSource (
src string ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-06-19 07:17:50 +00:00
) ( [ ] string , error ) {
2024-10-21 17:58:59 +00:00
ipSet , err := pol . ExpandAlias ( nodes , users , src )
2023-06-19 07:17:50 +00:00
if err != nil {
return [ ] string { } , err
}
2024-06-23 20:06:50 +00:00
var prefixes [ ] string
2023-06-19 07:17:50 +00:00
for _ , prefix := range ipSet . Prefixes ( ) {
prefixes = append ( prefixes , prefix . String ( ) )
}
return prefixes , nil
}
2022-02-05 16:18:39 +00:00
// expandalias has an input of either
2023-01-17 16:43:44 +00:00
// - a user
2022-02-05 16:18:39 +00:00
// - a group
// - a tag
2023-01-30 08:39:27 +00:00
// - a host
2023-04-16 10:26:35 +00:00
// - an ip
// - a cidr
2024-04-30 05:23:16 +00:00
// - an autogroup
2022-02-14 14:26:54 +00:00
// and transform these in IPAddresses.
2023-05-21 16:37:59 +00:00
func ( pol * ACLPolicy ) ExpandAlias (
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2022-02-14 14:54:51 +00:00
alias string ,
2023-04-28 14:11:02 +00:00
) ( * netipx . IPSet , error ) {
if isWildcard ( alias ) {
2023-05-21 16:37:59 +00:00
return util . ParseIPSet ( "*" , nil )
2021-07-03 15:31:32 +00:00
}
2023-04-28 14:11:02 +00:00
build := netipx . IPSetBuilder { }
2022-03-02 20:46:02 +00:00
log . Debug ( ) .
Str ( "alias" , alias ) .
Msg ( "Expanding" )
2023-04-26 08:58:26 +00:00
// if alias is a group
2023-04-28 14:11:02 +00:00
if isGroup ( alias ) {
2024-10-21 17:58:59 +00:00
return pol . expandIPsFromGroup ( alias , users , nodes )
2021-07-03 15:31:32 +00:00
}
2023-04-26 08:58:26 +00:00
// if alias is a tag
2023-04-28 14:11:02 +00:00
if isTag ( alias ) {
2024-10-21 17:58:59 +00:00
return pol . expandIPsFromTag ( alias , users , nodes )
2021-07-03 15:31:32 +00:00
}
2024-04-30 05:23:16 +00:00
if isAutoGroup ( alias ) {
return expandAutoGroup ( alias )
}
2023-01-17 16:43:44 +00:00
// if alias is a user
2024-10-21 17:58:59 +00:00
if ips , err := pol . expandIPsFromUser ( alias , users , nodes ) ; ips != nil {
2023-04-28 14:11:02 +00:00
return ips , err
2021-07-03 15:31:32 +00:00
}
2022-02-07 15:12:05 +00:00
// if alias is an host
2023-04-26 12:04:12 +00:00
// Note, this is recursive.
2023-04-26 08:58:26 +00:00
if h , ok := pol . Hosts [ alias ] ; ok {
2023-05-21 16:37:59 +00:00
log . Trace ( ) . Str ( "host" , h . String ( ) ) . Msg ( "ExpandAlias got hosts entry" )
2023-04-16 10:26:35 +00:00
2024-10-21 17:58:59 +00:00
return pol . ExpandAlias ( nodes , users , h . String ( ) )
2021-07-03 15:31:32 +00:00
}
2022-02-07 15:12:05 +00:00
// if alias is an IP
2023-04-16 10:26:35 +00:00
if ip , err := netip . ParseAddr ( alias ) ; err == nil {
2023-09-24 11:42:05 +00:00
return pol . expandIPsFromSingleIP ( ip , nodes )
2021-07-03 15:31:32 +00:00
}
2023-04-26 08:58:26 +00:00
// if alias is an IP Prefix (CIDR)
if prefix , err := netip . ParsePrefix ( alias ) ; err == nil {
2023-09-24 11:42:05 +00:00
return pol . expandIPsFromIPPrefix ( prefix , nodes )
2021-07-03 15:31:32 +00:00
}
2022-03-02 20:46:02 +00:00
log . Warn ( ) . Msgf ( "No IPs found with the alias %v" , alias )
2023-04-28 14:11:02 +00:00
return build . IPSet ( )
2021-07-03 09:55:32 +00:00
}
2021-07-04 10:35:18 +00:00
2022-02-07 15:12:05 +00:00
// excludeCorrectlyTaggedNodes will remove from the list of input nodes the ones
2023-01-17 16:43:44 +00:00
// that are correctly tagged since they should not be listed as being in the user
// we assume in this function that we only have nodes from 1 user.
2024-10-02 09:41:58 +00:00
//
// TODO(kradalby): It is quite hard to understand what this function is doing,
// it seems like it trying to ensure that we dont include nodes that are tagged
// when we look up the nodes owned by a user.
2024-11-22 15:54:58 +00:00
// This should be refactored to be more clear as part of the Tags work in #1369.
2022-02-14 14:54:51 +00:00
func excludeCorrectlyTaggedNodes (
2023-04-26 08:58:26 +00:00
aclPolicy * ACLPolicy ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-01-17 16:43:44 +00:00
user string ,
2023-09-24 11:42:05 +00:00
) types . Nodes {
2024-06-23 20:06:50 +00:00
var out types . Nodes
var tags [ ] string
2022-08-11 12:12:45 +00:00
for tag := range aclPolicy . TagOwners {
2023-06-19 07:17:50 +00:00
owners , _ := expandOwnersFromTag ( aclPolicy , user )
2023-01-17 16:43:44 +00:00
ns := append ( owners , user )
2024-10-02 07:06:09 +00:00
if slices . Contains ( ns , user ) {
2022-02-07 15:12:05 +00:00
tags = append ( tags , tag )
}
2022-02-05 16:18:39 +00:00
}
2023-09-24 11:42:05 +00:00
// for each node if tag is in tags list, don't append it.
for _ , node := range nodes {
2022-02-07 15:12:05 +00:00
found := false
2023-11-21 17:20:06 +00:00
2024-10-02 09:41:58 +00:00
if node . Hostinfo != nil {
for _ , t := range node . Hostinfo . RequestTags {
if slices . Contains ( tags , t ) {
found = true
2022-02-14 14:26:54 +00:00
2024-10-02 09:41:58 +00:00
break
}
2022-02-05 16:18:39 +00:00
}
}
2024-10-02 09:41:58 +00:00
2023-09-24 11:42:05 +00:00
if len ( node . ForcedTags ) > 0 {
2022-04-15 16:01:13 +00:00
found = true
}
2022-02-07 15:12:05 +00:00
if ! found {
2023-09-24 11:42:05 +00:00
out = append ( out , node )
2022-02-05 16:18:39 +00:00
}
}
2022-02-14 14:26:54 +00:00
2022-03-02 08:15:14 +00:00
return out
2022-02-05 16:18:39 +00:00
}
2023-06-13 08:03:22 +00:00
func expandPorts ( portsStr string , isWild bool ) ( * [ ] tailcfg . PortRange , error ) {
2023-04-28 14:11:02 +00:00
if isWildcard ( portsStr ) {
2021-11-14 17:31:51 +00:00
return & [ ] tailcfg . PortRange {
2021-11-15 17:24:24 +00:00
{ First : portRangeBegin , Last : portRangeEnd } ,
2021-11-14 17:31:51 +00:00
} , nil
2021-07-04 10:35:18 +00:00
}
2023-06-13 08:03:22 +00:00
if isWild {
2023-05-21 16:37:59 +00:00
return nil , ErrWildcardIsNeeded
2022-06-08 15:43:59 +00:00
}
2024-06-23 20:06:50 +00:00
var ports [ ] tailcfg . PortRange
2021-11-14 19:32:03 +00:00
for _ , portStr := range strings . Split ( portsStr , "," ) {
2023-04-16 10:26:35 +00:00
log . Trace ( ) . Msgf ( "parsing portstring: %s" , portStr )
2021-11-14 19:32:03 +00:00
rang := strings . Split ( portStr , "-" )
2021-11-14 17:44:37 +00:00
switch len ( rang ) {
case 1 :
2023-05-11 07:09:18 +00:00
port , err := strconv . ParseUint ( rang [ 0 ] , util . Base10 , util . BitSize16 )
2021-07-04 10:35:18 +00:00
if err != nil {
return nil , err
}
ports = append ( ports , tailcfg . PortRange {
2021-11-14 19:32:03 +00:00
First : uint16 ( port ) ,
Last : uint16 ( port ) ,
2021-07-04 10:35:18 +00:00
} )
2021-11-14 17:44:37 +00:00
2021-11-15 17:24:24 +00:00
case expectedTokenItems :
2023-05-11 07:09:18 +00:00
start , err := strconv . ParseUint ( rang [ 0 ] , util . Base10 , util . BitSize16 )
2021-07-04 10:35:18 +00:00
if err != nil {
return nil , err
}
2023-05-11 07:09:18 +00:00
last , err := strconv . ParseUint ( rang [ 1 ] , util . Base10 , util . BitSize16 )
2021-07-04 10:35:18 +00:00
if err != nil {
return nil , err
}
ports = append ( ports , tailcfg . PortRange {
First : uint16 ( start ) ,
Last : uint16 ( last ) ,
} )
2021-11-14 17:44:37 +00:00
default :
2023-05-21 16:37:59 +00:00
return nil , ErrInvalidPortFormat
2021-07-04 10:35:18 +00:00
}
}
2021-11-14 15:46:09 +00:00
2021-07-04 10:35:18 +00:00
return & ports , nil
}
2022-02-07 15:12:05 +00:00
2023-06-19 07:17:50 +00:00
// expandOwnersFromTag will return a list of user. An owner can be either a user or a group
2022-02-14 14:26:54 +00:00
// a group cannot be composed of groups.
2023-06-19 07:17:50 +00:00
func expandOwnersFromTag (
2023-04-26 08:58:26 +00:00
pol * ACLPolicy ,
2022-03-01 20:01:46 +00:00
tag string ,
) ( [ ] string , error ) {
2024-01-04 20:26:49 +00:00
noTagErr := fmt . Errorf (
"%w. %v isn't owned by a TagOwner. Please add one first. https://tailscale.com/kb/1018/acls/#tag-owners" ,
ErrInvalidTag ,
tag ,
)
if pol == nil {
return [ ] string { } , noTagErr
}
2022-02-07 15:12:05 +00:00
var owners [ ] string
2023-04-26 08:58:26 +00:00
ows , ok := pol . TagOwners [ tag ]
2022-02-07 15:12:05 +00:00
if ! ok {
2024-01-04 20:26:49 +00:00
return [ ] string { } , noTagErr
2022-02-07 15:12:05 +00:00
}
2022-02-14 14:26:54 +00:00
for _ , owner := range ows {
2023-04-28 14:11:02 +00:00
if isGroup ( owner ) {
2023-06-19 07:17:50 +00:00
gs , err := pol . expandUsersFromGroup ( owner )
2022-02-07 15:12:05 +00:00
if err != nil {
return [ ] string { } , err
}
owners = append ( owners , gs ... )
} else {
2022-02-14 14:26:54 +00:00
owners = append ( owners , owner )
2022-02-07 15:12:05 +00:00
}
}
2022-02-14 14:26:54 +00:00
2022-02-07 15:12:05 +00:00
return owners , nil
}
2023-06-19 07:17:50 +00:00
// expandUsersFromGroup will return the list of user inside the group
2022-02-14 14:26:54 +00:00
// after some validation.
2023-06-19 07:17:50 +00:00
func ( pol * ACLPolicy ) expandUsersFromGroup (
2022-03-01 20:01:46 +00:00
group string ,
) ( [ ] string , error ) {
2024-06-23 20:06:50 +00:00
var users [ ] string
2023-04-26 08:58:26 +00:00
log . Trace ( ) . Caller ( ) . Interface ( "pol" , pol ) . Msg ( "test" )
aclGroups , ok := pol . Groups [ group ]
2022-02-07 15:12:05 +00:00
if ! ok {
2022-02-14 14:54:51 +00:00
return [ ] string { } , fmt . Errorf (
"group %v isn't registered. %w" ,
group ,
2023-05-21 16:37:59 +00:00
ErrInvalidGroup ,
2022-02-14 14:54:51 +00:00
)
2022-02-07 15:12:05 +00:00
}
2022-03-01 20:01:46 +00:00
for _ , group := range aclGroups {
2023-04-28 14:11:02 +00:00
if isGroup ( group ) {
2022-02-14 14:54:51 +00:00
return [ ] string { } , fmt . Errorf (
"%w. A group cannot be composed of groups. https://tailscale.com/kb/1018/acls/#groups" ,
2023-05-21 16:37:59 +00:00
ErrInvalidGroup ,
2022-02-14 14:54:51 +00:00
)
2022-02-07 15:12:05 +00:00
}
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
users = append ( users , group )
2023-04-26 08:58:26 +00:00
}
return users , nil
}
2023-06-19 07:17:50 +00:00
func ( pol * ACLPolicy ) expandIPsFromGroup (
2023-04-26 08:58:26 +00:00
group string ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-04-28 14:11:02 +00:00
) ( * netipx . IPSet , error ) {
2024-06-23 20:06:50 +00:00
var build netipx . IPSetBuilder
2023-04-26 08:58:26 +00:00
2024-10-21 17:58:59 +00:00
userTokens , err := pol . expandUsersFromGroup ( group )
2023-04-26 08:58:26 +00:00
if err != nil {
2023-04-28 14:11:02 +00:00
return & netipx . IPSet { } , err
2023-04-26 08:58:26 +00:00
}
2024-10-21 17:58:59 +00:00
for _ , user := range userTokens {
filteredNodes := filterNodesByUser ( nodes , users , user )
2023-09-24 11:42:05 +00:00
for _ , node := range filteredNodes {
2024-04-17 05:03:06 +00:00
node . AppendToIPSet ( & build )
2023-04-26 08:58:26 +00:00
}
}
2023-04-28 14:11:02 +00:00
return build . IPSet ( )
2023-04-26 08:58:26 +00:00
}
2023-06-19 07:17:50 +00:00
func ( pol * ACLPolicy ) expandIPsFromTag (
2023-04-26 08:58:26 +00:00
alias string ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-04-28 14:11:02 +00:00
) ( * netipx . IPSet , error ) {
2024-06-23 20:06:50 +00:00
var build netipx . IPSetBuilder
2023-04-26 08:58:26 +00:00
// check for forced tags
2023-09-24 11:42:05 +00:00
for _ , node := range nodes {
2024-10-02 07:06:09 +00:00
if slices . Contains ( node . ForcedTags , alias ) {
2024-04-17 05:03:06 +00:00
node . AppendToIPSet ( & build )
2023-04-26 08:58:26 +00:00
}
}
// find tag owners
2023-06-19 07:17:50 +00:00
owners , err := expandOwnersFromTag ( pol , alias )
2023-04-26 08:58:26 +00:00
if err != nil {
2023-05-21 16:37:59 +00:00
if errors . Is ( err , ErrInvalidTag ) {
2023-04-28 14:11:02 +00:00
ipSet , _ := build . IPSet ( )
if len ( ipSet . Prefixes ( ) ) == 0 {
return ipSet , fmt . Errorf (
2023-04-26 08:58:26 +00:00
"%w. %v isn't owned by a TagOwner and no forced tags are defined" ,
2023-05-21 16:37:59 +00:00
ErrInvalidTag ,
2023-04-26 08:58:26 +00:00
alias ,
)
}
2023-04-28 14:11:02 +00:00
return build . IPSet ( )
2023-04-26 08:58:26 +00:00
} else {
2023-04-28 14:11:02 +00:00
return nil , err
2023-04-26 08:58:26 +00:00
}
}
2023-09-24 11:42:05 +00:00
// filter out nodes per tag owner
2023-04-26 08:58:26 +00:00
for _ , user := range owners {
2024-10-21 17:58:59 +00:00
nodes := filterNodesByUser ( nodes , users , user )
2023-09-24 11:42:05 +00:00
for _ , node := range nodes {
2023-11-21 17:20:06 +00:00
if node . Hostinfo == nil {
continue
}
2024-10-02 07:06:09 +00:00
if slices . Contains ( node . Hostinfo . RequestTags , alias ) {
2024-04-17 05:03:06 +00:00
node . AppendToIPSet ( & build )
2023-04-26 08:58:26 +00:00
}
}
}
2023-04-28 14:11:02 +00:00
return build . IPSet ( )
2023-04-26 08:58:26 +00:00
}
2023-06-19 07:17:50 +00:00
func ( pol * ACLPolicy ) expandIPsFromUser (
2023-04-26 08:58:26 +00:00
user string ,
2024-10-21 17:58:59 +00:00
users [ ] types . User ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-04-28 14:11:02 +00:00
) ( * netipx . IPSet , error ) {
2024-06-23 20:06:50 +00:00
var build netipx . IPSetBuilder
2023-04-26 08:58:26 +00:00
2024-10-21 17:58:59 +00:00
filteredNodes := filterNodesByUser ( nodes , users , user )
2023-09-24 11:42:05 +00:00
filteredNodes = excludeCorrectlyTaggedNodes ( pol , filteredNodes , user )
2023-04-26 08:58:26 +00:00
2023-09-24 11:42:05 +00:00
// shortcurcuit if we have no nodes to get ips from.
if len ( filteredNodes ) == 0 {
2024-07-18 05:38:25 +00:00
return nil , nil // nolint
2023-04-26 08:58:26 +00:00
}
2023-09-24 11:42:05 +00:00
for _ , node := range filteredNodes {
2024-04-17 05:03:06 +00:00
node . AppendToIPSet ( & build )
2023-04-28 14:11:02 +00:00
}
return build . IPSet ( )
2023-04-26 08:58:26 +00:00
}
2023-06-19 07:17:50 +00:00
func ( pol * ACLPolicy ) expandIPsFromSingleIP (
2023-04-26 08:58:26 +00:00
ip netip . Addr ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-04-28 14:11:02 +00:00
) ( * netipx . IPSet , error ) {
2023-05-21 16:37:59 +00:00
log . Trace ( ) . Str ( "ip" , ip . String ( ) ) . Msg ( "ExpandAlias got ip" )
2023-04-26 08:58:26 +00:00
2023-09-24 11:42:05 +00:00
matches := nodes . FilterByIP ( ip )
2023-04-26 08:58:26 +00:00
2024-06-23 20:06:50 +00:00
var build netipx . IPSetBuilder
2023-04-28 14:11:02 +00:00
build . Add ( ip )
2023-09-24 11:42:05 +00:00
for _ , node := range matches {
2024-04-17 05:03:06 +00:00
node . AppendToIPSet ( & build )
2023-04-26 08:58:26 +00:00
}
2023-04-28 14:11:02 +00:00
return build . IPSet ( )
2023-04-26 08:58:26 +00:00
}
2023-06-19 07:17:50 +00:00
func ( pol * ACLPolicy ) expandIPsFromIPPrefix (
2023-04-26 08:58:26 +00:00
prefix netip . Prefix ,
2023-09-24 11:42:05 +00:00
nodes types . Nodes ,
2023-04-28 14:11:02 +00:00
) ( * netipx . IPSet , error ) {
2023-04-26 08:58:26 +00:00
log . Trace ( ) . Str ( "prefix" , prefix . String ( ) ) . Msg ( "expandAlias got prefix" )
2024-06-23 20:06:50 +00:00
var build netipx . IPSetBuilder
2023-04-28 14:11:02 +00:00
build . AddPrefix ( prefix )
2023-04-26 08:58:26 +00:00
// This is suboptimal and quite expensive, but if we only add the prefix, we will miss all the relevant IPv6
// addresses for the hosts that belong to tailscale. This doesnt really affect stuff like subnet routers.
2023-09-24 11:42:05 +00:00
for _ , node := range nodes {
2024-04-17 05:03:06 +00:00
for _ , ip := range node . IPs ( ) {
2023-04-26 08:58:26 +00:00
// log.Trace().
2023-09-24 11:42:05 +00:00
// Msgf("checking if node ip (%s) is part of prefix (%s): %v, is single ip prefix (%v), addr: %s", ip.String(), prefix.String(), prefix.Contains(ip), prefix.IsSingleIP(), prefix.Addr().String())
2023-04-26 08:58:26 +00:00
if prefix . Contains ( ip ) {
2024-04-17 05:03:06 +00:00
node . AppendToIPSet ( & build )
2023-04-26 08:58:26 +00:00
}
}
2022-02-07 15:12:05 +00:00
}
2022-02-14 14:26:54 +00:00
2023-04-28 14:11:02 +00:00
return build . IPSet ( )
}
2024-04-30 05:23:16 +00:00
func expandAutoGroup ( alias string ) ( * netipx . IPSet , error ) {
switch {
case strings . HasPrefix ( alias , "autogroup:internet" ) :
return theInternet ( ) , nil
default :
return nil , fmt . Errorf ( "unknown autogroup %q" , alias )
}
}
2023-04-28 14:11:02 +00:00
func isWildcard ( str string ) bool {
return str == "*"
}
func isGroup ( str string ) bool {
return strings . HasPrefix ( str , "group:" )
}
func isTag ( str string ) bool {
return strings . HasPrefix ( str , "tag:" )
2022-02-07 15:12:05 +00:00
}
2023-05-21 16:37:59 +00:00
2024-04-30 05:23:16 +00:00
func isAutoGroup ( str string ) bool {
return strings . HasPrefix ( str , "autogroup:" )
}
2023-09-24 11:42:05 +00:00
// TagsOfNode will return the tags of the current node.
2023-05-21 16:37:59 +00:00
// Invalid tags are tags added by a user on a node, and that user doesn't have authority to add this tag.
// Valid tags are tags added by a user that is allowed in the ACL policy to add this tag.
2023-09-24 11:42:05 +00:00
func ( pol * ACLPolicy ) TagsOfNode (
node * types . Node ,
2023-05-21 16:37:59 +00:00
) ( [ ] string , [ ] string ) {
2024-06-23 20:06:50 +00:00
var validTags [ ] string
var invalidTags [ ] string
2023-05-21 16:37:59 +00:00
2024-02-08 16:28:19 +00:00
// TODO(kradalby): Why is this sometimes nil? coming from tailNode?
if node == nil {
return validTags , invalidTags
}
2023-05-21 16:37:59 +00:00
validTagMap := make ( map [ string ] bool )
invalidTagMap := make ( map [ string ] bool )
2024-02-08 16:28:19 +00:00
if node . Hostinfo != nil {
for _ , tag := range node . Hostinfo . RequestTags {
owners , err := expandOwnersFromTag ( pol , tag )
if errors . Is ( err , ErrInvalidTag ) {
invalidTagMap [ tag ] = true
2023-05-21 16:37:59 +00:00
2024-02-08 16:28:19 +00:00
continue
}
var found bool
for _ , owner := range owners {
Redo OIDC configuration (#2020)
expand user, add claims to user
This commit expands the user table with additional fields that
can be retrieved from OIDC providers (and other places) and
uses this data in various tailscale response objects if it is
available.
This is the beginning of implementing
https://docs.google.com/document/d/1X85PMxIaVWDF6T_UPji3OeeUqVBcGj_uHRM5CI-AwlY/edit
trying to make OIDC more coherant and maintainable in addition
to giving the user a better experience and integration with a
provider.
remove usernames in magic dns, normalisation of emails
this commit removes the option to have usernames as part of MagicDNS
domains and headscale will now align with Tailscale, where there is a
root domain, and the machine name.
In addition, the various normalisation functions for dns names has been
made lighter not caring about username and special character that wont
occur.
Email are no longer normalised as part of the policy processing.
untagle oidc and regcache, use typed cache
This commits stops reusing the registration cache for oidc
purposes and switches the cache to be types and not use any
allowing the removal of a bunch of casting.
try to make reauth/register branches clearer in oidc
Currently there was a function that did a bunch of stuff,
finding the machine key, trying to find the node, reauthing
the node, returning some status, and it was called validate
which was very confusing.
This commit tries to split this into what to do if the node
exists, if it needs to register etc.
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
2024-10-02 12:50:17 +00:00
if node . User . Username ( ) == owner {
2024-02-08 16:28:19 +00:00
found = true
}
}
if found {
validTagMap [ tag ] = true
} else {
invalidTagMap [ tag ] = true
2023-05-21 16:37:59 +00:00
}
}
2024-02-08 16:28:19 +00:00
for tag := range invalidTagMap {
invalidTags = append ( invalidTags , tag )
}
for tag := range validTagMap {
validTags = append ( validTags , tag )
2023-05-21 16:37:59 +00:00
}
}
return validTags , invalidTags
}
2024-10-21 17:58:59 +00:00
// filterNodesByUser returns a list of nodes that match the given userToken from a
// policy.
// Matching nodes are determined by first matching the user token to a user by checking:
// - If it is an ID that mactches the user database ID
// - It is the Provider Identifier from OIDC
// - It matches the username or email of a user
//
// If the token matches more than one user, zero nodes will returned.
func filterNodesByUser ( nodes types . Nodes , users [ ] types . User , userToken string ) types . Nodes {
2024-06-23 20:06:50 +00:00
var out types . Nodes
2024-10-21 17:58:59 +00:00
var potentialUsers [ ] types . User
for _ , user := range users {
2024-11-18 14:58:42 +00:00
if user . ProviderIdentifier . Valid && user . ProviderIdentifier . String == userToken {
2024-11-18 01:19:23 +00:00
// If a user is matching with a known unique field,
// disgard all other users and only keep the current
// user.
potentialUsers = [ ] types . User { user }
2024-10-21 17:58:59 +00:00
break
}
if user . Email == userToken {
potentialUsers = append ( potentialUsers , user )
}
if user . Name == userToken {
potentialUsers = append ( potentialUsers , user )
}
}
if len ( potentialUsers ) != 1 {
return nil
}
user := potentialUsers [ 0 ]
2023-09-24 11:42:05 +00:00
for _ , node := range nodes {
2024-10-21 17:58:59 +00:00
if node . User . ID == user . ID {
2023-09-24 11:42:05 +00:00
out = append ( out , node )
2023-06-19 07:17:50 +00:00
}
}
return out
}
2023-09-24 11:42:05 +00:00
// FilterNodesByACL returns the list of peers authorized to be accessed from a given node.
func FilterNodesByACL (
node * types . Node ,
nodes types . Nodes ,
2023-05-21 16:37:59 +00:00
filter [ ] tailcfg . FilterRule ,
2023-09-24 11:42:05 +00:00
) types . Nodes {
2024-06-23 20:06:50 +00:00
var result types . Nodes
2023-05-21 16:37:59 +00:00
2023-09-24 11:42:05 +00:00
for index , peer := range nodes {
if peer . ID == node . ID {
2023-05-21 16:37:59 +00:00
continue
}
2024-10-02 09:41:58 +00:00
log . Printf ( "Checking if %s can access %s" , node . Hostname , peer . Hostname )
2023-09-24 11:42:05 +00:00
if node . CanAccess ( filter , nodes [ index ] ) || peer . CanAccess ( filter , node ) {
2024-10-02 09:41:58 +00:00
log . Printf ( "CAN ACCESS %s can access %s" , node . Hostname , peer . Hostname )
2023-05-21 16:37:59 +00:00
result = append ( result , peer )
}
}
return result
}