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"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"iter"
 | 
				
			||||||
	"net/netip"
 | 
						"net/netip"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"slices"
 | 
						"slices"
 | 
				
			||||||
@ -361,37 +362,67 @@ func (pol *ACLPolicy) CompileSSHPolicy(
 | 
				
			|||||||
			)
 | 
								)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		principals := make([]*tailcfg.SSHPrincipal, 0, len(sshACL.Sources))
 | 
							var principals []*tailcfg.SSHPrincipal
 | 
				
			||||||
		for innerIndex, rawSrc := range sshACL.Sources {
 | 
							for innerIndex, srcToken := range sshACL.Sources {
 | 
				
			||||||
			if isWildcard(rawSrc) {
 | 
								if isWildcard(srcToken) {
 | 
				
			||||||
				principals = append(principals, &tailcfg.SSHPrincipal{
 | 
									principals = []*tailcfg.SSHPrincipal{{
 | 
				
			||||||
					Any: true,
 | 
										Any: true,
 | 
				
			||||||
				})
 | 
									}}
 | 
				
			||||||
			} else if isGroup(rawSrc) {
 | 
									break
 | 
				
			||||||
				users, err := pol.expandUsersFromGroup(rawSrc)
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 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 {
 | 
									if err != nil {
 | 
				
			||||||
					return nil, fmt.Errorf("parsing SSH policy, expanding user from group, index: %d->%d: %w", index, innerIndex, err)
 | 
										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{
 | 
										principals = append(principals, &tailcfg.SSHPrincipal{
 | 
				
			||||||
						UserLogin: user,
 | 
											UserLogin: user.Username(),
 | 
				
			||||||
					})
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				expandedSrcs, err := pol.ExpandAlias(
 | 
					 | 
				
			||||||
					peers,
 | 
					 | 
				
			||||||
					users,
 | 
					 | 
				
			||||||
					rawSrc,
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return nil, fmt.Errorf("parsing SSH policy, expanding alias, index: %d->%d: %w", index, innerIndex, err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				for _, expandedSrc := range expandedSrcs.Prefixes() {
 | 
					 | 
				
			||||||
					principals = append(principals, &tailcfg.SSHPrincipal{
 | 
					 | 
				
			||||||
						NodeIP: expandedSrc.Addr().String(),
 | 
					 | 
				
			||||||
					})
 | 
										})
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									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,
 | 
				
			||||||
 | 
									srcToken,
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, fmt.Errorf("parsing SSH policy, expanding alias, index: %d->%d: %w", index, innerIndex, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for addr := range ipSetAll(ips) {
 | 
				
			||||||
 | 
									principals = append(principals, &tailcfg.SSHPrincipal{
 | 
				
			||||||
 | 
										NodeIP: addr.String(),
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -411,6 +442,19 @@ func (pol *ACLPolicy) CompileSSHPolicy(
 | 
				
			|||||||
	}, nil
 | 
						}, 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) {
 | 
					func sshCheckAction(duration string) (*tailcfg.SSHAction, error) {
 | 
				
			||||||
	sessionLength, err := time.ParseDuration(duration)
 | 
						sessionLength, err := time.ParseDuration(duration)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user