mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	expand principles to correct login name
and if fix an issue where nodeip principles might not expand to all relevant IPs instead of taking the first in a prefix. Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
		
							parent
							
								
									2ac4d3fbe5
								
							
						
					
					
						commit
						64560bbf6e
					
				@ -5,6 +5,7 @@ import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"iter"
 | 
			
		||||
	"net/netip"
 | 
			
		||||
	"os"
 | 
			
		||||
	"slices"
 | 
			
		||||
@ -361,39 +362,69 @@ func (pol *ACLPolicy) CompileSSHPolicy(
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		principals := make([]*tailcfg.SSHPrincipal, 0, len(sshACL.Sources))
 | 
			
		||||
		for innerIndex, rawSrc := range sshACL.Sources {
 | 
			
		||||
			if isWildcard(rawSrc) {
 | 
			
		||||
				principals = append(principals, &tailcfg.SSHPrincipal{
 | 
			
		||||
		var principals []*tailcfg.SSHPrincipal
 | 
			
		||||
		for innerIndex, srcToken := range sshACL.Sources {
 | 
			
		||||
			if isWildcard(srcToken) {
 | 
			
		||||
				principals = []*tailcfg.SSHPrincipal{{
 | 
			
		||||
					Any: true,
 | 
			
		||||
				})
 | 
			
		||||
			} else if isGroup(rawSrc) {
 | 
			
		||||
				users, err := pol.expandUsersFromGroup(rawSrc)
 | 
			
		||||
				}}
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If the token is a group, expand the users and validate
 | 
			
		||||
			// them. Then use the .Username() to get the login name
 | 
			
		||||
			// that corresponds with the User info in the netmap.
 | 
			
		||||
			if isGroup(srcToken) {
 | 
			
		||||
				usersFromGroup, err := pol.expandUsersFromGroup(srcToken)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, fmt.Errorf("parsing SSH policy, expanding user from group, index: %d->%d: %w", index, innerIndex, err)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				for _, user := range users {
 | 
			
		||||
				for _, userStr := range usersFromGroup {
 | 
			
		||||
					user, err := findUserFromTokenOrErr(users, userStr)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						log.Trace().Err(err).Msg("user not found")
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					principals = append(principals, &tailcfg.SSHPrincipal{
 | 
			
		||||
						UserLogin: user,
 | 
			
		||||
						UserLogin: user.Username(),
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				expandedSrcs, err := pol.ExpandAlias(
 | 
			
		||||
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Try to check if the token is a user, if it is, then we
 | 
			
		||||
			// can use the .Username() to get the login name that
 | 
			
		||||
			// corresponds with the User info in the netmap.
 | 
			
		||||
			// TODO(kradalby): This is a bit of a hack, and it should go
 | 
			
		||||
			// away with the new policy where users can be reliably determined.
 | 
			
		||||
			if user, err := findUserFromTokenOrErr(users, srcToken); err == nil {
 | 
			
		||||
				principals = append(principals, &tailcfg.SSHPrincipal{
 | 
			
		||||
					UserLogin: user.Username(),
 | 
			
		||||
				})
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// This is kind of then non-ideal scenario where we dont really know
 | 
			
		||||
			// what to do with the token, so we expand it to IP addresses of nodes.
 | 
			
		||||
			// The pro here is that we have a pretty good lockdown on the mapping
 | 
			
		||||
			// between users and node, but it can explode if a user owns many nodes.
 | 
			
		||||
			ips, err := pol.ExpandAlias(
 | 
			
		||||
				peers,
 | 
			
		||||
				users,
 | 
			
		||||
					rawSrc,
 | 
			
		||||
				srcToken,
 | 
			
		||||
			)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("parsing SSH policy, expanding alias, index: %d->%d: %w", index, innerIndex, err)
 | 
			
		||||
			}
 | 
			
		||||
				for _, expandedSrc := range expandedSrcs.Prefixes() {
 | 
			
		||||
			for addr := range ipSetAll(ips) {
 | 
			
		||||
				principals = append(principals, &tailcfg.SSHPrincipal{
 | 
			
		||||
						NodeIP: expandedSrc.Addr().String(),
 | 
			
		||||
					NodeIP: addr.String(),
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		userMap := make(map[string]string, len(sshACL.Users))
 | 
			
		||||
		for _, user := range sshACL.Users {
 | 
			
		||||
@ -411,6 +442,19 @@ func (pol *ACLPolicy) CompileSSHPolicy(
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ipSetAll returns a function that iterates over all the IPs in the IPSet.
 | 
			
		||||
func ipSetAll(ipSet *netipx.IPSet) iter.Seq[netip.Addr] {
 | 
			
		||||
	return func(yield func(netip.Addr) bool) {
 | 
			
		||||
		for _, rng := range ipSet.Ranges() {
 | 
			
		||||
			for ip := rng.From(); ip.Compare(rng.To()) <= 0; ip = ip.Next() {
 | 
			
		||||
				if !yield(ip) {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sshCheckAction(duration string) (*tailcfg.SSHAction, error) {
 | 
			
		||||
	sessionLength, err := time.ParseDuration(duration)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user