Browse code

Consolidate security options to use `=` as separator.

All other options we have use `=` as separator, labels,
log configurations, graph configurations and so on.
We should be consistent and use `=` for the security
options too.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2016/03/16 07:34:29
Showing 11 changed files
... ...
@@ -1788,17 +1788,17 @@ _docker_run() {
1788 1788
 			;;
1789 1789
 		--security-opt)
1790 1790
 			case "$cur" in
1791
-				label:*:*)
1791
+				label=*:*)
1792 1792
 					;;
1793
-				label:*)
1794
-					local cur=${cur##*:}
1793
+				label=*)
1794
+					local cur=${cur##*=}
1795 1795
 					COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "$cur") )
1796 1796
 					if [ "${COMPREPLY[*]}" != "disable" ] ; then
1797 1797
 						__docker_nospace
1798 1798
 					fi
1799 1799
 					;;
1800
-				seccomp:*)
1801
-					local cur=${cur##*:}
1800
+				seccomp=*)
1801
+					local cur=${cur##*=}
1802 1802
 					_filedir
1803 1803
 					COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
1804 1804
 					;;
... ...
@@ -73,15 +73,21 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
73 73
 	)
74 74
 
75 75
 	for _, opt := range config.SecurityOpt {
76
-		con := strings.SplitN(opt, ":", 2)
77
-		if len(con) == 1 {
78
-			switch con[0] {
79
-			case "no-new-privileges":
80
-				container.NoNewPrivileges = true
81
-			default:
76
+		if opt == "no-new-privileges" {
77
+			container.NoNewPrivileges = true
78
+		} else {
79
+			var con []string
80
+			if strings.Contains(opt, "=") {
81
+				con = strings.SplitN(opt, "=", 2)
82
+			} else if strings.Contains(opt, ":") {
83
+				con = strings.SplitN(opt, ":", 2)
84
+				logrus.Warnf("Security options with `:` as a separator are deprecated and will be completely unsupported in 1.13, use `=` instead.")
85
+			}
86
+
87
+			if len(con) != 2 {
82 88
 				return fmt.Errorf("Invalid --security-opt 1: %q", opt)
83 89
 			}
84
-		} else {
90
+
85 91
 			switch con[0] {
86 92
 			case "label":
87 93
 				labelOpts = append(labelOpts, con[1])
... ...
@@ -90,12 +90,12 @@ func TestAdjustCPUSharesNoAdjustment(t *testing.T) {
90 90
 }
91 91
 
92 92
 // Unix test as uses settings which are not available on Windows
93
-func TestParseSecurityOpt(t *testing.T) {
93
+func TestParseSecurityOptWithDeprecatedColon(t *testing.T) {
94 94
 	container := &container.Container{}
95 95
 	config := &containertypes.HostConfig{}
96 96
 
97 97
 	// test apparmor
98
-	config.SecurityOpt = []string{"apparmor:test_profile"}
98
+	config.SecurityOpt = []string{"apparmor=test_profile"}
99 99
 	if err := parseSecurityOpt(container, config); err != nil {
100 100
 		t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
101 101
 	}
... ...
@@ -105,7 +105,7 @@ func TestParseSecurityOpt(t *testing.T) {
105 105
 
106 106
 	// test seccomp
107 107
 	sp := "/path/to/seccomp_test.json"
108
-	config.SecurityOpt = []string{"seccomp:" + sp}
108
+	config.SecurityOpt = []string{"seccomp=" + sp}
109 109
 	if err := parseSecurityOpt(container, config); err != nil {
110 110
 		t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
111 111
 	}
... ...
@@ -114,7 +114,49 @@ func TestParseSecurityOpt(t *testing.T) {
114 114
 	}
115 115
 
116 116
 	// test valid label
117
-	config.SecurityOpt = []string{"label:user:USER"}
117
+	config.SecurityOpt = []string{"label=user:USER"}
118
+	if err := parseSecurityOpt(container, config); err != nil {
119
+		t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
120
+	}
121
+
122
+	// test invalid label
123
+	config.SecurityOpt = []string{"label"}
124
+	if err := parseSecurityOpt(container, config); err == nil {
125
+		t.Fatal("Expected parseSecurityOpt error, got nil")
126
+	}
127
+
128
+	// test invalid opt
129
+	config.SecurityOpt = []string{"test"}
130
+	if err := parseSecurityOpt(container, config); err == nil {
131
+		t.Fatal("Expected parseSecurityOpt error, got nil")
132
+	}
133
+}
134
+
135
+func TestParseSecurityOpt(t *testing.T) {
136
+	container := &container.Container{}
137
+	config := &containertypes.HostConfig{}
138
+
139
+	// test apparmor
140
+	config.SecurityOpt = []string{"apparmor=test_profile"}
141
+	if err := parseSecurityOpt(container, config); err != nil {
142
+		t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
143
+	}
144
+	if container.AppArmorProfile != "test_profile" {
145
+		t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", container.AppArmorProfile)
146
+	}
147
+
148
+	// test seccomp
149
+	sp := "/path/to/seccomp_test.json"
150
+	config.SecurityOpt = []string{"seccomp=" + sp}
151
+	if err := parseSecurityOpt(container, config); err != nil {
152
+		t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
153
+	}
154
+	if container.SeccompProfile != sp {
155
+		t.Fatalf("Unexpected SeccompProfile, expected: %q, got %q", sp, container.SeccompProfile)
156
+	}
157
+
158
+	// test valid label
159
+	config.SecurityOpt = []string{"label=user:USER"}
118 160
 	if err := parseSecurityOpt(container, config); err != nil {
119 161
 		t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
120 162
 	}
... ...
@@ -21,6 +21,8 @@ The following list of features are deprecated in Engine.
21 21
 
22 22
 The docker login command is removing the ability to automatically register for an account with the target registry if the given username doesn't exist. Due to this change, the email flag is no longer required, and will be deprecated.
23 23
 
24
+The flag `--security-opt` doesn't use the colon separator(`:`) anymore to divide keys and values, it uses the equal symbol(`=`) for consinstency with other similar flags, like `--storage-opt`.
25
+
24 26
 ### Ambiguous event fields in API
25 27
 **Deprecated In Release: v1.10**
26 28
 
... ...
@@ -599,12 +599,12 @@ but the volume for `/bar` will not. Volumes inheritted via `--volumes-from` will
599 599
 with the same logic -- if the original volume was specified with a name it will **not** be removed.
600 600
 
601 601
 ## Security configuration
602
-    --security-opt="label:user:USER"   : Set the label user for the container
603
-    --security-opt="label:role:ROLE"   : Set the label role for the container
604
-    --security-opt="label:type:TYPE"   : Set the label type for the container
605
-    --security-opt="label:level:LEVEL" : Set the label level for the container
606
-    --security-opt="label:disable"     : Turn off label confinement for the container
607
-    --security-opt="apparmor:PROFILE"  : Set the apparmor profile to be applied
602
+    --security-opt="label=user:USER"   : Set the label user for the container
603
+    --security-opt="label=role:ROLE"   : Set the label role for the container
604
+    --security-opt="label=type:TYPE"   : Set the label type for the container
605
+    --security-opt="label=level:LEVEL" : Set the label level for the container
606
+    --security-opt="label=disable"     : Turn off label confinement for the container
607
+    --security-opt="apparmor=PROFILE"  : Set the apparmor profile to be applied
608 608
                                          to the container
609 609
     --security-opt="no-new-privileges" : Disable container processes from gaining
610 610
                                          new privileges
... ...
@@ -617,23 +617,23 @@ the `--security-opt` flag. For example, you can specify the MCS/MLS level, a
617 617
 requirement for MLS systems. Specifying the level in the following command
618 618
 allows you to share the same content between containers.
619 619
 
620
-    $ docker run --security-opt label:level:s0:c100,c200 -it fedora bash
620
+    $ docker run --security-opt label=level:s0:c100,c200 -it fedora bash
621 621
 
622 622
 An MLS example might be:
623 623
 
624
-    $ docker run --security-opt label:level:TopSecret -it rhel7 bash
624
+    $ docker run --security-opt label=level:TopSecret -it rhel7 bash
625 625
 
626 626
 To disable the security labeling for this container versus running with the
627 627
 `--permissive` flag, use the following command:
628 628
 
629
-    $ docker run --security-opt label:disable -it fedora bash
629
+    $ docker run --security-opt label=disable -it fedora bash
630 630
 
631 631
 If you want a tighter security policy on the processes within a container,
632 632
 you can specify an alternate type for the container. You could run a container
633 633
 that is only allowed to listen on Apache ports by executing the following
634 634
 command:
635 635
 
636
-    $ docker run --security-opt label:type:svirt_apache_t -it centos bash
636
+    $ docker run --security-opt label=type:svirt_apache_t -it centos bash
637 637
 
638 638
 > **Note**: You would have to write policy defining a `svirt_apache_t` type.
639 639
 
... ...
@@ -1078,7 +1078,7 @@ one can use this flag:
1078 1078
 > these cases to create your own custom seccomp profile based off our
1079 1079
 > [default](https://github.com/docker/docker/blob/master/profiles/seccomp/default.json).
1080 1080
 > Or if you don't want to run with the default seccomp profile, you can pass
1081
-> `--security-opt=seccomp:unconfined` on run.
1081
+> `--security-opt=seccomp=unconfined` on run.
1082 1082
 
1083 1083
 By default, Docker containers are "unprivileged" and cannot, for
1084 1084
 example, run a Docker daemon inside a Docker container. This is because
... ...
@@ -69,7 +69,7 @@ override it with the `security-opt` option. For example, the following
69 69
 explicitly specifies the default policy:
70 70
 
71 71
 ```bash
72
-$ docker run --rm -it --security-opt apparmor:docker-default hello-world
72
+$ docker run --rm -it --security-opt apparmor=docker-default hello-world
73 73
 ```
74 74
 
75 75
 ## Loading and Unloading Profiles
... ...
@@ -83,7 +83,7 @@ $ apparmor_parser -r -W /path/to/your_profile
83 83
 Then you can run the custom profile with `--security-opt` like so:
84 84
 
85 85
 ```bash
86
-$ docker run --rm -it --security-opt apparmor:your_profile hello-world
86
+$ docker run --rm -it --security-opt apparmor=your_profile hello-world
87 87
 ```
88 88
 
89 89
 To unload a profile from AppArmor:
... ...
@@ -66,7 +66,7 @@ it with the `security-opt` option. For example, the following explicitly
66 66
 specifies the default policy:
67 67
 
68 68
 ```
69
-$ docker run --rm -it --security-opt seccomp:/path/to/seccomp/profile.json hello-world
69
+$ docker run --rm -it --security-opt seccomp=/path/to/seccomp/profile.json hello-world
70 70
 ```
71 71
 
72 72
 ### Significant syscalls blocked by the default profile
... ...
@@ -138,6 +138,6 @@ You can pass `unconfined` to run a container without the default seccomp
138 138
 profile.
139 139
 
140 140
 ```
141
-$ docker run --rm -it --security-opt seccomp:unconfined debian:jessie \
141
+$ docker run --rm -it --security-opt seccomp=unconfined debian:jessie \
142 142
     unshare --map-root-user --user sh -c whoami
143 143
 ```
... ...
@@ -2971,7 +2971,7 @@ func (s *DockerSuite) TestRunReadFilteredProc(c *check.C) {
2971 2971
 		name := fmt.Sprintf("procsieve-%d", i)
2972 2972
 		shellCmd := fmt.Sprintf("exec 3<%s", filePath)
2973 2973
 
2974
-		out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
2974
+		out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
2975 2975
 		if exitCode != 0 {
2976 2976
 			return
2977 2977
 		}
... ...
@@ -3006,7 +3006,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
3006 3006
 
3007 3007
 	go func() {
3008 3008
 		name := "acidburn"
3009
-		out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
3009
+		out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
3010 3010
 		if err == nil ||
3011 3011
 			!(strings.Contains(strings.ToLower(out), "permission denied") ||
3012 3012
 				strings.Contains(strings.ToLower(out), "operation not permitted")) {
... ...
@@ -3018,7 +3018,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
3018 3018
 
3019 3019
 	go func() {
3020 3020
 		name := "cereal"
3021
-		out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
3021
+		out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
3022 3022
 		if err == nil ||
3023 3023
 			!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
3024 3024
 				strings.Contains(strings.ToLower(out), "permission denied")) {
... ...
@@ -3031,7 +3031,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
3031 3031
 	/* Ensure still fails if running privileged with the default policy */
3032 3032
 	go func() {
3033 3033
 		name := "crashoverride"
3034
-		out, _, err := dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp:unconfined", "--security-opt", "apparmor:docker-default", "--name", name, "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
3034
+		out, _, err := dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp=unconfined", "--security-opt", "apparmor=docker-default", "--name", name, "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
3035 3035
 		if err == nil ||
3036 3036
 			!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
3037 3037
 				strings.Contains(strings.ToLower(out), "permission denied")) {
... ...
@@ -3128,7 +3128,7 @@ func (s *DockerSuite) TestRunWriteFilteredProc(c *check.C) {
3128 3128
 		name := fmt.Sprintf("writeprocsieve-%d", i)
3129 3129
 
3130 3130
 		shellCmd := fmt.Sprintf("exec 3>%s", filePath)
3131
-		out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
3131
+		out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
3132 3132
 		if code != 0 {
3133 3133
 			return
3134 3134
 		}
... ...
@@ -709,7 +709,7 @@ func (s *DockerSuite) TestRunTmpfsMounts(c *check.C) {
709 709
 	}
710 710
 }
711 711
 
712
-// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp:/tmp/profile.json debian:jessie unshare' exits with operation not permitted.
712
+// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp=/tmp/profile.json debian:jessie unshare' exits with operation not permitted.
713 713
 func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
714 714
 	testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor)
715 715
 	jsonData := `{
... ...
@@ -730,14 +730,14 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
730 730
 	if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
731 731
 		c.Fatal(err)
732 732
 	}
733
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
733
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
734 734
 	out, _, _ := runCommandWithOutput(runCmd)
735 735
 	if !strings.Contains(out, "Operation not permitted") {
736 736
 		c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
737 737
 	}
738 738
 }
739 739
 
740
-// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp:/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
740
+// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp=/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
741 741
 func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
742 742
 	testRequires(c, SameHostDaemon, seccompEnabled)
743 743
 	jsonData := `{
... ...
@@ -758,7 +758,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
758 758
 	if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
759 759
 		c.Fatal(err)
760 760
 	}
761
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname")
761
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname")
762 762
 	out, _, _ := runCommandWithOutput(runCmd)
763 763
 	if !strings.Contains(out, "Operation not permitted") {
764 764
 		c.Fatalf("expected chmod with seccomp profile denied to fail, got %s", out)
... ...
@@ -795,7 +795,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
795 795
 	if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
796 796
 		c.Fatal(err)
797 797
 	}
798
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
798
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
799 799
 	out, _, _ := runCommandWithOutput(runCmd)
800 800
 	if !strings.Contains(out, "Operation not permitted") {
801 801
 		c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out)
... ...
@@ -815,14 +815,14 @@ func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
815 815
 }
816 816
 
817 817
 // TestRunSeccompUnconfinedCloneUserns checks that
818
-// 'docker run --security-opt seccomp:unconfined syscall-test' allows creating a userns.
818
+// 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns.
819 819
 func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) {
820 820
 	testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace)
821 821
 
822 822
 	// make sure running w privileged is ok
823
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "syscall-test", "userns-test", "id")
823
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id")
824 824
 	if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") {
825
-		c.Fatalf("expected clone userns with --security-opt seccomp:unconfined to succeed, got %s: %v", out, err)
825
+		c.Fatalf("expected clone userns with --security-opt seccomp=unconfined to succeed, got %s: %v", out, err)
826 826
 	}
827 827
 }
828 828
 
... ...
@@ -872,7 +872,7 @@ func (s *DockerSuite) TestRunSeccompDefaultProfile(c *check.C) {
872 872
 	}()
873 873
 
874 874
 	go func() {
875
-		out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp:unconfined", "syscall-test", "acct-test")
875
+		out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "acct-test")
876 876
 		if err == nil || !strings.Contains(out, "No such file or directory") {
877 877
 			errChan <- fmt.Errorf("expected No such file or directory, got: %s", out)
878 878
 		}
... ...
@@ -880,7 +880,7 @@ func (s *DockerSuite) TestRunSeccompDefaultProfile(c *check.C) {
880 880
 	}()
881 881
 
882 882
 	go func() {
883
-		out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp:unconfined", "syscall-test", "ns-test", "echo", "hello")
883
+		out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "ns-test", "echo", "hello")
884 884
 		if err != nil || !strings.Contains(out, "hello") {
885 885
 			errChan <- fmt.Errorf("expected hello, got: %s, %v", out, err)
886 886
 		}
... ...
@@ -911,12 +911,12 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
911 911
 	testRequires(c, SameHostDaemon, Apparmor)
912 912
 
913 913
 	// running w seccomp unconfined tests the apparmor profile
914
-	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "busybox", "chmod", "777", "/proc/1/cgroup")
914
+	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/cgroup")
915 915
 	if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
916 916
 		c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err)
917 917
 	}
918 918
 
919
-	runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "busybox", "chmod", "777", "/proc/1/attr/current")
919
+	runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/attr/current")
920 920
 	if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
921 921
 		c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err)
922 922
 	}
... ...
@@ -927,7 +927,7 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
927 927
 func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) {
928 928
 	testRequires(c, SameHostDaemon, seccompEnabled)
929 929
 
930
-	out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp:../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
930
+	out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
931 931
 	c.Assert(err, checker.NotNil, check.Commentf(out))
932 932
 	c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted")
933 933
 }
... ...
@@ -463,16 +463,18 @@ its root filesystem mounted as read only prohibiting any writes.
463 463
 **--security-opt**=[]
464 464
    Security Options
465 465
 
466
-   "label:user:USER"   : Set the label user for the container
467
-    "label:role:ROLE"   : Set the label role for the container
468
-    "label:type:TYPE"   : Set the label type for the container
469
-    "label:level:LEVEL" : Set the label level for the container
470
-    "label:disable"     : Turn off label confinement for the container
471
-
466
+    "label=user:USER"   : Set the label user for the container
467
+    "label=role:ROLE"   : Set the label role for the container
468
+    "label=type:TYPE"   : Set the label type for the container
469
+    "label=level:LEVEL" : Set the label level for the container
470
+    "label=disable"     : Turn off label confinement for the container
472 471
     "no-new-privileges" : Disable container processes from gaining additional privileges
473 472
 
474
-    "seccomp:unconfined" : Turn off seccomp confinement for the container
475
-    "seccomp:profile.json :  White listed syscalls seccomp Json file to be used as a seccomp filter
473
+    "seccomp=unconfined" : Turn off seccomp confinement for the container
474
+    "seccomp=profile.json :  White listed syscalls seccomp Json file to be used as a seccomp filter
475
+
476
+    "apparmor=unconfined" : Turn off apparmor confinement for the container
477
+    "apparmor=your-profile" : Set the apparmor confinement profile for the container
476 478
 
477 479
 **--stop-signal**=*SIGTERM*
478 480
   Signal to stop a container. Default is SIGTERM.
... ...
@@ -880,23 +882,23 @@ the `--security-opt` flag. For example, you can specify the MCS/MLS level, a
880 880
 requirement for MLS systems. Specifying the level in the following command
881 881
 allows you to share the same content between containers.
882 882
 
883
-    # docker run --security-opt label:level:s0:c100,c200 -i -t fedora bash
883
+    # docker run --security-opt label=level:s0:c100,c200 -i -t fedora bash
884 884
 
885 885
 An MLS example might be:
886 886
 
887
-    # docker run --security-opt label:level:TopSecret -i -t rhel7 bash
887
+    # docker run --security-opt label=level:TopSecret -i -t rhel7 bash
888 888
 
889 889
 To disable the security labeling for this container versus running with the
890 890
 `--permissive` flag, use the following command:
891 891
 
892
-    # docker run --security-opt label:disable -i -t fedora bash
892
+    # docker run --security-opt label=disable -i -t fedora bash
893 893
 
894 894
 If you want a tighter security policy on the processes within a container,
895 895
 you can specify an alternate type for the container. You could run a container
896 896
 that is only allowed to listen on Apache ports by executing the following
897 897
 command:
898 898
 
899
-    # docker run --security-opt label:type:svirt_apache_t -i -t centos bash
899
+    # docker run --security-opt label=type:svirt_apache_t -i -t centos bash
900 900
 
901 901
 Note:
902 902
 
... ...
@@ -508,9 +508,13 @@ func parseLoggingOpts(loggingDriver string, loggingOpts []string) (map[string]st
508 508
 // takes a local seccomp daemon, reads the file contents for sending to the daemon
509 509
 func parseSecurityOpts(securityOpts []string) ([]string, error) {
510 510
 	for key, opt := range securityOpts {
511
-		con := strings.SplitN(opt, ":", 2)
511
+		con := strings.SplitN(opt, "=", 2)
512 512
 		if len(con) == 1 && con[0] != "no-new-privileges" {
513
-			return securityOpts, fmt.Errorf("Invalid --security-opt: %q", opt)
513
+			if strings.Index(opt, ":") != -1 {
514
+				con = strings.SplitN(opt, ":", 2)
515
+			} else {
516
+				return securityOpts, fmt.Errorf("Invalid --security-opt: %q", opt)
517
+			}
514 518
 		}
515 519
 		if con[0] == "seccomp" && con[1] != "unconfined" {
516 520
 			f, err := ioutil.ReadFile(con[1])
... ...
@@ -521,7 +525,7 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
521 521
 			if err := json.Compact(b, f); err != nil {
522 522
 				return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
523 523
 			}
524
-			securityOpts[key] = fmt.Sprintf("seccomp:%s", b.Bytes())
524
+			securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
525 525
 		}
526 526
 	}
527 527