|
@@ -14,6 +14,7 @@ import (
|
|
"github.com/docker/docker/container"
|
|
"github.com/docker/docker/container"
|
|
"github.com/docker/docker/daemon/config"
|
|
"github.com/docker/docker/daemon/config"
|
|
"github.com/docker/docker/pkg/sysinfo"
|
|
"github.com/docker/docker/pkg/sysinfo"
|
|
|
|
+ "github.com/opencontainers/selinux/go-selinux"
|
|
"golang.org/x/sys/unix"
|
|
"golang.org/x/sys/unix"
|
|
"gotest.tools/v3/assert"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
@@ -138,115 +139,136 @@ 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 TestParseSecurityOptWithDeprecatedColon(t *testing.T) {
|
|
func TestParseSecurityOptWithDeprecatedColon(t *testing.T) {
|
|
- ctr := &container.Container{}
|
|
|
|
|
|
+ opts := &container.SecurityOptions{}
|
|
cfg := &containertypes.HostConfig{}
|
|
cfg := &containertypes.HostConfig{}
|
|
|
|
|
|
// test apparmor
|
|
// test apparmor
|
|
cfg.SecurityOpt = []string{"apparmor=test_profile"}
|
|
cfg.SecurityOpt = []string{"apparmor=test_profile"}
|
|
- if err := parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
|
|
+ if err := parseSecurityOpt(opts, cfg); err != nil {
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
}
|
|
}
|
|
- if ctr.AppArmorProfile != "test_profile" {
|
|
|
|
- t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", ctr.AppArmorProfile)
|
|
|
|
|
|
+ if opts.AppArmorProfile != "test_profile" {
|
|
|
|
+ t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", opts.AppArmorProfile)
|
|
}
|
|
}
|
|
|
|
|
|
// test seccomp
|
|
// test seccomp
|
|
sp := "/path/to/seccomp_test.json"
|
|
sp := "/path/to/seccomp_test.json"
|
|
cfg.SecurityOpt = []string{"seccomp=" + sp}
|
|
cfg.SecurityOpt = []string{"seccomp=" + sp}
|
|
- if err := parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
|
|
+ if err := parseSecurityOpt(opts, cfg); err != nil {
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
}
|
|
}
|
|
- if ctr.SeccompProfile != sp {
|
|
|
|
- t.Fatalf("Unexpected AppArmorProfile, expected: %q, got %q", sp, ctr.SeccompProfile)
|
|
|
|
|
|
+ if opts.SeccompProfile != sp {
|
|
|
|
+ t.Fatalf("Unexpected AppArmorProfile, expected: %q, got %q", sp, opts.SeccompProfile)
|
|
}
|
|
}
|
|
|
|
|
|
// test valid label
|
|
// test valid label
|
|
cfg.SecurityOpt = []string{"label=user:USER"}
|
|
cfg.SecurityOpt = []string{"label=user:USER"}
|
|
- if err := parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
|
|
+ if err := parseSecurityOpt(opts, cfg); err != nil {
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
}
|
|
}
|
|
|
|
|
|
// test invalid label
|
|
// test invalid label
|
|
cfg.SecurityOpt = []string{"label"}
|
|
cfg.SecurityOpt = []string{"label"}
|
|
- if err := parseSecurityOpt(ctr, cfg); err == nil {
|
|
|
|
|
|
+ if err := parseSecurityOpt(opts, cfg); err == nil {
|
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
}
|
|
}
|
|
|
|
|
|
// test invalid opt
|
|
// test invalid opt
|
|
cfg.SecurityOpt = []string{"test"}
|
|
cfg.SecurityOpt = []string{"test"}
|
|
- if err := parseSecurityOpt(ctr, cfg); err == nil {
|
|
|
|
|
|
+ if err := parseSecurityOpt(opts, cfg); err == nil {
|
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func TestParseSecurityOpt(t *testing.T) {
|
|
func TestParseSecurityOpt(t *testing.T) {
|
|
- ctr := &container.Container{}
|
|
|
|
- cfg := &containertypes.HostConfig{}
|
|
|
|
-
|
|
|
|
- // test apparmor
|
|
|
|
- cfg.SecurityOpt = []string{"apparmor=test_profile"}
|
|
|
|
- if err := parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
- t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
|
|
- }
|
|
|
|
- if ctr.AppArmorProfile != "test_profile" {
|
|
|
|
- t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", ctr.AppArmorProfile)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // test seccomp
|
|
|
|
- sp := "/path/to/seccomp_test.json"
|
|
|
|
- cfg.SecurityOpt = []string{"seccomp=" + sp}
|
|
|
|
- if err := parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
- t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
|
|
- }
|
|
|
|
- if ctr.SeccompProfile != sp {
|
|
|
|
- t.Fatalf("Unexpected SeccompProfile, expected: %q, got %q", sp, ctr.SeccompProfile)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // test valid label
|
|
|
|
- cfg.SecurityOpt = []string{"label=user:USER"}
|
|
|
|
- if err := parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
- t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // test invalid label
|
|
|
|
- cfg.SecurityOpt = []string{"label"}
|
|
|
|
- if err := parseSecurityOpt(ctr, cfg); err == nil {
|
|
|
|
- t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // test invalid opt
|
|
|
|
- cfg.SecurityOpt = []string{"test"}
|
|
|
|
- if err := parseSecurityOpt(ctr, cfg); err == nil {
|
|
|
|
- t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
|
|
- }
|
|
|
|
|
|
+ t.Run("apparmor", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"apparmor=test_profile"},
|
|
|
|
+ })
|
|
|
|
+ assert.Check(t, err)
|
|
|
|
+ assert.Equal(t, secOpts.AppArmorProfile, "test_profile")
|
|
|
|
+ })
|
|
|
|
+ t.Run("apparmor using legacy separator", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"apparmor:test_profile"},
|
|
|
|
+ })
|
|
|
|
+ assert.Check(t, err)
|
|
|
|
+ assert.Equal(t, secOpts.AppArmorProfile, "test_profile")
|
|
|
|
+ })
|
|
|
|
+ t.Run("seccomp", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"seccomp=/path/to/seccomp_test.json"},
|
|
|
|
+ })
|
|
|
|
+ assert.Check(t, err)
|
|
|
|
+ assert.Equal(t, secOpts.SeccompProfile, "/path/to/seccomp_test.json")
|
|
|
|
+ })
|
|
|
|
+ t.Run("valid label", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"label=user:USER"},
|
|
|
|
+ })
|
|
|
|
+ assert.Check(t, err)
|
|
|
|
+ if selinux.GetEnabled() {
|
|
|
|
+ // TODO(thaJeztah): set expected labels here (or "partial" if depends on host)
|
|
|
|
+ // assert.Check(t, is.Equal(secOpts.MountLabel, ""))
|
|
|
|
+ // assert.Check(t, is.Equal(secOpts.ProcessLabel, ""))
|
|
|
|
+ } else {
|
|
|
|
+ assert.Check(t, is.Equal(secOpts.MountLabel, ""))
|
|
|
|
+ assert.Check(t, is.Equal(secOpts.ProcessLabel, ""))
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ t.Run("invalid label", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"label"},
|
|
|
|
+ })
|
|
|
|
+ assert.Error(t, err, `invalid --security-opt 1: "label"`)
|
|
|
|
+ })
|
|
|
|
+ t.Run("invalid option (no value)", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"unknown"},
|
|
|
|
+ })
|
|
|
|
+ assert.Error(t, err, `invalid --security-opt 1: "unknown"`)
|
|
|
|
+ })
|
|
|
|
+ t.Run("unknown option", func(t *testing.T) {
|
|
|
|
+ secOpts := &container.SecurityOptions{}
|
|
|
|
+ err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
+ SecurityOpt: []string{"unknown=something"},
|
|
|
|
+ })
|
|
|
|
+ assert.Error(t, err, `invalid --security-opt 2: "unknown=something"`)
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
func TestParseNNPSecurityOptions(t *testing.T) {
|
|
func TestParseNNPSecurityOptions(t *testing.T) {
|
|
daemon := &Daemon{
|
|
daemon := &Daemon{
|
|
configStore: &config.Config{NoNewPrivileges: true},
|
|
configStore: &config.Config{NoNewPrivileges: true},
|
|
}
|
|
}
|
|
- ctr := &container.Container{}
|
|
|
|
|
|
+ opts := &container.SecurityOptions{}
|
|
cfg := &containertypes.HostConfig{}
|
|
cfg := &containertypes.HostConfig{}
|
|
|
|
|
|
// test NNP when "daemon:true" and "no-new-privileges=false""
|
|
// test NNP when "daemon:true" and "no-new-privileges=false""
|
|
cfg.SecurityOpt = []string{"no-new-privileges=false"}
|
|
cfg.SecurityOpt = []string{"no-new-privileges=false"}
|
|
|
|
|
|
- if err := daemon.parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
|
|
+ if err := daemon.parseSecurityOpt(opts, cfg); err != nil {
|
|
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
|
|
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
|
|
}
|
|
}
|
|
- if ctr.NoNewPrivileges {
|
|
|
|
- t.Fatalf("container.NoNewPrivileges should be FALSE: %v", ctr.NoNewPrivileges)
|
|
|
|
|
|
+ if opts.NoNewPrivileges {
|
|
|
|
+ t.Fatalf("container.NoNewPrivileges should be FALSE: %v", opts.NoNewPrivileges)
|
|
}
|
|
}
|
|
|
|
|
|
// test NNP when "daemon:false" and "no-new-privileges=true""
|
|
// test NNP when "daemon:false" and "no-new-privileges=true""
|
|
daemon.configStore.NoNewPrivileges = false
|
|
daemon.configStore.NoNewPrivileges = false
|
|
cfg.SecurityOpt = []string{"no-new-privileges=true"}
|
|
cfg.SecurityOpt = []string{"no-new-privileges=true"}
|
|
|
|
|
|
- if err := daemon.parseSecurityOpt(ctr, cfg); err != nil {
|
|
|
|
|
|
+ if err := daemon.parseSecurityOpt(opts, cfg); err != nil {
|
|
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
|
|
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
|
|
}
|
|
}
|
|
- if !ctr.NoNewPrivileges {
|
|
|
|
- t.Fatalf("container.NoNewPrivileges should be TRUE: %v", ctr.NoNewPrivileges)
|
|
|
|
|
|
+ if !opts.NoNewPrivileges {
|
|
|
|
+ t.Fatalf("container.NoNewPrivileges should be TRUE: %v", opts.NoNewPrivileges)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|