Always mount configs with tmpfs
This makes configs and secrets behavior identical. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
parent
426f4e48e3
commit
8e8f5f4457
3 changed files with 88 additions and 121 deletions
|
@ -3339,17 +3339,12 @@ definitions:
|
||||||
description: "Name of the secrets driver used to fetch the secret's value from an external secret store"
|
description: "Name of the secrets driver used to fetch the secret's value from an external secret store"
|
||||||
$ref: "#/definitions/Driver"
|
$ref: "#/definitions/Driver"
|
||||||
Templating:
|
Templating:
|
||||||
description: "Templating driver, if applicable"
|
description: |
|
||||||
type: "object"
|
Templating driver, if applicable
|
||||||
properties:
|
|
||||||
Name:
|
Templating controls whether and how to evaluate the config payload as
|
||||||
description: "Name of the templating driver (i.e. 'golang')"
|
a template. If no driver is set, no templating is used.
|
||||||
type: "string"
|
$ref: "#/definitions/Driver"
|
||||||
Options:
|
|
||||||
description: "key/value map of driver specific options."
|
|
||||||
type: "object"
|
|
||||||
additionalProperties:
|
|
||||||
type: "string"
|
|
||||||
|
|
||||||
Secret:
|
Secret:
|
||||||
type: "object"
|
type: "object"
|
||||||
|
@ -3387,17 +3382,12 @@ definitions:
|
||||||
config data.
|
config data.
|
||||||
type: "string"
|
type: "string"
|
||||||
Templating:
|
Templating:
|
||||||
description: "Templating driver, if applicable"
|
description: |
|
||||||
type: "object"
|
Templating driver, if applicable
|
||||||
properties:
|
|
||||||
Name:
|
Templating controls whether and how to evaluate the config payload as
|
||||||
description: "Name of the templating driver (i.e. 'golang')"
|
a template. If no driver is set, no templating is used.
|
||||||
type: "string"
|
$ref: "#/definitions/Driver"
|
||||||
Options:
|
|
||||||
description: "key/value map of driver specific options."
|
|
||||||
type: "object"
|
|
||||||
additionalProperties:
|
|
||||||
type: "string"
|
|
||||||
|
|
||||||
Config:
|
Config:
|
||||||
type: "object"
|
type: "object"
|
||||||
|
|
|
@ -19,7 +19,6 @@ 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"
|
||||||
|
@ -161,17 +160,23 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) setupSecretDir(c *container.Container, hasSecretDir *bool) (setupErr error) {
|
func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
||||||
if len(c.SecretReferences) == 0 {
|
if len(c.SecretReferences) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*hasSecretDir {
|
localMountPath, err := c.SecretMountPath()
|
||||||
if err := daemon.createSecretDir(c); err != nil {
|
if err != nil {
|
||||||
return err
|
return errors.Wrap(err, "error getting secrets mount path for container")
|
||||||
}
|
|
||||||
*hasSecretDir = true
|
|
||||||
}
|
}
|
||||||
|
if err := daemon.createSecretsDir(localMountPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if setupErr != nil {
|
||||||
|
daemon.cleanupSecretDir(localMountPath)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if c.DependencyStore == nil {
|
if c.DependencyStore == nil {
|
||||||
return fmt.Errorf("secret store is not initialized")
|
return fmt.Errorf("secret store is not initialized")
|
||||||
|
@ -226,64 +231,52 @@ func (daemon *Daemon) setupSecretDir(c *container.Container, hasSecretDir *bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return daemon.remountSecretDir(c.MountLabel, localMountPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) createSecretDir(c *container.Container) error {
|
// createSecretsDir is used to create a dir suitable for storing container secrets.
|
||||||
localMountPath, err := c.SecretMountPath()
|
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
|
||||||
if err != nil {
|
func (daemon *Daemon) createSecretsDir(dir string) error {
|
||||||
return err
|
|
||||||
}
|
|
||||||
logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
|
|
||||||
|
|
||||||
// retrieve possible remapped range start for root UID, GID
|
// retrieve possible remapped range start for root UID, GID
|
||||||
rootIDs := daemon.idMappings.RootPair()
|
rootIDs := daemon.idMappings.RootPair()
|
||||||
// create tmpfs
|
// create tmpfs
|
||||||
if err := idtools.MkdirAllAndChown(localMountPath, 0700, rootIDs); err != nil {
|
if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
|
||||||
return errors.Wrap(err, "error creating secret local mount path")
|
return errors.Wrap(err, "error creating secret local mount path")
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
||||||
if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
|
if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
|
||||||
return errors.Wrap(err, "unable to setup secret mount")
|
return errors.Wrap(err, "unable to setup secret mount")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) remountSecretDir(c *container.Container) error {
|
func (daemon *Daemon) remountSecretDir(mountLabel, dir string) error {
|
||||||
localMountPath, err := c.SecretMountPath()
|
if err := label.Relabel(dir, mountLabel, false); err != nil {
|
||||||
if err != nil {
|
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
label.Relabel(localMountPath, c.MountLabel, false)
|
|
||||||
|
|
||||||
rootIDs := daemon.idMappings.RootPair()
|
rootIDs := daemon.idMappings.RootPair()
|
||||||
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
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", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
||||||
return errors.Wrap(err, "unable to remount secret dir as readonly")
|
return errors.Wrap(err, "unable to remount dir as readonly")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
|
func (daemon *Daemon) cleanupSecretDir(dir string) {
|
||||||
localMountPath, err := c.SecretMountPath()
|
if err := mount.RecursiveUnmount(dir); err != nil {
|
||||||
if err != nil {
|
logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
|
||||||
logrus.WithError(err).WithField("container", c.ID).Errorf("error getting secrets mounth path for cleanup")
|
|
||||||
}
|
}
|
||||||
|
if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
|
||||||
detachMounted(localMountPath)
|
logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
|
||||||
|
|
||||||
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) {
|
func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
||||||
if len(c.ConfigReferences) == 0 {
|
if len(c.ConfigReferences) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -293,73 +286,55 @@ func (daemon *Daemon) setupConfigDir(c *container.Container, hasSecretDir *bool)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logrus.Debugf("configs: setting up config dir: %s", localPath)
|
logrus.Debugf("configs: setting up config dir: %s", localPath)
|
||||||
|
if err := daemon.createSecretsDir(localPath); err != nil {
|
||||||
// retrieve possible remapped range start for root UID, GID
|
return err
|
||||||
rootIDs := daemon.idMappings.RootPair()
|
|
||||||
// create tmpfs
|
|
||||||
if err := idtools.MkdirAllAndChown(localPath, 0700, rootIDs); err != nil {
|
|
||||||
return errors.Wrap(err, "error creating config dir")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if setupErr != nil {
|
if setupErr != nil {
|
||||||
if err := os.RemoveAll(localPath); err != nil {
|
daemon.cleanupSecretDir(localPath)
|
||||||
logrus.Errorf("error cleaning up config dir: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if c.DependencyStore == nil {
|
if c.DependencyStore == nil {
|
||||||
return fmt.Errorf("config store is not initialized")
|
return errors.New("config store is not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, configRef := range c.ConfigReferences {
|
// retrieve possible remapped range start for root UID, GID
|
||||||
|
rootIDs := daemon.idMappings.RootPair()
|
||||||
|
|
||||||
|
for _, ref := range c.ConfigReferences {
|
||||||
// TODO (ehazlett): use type switch when more are supported
|
// TODO (ehazlett): use type switch when more are supported
|
||||||
if configRef.File == nil {
|
if ref.File == nil {
|
||||||
logrus.Error("config target type is not a file target")
|
logrus.Error("config target type is not a file target")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// configs are created in the ConfigsDirPath on the host, at a
|
||||||
getter := c.DependencyStore.Configs().(template.TemplatedConfigGetter)
|
// single level
|
||||||
config, sensitive, err := getter.GetAndFlagSecretData(configRef.ConfigID)
|
fPath, err := c.ConfigFilePath(*ref.ConfigReference)
|
||||||
if err != nil {
|
|
||||||
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 {
|
|
||||||
if err := daemon.createSecretDir(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*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.Debug("injecting config")
|
|
||||||
|
|
||||||
if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
|
|
||||||
return errors.Wrap(err, "error creating config path")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil {
|
|
||||||
return errors.Wrap(err, "error injecting config")
|
|
||||||
}
|
|
||||||
|
|
||||||
uid, err := strconv.Atoi(configRef.File.UID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gid, err := strconv.Atoi(configRef.File.GID)
|
if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
|
||||||
|
return errors.Wrap(err, "error creating config mount path")
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"name": ref.File.Name,
|
||||||
|
"path": fPath,
|
||||||
|
}).Debug("injecting config")
|
||||||
|
config, err := c.DependencyStore.Configs().Get(ref.ConfigID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "unable to get config from config store")
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(fPath, config.Spec.Data, ref.File.Mode); err != nil {
|
||||||
|
return errors.Wrap(err, "error injecting config")
|
||||||
|
}
|
||||||
|
|
||||||
|
uid, err := strconv.Atoi(ref.File.UID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gid, err := strconv.Atoi(ref.File.GID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -374,7 +349,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container, hasSecretDir *bool)
|
||||||
label.Relabel(fPath, c.MountLabel, false)
|
label.Relabel(fPath, c.MountLabel, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return daemon.remountSecretDir(c.MountLabel, localPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func killProcessDirectly(cntr *container.Container) error {
|
func killProcessDirectly(cntr *container.Container) error {
|
||||||
|
|
|
@ -842,27 +842,29 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasSecretDir bool
|
secretMountPath, err := c.SecretMountPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
configsMountPath, err := c.ConfigsDirPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if hasSecretDir && err != nil {
|
if err != nil {
|
||||||
daemon.cleanupSecretDir(c)
|
daemon.cleanupSecretDir(secretMountPath)
|
||||||
|
daemon.cleanupSecretDir(configsMountPath)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := daemon.setupSecretDir(c, &hasSecretDir); err != nil {
|
if err := daemon.setupSecretDir(c); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := daemon.setupConfigDir(c, &hasSecretDir); err != nil {
|
if err := daemon.setupConfigDir(c); 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
|
||||||
|
|
Loading…
Reference in a new issue