mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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>
This commit is contained in:
parent
b4da157846
commit
cb9aeb0413
11 changed files with 120 additions and 64 deletions
|
@ -1788,17 +1788,17 @@ _docker_run() {
|
||||||
;;
|
;;
|
||||||
--security-opt)
|
--security-opt)
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
label:*:*)
|
label=*:*)
|
||||||
;;
|
;;
|
||||||
label:*)
|
label=*)
|
||||||
local cur=${cur##*:}
|
local cur=${cur##*=}
|
||||||
COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "$cur") )
|
COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "$cur") )
|
||||||
if [ "${COMPREPLY[*]}" != "disable" ] ; then
|
if [ "${COMPREPLY[*]}" != "disable" ] ; then
|
||||||
__docker_nospace
|
__docker_nospace
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
seccomp:*)
|
seccomp=*)
|
||||||
local cur=${cur##*:}
|
local cur=${cur##*=}
|
||||||
_filedir
|
_filedir
|
||||||
COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
|
COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -73,15 +73,21 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, opt := range config.SecurityOpt {
|
for _, opt := range config.SecurityOpt {
|
||||||
con := strings.SplitN(opt, ":", 2)
|
if opt == "no-new-privileges" {
|
||||||
if len(con) == 1 {
|
container.NoNewPrivileges = true
|
||||||
switch con[0] {
|
} else {
|
||||||
case "no-new-privileges":
|
var con []string
|
||||||
container.NoNewPrivileges = true
|
if strings.Contains(opt, "=") {
|
||||||
default:
|
con = strings.SplitN(opt, "=", 2)
|
||||||
|
} else if strings.Contains(opt, ":") {
|
||||||
|
con = strings.SplitN(opt, ":", 2)
|
||||||
|
logrus.Warnf("Security options with `:` as a separator are deprecated and will be completely unsupported in 1.13, use `=` instead.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(con) != 2 {
|
||||||
return fmt.Errorf("Invalid --security-opt 1: %q", opt)
|
return fmt.Errorf("Invalid --security-opt 1: %q", opt)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
switch con[0] {
|
switch con[0] {
|
||||||
case "label":
|
case "label":
|
||||||
labelOpts = append(labelOpts, con[1])
|
labelOpts = append(labelOpts, con[1])
|
||||||
|
|
|
@ -90,12 +90,12 @@ func TestAdjustCPUSharesNoAdjustment(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unix test as uses settings which are not available on Windows
|
// Unix test as uses settings which are not available on Windows
|
||||||
func TestParseSecurityOpt(t *testing.T) {
|
func TestParseSecurityOptWithDeprecatedColon(t *testing.T) {
|
||||||
container := &container.Container{}
|
container := &container.Container{}
|
||||||
config := &containertypes.HostConfig{}
|
config := &containertypes.HostConfig{}
|
||||||
|
|
||||||
// test apparmor
|
// test apparmor
|
||||||
config.SecurityOpt = []string{"apparmor:test_profile"}
|
config.SecurityOpt = []string{"apparmor=test_profile"}
|
||||||
if err := parseSecurityOpt(container, config); err != nil {
|
if err := parseSecurityOpt(container, config); err != nil {
|
||||||
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func TestParseSecurityOpt(t *testing.T) {
|
||||||
|
|
||||||
// test seccomp
|
// test seccomp
|
||||||
sp := "/path/to/seccomp_test.json"
|
sp := "/path/to/seccomp_test.json"
|
||||||
config.SecurityOpt = []string{"seccomp:" + sp}
|
config.SecurityOpt = []string{"seccomp=" + sp}
|
||||||
if err := parseSecurityOpt(container, config); err != nil {
|
if err := parseSecurityOpt(container, config); err != nil {
|
||||||
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,49 @@ func TestParseSecurityOpt(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test valid label
|
// test valid label
|
||||||
config.SecurityOpt = []string{"label:user:USER"}
|
config.SecurityOpt = []string{"label=user:USER"}
|
||||||
|
if err := parseSecurityOpt(container, config); err != nil {
|
||||||
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test invalid label
|
||||||
|
config.SecurityOpt = []string{"label"}
|
||||||
|
if err := parseSecurityOpt(container, config); err == nil {
|
||||||
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// test invalid opt
|
||||||
|
config.SecurityOpt = []string{"test"}
|
||||||
|
if err := parseSecurityOpt(container, config); err == nil {
|
||||||
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseSecurityOpt(t *testing.T) {
|
||||||
|
container := &container.Container{}
|
||||||
|
config := &containertypes.HostConfig{}
|
||||||
|
|
||||||
|
// test apparmor
|
||||||
|
config.SecurityOpt = []string{"apparmor=test_profile"}
|
||||||
|
if err := parseSecurityOpt(container, config); err != nil {
|
||||||
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
||||||
|
}
|
||||||
|
if container.AppArmorProfile != "test_profile" {
|
||||||
|
t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", container.AppArmorProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test seccomp
|
||||||
|
sp := "/path/to/seccomp_test.json"
|
||||||
|
config.SecurityOpt = []string{"seccomp=" + sp}
|
||||||
|
if err := parseSecurityOpt(container, config); err != nil {
|
||||||
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
||||||
|
}
|
||||||
|
if container.SeccompProfile != sp {
|
||||||
|
t.Fatalf("Unexpected SeccompProfile, expected: %q, got %q", sp, container.SeccompProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test valid label
|
||||||
|
config.SecurityOpt = []string{"label=user:USER"}
|
||||||
if err := parseSecurityOpt(container, config); err != nil {
|
if err := parseSecurityOpt(container, config); err != nil {
|
||||||
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ The following list of features are deprecated in Engine.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
### Ambiguous event fields in API
|
### Ambiguous event fields in API
|
||||||
**Deprecated In Release: v1.10**
|
**Deprecated In Release: v1.10**
|
||||||
|
|
||||||
|
|
|
@ -599,12 +599,12 @@ but the volume for `/bar` will not. Volumes inheritted via `--volumes-from` will
|
||||||
with the same logic -- if the original volume was specified with a name it will **not** be removed.
|
with the same logic -- if the original volume was specified with a name it will **not** be removed.
|
||||||
|
|
||||||
## Security configuration
|
## Security configuration
|
||||||
--security-opt="label:user:USER" : Set the label user for the 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=role:ROLE" : Set the label role for the container
|
||||||
--security-opt="label:type:TYPE" : Set the label type 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=level:LEVEL" : Set the label level for the container
|
||||||
--security-opt="label:disable" : Turn off label confinement for the container
|
--security-opt="label=disable" : Turn off label confinement for the container
|
||||||
--security-opt="apparmor:PROFILE" : Set the apparmor profile to be applied
|
--security-opt="apparmor=PROFILE" : Set the apparmor profile to be applied
|
||||||
to the container
|
to the container
|
||||||
--security-opt="no-new-privileges" : Disable container processes from gaining
|
--security-opt="no-new-privileges" : Disable container processes from gaining
|
||||||
new privileges
|
new privileges
|
||||||
|
@ -617,23 +617,23 @@ the `--security-opt` flag. For example, you can specify the MCS/MLS level, a
|
||||||
requirement for MLS systems. Specifying the level in the following command
|
requirement for MLS systems. Specifying the level in the following command
|
||||||
allows you to share the same content between containers.
|
allows you to share the same content between containers.
|
||||||
|
|
||||||
$ docker run --security-opt label:level:s0:c100,c200 -it fedora bash
|
$ docker run --security-opt label=level:s0:c100,c200 -it fedora bash
|
||||||
|
|
||||||
An MLS example might be:
|
An MLS example might be:
|
||||||
|
|
||||||
$ docker run --security-opt label:level:TopSecret -it rhel7 bash
|
$ docker run --security-opt label=level:TopSecret -it rhel7 bash
|
||||||
|
|
||||||
To disable the security labeling for this container versus running with the
|
To disable the security labeling for this container versus running with the
|
||||||
`--permissive` flag, use the following command:
|
`--permissive` flag, use the following command:
|
||||||
|
|
||||||
$ docker run --security-opt label:disable -it fedora bash
|
$ docker run --security-opt label=disable -it fedora bash
|
||||||
|
|
||||||
If you want a tighter security policy on the processes within a container,
|
If you want a tighter security policy on the processes within a container,
|
||||||
you can specify an alternate type for the container. You could run a container
|
you can specify an alternate type for the container. You could run a container
|
||||||
that is only allowed to listen on Apache ports by executing the following
|
that is only allowed to listen on Apache ports by executing the following
|
||||||
command:
|
command:
|
||||||
|
|
||||||
$ docker run --security-opt label:type:svirt_apache_t -it centos bash
|
$ docker run --security-opt label=type:svirt_apache_t -it centos bash
|
||||||
|
|
||||||
> **Note**: You would have to write policy defining a `svirt_apache_t` type.
|
> **Note**: You would have to write policy defining a `svirt_apache_t` type.
|
||||||
|
|
||||||
|
@ -1078,7 +1078,7 @@ one can use this flag:
|
||||||
> these cases to create your own custom seccomp profile based off our
|
> these cases to create your own custom seccomp profile based off our
|
||||||
> [default](https://github.com/docker/docker/blob/master/profiles/seccomp/default.json).
|
> [default](https://github.com/docker/docker/blob/master/profiles/seccomp/default.json).
|
||||||
> Or if you don't want to run with the default seccomp profile, you can pass
|
> Or if you don't want to run with the default seccomp profile, you can pass
|
||||||
> `--security-opt=seccomp:unconfined` on run.
|
> `--security-opt=seccomp=unconfined` on run.
|
||||||
|
|
||||||
By default, Docker containers are "unprivileged" and cannot, for
|
By default, Docker containers are "unprivileged" and cannot, for
|
||||||
example, run a Docker daemon inside a Docker container. This is because
|
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
|
||||||
explicitly specifies the default policy:
|
explicitly specifies the default policy:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker run --rm -it --security-opt apparmor:docker-default hello-world
|
$ docker run --rm -it --security-opt apparmor=docker-default hello-world
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loading and Unloading Profiles
|
## Loading and Unloading Profiles
|
||||||
|
@ -83,7 +83,7 @@ $ apparmor_parser -r -W /path/to/your_profile
|
||||||
Then you can run the custom profile with `--security-opt` like so:
|
Then you can run the custom profile with `--security-opt` like so:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker run --rm -it --security-opt apparmor:your_profile hello-world
|
$ docker run --rm -it --security-opt apparmor=your_profile hello-world
|
||||||
```
|
```
|
||||||
|
|
||||||
To unload a profile from AppArmor:
|
To unload a profile from AppArmor:
|
||||||
|
|
|
@ -66,7 +66,7 @@ it with the `security-opt` option. For example, the following explicitly
|
||||||
specifies the default policy:
|
specifies the default policy:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ docker run --rm -it --security-opt seccomp:/path/to/seccomp/profile.json hello-world
|
$ docker run --rm -it --security-opt seccomp=/path/to/seccomp/profile.json hello-world
|
||||||
```
|
```
|
||||||
|
|
||||||
### Significant syscalls blocked by the default profile
|
### Significant syscalls blocked by the default profile
|
||||||
|
@ -138,6 +138,6 @@ You can pass `unconfined` to run a container without the default seccomp
|
||||||
profile.
|
profile.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ docker run --rm -it --security-opt seccomp:unconfined debian:jessie \
|
$ docker run --rm -it --security-opt seccomp=unconfined debian:jessie \
|
||||||
unshare --map-root-user --user sh -c whoami
|
unshare --map-root-user --user sh -c whoami
|
||||||
```
|
```
|
||||||
|
|
|
@ -2971,7 +2971,7 @@ func (s *DockerSuite) TestRunReadFilteredProc(c *check.C) {
|
||||||
name := fmt.Sprintf("procsieve-%d", i)
|
name := fmt.Sprintf("procsieve-%d", i)
|
||||||
shellCmd := fmt.Sprintf("exec 3<%s", filePath)
|
shellCmd := fmt.Sprintf("exec 3<%s", filePath)
|
||||||
|
|
||||||
out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
|
out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -3006,7 +3006,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
name := "acidburn"
|
name := "acidburn"
|
||||||
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
|
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
|
||||||
if err == nil ||
|
if err == nil ||
|
||||||
!(strings.Contains(strings.ToLower(out), "permission denied") ||
|
!(strings.Contains(strings.ToLower(out), "permission denied") ||
|
||||||
strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
strings.Contains(strings.ToLower(out), "operation not permitted")) {
|
||||||
|
@ -3018,7 +3018,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
name := "cereal"
|
name := "cereal"
|
||||||
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
|
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
|
||||||
if err == nil ||
|
if err == nil ||
|
||||||
!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
|
!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
|
||||||
strings.Contains(strings.ToLower(out), "permission denied")) {
|
strings.Contains(strings.ToLower(out), "permission denied")) {
|
||||||
|
@ -3031,7 +3031,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
||||||
/* Ensure still fails if running privileged with the default policy */
|
/* Ensure still fails if running privileged with the default policy */
|
||||||
go func() {
|
go func() {
|
||||||
name := "crashoverride"
|
name := "crashoverride"
|
||||||
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")
|
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")
|
||||||
if err == nil ||
|
if err == nil ||
|
||||||
!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
|
!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
|
||||||
strings.Contains(strings.ToLower(out), "permission denied")) {
|
strings.Contains(strings.ToLower(out), "permission denied")) {
|
||||||
|
@ -3128,7 +3128,7 @@ func (s *DockerSuite) TestRunWriteFilteredProc(c *check.C) {
|
||||||
name := fmt.Sprintf("writeprocsieve-%d", i)
|
name := fmt.Sprintf("writeprocsieve-%d", i)
|
||||||
|
|
||||||
shellCmd := fmt.Sprintf("exec 3>%s", filePath)
|
shellCmd := fmt.Sprintf("exec 3>%s", filePath)
|
||||||
out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
|
out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -709,7 +709,7 @@ func (s *DockerSuite) TestRunTmpfsMounts(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp:/tmp/profile.json debian:jessie unshare' exits with operation not permitted.
|
// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp=/tmp/profile.json debian:jessie unshare' exits with operation not permitted.
|
||||||
func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
|
func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
|
||||||
testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor)
|
testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor)
|
||||||
jsonData := `{
|
jsonData := `{
|
||||||
|
@ -730,14 +730,14 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
|
||||||
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
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")
|
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")
|
||||||
out, _, _ := runCommandWithOutput(runCmd)
|
out, _, _ := runCommandWithOutput(runCmd)
|
||||||
if !strings.Contains(out, "Operation not permitted") {
|
if !strings.Contains(out, "Operation not permitted") {
|
||||||
c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
|
c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp:/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
|
// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp=/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
|
||||||
func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
|
func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
|
||||||
testRequires(c, SameHostDaemon, seccompEnabled)
|
testRequires(c, SameHostDaemon, seccompEnabled)
|
||||||
jsonData := `{
|
jsonData := `{
|
||||||
|
@ -758,7 +758,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
|
||||||
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname")
|
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname")
|
||||||
out, _, _ := runCommandWithOutput(runCmd)
|
out, _, _ := runCommandWithOutput(runCmd)
|
||||||
if !strings.Contains(out, "Operation not permitted") {
|
if !strings.Contains(out, "Operation not permitted") {
|
||||||
c.Fatalf("expected chmod with seccomp profile denied to fail, got %s", out)
|
c.Fatalf("expected chmod with seccomp profile denied to fail, got %s", out)
|
||||||
|
@ -795,7 +795,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
|
||||||
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
|
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
|
||||||
out, _, _ := runCommandWithOutput(runCmd)
|
out, _, _ := runCommandWithOutput(runCmd)
|
||||||
if !strings.Contains(out, "Operation not permitted") {
|
if !strings.Contains(out, "Operation not permitted") {
|
||||||
c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out)
|
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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRunSeccompUnconfinedCloneUserns checks that
|
// TestRunSeccompUnconfinedCloneUserns checks that
|
||||||
// 'docker run --security-opt seccomp:unconfined syscall-test' allows creating a userns.
|
// 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns.
|
||||||
func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) {
|
func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) {
|
||||||
testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace)
|
testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace)
|
||||||
|
|
||||||
// make sure running w privileged is ok
|
// make sure running w privileged is ok
|
||||||
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "syscall-test", "userns-test", "id")
|
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id")
|
||||||
if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") {
|
if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") {
|
||||||
c.Fatalf("expected clone userns with --security-opt seccomp:unconfined to succeed, got %s: %v", out, err)
|
c.Fatalf("expected clone userns with --security-opt seccomp=unconfined to succeed, got %s: %v", out, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,7 +872,7 @@ func (s *DockerSuite) TestRunSeccompDefaultProfile(c *check.C) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp:unconfined", "syscall-test", "acct-test")
|
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "acct-test")
|
||||||
if err == nil || !strings.Contains(out, "No such file or directory") {
|
if err == nil || !strings.Contains(out, "No such file or directory") {
|
||||||
errChan <- fmt.Errorf("expected No such file or directory, got: %s", out)
|
errChan <- fmt.Errorf("expected No such file or directory, got: %s", out)
|
||||||
}
|
}
|
||||||
|
@ -880,7 +880,7 @@ func (s *DockerSuite) TestRunSeccompDefaultProfile(c *check.C) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp:unconfined", "syscall-test", "ns-test", "echo", "hello")
|
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "ns-test", "echo", "hello")
|
||||||
if err != nil || !strings.Contains(out, "hello") {
|
if err != nil || !strings.Contains(out, "hello") {
|
||||||
errChan <- fmt.Errorf("expected hello, got: %s, %v", out, err)
|
errChan <- fmt.Errorf("expected hello, got: %s, %v", out, err)
|
||||||
}
|
}
|
||||||
|
@ -911,12 +911,12 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
|
||||||
testRequires(c, SameHostDaemon, Apparmor)
|
testRequires(c, SameHostDaemon, Apparmor)
|
||||||
|
|
||||||
// running w seccomp unconfined tests the apparmor profile
|
// running w seccomp unconfined tests the apparmor profile
|
||||||
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "busybox", "chmod", "777", "/proc/1/cgroup")
|
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/cgroup")
|
||||||
if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
|
if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
|
||||||
c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err)
|
c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "busybox", "chmod", "777", "/proc/1/attr/current")
|
runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/attr/current")
|
||||||
if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
|
if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
|
||||||
c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err)
|
c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err)
|
||||||
}
|
}
|
||||||
|
@ -927,7 +927,7 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
|
||||||
func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) {
|
func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) {
|
||||||
testRequires(c, SameHostDaemon, seccompEnabled)
|
testRequires(c, SameHostDaemon, seccompEnabled)
|
||||||
|
|
||||||
out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp:../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
|
out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
|
||||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||||
c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted")
|
c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted")
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,16 +463,18 @@ its root filesystem mounted as read only prohibiting any writes.
|
||||||
**--security-opt**=[]
|
**--security-opt**=[]
|
||||||
Security Options
|
Security Options
|
||||||
|
|
||||||
"label:user:USER" : Set the label user for the container
|
"label=user:USER" : Set the label user for the container
|
||||||
"label:role:ROLE" : Set the label role for the container
|
"label=role:ROLE" : Set the label role for the container
|
||||||
"label:type:TYPE" : Set the label type for the container
|
"label=type:TYPE" : Set the label type for the container
|
||||||
"label:level:LEVEL" : Set the label level for the container
|
"label=level:LEVEL" : Set the label level for the container
|
||||||
"label:disable" : Turn off label confinement for the container
|
"label=disable" : Turn off label confinement for the container
|
||||||
|
|
||||||
"no-new-privileges" : Disable container processes from gaining additional privileges
|
"no-new-privileges" : Disable container processes from gaining additional privileges
|
||||||
|
|
||||||
"seccomp:unconfined" : Turn off seccomp confinement for the container
|
"seccomp=unconfined" : Turn off seccomp confinement for the container
|
||||||
"seccomp:profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
|
"seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
|
||||||
|
|
||||||
|
"apparmor=unconfined" : Turn off apparmor confinement for the container
|
||||||
|
"apparmor=your-profile" : Set the apparmor confinement profile for the container
|
||||||
|
|
||||||
**--stop-signal**=*SIGTERM*
|
**--stop-signal**=*SIGTERM*
|
||||||
Signal to stop a container. Default is SIGTERM.
|
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
|
||||||
requirement for MLS systems. Specifying the level in the following command
|
requirement for MLS systems. Specifying the level in the following command
|
||||||
allows you to share the same content between containers.
|
allows you to share the same content between containers.
|
||||||
|
|
||||||
# docker run --security-opt label:level:s0:c100,c200 -i -t fedora bash
|
# docker run --security-opt label=level:s0:c100,c200 -i -t fedora bash
|
||||||
|
|
||||||
An MLS example might be:
|
An MLS example might be:
|
||||||
|
|
||||||
# docker run --security-opt label:level:TopSecret -i -t rhel7 bash
|
# docker run --security-opt label=level:TopSecret -i -t rhel7 bash
|
||||||
|
|
||||||
To disable the security labeling for this container versus running with the
|
To disable the security labeling for this container versus running with the
|
||||||
`--permissive` flag, use the following command:
|
`--permissive` flag, use the following command:
|
||||||
|
|
||||||
# docker run --security-opt label:disable -i -t fedora bash
|
# docker run --security-opt label=disable -i -t fedora bash
|
||||||
|
|
||||||
If you want a tighter security policy on the processes within a container,
|
If you want a tighter security policy on the processes within a container,
|
||||||
you can specify an alternate type for the container. You could run a container
|
you can specify an alternate type for the container. You could run a container
|
||||||
that is only allowed to listen on Apache ports by executing the following
|
that is only allowed to listen on Apache ports by executing the following
|
||||||
command:
|
command:
|
||||||
|
|
||||||
# docker run --security-opt label:type:svirt_apache_t -i -t centos bash
|
# docker run --security-opt label=type:svirt_apache_t -i -t centos bash
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
|
||||||
|
|
|
@ -508,9 +508,13 @@ func parseLoggingOpts(loggingDriver string, loggingOpts []string) (map[string]st
|
||||||
// takes a local seccomp daemon, reads the file contents for sending to the daemon
|
// takes a local seccomp daemon, reads the file contents for sending to the daemon
|
||||||
func parseSecurityOpts(securityOpts []string) ([]string, error) {
|
func parseSecurityOpts(securityOpts []string) ([]string, error) {
|
||||||
for key, opt := range securityOpts {
|
for key, opt := range securityOpts {
|
||||||
con := strings.SplitN(opt, ":", 2)
|
con := strings.SplitN(opt, "=", 2)
|
||||||
if len(con) == 1 && con[0] != "no-new-privileges" {
|
if len(con) == 1 && con[0] != "no-new-privileges" {
|
||||||
return securityOpts, fmt.Errorf("Invalid --security-opt: %q", opt)
|
if strings.Index(opt, ":") != -1 {
|
||||||
|
con = strings.SplitN(opt, ":", 2)
|
||||||
|
} else {
|
||||||
|
return securityOpts, fmt.Errorf("Invalid --security-opt: %q", opt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if con[0] == "seccomp" && con[1] != "unconfined" {
|
if con[0] == "seccomp" && con[1] != "unconfined" {
|
||||||
f, err := ioutil.ReadFile(con[1])
|
f, err := ioutil.ReadFile(con[1])
|
||||||
|
@ -521,7 +525,7 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
|
||||||
if err := json.Compact(b, f); err != nil {
|
if err := json.Compact(b, f); err != nil {
|
||||||
return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
|
return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
|
||||||
}
|
}
|
||||||
securityOpts[key] = fmt.Sprintf("seccomp:%s", b.Bytes())
|
securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue