فهرست منبع

Store configs that contain secrets on tmpfs

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Aaron Lehmann 8 سال پیش
والد
کامیت
cd3d0486a6
6فایلهای تغییر یافته به همراه131 افزوده شده و 44 حذف شده
  1. 18 1
      container/container.go
  2. 16 2
      container/container_unix.go
  3. 4 1
      daemon/configs.go
  4. 76 36
      daemon/container_operations_unix.go
  5. 1 1
      daemon/container_operations_windows.go
  6. 16 3
      daemon/oci_linux.go

+ 18 - 1
container/container.go

@@ -68,6 +68,13 @@ type ExitStatus struct {
 	ExitedAt time.Time
 	ExitedAt time.Time
 }
 }
 
 
+// ConfigReference wraps swarmtypes.ConfigReference to add a Sensitive flag.
+type ConfigReference struct {
+	*swarmtypes.ConfigReference
+	// Sensitive is set if this config should not be written to disk.
+	Sensitive bool
+}
+
 // Container holds the structure defining a container object.
 // Container holds the structure defining a container object.
 type Container struct {
 type Container struct {
 	StreamConfig *stream.Config
 	StreamConfig *stream.Config
@@ -99,7 +106,7 @@ type Container struct {
 	ExecCommands           *exec.Store                `json:"-"`
 	ExecCommands           *exec.Store                `json:"-"`
 	DependencyStore        agentexec.DependencyGetter `json:"-"`
 	DependencyStore        agentexec.DependencyGetter `json:"-"`
 	SecretReferences       []*swarmtypes.SecretReference
 	SecretReferences       []*swarmtypes.SecretReference
-	ConfigReferences       []*swarmtypes.ConfigReference
+	ConfigReferences       []*ConfigReference
 	// logDriver for closing
 	// logDriver for closing
 	LogDriver      logger.Logger  `json:"-"`
 	LogDriver      logger.Logger  `json:"-"`
 	LogCopier      *logger.Copier `json:"-"`
 	LogCopier      *logger.Copier `json:"-"`
@@ -1064,6 +1071,16 @@ func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference)
 	return filepath.Join(configs, configRef.ConfigID), nil
 	return filepath.Join(configs, configRef.ConfigID), nil
 }
 }
 
 
+// SensitiveConfigFilePath returns the path to the location of a config mounted
+// as a secret.
+func (container *Container) SensitiveConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
+	secretMountPath, err := container.SecretMountPath()
+	if err != nil {
+		return "", err
+	}
+	return filepath.Join(secretMountPath, configRef.ConfigID+"c"), nil
+}
+
 // CreateDaemonEnvironment creates a new environment variable slice for this container.
 // CreateDaemonEnvironment creates a new environment variable slice for this container.
 func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
 func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
 	// Setup environment
 	// Setup environment

+ 16 - 2
container/container_unix.go

@@ -233,6 +233,20 @@ func (container *Container) SecretMounts() ([]Mount, error) {
 			Writable:    false,
 			Writable:    false,
 		})
 		})
 	}
 	}
+	for _, r := range container.ConfigReferences {
+		if !r.Sensitive || r.File == nil {
+			continue
+		}
+		fPath, err := container.SensitiveConfigFilePath(*r.ConfigReference)
+		if err != nil {
+			return nil, err
+		}
+		mounts = append(mounts, Mount{
+			Source:      fPath,
+			Destination: r.File.Name,
+			Writable:    false,
+		})
+	}
 
 
 	return mounts, nil
 	return mounts, nil
 }
 }
@@ -257,10 +271,10 @@ func (container *Container) UnmountSecrets() error {
 func (container *Container) ConfigMounts() ([]Mount, error) {
 func (container *Container) ConfigMounts() ([]Mount, error) {
 	var mounts []Mount
 	var mounts []Mount
 	for _, configRef := range container.ConfigReferences {
 	for _, configRef := range container.ConfigReferences {
-		if configRef.File == nil {
+		if configRef.Sensitive || configRef.File == nil {
 			continue
 			continue
 		}
 		}
-		src, err := container.ConfigFilePath(*configRef)
+		src, err := container.ConfigFilePath(*configRef.ConfigReference)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 4 - 1
daemon/configs.go

@@ -2,6 +2,7 @@ package daemon // import "github.com/docker/docker/daemon"
 
 
 import (
 import (
 	swarmtypes "github.com/docker/docker/api/types/swarm"
 	swarmtypes "github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/container"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
 
 
@@ -17,7 +18,9 @@ func (daemon *Daemon) SetContainerConfigReferences(name string, refs []*swarmtyp
 		return err
 		return err
 	}
 	}
 
 
-	c.ConfigReferences = refs
+	for _, ref := range refs {
+		c.ConfigReferences = append(c.ConfigReferences, &container.ConfigReference{ConfigReference: ref})
+	}
 
 
 	return nil
 	return nil
 }
 }

+ 76 - 36
daemon/container_operations_unix.go

@@ -19,6 +19,7 @@ import (
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
+	"github.com/docker/swarmkit/template"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
@@ -160,44 +161,23 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
 	return nil
 	return nil
 }
 }
 
 
-func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
+func (daemon *Daemon) setupSecretDir(c *container.Container, hasSecretDir *bool) (setupErr error) {
 	if len(c.SecretReferences) == 0 {
 	if len(c.SecretReferences) == 0 {
 		return nil
 		return nil
 	}
 	}
 
 
-	localMountPath, err := c.SecretMountPath()
-	if err != nil {
-		return errors.Wrap(err, "error getting secrets mount dir")
-	}
-	logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
-
-	// retrieve possible remapped range start for root UID, GID
-	rootIDs := daemon.idMappings.RootPair()
-	// create tmpfs
-	if err := idtools.MkdirAllAndChown(localMountPath, 0700, rootIDs); err != nil {
-		return errors.Wrap(err, "error creating secret local mount path")
-	}
-
-	defer func() {
-		if setupErr != nil {
-			// cleanup
-			_ = detachMounted(localMountPath)
-
-			if err := os.RemoveAll(localMountPath); err != nil {
-				logrus.Errorf("error cleaning up secret mount: %s", err)
-			}
-		}
-	}()
-
-	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
-	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
-		return errors.Wrap(err, "unable to setup secret mount")
+	if !*hasSecretDir {
+		daemon.createSecretDir(c)
+		*hasSecretDir = true
 	}
 	}
 
 
 	if c.DependencyStore == nil {
 	if c.DependencyStore == nil {
 		return fmt.Errorf("secret store is not initialized")
 		return fmt.Errorf("secret store is not initialized")
 	}
 	}
 
 
+	// retrieve possible remapped range start for root UID, GID
+	rootIDs := daemon.idMappings.RootPair()
+
 	for _, s := range c.SecretReferences {
 	for _, s := range c.SecretReferences {
 		// TODO (ehazlett): use type switch when more are supported
 		// TODO (ehazlett): use type switch when more are supported
 		if s.File == nil {
 		if s.File == nil {
@@ -244,8 +224,42 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
 		}
 		}
 	}
 	}
 
 
+	return nil
+}
+
+func (daemon *Daemon) createSecretDir(c *container.Container) error {
+	localMountPath, err := c.SecretMountPath()
+	if err != nil {
+		return err
+	}
+	logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
+
+	// retrieve possible remapped range start for root UID, GID
+	rootIDs := daemon.idMappings.RootPair()
+	// create tmpfs
+	if err := idtools.MkdirAllAndChown(localMountPath, 0700, rootIDs); err != nil {
+		return errors.Wrap(err, "error creating secret local mount path")
+	}
+
+	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
+	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
+		return errors.Wrap(err, "unable to setup secret mount")
+	}
+
+	return nil
+}
+
+func (daemon *Daemon) remountSecretDir(c *container.Container) error {
+	localMountPath, err := c.SecretMountPath()
+	if err != nil {
+		return err
+	}
+
 	label.Relabel(localMountPath, c.MountLabel, false)
 	label.Relabel(localMountPath, c.MountLabel, false)
 
 
+	rootIDs := daemon.idMappings.RootPair()
+	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
+
 	// remount secrets ro
 	// remount secrets ro
 	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
 	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
 		return errors.Wrap(err, "unable to remount secret dir as readonly")
 		return errors.Wrap(err, "unable to remount secret dir as readonly")
@@ -254,7 +268,20 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
 	return nil
 	return nil
 }
 }
 
 
-func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
+func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
+	localMountPath, err := c.SecretMountPath()
+	if err != nil {
+		logrus.WithError(err).WithField("container", c.ID).Errorf("error getting secrets mounth path for cleanup")
+	}
+
+	detachMounted(localMountPath)
+
+	if err := os.RemoveAll(localMountPath); err != nil {
+		logrus.Errorf("error cleaning up secret mount: %s", err)
+	}
+}
+
+func (daemon *Daemon) setupConfigDir(c *container.Container, hasSecretDir *bool) (setupErr error) {
 	if len(c.ConfigReferences) == 0 {
 	if len(c.ConfigReferences) == 0 {
 		return nil
 		return nil
 	}
 	}
@@ -291,22 +318,35 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
 			continue
 			continue
 		}
 		}
 
 
-		fPath, err := c.ConfigFilePath(*configRef)
+		getter := c.DependencyStore.Configs().(template.TemplatedConfigGetter)
+		config, sensitive, err := getter.GetAndFlagSecretData(configRef.ConfigID)
 		if err != nil {
 		if err != nil {
-			return err
+			return errors.Wrap(err, "unable to get config from config store")
+		}
+
+		var fPath string
+		if sensitive {
+			configRef.Sensitive = true
+			fPath, err = c.SensitiveConfigFilePath(*configRef.ConfigReference)
+			if !*hasSecretDir {
+				daemon.createSecretDir(c)
+				*hasSecretDir = true
+			}
+		} else {
+			fPath, err = c.ConfigFilePath(*configRef.ConfigReference)
+		}
+		if err != nil {
+			return errors.Wrap(err, "error getting config file path")
 		}
 		}
 
 
 		log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
 		log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
 
 
+		log.Debug("injecting config")
+
 		if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
 		if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
 			return errors.Wrap(err, "error creating config path")
 			return errors.Wrap(err, "error creating config path")
 		}
 		}
 
 
-		log.Debug("injecting config")
-		config, err := c.DependencyStore.Configs().Get(configRef.ConfigID)
-		if err != nil {
-			return errors.Wrap(err, "unable to get config from config store")
-		}
 		if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil {
 		if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil {
 			return errors.Wrap(err, "error injecting config")
 			return errors.Wrap(err, "error injecting config")
 		}
 		}

+ 1 - 1
daemon/container_operations_windows.go

@@ -51,7 +51,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
 			continue
 			continue
 		}
 		}
 
 
-		fPath, err := c.ConfigFilePath(*configRef)
+		fPath, err := c.ConfigFilePath(*configRef.ConfigReference)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 16 - 3
daemon/oci_linux.go

@@ -760,7 +760,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
 	return nil
 	return nil
 }
 }
 
 
-func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
+func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, err error) {
 	s := oci.DefaultSpec()
 	s := oci.DefaultSpec()
 	if err := daemon.populateCommonSpec(&s, c); err != nil {
 	if err := daemon.populateCommonSpec(&s, c); err != nil {
 		return nil, err
 		return nil, err
@@ -842,14 +842,27 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err := daemon.setupSecretDir(c); err != nil {
+	var hasSecretDir bool
+	defer func() {
+		if hasSecretDir && err != nil {
+			daemon.cleanupSecretDir(c)
+		}
+	}()
+
+	if err := daemon.setupSecretDir(c, &hasSecretDir); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err := daemon.setupConfigDir(c); err != nil {
+	if err := daemon.setupConfigDir(c, &hasSecretDir); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	if hasSecretDir {
+		if err := daemon.remountSecretDir(c); err != nil {
+			return nil, err
+		}
+	}
+
 	ms, err := daemon.setupMounts(c)
 	ms, err := daemon.setupMounts(c)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err