Skip to content
This repository was archived by the owner on Oct 13, 2023. It is now read-only.

Commit c021718

Browse files
committed
Merge configs/secrets in unix implementation
On unix, merge secrets/configs handling. This is important because configs can contain secrets (via templating) and potentially a config could just simply have secret information "by accident" from the user. This just make sure that configs are as secure as secrets and de-dups a lot of code. Generally this makes everything simpler and configs more secure. Signed-off-by: Brian Goff <[email protected]>
1 parent 8e8f5f4 commit c021718

10 files changed

+125
-201
lines changed

container/container.go

+1-33
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,6 @@ type ExitStatus struct {
6868
ExitedAt time.Time
6969
}
7070

71-
// ConfigReference wraps swarmtypes.ConfigReference to add a Sensitive flag.
72-
type ConfigReference struct {
73-
*swarmtypes.ConfigReference
74-
// Sensitive is set if this config should not be written to disk.
75-
Sensitive bool
76-
}
77-
7871
// Container holds the structure defining a container object.
7972
type Container struct {
8073
StreamConfig *stream.Config
@@ -106,7 +99,7 @@ type Container struct {
10699
ExecCommands *exec.Store `json:"-"`
107100
DependencyStore agentexec.DependencyGetter `json:"-"`
108101
SecretReferences []*swarmtypes.SecretReference
109-
ConfigReferences []*ConfigReference
102+
ConfigReferences []*swarmtypes.ConfigReference
110103
// logDriver for closing
111104
LogDriver logger.Logger `json:"-"`
112105
LogCopier *logger.Copier `json:"-"`
@@ -1056,31 +1049,6 @@ func getSecretTargetPath(r *swarmtypes.SecretReference) string {
10561049
return filepath.Join(containerSecretMountPath, r.File.Name)
10571050
}
10581051

1059-
// ConfigsDirPath returns the path to the directory where configs are stored on
1060-
// disk.
1061-
func (container *Container) ConfigsDirPath() (string, error) {
1062-
return container.GetRootResourcePath("configs")
1063-
}
1064-
1065-
// ConfigFilePath returns the path to the on-disk location of a config.
1066-
func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
1067-
configs, err := container.ConfigsDirPath()
1068-
if err != nil {
1069-
return "", err
1070-
}
1071-
return filepath.Join(configs, configRef.ConfigID), nil
1072-
}
1073-
1074-
// SensitiveConfigFilePath returns the path to the location of a config mounted
1075-
// as a secret.
1076-
func (container *Container) SensitiveConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
1077-
secretMountPath, err := container.SecretMountPath()
1078-
if err != nil {
1079-
return "", err
1080-
}
1081-
return filepath.Join(secretMountPath, configRef.ConfigID+"c"), nil
1082-
}
1083-
10841052
// CreateDaemonEnvironment creates a new environment variable slice for this container.
10851053
func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
10861054
// Setup environment

container/container_unix.go

+13-25
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ package container // import "github.com/docker/docker/container"
55
import (
66
"io/ioutil"
77
"os"
8+
"path/filepath"
89

910
"github.com/containerd/continuity/fs"
1011
"github.com/docker/docker/api/types"
1112
containertypes "github.com/docker/docker/api/types/container"
1213
mounttypes "github.com/docker/docker/api/types/mount"
14+
swarmtypes "github.com/docker/docker/api/types/swarm"
1315
"github.com/docker/docker/pkg/mount"
1416
"github.com/docker/docker/pkg/stringid"
1517
"github.com/docker/docker/volume"
@@ -234,10 +236,7 @@ func (container *Container) SecretMounts() ([]Mount, error) {
234236
})
235237
}
236238
for _, r := range container.ConfigReferences {
237-
if !r.Sensitive || r.File == nil {
238-
continue
239-
}
240-
fPath, err := container.SensitiveConfigFilePath(*r.ConfigReference)
239+
fPath, err := container.ConfigFilePath(*r)
241240
if err != nil {
242241
return nil, err
243242
}
@@ -267,27 +266,6 @@ func (container *Container) UnmountSecrets() error {
267266
return mount.RecursiveUnmount(p)
268267
}
269268

270-
// ConfigMounts returns the mounts for configs.
271-
func (container *Container) ConfigMounts() ([]Mount, error) {
272-
var mounts []Mount
273-
for _, configRef := range container.ConfigReferences {
274-
if configRef.Sensitive || configRef.File == nil {
275-
continue
276-
}
277-
src, err := container.ConfigFilePath(*configRef.ConfigReference)
278-
if err != nil {
279-
return nil, err
280-
}
281-
mounts = append(mounts, Mount{
282-
Source: src,
283-
Destination: configRef.File.Name,
284-
Writable: false,
285-
})
286-
}
287-
288-
return mounts, nil
289-
}
290-
291269
type conflictingUpdateOptions string
292270

293271
func (e conflictingUpdateOptions) Error() string {
@@ -471,3 +449,13 @@ func (container *Container) GetMountPoints() []types.MountPoint {
471449
}
472450
return mountPoints
473451
}
452+
453+
// ConfigFilePath returns the path to the on-disk location of a config.
454+
// On unix, configs are always considered secret
455+
func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
456+
mounts, err := container.SecretMountPath()
457+
if err != nil {
458+
return "", err
459+
}
460+
return filepath.Join(mounts, configRef.ConfigID), nil
461+
}

container/container_windows.go

+16-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/docker/docker/api/types"
99
containertypes "github.com/docker/docker/api/types/container"
10+
swarmtypes "github.com/docker/docker/api/types/swarm"
1011
"github.com/docker/docker/pkg/system"
1112
)
1213

@@ -102,23 +103,20 @@ func (container *Container) CreateConfigSymlinks() error {
102103
}
103104

104105
// ConfigMounts returns the mount for configs.
105-
// All configs are stored in a single mount on Windows. Target symlinks are
106-
// created for each config, pointing to the files in this mount.
107-
func (container *Container) ConfigMounts() ([]Mount, error) {
106+
// TODO: Right now Windows doesn't really have a "secure" storage for secrets,
107+
// however some configs may contain secrets. Once secure storage is worked out,
108+
// configs and secret handling should be merged.
109+
func (container *Container) ConfigMounts() []Mount {
108110
var mounts []Mount
109111
if len(container.ConfigReferences) > 0 {
110-
src, err := container.ConfigsDirPath()
111-
if err != nil {
112-
return nil, err
113-
}
114112
mounts = append(mounts, Mount{
115-
Source: src,
113+
Source: container.ConfigsDirPath(),
116114
Destination: containerInternalConfigsDirPath,
117115
Writable: false,
118116
})
119117
}
120118

121-
return mounts, nil
119+
return mounts
122120
}
123121

124122
// DetachAndUnmount unmounts all volumes.
@@ -204,3 +202,12 @@ func (container *Container) GetMountPoints() []types.MountPoint {
204202
}
205203
return mountPoints
206204
}
205+
206+
func (container *Container) ConfigsDirPath() string {
207+
return filepath.Join(container.Root, "configs")
208+
}
209+
210+
// ConfigFilePath returns the path to the on-disk location of a config.
211+
func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) string {
212+
return filepath.Join(container.ConfigsDirPath(), configRef.ConfigID)
213+
}

daemon/configs.go

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package daemon // import "github.com/docker/docker/daemon"
22

33
import (
44
swarmtypes "github.com/docker/docker/api/types/swarm"
5-
"github.com/docker/docker/container"
65
"github.com/sirupsen/logrus"
76
)
87

@@ -17,10 +16,6 @@ func (daemon *Daemon) SetContainerConfigReferences(name string, refs []*swarmtyp
1716
if err != nil {
1817
return err
1918
}
20-
21-
for _, ref := range refs {
22-
c.ConfigReferences = append(c.ConfigReferences, &container.ConfigReference{ConfigReference: ref})
23-
}
24-
19+
c.ConfigReferences = append(c.ConfigReferences, refs...)
2520
return nil
2621
}

daemon/container_operations_unix.go

+62-85
Original file line numberDiff line numberDiff line change
@@ -161,20 +161,16 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
161161
}
162162

163163
func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
164-
if len(c.SecretReferences) == 0 {
164+
if len(c.SecretReferences) == 0 && len(c.ConfigReferences) == 0 {
165165
return nil
166166
}
167167

168-
localMountPath, err := c.SecretMountPath()
169-
if err != nil {
170-
return errors.Wrap(err, "error getting secrets mount path for container")
171-
}
172-
if err := daemon.createSecretsDir(localMountPath); err != nil {
168+
if err := daemon.createSecretsDir(c); err != nil {
173169
return err
174170
}
175171
defer func() {
176172
if setupErr != nil {
177-
daemon.cleanupSecretDir(localMountPath)
173+
daemon.cleanupSecretDir(c)
178174
}
179175
}()
180176

@@ -231,88 +227,16 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
231227
}
232228
}
233229

234-
return daemon.remountSecretDir(c.MountLabel, localMountPath)
235-
}
236-
237-
// createSecretsDir is used to create a dir suitable for storing container secrets.
238-
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
239-
func (daemon *Daemon) createSecretsDir(dir string) error {
240-
// retrieve possible remapped range start for root UID, GID
241-
rootIDs := daemon.idMappings.RootPair()
242-
// create tmpfs
243-
if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
244-
return errors.Wrap(err, "error creating secret local mount path")
245-
}
246-
247-
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
248-
if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
249-
return errors.Wrap(err, "unable to setup secret mount")
250-
}
251-
252-
return nil
253-
}
254-
255-
func (daemon *Daemon) remountSecretDir(mountLabel, dir string) error {
256-
if err := label.Relabel(dir, mountLabel, false); err != nil {
257-
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
258-
}
259-
rootIDs := daemon.idMappings.RootPair()
260-
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
261-
262-
// remount secrets ro
263-
if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
264-
return errors.Wrap(err, "unable to remount dir as readonly")
265-
}
266-
267-
return nil
268-
}
269-
270-
func (daemon *Daemon) cleanupSecretDir(dir string) {
271-
if err := mount.RecursiveUnmount(dir); err != nil {
272-
logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
273-
}
274-
if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
275-
logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
276-
}
277-
}
278-
279-
func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
280-
if len(c.ConfigReferences) == 0 {
281-
return nil
282-
}
283-
284-
localPath, err := c.ConfigsDirPath()
285-
if err != nil {
286-
return err
287-
}
288-
logrus.Debugf("configs: setting up config dir: %s", localPath)
289-
if err := daemon.createSecretsDir(localPath); err != nil {
290-
return err
291-
}
292-
defer func() {
293-
if setupErr != nil {
294-
daemon.cleanupSecretDir(localPath)
295-
}
296-
}()
297-
298-
if c.DependencyStore == nil {
299-
return errors.New("config store is not initialized")
300-
}
301-
302-
// retrieve possible remapped range start for root UID, GID
303-
rootIDs := daemon.idMappings.RootPair()
304-
305230
for _, ref := range c.ConfigReferences {
306231
// TODO (ehazlett): use type switch when more are supported
307232
if ref.File == nil {
308233
logrus.Error("config target type is not a file target")
309234
continue
310235
}
311-
// configs are created in the ConfigsDirPath on the host, at a
312-
// single level
313-
fPath, err := c.ConfigFilePath(*ref.ConfigReference)
236+
237+
fPath, err := c.ConfigFilePath(*ref)
314238
if err != nil {
315-
return err
239+
return errors.Wrap(err, "error getting config file path for container")
316240
}
317241
if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
318242
return errors.Wrap(err, "error creating config mount path")
@@ -342,14 +266,67 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
342266
if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
343267
return errors.Wrap(err, "error setting ownership for config")
344268
}
345-
if err := os.Chmod(fPath, configRef.File.Mode); err != nil {
269+
if err := os.Chmod(fPath, ref.File.Mode); err != nil {
346270
return errors.Wrap(err, "error setting file mode for config")
347271
}
272+
}
273+
274+
return daemon.remountSecretDir(c)
275+
}
276+
277+
// createSecretsDir is used to create a dir suitable for storing container secrets.
278+
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
279+
func (daemon *Daemon) createSecretsDir(c *container.Container) error {
280+
// retrieve possible remapped range start for root UID, GID
281+
rootIDs := daemon.idMappings.RootPair()
282+
dir, err := c.SecretMountPath()
283+
if err != nil {
284+
return errors.Wrap(err, "error getting container secrets dir")
285+
}
286+
287+
// create tmpfs
288+
if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
289+
return errors.Wrap(err, "error creating secret local mount path")
290+
}
291+
292+
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
293+
if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
294+
return errors.Wrap(err, "unable to setup secret mount")
295+
}
348296

349-
label.Relabel(fPath, c.MountLabel, false)
297+
return nil
298+
}
299+
300+
func (daemon *Daemon) remountSecretDir(c *container.Container) error {
301+
dir, err := c.SecretMountPath()
302+
if err != nil {
303+
return errors.Wrap(err, "error getting container secrets path")
350304
}
305+
if err := label.Relabel(dir, c.MountLabel, false); err != nil {
306+
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
307+
}
308+
rootIDs := daemon.idMappings.RootPair()
309+
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
351310

352-
return daemon.remountSecretDir(c.MountLabel, localPath)
311+
// remount secrets ro
312+
if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
313+
return errors.Wrap(err, "unable to remount dir as readonly")
314+
}
315+
316+
return nil
317+
}
318+
319+
func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
320+
dir, err := c.SecretMountPath()
321+
if err != nil {
322+
logrus.WithError(err).WithField("container", c.ID).Warn("error getting secrets mount path for container")
323+
}
324+
if err := mount.RecursiveUnmount(dir); err != nil {
325+
logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
326+
}
327+
if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
328+
logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
329+
}
353330
}
354331

355332
func killProcessDirectly(cntr *container.Container) error {

0 commit comments

Comments
 (0)