Skip to content

Commit

Permalink
Parse security_opts before sending them to docker daemon
Browse files Browse the repository at this point in the history
Fixes #6720

Copy the parsing function from the docker CLI. Docker daemon expects to see JSON for seccomp file not a path.
  • Loading branch information
Ben Buzbee committed Mar 31, 2020
1 parent ce4c9af commit 6a37b45
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 1 deletion.
37 changes: 37 additions & 0 deletions drivers/docker/driver.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package docker

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
Expand Down Expand Up @@ -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) {

Expand Down Expand Up @@ -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)
Expand Down
30 changes: 29 additions & 1 deletion drivers/docker/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand All @@ -1004,6 +1004,34 @@ func TestDockerDriver_SecurityOpt(t *testing.T) {
require.Exactly(t, cfg.SecurityOpt, container.HostConfig.SecurityOpt)
}

func TestDockerDriver_SecurityOptFromFile(t *testing.T) {
seccompPath := "./test-resources/docker/seccomp.json"

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{fmt.Sprintf("seccomp=%s", seccompPath)}
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)
if err != nil {
t.Fatalf("err: %v", err)
}

require.Contains(t, container.HostConfig.SecurityOpt[0], "reboot")
}

func TestDockerDriver_CreateContainerConfig(t *testing.T) {
t.Parallel()

Expand Down
15 changes: 15 additions & 0 deletions drivers/docker/test-resources/docker/seccomp.json
Original file line number Diff line number Diff line change
@@ -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": []
}
]
}

0 comments on commit 6a37b45

Please sign in to comment.