Browse code

Always mount configs with tmpfs

This makes configs and secrets behavior identical.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2018/01/12 07:28:56
Showing 3 changed files
... ...
@@ -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