File fix-seccomp-localhost-error-handling.patch of Package kubernetes1.23.39219
From b9791a93a8afbb13d594d4969e5c595781bb430a Mon Sep 17 00:00:00 2001
From: Craig Ingram <cjingram@google.com>
Date: Fri, 24 Feb 2023 15:24:49 -0500
Subject: [PATCH] Return error for localhost seccomp type with no localhost
profile defined
---
pkg/kubelet/kuberuntime/helpers.go | 66 ++--
pkg/kubelet/kuberuntime/helpers_test.go | 350 ++++--------------
.../kuberuntime_container_linux.go | 16 +-
.../kuberuntime_container_linux_test.go | 22 +-
pkg/kubelet/kuberuntime/security_context.go | 15 +-
5 files changed, 153 insertions(+), 316 deletions(-)
diff --git a/pkg/kubelet/kuberuntime/helpers.go b/pkg/kubelet/kuberuntime/helpers.go
index fa580335cf8..b36e01166f8 100644
--- a/pkg/kubelet/kuberuntime/helpers.go
+++ b/pkg/kubelet/kuberuntime/helpers.go
@@ -209,28 +209,32 @@ func toKubeRuntimeStatus(status *runtimeapi.RuntimeStatus) *kubecontainer.Runtim
return &kubecontainer.RuntimeStatus{Conditions: conditions}
}
-func fieldProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) string {
+func fieldProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) (string, error) {
if scmp == nil {
if fallbackToRuntimeDefault {
- return v1.SeccompProfileRuntimeDefault
+ return v1.SeccompProfileRuntimeDefault, nil
}
- return ""
+ return "", nil
}
if scmp.Type == v1.SeccompProfileTypeRuntimeDefault {
- return v1.SeccompProfileRuntimeDefault
- }
- if scmp.Type == v1.SeccompProfileTypeLocalhost && scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
- fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
- return v1.SeccompLocalhostProfileNamePrefix + fname
+ return v1.SeccompProfileRuntimeDefault, nil
+ }
+ if scmp.Type == v1.SeccompProfileTypeLocalhost {
+ if scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
+ fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
+ return v1.SeccompLocalhostProfileNamePrefix + fname, nil
+ } else {
+ return "", fmt.Errorf("localhostProfile must be set if seccompProfile type is Localhost.")
+ }
}
if scmp.Type == v1.SeccompProfileTypeUnconfined {
- return v1.SeccompProfileNameUnconfined
+ return v1.SeccompProfileNameUnconfined, nil
}
if fallbackToRuntimeDefault {
- return v1.SeccompProfileRuntimeDefault
+ return v1.SeccompProfileRuntimeDefault, nil
}
- return ""
+ return "", nil
}
func annotationProfile(profile, profileRootPath string) string {
@@ -243,7 +247,7 @@ func annotationProfile(profile, profileRootPath string) string {
}
func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string]string, containerName string,
- podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) string {
+ podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) (string, error) {
// container fields are applied first
if containerSecContext != nil && containerSecContext.SeccompProfile != nil {
return fieldProfile(containerSecContext.SeccompProfile, m.seccompProfileRoot, fallbackToRuntimeDefault)
@@ -252,7 +256,7 @@ func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string
// if container field does not exist, try container annotation (deprecated)
if containerName != "" {
if profile, ok := annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName]; ok {
- return annotationProfile(profile, m.seccompProfileRoot)
+ return annotationProfile(profile, m.seccompProfileRoot), nil
}
}
@@ -263,46 +267,50 @@ func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string
// as last resort, try to apply pod annotation (deprecated)
if profile, ok := annotations[v1.SeccompPodAnnotationKey]; ok {
- return annotationProfile(profile, m.seccompProfileRoot)
+ return annotationProfile(profile, m.seccompProfileRoot), nil
}
if fallbackToRuntimeDefault {
- return v1.SeccompProfileRuntimeDefault
+ return v1.SeccompProfileRuntimeDefault, nil
}
- return ""
+ return "", nil
}
-func fieldSeccompProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) *runtimeapi.SecurityProfile {
+func fieldSeccompProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRuntimeDefault bool) (*runtimeapi.SecurityProfile, error) {
if scmp == nil {
if fallbackToRuntimeDefault {
return &runtimeapi.SecurityProfile{
ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
- }
+ }, nil
}
return &runtimeapi.SecurityProfile{
ProfileType: runtimeapi.SecurityProfile_Unconfined,
- }
+ }, nil
}
if scmp.Type == v1.SeccompProfileTypeRuntimeDefault {
return &runtimeapi.SecurityProfile{
ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
- }
+ }, nil
}
- if scmp.Type == v1.SeccompProfileTypeLocalhost && scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
- fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
- return &runtimeapi.SecurityProfile{
- ProfileType: runtimeapi.SecurityProfile_Localhost,
- LocalhostRef: fname,
+ if scmp.Type == v1.SeccompProfileTypeLocalhost {
+ if scmp.LocalhostProfile != nil && len(*scmp.LocalhostProfile) > 0 {
+ fname := filepath.Join(profileRootPath, *scmp.LocalhostProfile)
+ return &runtimeapi.SecurityProfile{
+ ProfileType: runtimeapi.SecurityProfile_Localhost,
+ LocalhostRef: fname,
+ }, nil
+ } else {
+ return nil, fmt.Errorf("localhostProfile must be set if seccompProfile type is Localhost.")
}
}
return &runtimeapi.SecurityProfile{
ProfileType: runtimeapi.SecurityProfile_Unconfined,
- }
+ }, nil
}
func (m *kubeGenericRuntimeManager) getSeccompProfile(annotations map[string]string, containerName string,
- podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) *runtimeapi.SecurityProfile {
+ podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) (*runtimeapi.SecurityProfile, error) {
// container fields are applied first
if containerSecContext != nil && containerSecContext.SeccompProfile != nil {
return fieldSeccompProfile(containerSecContext.SeccompProfile, m.seccompProfileRoot, fallbackToRuntimeDefault)
@@ -316,12 +324,12 @@ func (m *kubeGenericRuntimeManager) getSeccompProfile(annotations map[string]str
if fallbackToRuntimeDefault {
return &runtimeapi.SecurityProfile{
ProfileType: runtimeapi.SecurityProfile_RuntimeDefault,
- }
+ }, nil
}
return &runtimeapi.SecurityProfile{
ProfileType: runtimeapi.SecurityProfile_Unconfined,
- }
+ }, nil
}
func ipcNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
diff --git a/pkg/kubelet/kuberuntime/helpers_test.go b/pkg/kubelet/kuberuntime/helpers_test.go
index 25065f30411..70ad7250ce2 100644
--- a/pkg/kubelet/kuberuntime/helpers_test.go
+++ b/pkg/kubelet/kuberuntime/helpers_test.go
@@ -242,17 +242,18 @@ func TestFieldProfile(t *testing.T) {
scmpProfile *v1.SeccompProfile
rootPath string
expectedProfile string
+ expectedError string
}{
{
description: "no seccompProfile should return empty",
expectedProfile: "",
},
{
- description: "type localhost without profile should return empty",
+ description: "type localhost without profile should return error",
scmpProfile: &v1.SeccompProfile{
Type: v1.SeccompProfileTypeLocalhost,
},
- expectedProfile: "",
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
description: "unknown type should return empty",
@@ -279,7 +280,7 @@ func TestFieldProfile(t *testing.T) {
description: "SeccompProfileTypeLocalhost should return localhost",
scmpProfile: &v1.SeccompProfile{
Type: v1.SeccompProfileTypeLocalhost,
- LocalhostProfile: utilpointer.StringPtr("profile.json"),
+ LocalhostProfile: utilpointer.String("profile.json"),
},
rootPath: "/test/",
expectedProfile: "localhost//test/profile.json",
@@ -287,8 +288,13 @@ func TestFieldProfile(t *testing.T) {
}
for i, test := range tests {
- seccompProfile := fieldProfile(test.scmpProfile, test.rootPath, false)
- assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ seccompProfile, err := fieldProfile(test.scmpProfile, test.rootPath, false)
+ if test.expectedError != "" {
+ assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+ } else {
+ assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+ assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ }
}
}
@@ -298,17 +304,18 @@ func TestFieldProfileDefaultSeccomp(t *testing.T) {
scmpProfile *v1.SeccompProfile
rootPath string
expectedProfile string
+ expectedError string
}{
{
description: "no seccompProfile should return runtime/default",
expectedProfile: v1.SeccompProfileRuntimeDefault,
},
{
- description: "type localhost without profile should return runtime/default",
+ description: "type localhost without profile should return error",
scmpProfile: &v1.SeccompProfile{
Type: v1.SeccompProfileTypeLocalhost,
},
- expectedProfile: v1.SeccompProfileRuntimeDefault,
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
description: "unknown type should return runtime/default",
@@ -335,7 +342,7 @@ func TestFieldProfileDefaultSeccomp(t *testing.T) {
description: "SeccompProfileTypeLocalhost should return localhost",
scmpProfile: &v1.SeccompProfile{
Type: v1.SeccompProfileTypeLocalhost,
- LocalhostProfile: utilpointer.StringPtr("profile.json"),
+ LocalhostProfile: utilpointer.String("profile.json"),
},
rootPath: "/test/",
expectedProfile: "localhost//test/profile.json",
@@ -343,8 +350,13 @@ func TestFieldProfileDefaultSeccomp(t *testing.T) {
}
for i, test := range tests {
- seccompProfile := fieldProfile(test.scmpProfile, test.rootPath, true)
- assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ seccompProfile, err := fieldProfile(test.scmpProfile, test.rootPath, true)
+ if test.expectedError != "" {
+ assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+ } else {
+ assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+ assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ }
}
}
@@ -359,6 +371,7 @@ func TestGetSeccompProfilePath(t *testing.T) {
containerSc *v1.SecurityContext
containerName string
expectedProfile string
+ expectedError string
}{
{
description: "no seccomp should return empty",
@@ -369,91 +382,6 @@ func TestGetSeccompProfilePath(t *testing.T) {
containerName: "container1",
expectedProfile: "",
},
- {
- description: "annotations: pod runtime/default seccomp profile should return runtime/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
- },
- expectedProfile: "runtime/default",
- },
- {
- description: "annotations: pod docker/default seccomp profile should return docker/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
- },
- expectedProfile: "docker/default",
- },
- {
- description: "annotations: pod runtime/default seccomp profile with containerName should return runtime/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
- },
- containerName: "container1",
- expectedProfile: "runtime/default",
- },
- {
- description: "annotations: pod docker/default seccomp profile with containerName should return docker/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
- },
- containerName: "container1",
- expectedProfile: "docker/default",
- },
- {
- description: "annotations: pod unconfined seccomp profile should return unconfined",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
- },
- expectedProfile: "unconfined",
- },
- {
- description: "annotations: pod unconfined seccomp profile with containerName should return unconfined",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
- },
- containerName: "container1",
- expectedProfile: "unconfined",
- },
- {
- description: "annotations: pod localhost seccomp profile should return local profile path",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/chmod.json",
- },
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: pod localhost seccomp profile with containerName should return local profile path",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/chmod.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: container localhost seccomp profile with containerName should return local profile path",
- annotation: map[string]string{
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: container localhost seccomp profile should override pod profile",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: container localhost seccomp profile with unmatched containerName should return empty",
- annotation: map[string]string{
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
- },
- containerName: "container2",
- expectedProfile: "",
- },
{
description: "pod seccomp profile set to unconfined returns unconfined",
podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeUnconfined}},
@@ -480,14 +408,14 @@ func TestGetSeccompProfilePath(t *testing.T) {
expectedProfile: seccompLocalhostPath("filename"),
},
{
- description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns empty",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: "",
+ description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
- description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns empty",
- containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: "",
+ description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
description: "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -500,41 +428,16 @@ func TestGetSeccompProfilePath(t *testing.T) {
containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}},
expectedProfile: "runtime/default",
},
- {
- description: "prioritise container field over container annotation, pod field and pod annotation",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
- containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-cont-profile.json")}},
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("field-cont-profile.json"),
- },
- {
- description: "prioritise container annotation over pod field",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("annota-cont-profile.json"),
- },
- {
- description: "prioritise pod field over pod annotation",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("field-pod-profile.json"),
- },
}
for i, test := range tests {
- seccompProfile := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, false)
- assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ seccompProfile, err := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, false)
+ if test.expectedError != "" {
+ assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+ } else {
+ assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+ assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ }
}
}
@@ -549,6 +452,7 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
containerSc *v1.SecurityContext
containerName string
expectedProfile string
+ expectedError string
}{
{
description: "no seccomp should return runtime/default",
@@ -559,91 +463,6 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
containerName: "container1",
expectedProfile: v1.SeccompProfileRuntimeDefault,
},
- {
- description: "annotations: pod runtime/default seccomp profile should return runtime/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
- },
- expectedProfile: v1.SeccompProfileRuntimeDefault,
- },
- {
- description: "annotations: pod docker/default seccomp profile should return docker/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
- },
- expectedProfile: "docker/default",
- },
- {
- description: "annotations: pod runtime/default seccomp profile with containerName should return runtime/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
- },
- containerName: "container1",
- expectedProfile: v1.SeccompProfileRuntimeDefault,
- },
- {
- description: "annotations: pod docker/default seccomp profile with containerName should return docker/default",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
- },
- containerName: "container1",
- expectedProfile: "docker/default",
- },
- {
- description: "annotations: pod unconfined seccomp profile should return unconfined",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
- },
- expectedProfile: "unconfined",
- },
- {
- description: "annotations: pod unconfined seccomp profile with containerName should return unconfined",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
- },
- containerName: "container1",
- expectedProfile: "unconfined",
- },
- {
- description: "annotations: pod localhost seccomp profile should return local profile path",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/chmod.json",
- },
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: pod localhost seccomp profile with containerName should return local profile path",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/chmod.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: container localhost seccomp profile with containerName should return local profile path",
- annotation: map[string]string{
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: container localhost seccomp profile should override pod profile",
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("chmod.json"),
- },
- {
- description: "annotations: container localhost seccomp profile with unmatched containerName should return runtime/default",
- annotation: map[string]string{
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/chmod.json",
- },
- containerName: "container2",
- expectedProfile: v1.SeccompProfileRuntimeDefault,
- },
{
description: "pod seccomp profile set to unconfined returns unconfined",
podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeUnconfined}},
@@ -670,14 +489,14 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
expectedProfile: seccompLocalhostPath("filename"),
},
{
- description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns runtime/default",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: v1.SeccompProfileRuntimeDefault,
+ description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
- description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns runtime/default",
- containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: v1.SeccompProfileRuntimeDefault,
+ description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
description: "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -690,41 +509,16 @@ func TestGetSeccompProfilePathDefaultSeccomp(t *testing.T) {
containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}},
expectedProfile: "runtime/default",
},
- {
- description: "prioritise container field over container annotation, pod field and pod annotation",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
- containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-cont-profile.json")}},
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("field-cont-profile.json"),
- },
- {
- description: "prioritise container annotation over pod field",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
- v1.SeccompContainerAnnotationKeyPrefix + "container1": "localhost/annota-cont-profile.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("annota-cont-profile.json"),
- },
- {
- description: "prioritise pod field over pod annotation",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost, LocalhostProfile: getLocal("field-pod-profile.json")}},
- annotation: map[string]string{
- v1.SeccompPodAnnotationKey: "localhost/annota-pod-profile.json",
- },
- containerName: "container1",
- expectedProfile: seccompLocalhostPath("field-pod-profile.json"),
- },
}
for i, test := range tests {
- seccompProfile := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, true)
- assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ seccompProfile, err := m.getSeccompProfilePath(test.annotation, test.containerName, test.podSc, test.containerSc, true)
+ if test.expectedError != "" {
+ assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+ } else {
+ assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+ assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ }
}
}
@@ -747,6 +541,7 @@ func TestGetSeccompProfile(t *testing.T) {
containerSc *v1.SecurityContext
containerName string
expectedProfile *runtimeapi.SecurityProfile
+ expectedError string
}{
{
description: "no seccomp should return unconfined",
@@ -781,14 +576,14 @@ func TestGetSeccompProfile(t *testing.T) {
},
},
{
- description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: unconfinedProfile,
+ description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
- description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
- containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: unconfinedProfile,
+ description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
description: "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -817,8 +612,13 @@ func TestGetSeccompProfile(t *testing.T) {
}
for i, test := range tests {
- seccompProfile := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, false)
- assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ seccompProfile, err := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, false)
+ if test.expectedError != "" {
+ assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+ } else {
+ assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+ assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ }
}
}
@@ -841,6 +641,7 @@ func TestGetSeccompProfileDefaultSeccomp(t *testing.T) {
containerSc *v1.SecurityContext
containerName string
expectedProfile *runtimeapi.SecurityProfile
+ expectedError string
}{
{
description: "no seccomp should return RuntimeDefault",
@@ -875,14 +676,14 @@ func TestGetSeccompProfileDefaultSeccomp(t *testing.T) {
},
},
{
- description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
- podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: unconfinedProfile,
+ description: "pod seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ podSc: &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
- description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns unconfined",
- containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
- expectedProfile: unconfinedProfile,
+ description: "container seccomp profile set to SeccompProfileTypeLocalhost with empty LocalhostProfile returns error",
+ containerSc: &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeLocalhost}},
+ expectedError: "localhostProfile must be set if seccompProfile type is Localhost.",
},
{
description: "container seccomp profile set to SeccompProfileTypeLocalhost returns 'localhost/' + LocalhostProfile",
@@ -911,8 +712,13 @@ func TestGetSeccompProfileDefaultSeccomp(t *testing.T) {
}
for i, test := range tests {
- seccompProfile := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, true)
- assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ seccompProfile, err := m.getSeccompProfile(test.annotation, test.containerName, test.podSc, test.containerSc, true)
+ if test.expectedError != "" {
+ assert.EqualError(t, err, test.expectedError, "TestCase[%d]: %s", i, test.description)
+ } else {
+ assert.NoError(t, err, "TestCase[%d]: %s", i, test.description)
+ assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]: %s", i, test.description)
+ }
}
}
diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go b/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go
index 6cb9e54729e..54670673bcd 100644
--- a/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go
+++ b/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go
@@ -46,15 +46,23 @@ func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config
libcontainercgroups.IsCgroup2UnifiedMode() {
enforceMemoryQoS = true
}
- config.Linux = m.generateLinuxContainerConfig(container, pod, uid, username, nsTarget, enforceMemoryQoS)
+ cl, err := m.generateLinuxContainerConfig(container, pod, uid, username, nsTarget, enforceMemoryQoS)
+ if err != nil {
+ return err
+ }
+ config.Linux = cl
return nil
}
// generateLinuxContainerConfig generates linux container config for kubelet runtime v1.
-func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID, enforceMemoryQoS bool) *runtimeapi.LinuxContainerConfig {
+func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID, enforceMemoryQoS bool) (*runtimeapi.LinuxContainerConfig, error) {
+ sc, err := m.determineEffectiveSecurityContext(pod, container, uid, username)
+ if err != nil {
+ return nil, err
+ }
lc := &runtimeapi.LinuxContainerConfig{
Resources: &runtimeapi.LinuxContainerResources{},
- SecurityContext: m.determineEffectiveSecurityContext(pod, container, uid, username),
+ SecurityContext: sc,
}
if nsTarget != nil && lc.SecurityContext.NamespaceOptions.Pid == runtimeapi.NamespaceMode_CONTAINER {
@@ -125,7 +133,7 @@ func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.C
}
}
- return lc
+ return lc, nil
}
// calculateLinuxResources will create the linuxContainerResources type based on the provided CPU and memory resource requests, limits
diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go b/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go
index 46817e00fb0..98f635cc932 100644
--- a/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go
+++ b/pkg/kubelet/kuberuntime/kuberuntime_container_linux_test.go
@@ -47,6 +47,8 @@ func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerInde
restartCountUint32 := uint32(restartCount)
envs := make([]*runtimeapi.KeyValue, len(opts.Envs))
+ l, _ := m.generateLinuxContainerConfig(container, pod, new(int64), "", nil, enforceMemoryQoS)
+
expectedConfig := &runtimeapi.ContainerConfig{
Metadata: &runtimeapi.ContainerMetadata{
Name: container.Name,
@@ -64,7 +66,7 @@ func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerInde
Stdin: container.Stdin,
StdinOnce: container.StdinOnce,
Tty: container.TTY,
- Linux: m.generateLinuxContainerConfig(container, pod, new(int64), "", nil, enforceMemoryQoS),
+ Linux: l,
Envs: envs,
}
return expectedConfig
@@ -215,7 +217,8 @@ func TestGenerateLinuxContainerConfigResources(t *testing.T) {
},
}
- linuxConfig := m.generateLinuxContainerConfig(&pod.Spec.Containers[0], pod, new(int64), "", nil, false)
+ linuxConfig, err := m.generateLinuxContainerConfig(&pod.Spec.Containers[0], pod, new(int64), "", nil, false)
+ assert.NoError(t, err)
assert.Equal(t, test.expected.CpuPeriod, linuxConfig.GetResources().CpuPeriod, test.name)
assert.Equal(t, test.expected.CpuQuota, linuxConfig.GetResources().CpuQuota, test.name)
assert.Equal(t, test.expected.CpuShares, linuxConfig.GetResources().CpuShares, test.name)
@@ -329,6 +332,8 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
memoryLow int64
memoryHigh int64
}
+ l1, _ := m.generateLinuxContainerConfig(&pod1.Spec.Containers[0], pod1, new(int64), "", nil, true)
+ l2, _ := m.generateLinuxContainerConfig(&pod2.Spec.Containers[0], pod2, new(int64), "", nil, true)
tests := []struct {
name string
pod *v1.Pod
@@ -338,7 +343,7 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
name: "Request128MBLimit256MB",
pod: pod1,
expected: &expectedResult{
- m.generateLinuxContainerConfig(&pod1.Spec.Containers[0], pod1, new(int64), "", nil, true),
+ l1,
128 * 1024 * 1024,
int64(float64(256*1024*1024) * m.memoryThrottlingFactor),
},
@@ -347,7 +352,7 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
name: "Request128MBWithoutLimit",
pod: pod2,
expected: &expectedResult{
- m.generateLinuxContainerConfig(&pod2.Spec.Containers[0], pod2, new(int64), "", nil, true),
+ l2,
128 * 1024 * 1024,
int64(pod2MemoryHigh),
},
@@ -355,7 +360,8 @@ func TestGenerateContainerConfigWithMemoryQoSEnforced(t *testing.T) {
}
for _, test := range tests {
- linuxConfig := m.generateLinuxContainerConfig(&test.pod.Spec.Containers[0], test.pod, new(int64), "", nil, true)
+ linuxConfig, err := m.generateLinuxContainerConfig(&test.pod.Spec.Containers[0], test.pod, new(int64), "", nil, true)
+ assert.NoError(t, err)
assert.Equal(t, test.expected.containerConfig, linuxConfig, test.name)
assert.Equal(t, linuxConfig.GetResources().GetUnified()["memory.min"], strconv.FormatInt(test.expected.memoryLow, 10), test.name)
assert.Equal(t, linuxConfig.GetResources().GetUnified()["memory.high"], strconv.FormatInt(test.expected.memoryHigh, 10), test.name)
@@ -578,7 +584,8 @@ func TestGenerateLinuxContainerConfigNamespaces(t *testing.T) {
},
} {
t.Run(tc.name, func(t *testing.T) {
- got := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", tc.target, false)
+ got, err := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", tc.target, false)
+ assert.NoError(t, err)
if diff := cmp.Diff(tc.want, got.SecurityContext.NamespaceOptions); diff != "" {
t.Errorf("%v: diff (-want +got):\n%v", t.Name(), diff)
}
@@ -669,7 +676,8 @@ func TestGenerateLinuxContainerConfigSwap(t *testing.T) {
} {
t.Run(tc.name, func(t *testing.T) {
m.memorySwapBehavior = tc.swapSetting
- actual := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", nil, false)
+ actual, err := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", nil, false)
+ assert.NoError(t, err)
assert.Equal(t, tc.expected, actual.Resources.MemorySwapLimitInBytes, "memory swap config for %s", tc.name)
})
}
diff --git a/pkg/kubelet/kuberuntime/security_context.go b/pkg/kubelet/kuberuntime/security_context.go
index c9d33e44305..3b575c8e974 100644
--- a/pkg/kubelet/kuberuntime/security_context.go
+++ b/pkg/kubelet/kuberuntime/security_context.go
@@ -24,7 +24,7 @@ import (
)
// determineEffectiveSecurityContext gets container's security context from v1.Pod and v1.Container.
-func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container, uid *int64, username string) *runtimeapi.LinuxContainerSecurityContext {
+func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container, uid *int64, username string) (*runtimeapi.LinuxContainerSecurityContext, error) {
effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
synthesized := convertToRuntimeSecurityContext(effectiveSc)
if synthesized == nil {
@@ -36,9 +36,16 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
// TODO: Deprecated, remove after we switch to Seccomp field
// set SeccompProfilePath.
- synthesized.SeccompProfilePath = m.getSeccompProfilePath(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+ var err error
+ synthesized.SeccompProfilePath, err = m.getSeccompProfilePath(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+ if err != nil {
+ return nil, err
+ }
- synthesized.Seccomp = m.getSeccompProfile(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+ synthesized.Seccomp, err = m.getSeccompProfile(pod.Annotations, container.Name, pod.Spec.SecurityContext, container.SecurityContext, m.seccompDefault)
+ if err != nil {
+ return nil, err
+ }
// set ApparmorProfile.
synthesized.ApparmorProfile = apparmor.GetProfileNameFromPodAnnotations(pod.Annotations, container.Name)
@@ -74,7 +81,7 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
synthesized.MaskedPaths = securitycontext.ConvertToRuntimeMaskedPaths(effectiveSc.ProcMount)
synthesized.ReadonlyPaths = securitycontext.ConvertToRuntimeReadonlyPaths(effectiveSc.ProcMount)
- return synthesized
+ return synthesized, nil
}
// convertToRuntimeSecurityContext converts v1.SecurityContext to runtimeapi.SecurityContext.
--
2.41.0