Skip to content

Commit a3c3f7e

Browse files
author
Ben Buzbee
committed
Parse security_opts before sending them to docker daemon
Fixes #6720 Copy the parsing function from the docker CLI. Docker daemon expects to see JSON for seccomp file not a path.
1 parent ce4c9af commit a3c3f7e

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

drivers/docker/driver.go

+37
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package docker
22

33
import (
4+
"bytes"
45
"context"
6+
"encoding/json"
57
"fmt"
8+
"io/ioutil"
69
"net"
710
"os"
811
"path/filepath"
@@ -672,6 +675,35 @@ var userMountToUnixMount = map[string]string{
672675
nstructs.VolumeMountPropagationBidirectional: "rshared",
673676
}
674677

678+
// takes a local seccomp daemon, reads the file contents for sending to the daemon
679+
// this code modified slightly from the docker CLI code
680+
// https://github.com/docker/cli/blob/8ef8547eb6934b28497d309d21e280bcd25145f5/cli/command/container/opts.go#L840
681+
func parseSecurityOpts(securityOpts []string) ([]string, error) {
682+
for key, opt := range securityOpts {
683+
con := strings.SplitN(opt, "=", 2)
684+
if len(con) == 1 && con[0] != "no-new-privileges" {
685+
if strings.Contains(opt, ":") {
686+
con = strings.SplitN(opt, ":", 2)
687+
} else {
688+
return securityOpts, fmt.Errorf("invalid security_opt: %q", opt)
689+
}
690+
}
691+
if con[0] == "seccomp" && con[1] != "unconfined" {
692+
f, err := ioutil.ReadFile(con[1])
693+
if err != nil {
694+
return securityOpts, fmt.Errorf("opening seccomp profile (%s) failed: %v", con[1], err)
695+
}
696+
b := bytes.NewBuffer(nil)
697+
if err := json.Compact(b, f); err != nil {
698+
return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
699+
}
700+
securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
701+
}
702+
}
703+
704+
return securityOpts, nil
705+
}
706+
675707
func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *TaskConfig,
676708
imageID string) (docker.CreateContainerOptions, error) {
677709

@@ -895,6 +927,11 @@ func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *T
895927
hostConfig.SecurityOpt = driverConfig.SecurityOpt
896928
hostConfig.Sysctls = driverConfig.Sysctl
897929

930+
hostConfig.SecurityOpt, err = parseSecurityOpts(driverConfig.SecurityOpt)
931+
if err != nil {
932+
return c, fmt.Errorf("failed to parse security_opt configuration: %v", err)
933+
}
934+
898935
ulimits, err := sliceMergeUlimit(driverConfig.Ulimit)
899936
if err != nil {
900937
return c, fmt.Errorf("failed to parse ulimit configuration: %v", err)

drivers/docker/driver_test.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ func TestDockerDriver_ForcePull_RepoDigest(t *testing.T) {
978978
require.Equal(t, localDigest, container.Image)
979979
}
980980

981-
func TestDockerDriver_SecurityOpt(t *testing.T) {
981+
func TestDockerDriver_SecurityOptUnconfined(t *testing.T) {
982982
if runtime.GOOS == "windows" {
983983
t.Skip("Windows does not support seccomp")
984984
}
@@ -1004,6 +1004,31 @@ func TestDockerDriver_SecurityOpt(t *testing.T) {
10041004
require.Exactly(t, cfg.SecurityOpt, container.HostConfig.SecurityOpt)
10051005
}
10061006

1007+
func TestDockerDriver_SecurityOptFromFile(t *testing.T) {
1008+
1009+
if runtime.GOOS == "windows" {
1010+
t.Skip("Windows does not support seccomp")
1011+
}
1012+
if !tu.IsCI() {
1013+
t.Parallel()
1014+
}
1015+
testutil.DockerCompatible(t)
1016+
1017+
task, cfg, ports := dockerTask(t)
1018+
defer freeport.Return(ports)
1019+
cfg.SecurityOpt = []string{"seccomp=./test-resources/docker/seccomp.json"}
1020+
require.NoError(t, task.EncodeConcreteDriverConfig(cfg))
1021+
1022+
client, d, handle, cleanup := dockerSetup(t, task)
1023+
defer cleanup()
1024+
require.NoError(t, d.WaitUntilStarted(task.ID, 5*time.Second))
1025+
1026+
container, err := client.InspectContainer(handle.containerID)
1027+
require.NoError(t, err)
1028+
1029+
require.Contains(t, container.HostConfig.SecurityOpt[0], "reboot")
1030+
}
1031+
10071032
func TestDockerDriver_CreateContainerConfig(t *testing.T) {
10081033
t.Parallel()
10091034

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"defaultAction": "SCMP_ACT_ALLOW",
3+
"architectures": [
4+
"SCMP_ARCH_X86_64",
5+
"SCMP_ARCH_X86",
6+
"SCMP_ARCH_X32"
7+
],
8+
"syscalls": [
9+
{
10+
"name": "reboot",
11+
"action": "SCMP_ACT_ERRNO",
12+
"args": []
13+
}
14+
]
15+
}

0 commit comments

Comments
 (0)