github.com/damirazo/docker@v1.9.0/daemon/daemon_experimental.go (about)

     1  // +build experimental
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/docker/docker/pkg/directory"
    13  	"github.com/docker/docker/pkg/idtools"
    14  	"github.com/docker/docker/runconfig"
    15  )
    16  
    17  func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
    18  	if config.ExecDriver != "native" && config.RemappedRoot != "" {
    19  		return nil, nil, fmt.Errorf("User namespace remapping is only supported with the native execdriver")
    20  	}
    21  	if runtime.GOOS == "windows" && config.RemappedRoot != "" {
    22  		return nil, nil, fmt.Errorf("User namespaces are not supported on Windows")
    23  	}
    24  
    25  	// if the daemon was started with remapped root option, parse
    26  	// the config option to the int uid,gid values
    27  	var (
    28  		uidMaps, gidMaps []idtools.IDMap
    29  	)
    30  	if config.RemappedRoot != "" {
    31  		username, groupname, err := parseRemappedRoot(config.RemappedRoot)
    32  		if err != nil {
    33  			return nil, nil, err
    34  		}
    35  		if username == "root" {
    36  			// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
    37  			// effectively
    38  			logrus.Warnf("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
    39  			return uidMaps, gidMaps, nil
    40  		}
    41  		logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
    42  		// update remapped root setting now that we have resolved them to actual names
    43  		config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
    44  
    45  		uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
    46  		if err != nil {
    47  			return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
    48  		}
    49  	}
    50  	return uidMaps, gidMaps, nil
    51  }
    52  
    53  func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
    54  	// the main docker root needs to be accessible by all users, as user namespace support
    55  	// will create subdirectories owned by either a) the real system root (when no remapping
    56  	// is setup) or b) the remapped root host ID (when --root=uid:gid is used)
    57  	// for "first time" users of user namespaces, we need to migrate the current directory
    58  	// contents to the "0.0" (root == root "namespace" daemon root)
    59  	nsRoot := "0.0"
    60  	if _, err := os.Stat(rootDir); err == nil {
    61  		// root current exists; we need to check for a prior migration
    62  		if _, err := os.Stat(filepath.Join(rootDir, nsRoot)); err != nil && os.IsNotExist(err) {
    63  			// need to migrate current root to "0.0" subroot
    64  			// 1. create non-usernamespaced root as "0.0"
    65  			if err := os.Mkdir(filepath.Join(rootDir, nsRoot), 0700); err != nil {
    66  				return fmt.Errorf("Cannot create daemon root %q: %v", filepath.Join(rootDir, nsRoot), err)
    67  			}
    68  			// 2. move current root content to "0.0" new subroot
    69  			if err := directory.MoveToSubdir(rootDir, nsRoot); err != nil {
    70  				return fmt.Errorf("Cannot migrate current daemon root %q for user namespaces: %v", rootDir, err)
    71  			}
    72  			// 3. chmod outer root to 755
    73  			if chmodErr := os.Chmod(rootDir, 0755); chmodErr != nil {
    74  				return chmodErr
    75  			}
    76  		}
    77  	} else if os.IsNotExist(err) {
    78  		// no root exists yet, create it 0755 with root:root ownership
    79  		if err := os.MkdirAll(rootDir, 0755); err != nil {
    80  			return err
    81  		}
    82  		// create the "0.0" subroot (so no future "migration" happens of the root)
    83  		if err := os.Mkdir(filepath.Join(rootDir, nsRoot), 0700); err != nil {
    84  			return err
    85  		}
    86  	}
    87  
    88  	// for user namespaces we will create a subtree underneath the specified root
    89  	// with any/all specified remapped root uid/gid options on the daemon creating
    90  	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
    91  	// `chdir()` to work for containers namespaced to that uid/gid)
    92  	if config.RemappedRoot != "" {
    93  		nsRoot = fmt.Sprintf("%d.%d", rootUID, rootGID)
    94  	}
    95  	config.Root = filepath.Join(rootDir, nsRoot)
    96  	logrus.Debugf("Creating actual daemon root: %s", config.Root)
    97  
    98  	// Create the root directory if it doesn't exists
    99  	if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
   100  		return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
   101  	}
   102  	return nil
   103  }
   104  
   105  func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
   106  	if hostConfig.Privileged && daemon.config().RemappedRoot != "" {
   107  		return nil, fmt.Errorf("Privileged mode is incompatible with user namespace mappings")
   108  	}
   109  	return nil, nil
   110  }