This makes configs and secrets behavior identical.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -3339,17 +3339,12 @@ definitions: |
| 3339 | 3339 |
description: "Name of the secrets driver used to fetch the secret's value from an external secret store" |
| 3340 | 3340 |
$ref: "#/definitions/Driver" |
| 3341 | 3341 |
Templating: |
| 3342 |
- description: "Templating driver, if applicable" |
|
| 3343 |
- type: "object" |
|
| 3344 |
- properties: |
|
| 3345 |
- Name: |
|
| 3346 |
- description: "Name of the templating driver (i.e. 'golang')" |
|
| 3347 |
- type: "string" |
|
| 3348 |
- Options: |
|
| 3349 |
- description: "key/value map of driver specific options." |
|
| 3350 |
- type: "object" |
|
| 3351 |
- additionalProperties: |
|
| 3352 |
- type: "string" |
|
| 3342 |
+ description: | |
|
| 3343 |
+ Templating driver, if applicable |
|
| 3344 |
+ |
|
| 3345 |
+ Templating controls whether and how to evaluate the config payload as |
|
| 3346 |
+ a template. If no driver is set, no templating is used. |
|
| 3347 |
+ $ref: "#/definitions/Driver" |
|
| 3353 | 3348 |
|
| 3354 | 3349 |
Secret: |
| 3355 | 3350 |
type: "object" |
| ... | ... |
@@ -3387,17 +3382,12 @@ definitions: |
| 3387 | 3387 |
config data. |
| 3388 | 3388 |
type: "string" |
| 3389 | 3389 |
Templating: |
| 3390 |
- description: "Templating driver, if applicable" |
|
| 3391 |
- type: "object" |
|
| 3392 |
- properties: |
|
| 3393 |
- Name: |
|
| 3394 |
- description: "Name of the templating driver (i.e. 'golang')" |
|
| 3395 |
- type: "string" |
|
| 3396 |
- Options: |
|
| 3397 |
- description: "key/value map of driver specific options." |
|
| 3398 |
- type: "object" |
|
| 3399 |
- additionalProperties: |
|
| 3400 |
- type: "string" |
|
| 3390 |
+ description: | |
|
| 3391 |
+ Templating driver, if applicable |
|
| 3392 |
+ |
|
| 3393 |
+ Templating controls whether and how to evaluate the config payload as |
|
| 3394 |
+ a template. If no driver is set, no templating is used. |
|
| 3395 |
+ $ref: "#/definitions/Driver" |
|
| 3401 | 3396 |
|
| 3402 | 3397 |
Config: |
| 3403 | 3398 |
type: "object" |
| ... | ... |
@@ -19,7 +19,6 @@ import ( |
| 19 | 19 |
"github.com/docker/docker/pkg/stringid" |
| 20 | 20 |
"github.com/docker/docker/runconfig" |
| 21 | 21 |
"github.com/docker/libnetwork" |
| 22 |
- "github.com/docker/swarmkit/template" |
|
| 23 | 22 |
"github.com/opencontainers/selinux/go-selinux/label" |
| 24 | 23 |
"github.com/pkg/errors" |
| 25 | 24 |
"github.com/sirupsen/logrus" |
| ... | ... |
@@ -161,17 +160,23 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
| 161 | 161 |
return nil |
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 |
-func (daemon *Daemon) setupSecretDir(c *container.Container, hasSecretDir *bool) (setupErr error) {
|
|
| 164 |
+func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
|
| 165 | 165 |
if len(c.SecretReferences) == 0 {
|
| 166 | 166 |
return nil |
| 167 | 167 |
} |
| 168 | 168 |
|
| 169 |
- if !*hasSecretDir {
|
|
| 170 |
- if err := daemon.createSecretDir(c); err != nil {
|
|
| 171 |
- return err |
|
| 172 |
- } |
|
| 173 |
- *hasSecretDir = true |
|
| 169 |
+ localMountPath, err := c.SecretMountPath() |
|
| 170 |
+ if err != nil {
|
|
| 171 |
+ return errors.Wrap(err, "error getting secrets mount path for container") |
|
| 174 | 172 |
} |
| 173 |
+ if err := daemon.createSecretsDir(localMountPath); err != nil {
|
|
| 174 |
+ return err |
|
| 175 |
+ } |
|
| 176 |
+ defer func() {
|
|
| 177 |
+ if setupErr != nil {
|
|
| 178 |
+ daemon.cleanupSecretDir(localMountPath) |
|
| 179 |
+ } |
|
| 180 |
+ }() |
|
| 175 | 181 |
|
| 176 | 182 |
if c.DependencyStore == nil {
|
| 177 | 183 |
return fmt.Errorf("secret store is not initialized")
|
| ... | ... |
@@ -226,64 +231,52 @@ func (daemon *Daemon) setupSecretDir(c *container.Container, hasSecretDir *bool) |
| 226 | 226 |
} |
| 227 | 227 |
} |
| 228 | 228 |
|
| 229 |
- return nil |
|
| 229 |
+ return daemon.remountSecretDir(c.MountLabel, localMountPath) |
|
| 230 | 230 |
} |
| 231 | 231 |
|
| 232 |
-func (daemon *Daemon) createSecretDir(c *container.Container) error {
|
|
| 233 |
- localMountPath, err := c.SecretMountPath() |
|
| 234 |
- if err != nil {
|
|
| 235 |
- return err |
|
| 236 |
- } |
|
| 237 |
- logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
|
|
| 238 |
- |
|
| 232 |
+// createSecretsDir is used to create a dir suitable for storing container secrets. |
|
| 233 |
+// In practice this is using a tmpfs mount and is used for both "configs" and "secrets" |
|
| 234 |
+func (daemon *Daemon) createSecretsDir(dir string) error {
|
|
| 239 | 235 |
// retrieve possible remapped range start for root UID, GID |
| 240 | 236 |
rootIDs := daemon.idMappings.RootPair() |
| 241 | 237 |
// create tmpfs |
| 242 |
- if err := idtools.MkdirAllAndChown(localMountPath, 0700, rootIDs); err != nil {
|
|
| 238 |
+ if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
|
|
| 243 | 239 |
return errors.Wrap(err, "error creating secret local mount path") |
| 244 | 240 |
} |
| 245 | 241 |
|
| 246 | 242 |
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
| 247 |
- if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
|
|
| 243 |
+ if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
|
|
| 248 | 244 |
return errors.Wrap(err, "unable to setup secret mount") |
| 249 | 245 |
} |
| 250 | 246 |
|
| 251 | 247 |
return nil |
| 252 | 248 |
} |
| 253 | 249 |
|
| 254 |
-func (daemon *Daemon) remountSecretDir(c *container.Container) error {
|
|
| 255 |
- localMountPath, err := c.SecretMountPath() |
|
| 256 |
- if err != nil {
|
|
| 257 |
- return err |
|
| 250 |
+func (daemon *Daemon) remountSecretDir(mountLabel, dir string) error {
|
|
| 251 |
+ if err := label.Relabel(dir, mountLabel, false); err != nil {
|
|
| 252 |
+ logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
|
| 258 | 253 |
} |
| 259 |
- |
|
| 260 |
- label.Relabel(localMountPath, c.MountLabel, false) |
|
| 261 |
- |
|
| 262 | 254 |
rootIDs := daemon.idMappings.RootPair() |
| 263 | 255 |
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
| 264 | 256 |
|
| 265 | 257 |
// remount secrets ro |
| 266 |
- if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
|
| 267 |
- return errors.Wrap(err, "unable to remount secret dir as readonly") |
|
| 258 |
+ if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
|
| 259 |
+ return errors.Wrap(err, "unable to remount dir as readonly") |
|
| 268 | 260 |
} |
| 269 | 261 |
|
| 270 | 262 |
return nil |
| 271 | 263 |
} |
| 272 | 264 |
|
| 273 |
-func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
|
|
| 274 |
- localMountPath, err := c.SecretMountPath() |
|
| 275 |
- if err != nil {
|
|
| 276 |
- logrus.WithError(err).WithField("container", c.ID).Errorf("error getting secrets mounth path for cleanup")
|
|
| 265 |
+func (daemon *Daemon) cleanupSecretDir(dir string) {
|
|
| 266 |
+ if err := mount.RecursiveUnmount(dir); err != nil {
|
|
| 267 |
+ logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
|
|
| 277 | 268 |
} |
| 278 |
- |
|
| 279 |
- detachMounted(localMountPath) |
|
| 280 |
- |
|
| 281 |
- if err := os.RemoveAll(localMountPath); err != nil {
|
|
| 282 |
- logrus.Errorf("error cleaning up secret mount: %s", err)
|
|
| 269 |
+ if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
|
|
| 270 |
+ logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
|
|
| 283 | 271 |
} |
| 284 | 272 |
} |
| 285 | 273 |
|
| 286 |
-func (daemon *Daemon) setupConfigDir(c *container.Container, hasSecretDir *bool) (setupErr error) {
|
|
| 274 |
+func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
|
| 287 | 275 |
if len(c.ConfigReferences) == 0 {
|
| 288 | 276 |
return nil |
| 289 | 277 |
} |
| ... | ... |
@@ -293,73 +286,55 @@ func (daemon *Daemon) setupConfigDir(c *container.Container, hasSecretDir *bool) |
| 293 | 293 |
return err |
| 294 | 294 |
} |
| 295 | 295 |
logrus.Debugf("configs: setting up config dir: %s", localPath)
|
| 296 |
- |
|
| 297 |
- // retrieve possible remapped range start for root UID, GID |
|
| 298 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 299 |
- // create tmpfs |
|
| 300 |
- if err := idtools.MkdirAllAndChown(localPath, 0700, rootIDs); err != nil {
|
|
| 301 |
- return errors.Wrap(err, "error creating config dir") |
|
| 296 |
+ if err := daemon.createSecretsDir(localPath); err != nil {
|
|
| 297 |
+ return err |
|
| 302 | 298 |
} |
| 303 |
- |
|
| 304 | 299 |
defer func() {
|
| 305 | 300 |
if setupErr != nil {
|
| 306 |
- if err := os.RemoveAll(localPath); err != nil {
|
|
| 307 |
- logrus.Errorf("error cleaning up config dir: %s", err)
|
|
| 308 |
- } |
|
| 301 |
+ daemon.cleanupSecretDir(localPath) |
|
| 309 | 302 |
} |
| 310 | 303 |
}() |
| 311 | 304 |
|
| 312 | 305 |
if c.DependencyStore == nil {
|
| 313 |
- return fmt.Errorf("config store is not initialized")
|
|
| 306 |
+ return errors.New("config store is not initialized")
|
|
| 314 | 307 |
} |
| 315 | 308 |
|
| 316 |
- for _, configRef := range c.ConfigReferences {
|
|
| 309 |
+ // retrieve possible remapped range start for root UID, GID |
|
| 310 |
+ rootIDs := daemon.idMappings.RootPair() |
|
| 311 |
+ |
|
| 312 |
+ for _, ref := range c.ConfigReferences {
|
|
| 317 | 313 |
// TODO (ehazlett): use type switch when more are supported |
| 318 |
- if configRef.File == nil {
|
|
| 314 |
+ if ref.File == nil {
|
|
| 319 | 315 |
logrus.Error("config target type is not a file target")
|
| 320 | 316 |
continue |
| 321 | 317 |
} |
| 322 |
- |
|
| 323 |
- getter := c.DependencyStore.Configs().(template.TemplatedConfigGetter) |
|
| 324 |
- config, sensitive, err := getter.GetAndFlagSecretData(configRef.ConfigID) |
|
| 325 |
- if err != nil {
|
|
| 326 |
- return errors.Wrap(err, "unable to get config from config store") |
|
| 327 |
- } |
|
| 328 |
- |
|
| 329 |
- var fPath string |
|
| 330 |
- if sensitive {
|
|
| 331 |
- configRef.Sensitive = true |
|
| 332 |
- fPath, err = c.SensitiveConfigFilePath(*configRef.ConfigReference) |
|
| 333 |
- if !*hasSecretDir {
|
|
| 334 |
- if err := daemon.createSecretDir(c); err != nil {
|
|
| 335 |
- return err |
|
| 336 |
- } |
|
| 337 |
- *hasSecretDir = true |
|
| 338 |
- } |
|
| 339 |
- } else {
|
|
| 340 |
- fPath, err = c.ConfigFilePath(*configRef.ConfigReference) |
|
| 341 |
- } |
|
| 318 |
+ // configs are created in the ConfigsDirPath on the host, at a |
|
| 319 |
+ // single level |
|
| 320 |
+ fPath, err := c.ConfigFilePath(*ref.ConfigReference) |
|
| 342 | 321 |
if err != nil {
|
| 343 |
- return errors.Wrap(err, "error getting config file path") |
|
| 322 |
+ return err |
|
| 344 | 323 |
} |
| 345 |
- |
|
| 346 |
- log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
|
|
| 347 |
- |
|
| 348 |
- log.Debug("injecting config")
|
|
| 349 |
- |
|
| 350 | 324 |
if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
|
| 351 |
- return errors.Wrap(err, "error creating config path") |
|
| 325 |
+ return errors.Wrap(err, "error creating config mount path") |
|
| 352 | 326 |
} |
| 353 | 327 |
|
| 354 |
- if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil {
|
|
| 328 |
+ logrus.WithFields(logrus.Fields{
|
|
| 329 |
+ "name": ref.File.Name, |
|
| 330 |
+ "path": fPath, |
|
| 331 |
+ }).Debug("injecting config")
|
|
| 332 |
+ config, err := c.DependencyStore.Configs().Get(ref.ConfigID) |
|
| 333 |
+ if err != nil {
|
|
| 334 |
+ return errors.Wrap(err, "unable to get config from config store") |
|
| 335 |
+ } |
|
| 336 |
+ if err := ioutil.WriteFile(fPath, config.Spec.Data, ref.File.Mode); err != nil {
|
|
| 355 | 337 |
return errors.Wrap(err, "error injecting config") |
| 356 | 338 |
} |
| 357 | 339 |
|
| 358 |
- uid, err := strconv.Atoi(configRef.File.UID) |
|
| 340 |
+ uid, err := strconv.Atoi(ref.File.UID) |
|
| 359 | 341 |
if err != nil {
|
| 360 | 342 |
return err |
| 361 | 343 |
} |
| 362 |
- gid, err := strconv.Atoi(configRef.File.GID) |
|
| 344 |
+ gid, err := strconv.Atoi(ref.File.GID) |
|
| 363 | 345 |
if err != nil {
|
| 364 | 346 |
return err |
| 365 | 347 |
} |
| ... | ... |
@@ -374,7 +349,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container, hasSecretDir *bool) |
| 374 | 374 |
label.Relabel(fPath, c.MountLabel, false) |
| 375 | 375 |
} |
| 376 | 376 |
|
| 377 |
- return nil |
|
| 377 |
+ return daemon.remountSecretDir(c.MountLabel, localPath) |
|
| 378 | 378 |
} |
| 379 | 379 |
|
| 380 | 380 |
func killProcessDirectly(cntr *container.Container) error {
|
| ... | ... |
@@ -842,27 +842,29 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e |
| 842 | 842 |
return nil, err |
| 843 | 843 |
} |
| 844 | 844 |
|
| 845 |
- var hasSecretDir bool |
|
| 845 |
+ secretMountPath, err := c.SecretMountPath() |
|
| 846 |
+ if err != nil {
|
|
| 847 |
+ return nil, err |
|
| 848 |
+ } |
|
| 849 |
+ configsMountPath, err := c.ConfigsDirPath() |
|
| 850 |
+ if err != nil {
|
|
| 851 |
+ return nil, err |
|
| 852 |
+ } |
|
| 846 | 853 |
defer func() {
|
| 847 |
- if hasSecretDir && err != nil {
|
|
| 848 |
- daemon.cleanupSecretDir(c) |
|
| 854 |
+ if err != nil {
|
|
| 855 |
+ daemon.cleanupSecretDir(secretMountPath) |
|
| 856 |
+ daemon.cleanupSecretDir(configsMountPath) |
|
| 849 | 857 |
} |
| 850 | 858 |
}() |
| 851 | 859 |
|
| 852 |
- if err := daemon.setupSecretDir(c, &hasSecretDir); err != nil {
|
|
| 860 |
+ if err := daemon.setupSecretDir(c); err != nil {
|
|
| 853 | 861 |
return nil, err |
| 854 | 862 |
} |
| 855 | 863 |
|
| 856 |
- if err := daemon.setupConfigDir(c, &hasSecretDir); err != nil {
|
|
| 864 |
+ if err := daemon.setupConfigDir(c); err != nil {
|
|
| 857 | 865 |
return nil, err |
| 858 | 866 |
} |
| 859 | 867 |
|
| 860 |
- if hasSecretDir {
|
|
| 861 |
- if err := daemon.remountSecretDir(c); err != nil {
|
|
| 862 |
- return nil, err |
|
| 863 |
- } |
|
| 864 |
- } |
|
| 865 |
- |
|
| 866 | 868 |
ms, err := daemon.setupMounts(c) |
| 867 | 869 |
if err != nil {
|
| 868 | 870 |
return nil, err |