mirror of
https://github.com/docker/cli.git
synced 2026-09-24 07:25:07 -05:00
Merge pull request #33702 from aaronlehmann/templated-secrets-and-configs
Templated secrets and configs Upstream-commit: 0076343b29f508a5deb06861c0d85748659f8881 Component: engine
This commit is contained in:
@@ -2,6 +2,7 @@ package convert // import "github.com/docker/docker/daemon/cluster/convert"
|
||||
|
||||
import (
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
swarmapi "github.com/docker/swarmkit/api"
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
)
|
||||
@@ -21,18 +22,34 @@ func ConfigFromGRPC(s *swarmapi.Config) swarmtypes.Config {
|
||||
config.CreatedAt, _ = gogotypes.TimestampFromProto(s.Meta.CreatedAt)
|
||||
config.UpdatedAt, _ = gogotypes.TimestampFromProto(s.Meta.UpdatedAt)
|
||||
|
||||
if s.Spec.Templating != nil {
|
||||
config.Spec.Templating = &types.Driver{
|
||||
Name: s.Spec.Templating.Name,
|
||||
Options: s.Spec.Templating.Options,
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// ConfigSpecToGRPC converts Config to a grpc Config.
|
||||
func ConfigSpecToGRPC(s swarmtypes.ConfigSpec) swarmapi.ConfigSpec {
|
||||
return swarmapi.ConfigSpec{
|
||||
spec := swarmapi.ConfigSpec{
|
||||
Annotations: swarmapi.Annotations{
|
||||
Name: s.Name,
|
||||
Labels: s.Labels,
|
||||
},
|
||||
Data: s.Data,
|
||||
}
|
||||
|
||||
if s.Templating != nil {
|
||||
spec.Templating = &swarmapi.Driver{
|
||||
Name: s.Templating.Name,
|
||||
Options: s.Templating.Options,
|
||||
}
|
||||
}
|
||||
|
||||
return spec
|
||||
}
|
||||
|
||||
// ConfigReferencesFromGRPC converts a slice of grpc ConfigReference to ConfigReference
|
||||
|
||||
@@ -2,6 +2,7 @@ package convert // import "github.com/docker/docker/daemon/cluster/convert"
|
||||
|
||||
import (
|
||||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
swarmapi "github.com/docker/swarmkit/api"
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
)
|
||||
@@ -22,12 +23,19 @@ func SecretFromGRPC(s *swarmapi.Secret) swarmtypes.Secret {
|
||||
secret.CreatedAt, _ = gogotypes.TimestampFromProto(s.Meta.CreatedAt)
|
||||
secret.UpdatedAt, _ = gogotypes.TimestampFromProto(s.Meta.UpdatedAt)
|
||||
|
||||
if s.Spec.Templating != nil {
|
||||
secret.Spec.Templating = &types.Driver{
|
||||
Name: s.Spec.Templating.Name,
|
||||
Options: s.Spec.Templating.Options,
|
||||
}
|
||||
}
|
||||
|
||||
return secret
|
||||
}
|
||||
|
||||
// SecretSpecToGRPC converts Secret to a grpc Secret.
|
||||
func SecretSpecToGRPC(s swarmtypes.SecretSpec) swarmapi.SecretSpec {
|
||||
return swarmapi.SecretSpec{
|
||||
spec := swarmapi.SecretSpec{
|
||||
Annotations: swarmapi.Annotations{
|
||||
Name: s.Name,
|
||||
Labels: s.Labels,
|
||||
@@ -35,6 +43,15 @@ func SecretSpecToGRPC(s swarmtypes.SecretSpec) swarmapi.SecretSpec {
|
||||
Data: s.Data,
|
||||
Driver: driverToGRPC(s.Driver),
|
||||
}
|
||||
|
||||
if s.Templating != nil {
|
||||
spec.Templating = &swarmapi.Driver{
|
||||
Name: s.Templating.Name,
|
||||
Options: s.Templating.Options,
|
||||
}
|
||||
}
|
||||
|
||||
return spec
|
||||
}
|
||||
|
||||
// SecretReferencesFromGRPC converts a slice of grpc SecretReference to SecretReference
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/docker/swarmkit/agent/exec"
|
||||
"github.com/docker/swarmkit/api"
|
||||
"github.com/docker/swarmkit/api/naming"
|
||||
"github.com/docker/swarmkit/template"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
@@ -191,7 +192,7 @@ func (e *executor) Configure(ctx context.Context, node *api.Node) error {
|
||||
|
||||
// Controller returns a docker container runner.
|
||||
func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
|
||||
dependencyGetter := agent.Restrict(e.dependencies, t)
|
||||
dependencyGetter := template.NewTemplatedDependencyGetter(agent.Restrict(e.dependencies, t), t, nil)
|
||||
|
||||
// Get the node description from the executor field
|
||||
e.mutex.Lock()
|
||||
|
||||
@@ -16,8 +16,6 @@ func (daemon *Daemon) SetContainerConfigReferences(name string, refs []*swarmtyp
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ConfigReferences = refs
|
||||
|
||||
c.ConfigReferences = append(c.ConfigReferences, refs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -161,43 +161,26 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
||||
if len(c.SecretReferences) == 0 {
|
||||
if len(c.SecretReferences) == 0 && len(c.ConfigReferences) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
localMountPath, err := c.SecretMountPath()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error getting secrets mount dir")
|
||||
if err := daemon.createSecretsDir(c); 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")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if setupErr != nil {
|
||||
// cleanup
|
||||
_ = detachMounted(localMountPath)
|
||||
|
||||
if err := os.RemoveAll(localMountPath); err != nil {
|
||||
logrus.Errorf("error cleaning up secret mount: %s", err)
|
||||
}
|
||||
daemon.cleanupSecretDir(c)
|
||||
}
|
||||
}()
|
||||
|
||||
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 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,78 +227,38 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
||||
}
|
||||
}
|
||||
|
||||
label.Relabel(localMountPath, c.MountLabel, false)
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
||||
if len(c.ConfigReferences) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
localPath, err := c.ConfigsDirPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("configs: setting up config dir: %s", localPath)
|
||||
|
||||
// retrieve possible remapped range start for root UID, GID
|
||||
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() {
|
||||
if setupErr != nil {
|
||||
if err := os.RemoveAll(localPath); err != nil {
|
||||
logrus.Errorf("error cleaning up config dir: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if c.DependencyStore == nil {
|
||||
return fmt.Errorf("config store is not initialized")
|
||||
}
|
||||
|
||||
for _, configRef := range c.ConfigReferences {
|
||||
for _, ref := range c.ConfigReferences {
|
||||
// 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")
|
||||
continue
|
||||
}
|
||||
|
||||
fPath, err := c.ConfigFilePath(*configRef)
|
||||
fPath, err := c.ConfigFilePath(*ref)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "error getting config file path for container")
|
||||
}
|
||||
|
||||
log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
|
||||
|
||||
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 mount path")
|
||||
}
|
||||
|
||||
log.Debug("injecting config")
|
||||
config, err := c.DependencyStore.Configs().Get(configRef.ConfigID)
|
||||
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, configRef.File.Mode); err != nil {
|
||||
if err := ioutil.WriteFile(fPath, config.Spec.Data, ref.File.Mode); err != nil {
|
||||
return errors.Wrap(err, "error injecting config")
|
||||
}
|
||||
|
||||
uid, err := strconv.Atoi(configRef.File.UID)
|
||||
uid, err := strconv.Atoi(ref.File.UID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gid, err := strconv.Atoi(configRef.File.GID)
|
||||
gid, err := strconv.Atoi(ref.File.GID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -323,16 +266,69 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
||||
if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
|
||||
return errors.Wrap(err, "error setting ownership for config")
|
||||
}
|
||||
if err := os.Chmod(fPath, configRef.File.Mode); err != nil {
|
||||
if err := os.Chmod(fPath, ref.File.Mode); err != nil {
|
||||
return errors.Wrap(err, "error setting file mode for config")
|
||||
}
|
||||
}
|
||||
|
||||
label.Relabel(fPath, c.MountLabel, false)
|
||||
return daemon.remountSecretDir(c)
|
||||
}
|
||||
|
||||
// createSecretsDir is used to create a dir suitable for storing container secrets.
|
||||
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
|
||||
func (daemon *Daemon) createSecretsDir(c *container.Container) error {
|
||||
// retrieve possible remapped range start for root UID, GID
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
dir, err := c.SecretMountPath()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error getting container secrets dir")
|
||||
}
|
||||
|
||||
// create tmpfs
|
||||
if err := idtools.MkdirAllAndChown(dir, 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", dir, "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 {
|
||||
dir, err := c.SecretMountPath()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error getting container secrets path")
|
||||
}
|
||||
if err := label.Relabel(dir, c.MountLabel, false); err != nil {
|
||||
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
||||
}
|
||||
rootIDs := daemon.idMappings.RootPair()
|
||||
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
||||
|
||||
// remount secrets ro
|
||||
if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
||||
return errors.Wrap(err, "unable to remount dir as readonly")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
|
||||
dir, err := c.SecretMountPath()
|
||||
if err != nil {
|
||||
logrus.WithError(err).WithField("container", c.ID).Warn("error getting secrets mount path for container")
|
||||
}
|
||||
if err := mount.RecursiveUnmount(dir); err != nil {
|
||||
logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
|
||||
}
|
||||
if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
|
||||
logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
|
||||
}
|
||||
}
|
||||
|
||||
func killProcessDirectly(cntr *container.Container) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -21,10 +21,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
localPath, err := c.ConfigsDirPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localPath := c.ConfigsDirPath()
|
||||
logrus.Debugf("configs: setting up config dir: %s", localPath)
|
||||
|
||||
// create local config root
|
||||
@@ -51,11 +48,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
||||
continue
|
||||
}
|
||||
|
||||
fPath, err := c.ConfigFilePath(*configRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fPath := c.ConfigFilePath(*configRef)
|
||||
log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
|
||||
|
||||
log.Debug("injecting config")
|
||||
|
||||
@@ -755,7 +755,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
|
||||
@@ -837,11 +837,13 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := daemon.setupSecretDir(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
daemon.cleanupSecretDir(c)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := daemon.setupConfigDir(c); err != nil {
|
||||
if err := daemon.setupSecretDir(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -866,12 +868,6 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
}
|
||||
ms = append(ms, secretMounts...)
|
||||
|
||||
configMounts, err := c.ConfigMounts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ms = append(ms, configMounts...)
|
||||
|
||||
sort.Sort(mounts(ms))
|
||||
if err := setMounts(daemon, &s, c, ms); err != nil {
|
||||
return nil, fmt.Errorf("linux mounts: %v", err)
|
||||
|
||||
@@ -102,10 +102,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
mounts = append(mounts, secretMounts...)
|
||||
}
|
||||
|
||||
configMounts, err := c.ConfigMounts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configMounts := c.ConfigMounts()
|
||||
if configMounts != nil {
|
||||
mounts = append(mounts, configMounts...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user