diff --git a/drivers/docker/driver.go b/drivers/docker/driver.go index dfdaeb5a99f2..0e0fa5a4c405 100644 --- a/drivers/docker/driver.go +++ b/drivers/docker/driver.go @@ -1,8 +1,11 @@ package docker import ( + "bytes" "context" + "encoding/json" "fmt" + "io/ioutil" "net" "os" "path/filepath" @@ -672,6 +675,35 @@ var userMountToUnixMount = map[string]string{ nstructs.VolumeMountPropagationBidirectional: "rshared", } +// takes a local seccomp daemon, reads the file contents for sending to the daemon +// this code modified slightly from the docker CLI code +// https://github.com/docker/cli/blob/8ef8547eb6934b28497d309d21e280bcd25145f5/cli/command/container/opts.go#L840 +func parseSecurityOpts(securityOpts []string) ([]string, error) { + for key, opt := range securityOpts { + con := strings.SplitN(opt, "=", 2) + if len(con) == 1 && con[0] != "no-new-privileges" { + if strings.Contains(opt, ":") { + con = strings.SplitN(opt, ":", 2) + } else { + return securityOpts, fmt.Errorf("invalid security_opt: %q", opt) + } + } + if con[0] == "seccomp" && con[1] != "unconfined" { + f, err := ioutil.ReadFile(con[1]) + if err != nil { + return securityOpts, fmt.Errorf("opening seccomp profile (%s) failed: %v", con[1], err) + } + b := bytes.NewBuffer(nil) + if err := json.Compact(b, f); err != nil { + return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err) + } + securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes()) + } + } + + return securityOpts, nil +} + func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *TaskConfig, imageID string) (docker.CreateContainerOptions, error) { @@ -895,6 +927,11 @@ func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *T hostConfig.SecurityOpt = driverConfig.SecurityOpt hostConfig.Sysctls = driverConfig.Sysctl + hostConfig.SecurityOpt, err = parseSecurityOpts(driverConfig.SecurityOpt) + if err != nil { + return c, fmt.Errorf("failed to parse security_opt configuration: %v", err) + } + ulimits, err := sliceMergeUlimit(driverConfig.Ulimit) if err != nil { return c, fmt.Errorf("failed to parse ulimit configuration: %v", err) diff --git a/drivers/docker/driver_test.go b/drivers/docker/driver_test.go index 07ba4d4a42a6..ef0c413f918a 100644 --- a/drivers/docker/driver_test.go +++ b/drivers/docker/driver_test.go @@ -978,7 +978,7 @@ func TestDockerDriver_ForcePull_RepoDigest(t *testing.T) { require.Equal(t, localDigest, container.Image) } -func TestDockerDriver_SecurityOpt(t *testing.T) { +func TestDockerDriver_SecurityOptUnconfined(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Windows does not support seccomp") } @@ -1004,6 +1004,31 @@ func TestDockerDriver_SecurityOpt(t *testing.T) { require.Exactly(t, cfg.SecurityOpt, container.HostConfig.SecurityOpt) } +func TestDockerDriver_SecurityOptFromFile(t *testing.T) { + + if runtime.GOOS == "windows" { + t.Skip("Windows does not support seccomp") + } + if !tu.IsCI() { + t.Parallel() + } + testutil.DockerCompatible(t) + + task, cfg, ports := dockerTask(t) + defer freeport.Return(ports) + cfg.SecurityOpt = []string{"seccomp=./test-resources/docker/seccomp.json"} + require.NoError(t, task.EncodeConcreteDriverConfig(cfg)) + + client, d, handle, cleanup := dockerSetup(t, task) + defer cleanup() + require.NoError(t, d.WaitUntilStarted(task.ID, 5*time.Second)) + + container, err := client.InspectContainer(handle.containerID) + require.NoError(t, err) + + require.Contains(t, container.HostConfig.SecurityOpt[0], "reboot") +} + func TestDockerDriver_CreateContainerConfig(t *testing.T) { t.Parallel() diff --git a/drivers/docker/test-resources/docker/seccomp.json b/drivers/docker/test-resources/docker/seccomp.json new file mode 100644 index 000000000000..973d5e152cb4 --- /dev/null +++ b/drivers/docker/test-resources/docker/seccomp.json @@ -0,0 +1,15 @@ +{ + "defaultAction": "SCMP_ACT_ALLOW", + "architectures": [ + "SCMP_ARCH_X86_64", + "SCMP_ARCH_X86", + "SCMP_ARCH_X32" + ], + "syscalls": [ + { + "name": "reboot", + "action": "SCMP_ACT_ERRNO", + "args": [] + } + ] +} \ No newline at end of file