mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Store configs that contain secrets on tmpfs
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
cdd2e6efdb
commit
cd3d0486a6
6 changed files with 131 additions and 44 deletions
|
@ -68,6 +68,13 @@ type ExitStatus struct {
|
|||
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.
|
||||
type Container struct {
|
||||
StreamConfig *stream.Config
|
||||
|
@ -99,7 +106,7 @@ type Container struct {
|
|||
ExecCommands *exec.Store `json:"-"`
|
||||
DependencyStore agentexec.DependencyGetter `json:"-"`
|
||||
SecretReferences []*swarmtypes.SecretReference
|
||||
ConfigReferences []*swarmtypes.ConfigReference
|
||||
ConfigReferences []*ConfigReference
|
||||
// logDriver for closing
|
||||
LogDriver logger.Logger `json:"-"`
|
||||
LogCopier *logger.Copier `json:"-"`
|
||||
|
@ -1064,6 +1071,16 @@ func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference)
|
|||
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.
|
||||
func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
|
||||
// Setup environment
|
||||
|
|
|
@ -233,6 +233,20 @@ func (container *Container) SecretMounts() ([]Mount, error) {
|
|||
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
|
||||
}
|
||||
|
@ -257,10 +271,10 @@ func (container *Container) UnmountSecrets() error {
|
|||
func (container *Container) ConfigMounts() ([]Mount, error) {
|
||||
var mounts []Mount
|
||||
for _, configRef := range container.ConfigReferences {
|
||||
if configRef.File == nil {
|
||||
if configRef.Sensitive || configRef.File == nil {
|
||||
continue
|
||||
}
|
||||
src, err := container.ConfigFilePath(*configRef)
|
||||
src, err := container.ConfigFilePath(*configRef.ConfigReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package daemon // import "github.com/docker/docker/daemon"
|
|||
|
||||
import (
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -17,7 +18,9 @@ func (daemon *Daemon) SetContainerConfigReferences(name string, refs []*swarmtyp
|
|||
return err
|
||||
}
|
||||
|
||||
c.ConfigReferences = refs
|
||||
for _, ref := range refs {
|
||||
c.ConfigReferences = append(c.ConfigReferences, &container.ConfigReference{ConfigReference: ref})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/swarmkit/template"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -160,44 +161,23 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
|||
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 {
|
||||
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 {
|
||||
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 {
|
||||
// TODO (ehazlett): use type switch when more are supported
|
||||
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)
|
||||
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
||||
|
||||
// remount secrets ro
|
||||
if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
|
@ -291,22 +318,35 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
|||
continue
|
||||
}
|
||||
|
||||
fPath, err := c.ConfigFilePath(*configRef)
|
||||
getter := c.DependencyStore.Configs().(template.TemplatedConfigGetter)
|
||||
config, sensitive, err := getter.GetAndFlagSecretData(configRef.ConfigID)
|
||||
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.Debug("injecting config")
|
||||
|
||||
if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
|
||||
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 {
|
||||
return errors.Wrap(err, "error injecting config")
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
|||
continue
|
||||
}
|
||||
|
||||
fPath, err := c.ConfigFilePath(*configRef)
|
||||
fPath, err := c.ConfigFilePath(*configRef.ConfigReference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -760,7 +760,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
|
|||
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()
|
||||
if err := daemon.populateCommonSpec(&s, c); err != nil {
|
||||
return nil, err
|
||||
|
@ -842,14 +842,27 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
|||
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
|
||||
}
|
||||
|
||||
if err := daemon.setupConfigDir(c); err != nil {
|
||||
if err := daemon.setupConfigDir(c, &hasSecretDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hasSecretDir {
|
||||
if err := daemon.remountSecretDir(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ms, err := daemon.setupMounts(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
Loading…
Add table
Reference in a new issue