Browse Source

Add support for ambient capabilities

Linux kernel 4.3 and later supports "ambient capabilities" which are the
only way to pass capabilities to containers running as a non root uid.

Previously there was no way to allow containers not running as root
capabilities in a useful way.

Fix #8460

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
Justin Cormack 8 years ago
parent
commit
199e19548e

+ 4 - 0
docs/reference/run.md

@@ -1220,6 +1220,10 @@ since Docker 1.12. In Docker 1.10 and 1.11 this did not happen and it may be nec
 to use a custom seccomp profile or use `--security-opt seccomp=unconfined` when adding
 to use a custom seccomp profile or use `--security-opt seccomp=unconfined` when adding
 capabilities.
 capabilities.
 
 
+It is only possible to grant capabilities to a container running as a user other than `root`
+on a system with a Linux kernel version of 4.3 or later, as this requires "ambient capabilities"
+to be granted. These will be added if the kernel allows it from Docker version 1.13.
+
 ## Logging drivers (--log-driver)
 ## Logging drivers (--log-driver)
 
 
 The container can have a different logging driver than the Docker daemon. Use
 The container can have a different logging driver than the Docker daemon. Use

+ 8 - 0
docs/security/security.md

@@ -212,6 +212,14 @@ capability removal, or less secure through the addition of capabilities.
 The best practice for users would be to remove all capabilities except
 The best practice for users would be to remove all capabilities except
 those explicitly required for their processes.
 those explicitly required for their processes.
 
 
+Linux kernel versions since 4.3 allow Docker to grant capabilities to
+container processes running as a non root user. This adds an extra
+layer of protection as the process can then be denied access to be able
+to write files belonging to the root uid, for example. User namespaces
+also allow capabilities to be granted to processes that are effectively
+non root, but these capabilities are limited to resources created in the
+user namespace, so they have limitations.
+
 ## Other kernel security features
 ## Other kernel security features
 
 
 Capabilities are just one of the many security features provided by
 Capabilities are just one of the many security features provided by

+ 18 - 0
integration-cli/docker_cli_run_unix_test.go

@@ -1155,6 +1155,24 @@ func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) {
 	}
 	}
 }
 }
 
 
+func (s *DockerSuite) TestRunAmbientCapabilities(c *check.C) {
+	testRequires(c, DaemonIsLinux, ambientCapabilities)
+
+	// test that a non root user can gain capabilities
+	runCmd := exec.Command(dockerBinary, "run", "--user", "1000", "--cap-add", "chown", "busybox", "chown", "100", "/tmp")
+	_, _, err := runCommandWithOutput(runCmd)
+	c.Assert(err, check.IsNil)
+	// test that non root user has default capabilities
+	runCmd = exec.Command(dockerBinary, "run", "--user", "1000", "busybox", "chown", "100", "/tmp")
+	_, _, err = runCommandWithOutput(runCmd)
+	c.Assert(err, check.IsNil)
+	// test this fails without cap_chown
+	runCmd = exec.Command(dockerBinary, "run", "--user", "1000", "--cap-drop", "chown", "busybox", "chown", "100", "/tmp")
+	out, _, err := runCommandWithOutput(runCmd)
+	c.Assert(err, checker.NotNil, check.Commentf(out))
+	c.Assert(strings.TrimSpace(out), checker.Equals, "chown: /tmp: Operation not permitted")
+}
+
 func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
 func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
 	testRequires(c, SameHostDaemon, Apparmor)
 	testRequires(c, SameHostDaemon, Apparmor)
 
 

+ 10 - 0
integration-cli/requirements_unix.go

@@ -112,6 +112,16 @@ var (
 		},
 		},
 		"Test cannot be run with 'sysctl kernel.unprivileged_userns_clone' = 0",
 		"Test cannot be run with 'sysctl kernel.unprivileged_userns_clone' = 0",
 	}
 	}
+	ambientCapabilities = testRequirement{
+		func() bool {
+			content, err := ioutil.ReadFile("/proc/self/status")
+			if err == nil && strings.Contains(string(content), "CapAmb:") {
+				return true
+			}
+			return false
+		},
+		"Test cannot be run without a kernel (4.3+) supporting ambient capabilities",
+	}
 )
 )
 
 
 func init() {
 func init() {