Disable seccomp policy by default on docker versions >= v1.10

Signed-off-by: Vishnu kannan <vishnuk@google.com>
This commit is contained in:
Vishnu kannan 2016-02-23 13:27:28 -08:00
parent c1bd13ec4b
commit 5db37b0b2d
3 changed files with 144 additions and 26 deletions

View File

@ -56,8 +56,12 @@ type FakeDockerClient struct {
}
func NewFakeDockerClient() *FakeDockerClient {
return NewFakeDockerClientWithVersion("1.8.1", "1.20")
}
func NewFakeDockerClientWithVersion(version, apiVersion string) *FakeDockerClient {
return &FakeDockerClient{
VersionInfo: docker.Env{"Version=1.8.1", "ApiVersion=1.20"},
VersionInfo: docker.Env{fmt.Sprintf("Version=%s", version), fmt.Sprintf("ApiVersion=%s", apiVersion)},
Errors: make(map[string]error),
RemovedImages: sets.String{},
ContainerMap: make(map[string]*docker.Container),

View File

@ -79,13 +79,23 @@ const (
// networking). Must match the value returned by docker inspect -f
// '{{.HostConfig.NetworkMode}}'.
namespaceModeHost = "host"
// Remote API version for docker daemon version v1.10
// https://docs.docker.com/engine/reference/api/docker_remote_api/
dockerV110APIVersion = "1.22"
)
// DockerManager implements the Runtime interface.
var _ kubecontainer.Runtime = &DockerManager{}
var (
// DockerManager implements the Runtime interface.
_ kubecontainer.Runtime = &DockerManager{}
// TODO: make this a TTL based pull (if image older than X policy, pull)
var podInfraContainerImagePullPolicy = api.PullIfNotPresent
// TODO: make this a TTL based pull (if image older than X policy, pull)
podInfraContainerImagePullPolicy = api.PullIfNotPresent
// Default set of security options. Seccomp is disabled by default until
// github issue #20870 is resolved.
defaultSecurityOpt = []string{"seccomp:unconfined"}
)
type DockerManager struct {
client DockerInterface
@ -488,6 +498,11 @@ func (dm *DockerManager) runContainer(
ContainerName: container.Name,
}
securityOpts, err := dm.defaultSecurityOpt()
if err != nil {
return kubecontainer.ContainerID{}, err
}
// Pod information is recorded on the container as labels to preserve it in the event the pod is deleted
// while the Kubelet is down and there is no information available to recover the pod.
// TODO: keep these labels up to date if the pod changes
@ -551,9 +566,10 @@ func (dm *DockerManager) runContainer(
PidMode: pidMode,
ReadonlyRootfs: readOnlyRootFilesystem(container),
// Memory and CPU are set here for newer versions of Docker (1.6+).
Memory: memoryLimit,
MemorySwap: -1,
CPUShares: cpuShares,
Memory: memoryLimit,
MemorySwap: -1,
CPUShares: cpuShares,
SecurityOpt: securityOpts,
}
if dm.cpuCFSQuota {
@ -934,6 +950,22 @@ func (dm *DockerManager) nativeExecSupportExists() (bool, error) {
return false, err
}
func (dm *DockerManager) defaultSecurityOpt() ([]string, error) {
version, err := dm.APIVersion()
if err != nil {
return nil, err
}
// seccomp is to be disabled on docker versions >= v1.10
result, err := version.Compare(dockerV110APIVersion)
if err != nil {
return nil, err
}
if result >= 0 {
return defaultSecurityOpt, nil
}
return nil, nil
}
func (dm *DockerManager) getRunInContainerCommand(containerID kubecontainer.ContainerID, cmd []string) (*exec.Cmd, error) {
args := append([]string{"exec"}, cmd...)
command := exec.Command("/usr/sbin/nsinit", args...)

View File

@ -82,8 +82,8 @@ func (f *fakeRuntimeHelper) GetClusterDNS(pod *api.Pod) ([]string, []string, err
return nil, nil, fmt.Errorf("not implemented")
}
func newTestDockerManagerWithHTTPClient(fakeHTTPClient *fakeHTTP) (*DockerManager, *FakeDockerClient) {
fakeDocker := NewFakeDockerClient()
func newTestDockerManagerWithHTTPClientWithVersion(fakeHTTPClient *fakeHTTP, version, apiVersion string) (*DockerManager, *FakeDockerClient) {
fakeDocker := NewFakeDockerClientWithVersion(version, apiVersion)
fakeRecorder := &record.FakeRecorder{}
containerRefManager := kubecontainer.NewRefManager()
networkPlugin, _ := network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
@ -104,6 +104,10 @@ func newTestDockerManagerWithHTTPClient(fakeHTTPClient *fakeHTTP) (*DockerManage
return dockerManager, fakeDocker
}
func newTestDockerManagerWithHTTPClient(fakeHTTPClient *fakeHTTP) (*DockerManager, *FakeDockerClient) {
return newTestDockerManagerWithHTTPClientWithVersion(fakeHTTPClient, "1.8.1", "1.20")
}
func newTestDockerManager() (*DockerManager, *FakeDockerClient) {
return newTestDockerManagerWithHTTPClient(&fakeHTTP{})
}
@ -634,7 +638,7 @@ func TestSyncPodCreateNetAndContainer(t *testing.T) {
if len(fakeDocker.Created) != 2 ||
!matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
fakeDocker.Unlock()
}
@ -670,13 +674,13 @@ func TestSyncPodCreatesNetAndContainerPullsImage(t *testing.T) {
fakeDocker.Lock()
if !reflect.DeepEqual(puller.ImagesPulled, []string{"pod_infra_image", "something"}) {
t.Errorf("Unexpected pulled containers: %v", puller.ImagesPulled)
t.Errorf("unexpected pulled containers: %v", puller.ImagesPulled)
}
if len(fakeDocker.Created) != 2 ||
!matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
fakeDocker.Unlock()
}
@ -713,7 +717,7 @@ func TestSyncPodWithPodInfraCreatesContainer(t *testing.T) {
fakeDocker.Lock()
if len(fakeDocker.Created) != 1 ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
fakeDocker.Unlock()
}
@ -1151,7 +1155,7 @@ func TestGetRestartCount(t *testing.T) {
runSyncPod(t, dm, fakeDocker, pod, nil, false)
status, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
if err != nil {
t.Fatalf("Unexpected error %v", err)
t.Fatalf("unexpected error %v", err)
}
cs := status.FindContainerStatusByName(containerName)
if cs == nil {
@ -1166,7 +1170,7 @@ func TestGetRestartCount(t *testing.T) {
killOneContainer := func(pod *api.Pod) {
status, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
if err != nil {
t.Fatalf("Unexpected error %v", err)
t.Fatalf("unexpected error %v", err)
}
cs := status.FindContainerStatusByName(containerName)
if cs == nil {
@ -1234,11 +1238,11 @@ func TestGetTerminationMessagePath(t *testing.T) {
containerList := fakeDocker.ContainerList
if len(containerList) != 2 {
// One for infra container, one for container "bar"
t.Fatalf("Unexpected container list length %d", len(containerList))
t.Fatalf("unexpected container list length %d", len(containerList))
}
inspectResult, err := dm.client.InspectContainer(containerList[0].ID)
if err != nil {
t.Fatalf("Unexpected inspect error: %v", err)
t.Fatalf("unexpected inspect error: %v", err)
}
containerInfo := getContainerInfoFromLabel(inspectResult.Config.Labels)
terminationMessagePath := containerInfo.TerminationMessagePath
@ -1290,11 +1294,11 @@ func TestSyncPodWithPodInfraCreatesContainerCallsHandler(t *testing.T) {
fakeDocker.Lock()
if len(fakeDocker.Created) != 1 ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
fakeDocker.Unlock()
if fakeHTTPClient.url != "http://foo:8080/bar" {
t.Errorf("Unexpected handler: %q", fakeHTTPClient.url)
t.Errorf("unexpected handler: %q", fakeHTTPClient.url)
}
}
@ -1347,7 +1351,7 @@ func TestSyncPodEventHandlerFails(t *testing.T) {
}
dockerName, _, err := ParseDockerName(fakeDocker.Stopped[0])
if err != nil {
t.Errorf("Unexpected error: %v", err)
t.Errorf("unexpected error: %v", err)
}
if dockerName.ContainerName != "bar" {
t.Errorf("Wrong stopped container, expected: bar, get: %q", dockerName.ContainerName)
@ -1417,7 +1421,7 @@ func TestSyncPodWithTerminationLog(t *testing.T) {
if len(fakeDocker.Created) != 2 ||
!matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
fakeDocker.Unlock()
newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
@ -1426,10 +1430,10 @@ func TestSyncPodWithTerminationLog(t *testing.T) {
}
parts := strings.Split(newContainer.HostConfig.Binds[0], ":")
if !matchString(t, testPodContainerDir+"/[a-f0-9]", parts[0]) {
t.Errorf("Unexpected host path: %s", parts[0])
t.Errorf("unexpected host path: %s", parts[0])
}
if parts[1] != "/dev/somepath" {
t.Errorf("Unexpected container path: %s", parts[1])
t.Errorf("unexpected container path: %s", parts[1])
}
}
@ -1464,7 +1468,7 @@ func TestSyncPodWithHostNetwork(t *testing.T) {
if len(fakeDocker.Created) != 2 ||
!matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
fakeDocker.Unlock()
@ -1687,7 +1691,7 @@ func TestSyncPodWithPullPolicy(t *testing.T) {
assert.Equal(t, []string{"pod_infra_image", "pull_always_image", "pull_if_not_present_image"}, pulledImageSorted)
if len(fakeDocker.Created) != 5 {
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
t.Errorf("unexpected containers created %v", fakeDocker.Created)
}
}
@ -1781,3 +1785,81 @@ func verifySyncResults(t *testing.T, expectedResults []*kubecontainer.SyncResult
}
}
}
func TestSeccompIsDisabledWithDockerV110(t *testing.T) {
dm, fakeDocker := newTestDockerManagerWithHTTPClientWithVersion(&fakeHTTP{}, "1.10.1", "1.22")
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "12345678",
Name: "foo",
Namespace: "new",
},
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "bar"},
},
},
}
runSyncPod(t, dm, fakeDocker, pod, nil, false)
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]+_foo_new_", fakeDocker.Created[0]) ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_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, "seccomp:unconfined", "Pods with Docker versions >= 1.10 must have seccomp disabled.")
}
func TestSecurityOptsAreNilWithDockerV19(t *testing.T) {
dm, fakeDocker := newTestDockerManagerWithHTTPClientWithVersion(&fakeHTTP{}, "1.9.1", "1.21")
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "12345678",
Name: "foo",
Namespace: "new",
},
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "bar"},
},
},
}
runSyncPod(t, dm, fakeDocker, pod, nil, false)
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]+_foo_new_", fakeDocker.Created[0]) ||
!matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_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.NotContains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Pods with Docker versions < 1.10 must not have seccomp disabled by default")
}