Ver Fonte

Add --security-opts options to allow user to customize security configuration

security-opts will allow you to customise the security subsystem.

For example the labeling system like SELinux will run on a container.

    --security-opt="label:user:USER"   : Set the label user for the container
    --security-opt="label:role:ROLE"   : Set the label role for the container
    --security-opt="label:type:TYPE"   : Set the label type for the container
    --security-opt="label:level:LEVEL" : Set the label level for the container
    --security-opt="label:disabled"    : Turn off label confinement for the container

Since we are passing a list of string options instead of a space separated
string of options, I will change function calls to use InitLabels instead of
GenLabels.  Genlabels interface is Depracated.

Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)
Dan Walsh há 10 anos atrás
pai
commit
87e732a0f3

+ 3 - 2
contrib/completion/bash/docker

@@ -620,10 +620,11 @@ _docker_run()
 
 	case "$cur" in
 		-*)
-			COMPREPLY=( $( compgen -W "--rm -d --detach -n --networking --privileged -P --publish-all -i --interactive -t --tty --cidfile --entrypoint -h --hostname -m --memory -u --user -w --workdir --cpuset -c --cpu-shares --sig-proxy --name -a --attach -v --volume --link -e --env -p --publish --expose --dns --volumes-from --lxc-conf" -- "$cur" ) )
+			COMPREPLY=( $( compgen -W "--rm -d --detach -n --networking --privileged -P --publish-all -i --interactive -t --tty --cidfile --entrypoint -h --hostname -m --memory -u --user -w --workdir --cpuset -c --cpu-shares --sig-proxy --name -a --attach -v --volume --link -e --env -p --publish --expose --dns --volumes-from --lxc-conf --security-opt" -- "$cur" ) )
 			;;
 		*)
-			local counter=$(__docker_pos_first_nonflag '--cidfile|--volumes-from|-v|--volume|-e|--env|--entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|--cpuset|-c|--cpu-shares|-n|--name|-a|--attach|--link|-p|--publish|--expose|--dns|--lxc-conf')
+
+			local counter=$(__docker_pos_first_nonflag '--cidfile|--volumes-from|-v|--volume|-e|--env|--entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|--cpuset|-c|--cpu-shares|-n|--name|-a|--attach|--link|-p|--publish|--expose|--dns|--lxc-conf|--security-opt')
 
 			if [ $cword -eq $counter ]; then
 				__docker_image_repos_and_tags_and_ids

+ 11 - 3
daemon/daemon.go

@@ -529,8 +529,9 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint, configCmd []string)
 
 func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *image.Image) (*Container, error) {
 	var (
-		id  string
-		err error
+		id         string
+		err        error
+		label_opts []string
 	)
 	id, name, err = daemon.generateIdAndName(name)
 	if err != nil {
@@ -558,7 +559,14 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i
 	}
 	container.root = daemon.containerRoot(container.ID)
 
-	if container.ProcessLabel, container.MountLabel, err = label.GenLabels(""); err != nil {
+	for _, opt := range config.SecurityOpt {
+		con := strings.SplitN(opt, ":", 2)
+		if con[0] == "label" {
+			label_opts = append(label_opts, con[1])
+		}
+	}
+
+	if container.ProcessLabel, container.MountLabel, err = label.InitLabels(label_opts); err != nil {
 		return nil, err
 	}
 	return container, nil

+ 4 - 1
daemon/execdriver/lxc/driver.go

@@ -409,7 +409,10 @@ func rootIsShared() bool {
 }
 
 func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) {
-	root := path.Join(d.root, "containers", c.ID, "config.lxc")
+	var (
+		root       = path.Join(d.root, "containers", c.ID, "config.lxc")
+		label_opts []string
+	)
 
 	fo, err := os.Create(root)
 	if err != nil {

+ 31 - 0
docs/man/docker-run.1.md

@@ -23,6 +23,7 @@ docker-run - Run a command in a new container
 [**--expose**[=*[]*]]
 [**-h**|**--hostname**[=*HOSTNAME*]]
 [**-i**|**--interactive**[=*false*]]
+[**--security-opt**[=*[]*]]
 [**--link**[=*[]*]]
 [**--lxc-conf**[=*[]*]]
 [**-m**|**--memory**[=*MEMORY*]]
@@ -143,6 +144,13 @@ container can be started with the **--link**.
 **-i**, **--interactive**=*true*|*false*
    When set to true, keep stdin open even if not attached. The default is false.
 
+**--security-opt**=*secdriver*:*name*:*value*
+    "label:user:USER"   : Set the label user for the container
+    "label:role:ROLE"   : Set the label role for the container
+    "label:type:TYPE"   : Set the label type for the container
+    "label:level:LEVEL" : Set the label level for the container
+    "label:disable"     : Turn off label confinement for the container
+
 **--link**=*name*:*alias*
    Add link to another container. The format is name:alias. If the operator
 uses **--link** when starting the new client container, then the client
@@ -383,6 +391,29 @@ to the host directory:
 Now, writing to the /data1 volume in the container will be allowed and the
 changes will also be reflected on the host in /var/db.
 
+## Using alternative security labeling
+
+If you want to use the same label for multiple containers you can override use
+the security-opt flag to select an MCS level.  This is a common practive for MLS
+systems.  But it also might help in cases where you want to share the same 
+content between containers. Run the following command.
+
+    # docker run --security-opt label:level:s0:c100,c200 -i -t fedora bash
+
+Run the follwing command if you want to disable the labeling controls for just 
+this container.
+
+    # docker run --security-opt label:disable -i -t fedora bash
+
+If you decide you would like to work with a tighter policy on your container.  
+For example if you want to run a container that could only listen on apache 
+ports, and not connect to the network. You could select an alternate type to 
+run the container execute the following command.
+
+    # docker run --security-opt label:type:svirt_apache_t -i -t fedora bash
+
+Note: You would have to write policy defining a svirt_apache_t type.
+
 # HISTORY
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
 based on docker.com source material and internal work.

+ 26 - 0
docs/sources/reference/run.md

@@ -225,6 +225,32 @@ the container exits**, you can add the `--rm` flag:
 
     --rm=false: Automatically remove the container when it exits (incompatible with -d)
 
+## Security Configuration
+    --security-opt="label:user:USER"   : Set the label user for the container
+    --security-opt="label:role:ROLE"   : Set the label role for the container
+    --security-opt="label:type:TYPE"   : Set the label type for the container
+    --security-opt="label:level:LEVEL" : Set the label level for the container
+    --security-opt="label:disable"     : Turn off label confinement for the container
+
+If you want to use the same label for multiple containers you can override use
+the security-opt flag to select an MCS level.  This is a common practive for MLS
+systems.  But it also might help in cases where you want to share the same 
+content between containers. Run the following command.
+
+    # docker run --security-opt label:level:s0:c100,c200 -i -t fedora bash
+
+Run the follwing command if you want to disable the labeling controls for just 
+this container.
+
+    # docker run --security-opt label:disable -i -t fedora bash
+
+If you decide you would like to work with a tighter policy on your container.  
+For example if you want to run a container that could only listen on apache 
+ports, and not connect to the network. You could select an alternate type to 
+run the container execute the following command.
+
+    # docker run --security-opt label:type:svirt_apache_t -i -t fedora bash
+
 ## Runtime Constraints on CPU and Memory
 
 The operator can also adjust the performance parameters of the

+ 37 - 0
integration-cli/docker_cli_run_test.go

@@ -19,6 +19,7 @@ import (
 
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/networkfs/resolvconf"
+	"github.com/docker/libcontainer/label"
 	"github.com/kr/pty"
 )
 
@@ -1719,6 +1720,42 @@ func TestRunWriteResolvFileAndNotCommit(t *testing.T) {
 	logDone("run - write to /etc/resolv.conf and not commited")
 }
 
+func TestRunSecurityOptLevel(t *testing.T) {
+	plabel, _, _ := label.InitLabels(nil)
+	if plabel != "" {
+		defer deleteAllContainers()
+		cmd := exec.Command(dockerBinary, "run", "--security-opt", "label:level:s0:c0,c100", "busybox", "ps", "-eZ")
+		out, _, err := runCommandWithOutput(cmd)
+		if err != nil {
+			t.Fatal(err, out)
+		}
+		id := strings.TrimSpace(out)
+		if !strings.ContainsAny(id, "s0:c0,c100") {
+			t.Fatal("security-opt label:level:s0:c0,c100 failed")
+		}
+	}
+
+	logDone("run - security-opt label:level")
+}
+
+func TestRunSecurityOptDisable(t *testing.T) {
+	plabel, _, _ := label.InitLabels(nil)
+	if plabel != "" {
+		defer deleteAllContainers()
+		cmd := exec.Command(dockerBinary, "run", "--security-opt", "label:disable", "busybox", "ps", "-eZ")
+		out, _, err := runCommandWithOutput(cmd)
+		if err != nil {
+			t.Fatal(err, out)
+		}
+		id := strings.TrimSpace(out)
+		if !strings.ContainsAny(id, "svirt") {
+			t.Fatal("security-opt label:level:disable failed")
+		}
+	}
+
+	logDone("run - security-opt label:disable")
+}
+
 func TestRunWithBadDevice(t *testing.T) {
 	name := "baddevice"
 	cmd := exec.Command(dockerBinary, "run", "--name", name, "--device", "/etc", "busybox", "true")

+ 2 - 0
runconfig/config.go

@@ -32,6 +32,7 @@ type Config struct {
 	Entrypoint      []string
 	NetworkDisabled bool
 	OnBuild         []string
+	SecurityOpt     []string
 }
 
 func ContainerConfigFromJob(job *engine.Job) *Config {
@@ -55,6 +56,7 @@ func ContainerConfigFromJob(job *engine.Job) *Config {
 	}
 	job.GetenvJson("ExposedPorts", &config.ExposedPorts)
 	job.GetenvJson("Volumes", &config.Volumes)
+	config.SecurityOpt = job.GetenvList("SecurityOpt")
 	if PortSpecs := job.GetenvList("PortSpecs"); PortSpecs != nil {
 		config.PortSpecs = PortSpecs
 	}

+ 3 - 0
runconfig/parse.go

@@ -43,6 +43,7 @@ func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config,
 		flEnvFile     = opts.NewListOpts(nil)
 		flCapAdd      = opts.NewListOpts(nil)
 		flCapDrop     = opts.NewListOpts(nil)
+		flSecurityOpt = opts.NewListOpts(nil)
 
 		flNetwork         = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")
 		flPrivileged      = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
@@ -79,6 +80,7 @@ func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config,
 
 	cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities")
 	cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
+	cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil, nil, cmd, err
@@ -254,6 +256,7 @@ func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config,
 		Volumes:         flVolumes.GetMap(),
 		Entrypoint:      entrypoint,
 		WorkingDir:      *flWorkingDir,
+		SecurityOpt:     flSecurityOpt.GetAll(),
 	}
 
 	hostConfig := &HostConfig{