mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Add user namespace enable flag --userns-remap in experimental build
				
					
				
			This adds the capability to turn on user namespace support when using an experimental build Docker daemon binary using the `--userns-remap` flag. Also documentation is added to the experimental docs. Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
This commit is contained in:
		
							parent
							
								
									442b45628e
								
							
						
					
					
						commit
						44e1023a93
					
				
					 7 changed files with 449 additions and 0 deletions
				
			
		
							
								
								
									
										119
									
								
								daemon/config_experimental.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								daemon/config_experimental.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,119 @@
 | 
			
		|||
// +build experimental
 | 
			
		||||
 | 
			
		||||
package daemon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/pkg/idtools"
 | 
			
		||||
	flag "github.com/docker/docker/pkg/mflag"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/user"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
 | 
			
		||||
	cmd.StringVar(&config.RemappedRoot, []string{"-userns-remap"}, "", usageFn("User/Group setting for user namespaces"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	defaultIDSpecifier string = "default"
 | 
			
		||||
	defaultRemappedID  string = "dockremap"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Parse the remapped root (user namespace) option, which can be one of:
 | 
			
		||||
//   username            - valid username from /etc/passwd
 | 
			
		||||
//   username:groupname  - valid username; valid groupname from /etc/group
 | 
			
		||||
//   uid                 - 32-bit unsigned int valid Linux UID value
 | 
			
		||||
//   uid:gid             - uid value; 32-bit unsigned int Linux GID value
 | 
			
		||||
//
 | 
			
		||||
//  If no groupname is specified, and a username is specified, an attempt
 | 
			
		||||
//  will be made to lookup a gid for that username as a groupname
 | 
			
		||||
//
 | 
			
		||||
//  If names are used, they are verified to exist in passwd/group
 | 
			
		||||
func parseRemappedRoot(usergrp string) (string, string, error) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		userID, groupID     int
 | 
			
		||||
		username, groupname string
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	idparts := strings.Split(usergrp, ":")
 | 
			
		||||
	if len(idparts) > 2 {
 | 
			
		||||
		return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
 | 
			
		||||
		// must be a uid; take it as valid
 | 
			
		||||
		userID = int(uid)
 | 
			
		||||
		luser, err := user.LookupUid(userID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
 | 
			
		||||
		}
 | 
			
		||||
		username = luser.Name
 | 
			
		||||
		if len(idparts) == 1 {
 | 
			
		||||
			// if the uid was numeric and no gid was specified, take the uid as the gid
 | 
			
		||||
			groupID = userID
 | 
			
		||||
			lgrp, err := user.LookupGid(groupID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
 | 
			
		||||
			}
 | 
			
		||||
			groupname = lgrp.Name
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		lookupName := idparts[0]
 | 
			
		||||
		// special case: if the user specified "default", they want Docker to create or
 | 
			
		||||
		// use (after creation) the "dockremap" user/group for root remapping
 | 
			
		||||
		if lookupName == defaultIDSpecifier {
 | 
			
		||||
			lookupName = defaultRemappedID
 | 
			
		||||
		}
 | 
			
		||||
		luser, err := user.LookupUser(lookupName)
 | 
			
		||||
		if err != nil && idparts[0] != defaultIDSpecifier {
 | 
			
		||||
			// error if the name requested isn't the special "dockremap" ID
 | 
			
		||||
			return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			// special case-- if the username == "default", then we have been asked
 | 
			
		||||
			// to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
 | 
			
		||||
			// ranges will be used for the user and group mappings in user namespaced containers
 | 
			
		||||
			_, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				return defaultRemappedID, defaultRemappedID, nil
 | 
			
		||||
			}
 | 
			
		||||
			return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
 | 
			
		||||
		}
 | 
			
		||||
		userID = luser.Uid
 | 
			
		||||
		username = luser.Name
 | 
			
		||||
		if len(idparts) == 1 {
 | 
			
		||||
			// we only have a string username, and no group specified; look up gid from username as group
 | 
			
		||||
			group, err := user.LookupGroup(lookupName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
 | 
			
		||||
			}
 | 
			
		||||
			groupID = group.Gid
 | 
			
		||||
			groupname = group.Name
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(idparts) == 2 {
 | 
			
		||||
		// groupname or gid is separately specified and must be resolved
 | 
			
		||||
		// to a unsigned 32-bit gid
 | 
			
		||||
		if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
 | 
			
		||||
			// must be a gid, take it as valid
 | 
			
		||||
			groupID = int(gid)
 | 
			
		||||
			lgrp, err := user.LookupGid(groupID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
 | 
			
		||||
			}
 | 
			
		||||
			groupname = lgrp.Name
 | 
			
		||||
		} else {
 | 
			
		||||
			// not a number; attempt a lookup
 | 
			
		||||
			group, err := user.LookupGroup(idparts[1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", idparts[1], err)
 | 
			
		||||
			}
 | 
			
		||||
			groupID = group.Gid
 | 
			
		||||
			groupname = idparts[1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return username, groupname, nil
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue