diff --git a/pkg/kubelet/dockertools/fixtures/seccomp/sub/subtest b/pkg/kubelet/dockertools/fixtures/seccomp/sub/subtest new file mode 100644 index 00000000000..5dc0574216c --- /dev/null +++ b/pkg/kubelet/dockertools/fixtures/seccomp/sub/subtest @@ -0,0 +1,3 @@ +{ + "abc": "def" +} diff --git a/pkg/kubelet/dockertools/fixtures/seccomp/test b/pkg/kubelet/dockertools/fixtures/seccomp/test new file mode 100644 index 00000000000..e63d37b65a8 --- /dev/null +++ b/pkg/kubelet/dockertools/fixtures/seccomp/test @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/pkg/kubelet/dockertools/manager.go b/pkg/kubelet/dockertools/manager.go index 3c03b00441b..1dd213db595 100644 --- a/pkg/kubelet/dockertools/manager.go +++ b/pkg/kubelet/dockertools/manager.go @@ -1016,10 +1016,14 @@ func (dm *DockerManager) getSecurityOpt(pod *api.Pod, ctrName string) ([]string, } name := strings.TrimPrefix(profile, "localhost/") - fname := filepath.Join(dm.seccompProfileRoot, filepath.FromSlash(path.Clean("/"+name))) + cleanName := strings.TrimPrefix(path.Clean("/"+name), "/") + if name != cleanName { + return nil, fmt.Errorf("invalid seccomp profile name: %s", name) + } + fname := filepath.Join(dm.seccompProfileRoot, filepath.FromSlash(cleanName)) file, err := ioutil.ReadFile(fname) if err != nil { - return nil, err + return nil, fmt.Errorf("cannot load seccomp profile %q: %v", name, err) } b := bytes.NewBuffer(nil) @@ -1978,7 +1982,7 @@ func (dm *DockerManager) SyncPod(pod *api.Pod, _ api.PodStatus, podStatus *kubec podInfraContainerID, err, msg = dm.createPodInfraContainer(pod) if err != nil { startContainerResult.Fail(err, msg) - glog.Errorf("Failed to create pod infra container: %v; Skipping pod %q", err, format.Pod(pod)) + glog.Errorf("Failed to create pod infra container: %v; Skipping pod %q: %s", err, format.Pod(pod), msg) return } diff --git a/pkg/kubelet/dockertools/manager_test.go b/pkg/kubelet/dockertools/manager_test.go index 178f950bae7..09bba49f408 100644 --- a/pkg/kubelet/dockertools/manager_test.go +++ b/pkg/kubelet/dockertools/manager_test.go @@ -21,8 +21,10 @@ import ( "io/ioutil" "net/http" "os" + "path" "reflect" "regexp" + goruntime "runtime" "sort" "strconv" "strings" @@ -1881,6 +1883,104 @@ func TestSeccompContainerAnnotationTrumpsPod(t *testing.T) { assert.NotContains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Container annotation should trump the pod annotation for seccomp.") } +func TestSeccompLocalhostProfileIsLoaded(t *testing.T) { + tests := []struct { + annotations map[string]string + expectedSecOpt string + expectedError string + }{ + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost/test", + }, + expectedSecOpt: `seccomp={"foo":"bar"}`, + }, + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost/sub/subtest", + }, + expectedSecOpt: `seccomp={"abc":"def"}`, + }, + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost/not-existing", + }, + expectedError: "cannot load seccomp profile", + }, + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost/../test", + }, + expectedError: "invalid seccomp profile name", + }, + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost//test", + }, + expectedError: "invalid seccomp profile name", + }, + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost/sub//subtest", + }, + expectedError: "invalid seccomp profile name", + }, + { + annotations: map[string]string{ + "seccomp.security.alpha.kubernetes.io/pod": "localhost/test/", + }, + expectedError: "invalid seccomp profile name", + }, + } + + for _, test := range tests { + dm, fakeDocker := newTestDockerManagerWithVersion("1.10.1", "1.22") + _, filename, _, _ := goruntime.Caller(0) + dm.seccompProfileRoot = path.Join(path.Dir(filename), "fixtures", "seccomp") + + pod := &api.Pod{ + ObjectMeta: api.ObjectMeta{ + UID: "12345678", + Name: "foo2", + Namespace: "new", + Annotations: test.annotations, + }, + Spec: api.PodSpec{ + Containers: []api.Container{ + {Name: "bar2"}, + }, + }, + } + + result := runSyncPod(t, dm, fakeDocker, pod, nil, test.expectedError != "") + if test.expectedError != "" { + assert.Contains(t, result.Error().Error(), test.expectedError) + continue + } + + verifyCalls(t, fakeDocker, []string{ + // Create pod infra container. + "create", "start", "inspect_container", "inspect_container", + // Create container. + "create", "start", "inspect_container", + }) + + fakeDocker.Lock() + if len(fakeDocker.Created) != 2 || + !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo2_new_", fakeDocker.Created[0]) || + !matchString(t, "/k8s_bar2\\.[a-f0-9]+_foo2_new_", fakeDocker.Created[1]) { + t.Errorf("unexpected containers created %v", fakeDocker.Created) + } + fakeDocker.Unlock() + + newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1]) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + assert.Contains(t, newContainer.HostConfig.SecurityOpt, test.expectedSecOpt, "The compacted seccomp json profile should be loaded.") + } +} + func TestSecurityOptsAreNilWithDockerV19(t *testing.T) { dm, fakeDocker := newTestDockerManagerWithVersion("1.9.1", "1.21") pod := &api.Pod{