mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 02:41:25 +00:00
Partly remove support for seccomp annotations
We now partly drop the support for seccomp annotations which is planned for v1.25 as part of the KEP: https://github.com/kubernetes/enhancements/issues/135 Pod security policies are not touched by this change and therefore we have to keep the annotation key constants. This means we only allow the usage of the annotations for backwards compatibility reasons while the synchronization of the field to annotation is no longer supported. Using the annotations for static pods is also not supported any more. Making the annotations fully non-functional will be deferred to a future release. Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
This commit is contained in:
parent
d046a58de4
commit
584783ee9f
@ -777,36 +777,6 @@ func SeccompAnnotationForField(field *api.SeccompProfile) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// SeccompFieldForAnnotation takes a pod annotation and returns the converted
|
||||
// seccomp profile field.
|
||||
func SeccompFieldForAnnotation(annotation string) *api.SeccompProfile {
|
||||
// If only seccomp annotations are specified, copy the values into the
|
||||
// corresponding fields. This ensures that existing applications continue
|
||||
// to enforce seccomp, and prevents the kubelet from needing to resolve
|
||||
// annotations & fields.
|
||||
if annotation == v1.SeccompProfileNameUnconfined {
|
||||
return &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}
|
||||
}
|
||||
|
||||
if annotation == api.SeccompProfileRuntimeDefault || annotation == api.DeprecatedSeccompProfileDockerDefault {
|
||||
return &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(annotation, v1.SeccompLocalhostProfileNamePrefix) {
|
||||
localhostProfile := strings.TrimPrefix(annotation, v1.SeccompLocalhostProfileNamePrefix)
|
||||
if localhostProfile != "" {
|
||||
return &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeLocalhost,
|
||||
LocalhostProfile: &localhostProfile,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this code path if the localhostProfile name has a zero
|
||||
// length or if the annotation has an unrecognized value
|
||||
return nil
|
||||
}
|
||||
|
||||
// setsWindowsHostProcess returns true if WindowsOptions.HostProcess is set (true or false)
|
||||
// anywhere in the pod spec.
|
||||
func setsWindowsHostProcess(podSpec *api.PodSpec) bool {
|
||||
|
@ -240,7 +240,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta
|
||||
// use of pod seccomp annotation without accompanying field
|
||||
if podSpec.SecurityContext == nil || podSpec.SecurityContext.SeccompProfile == nil {
|
||||
if _, exists := meta.Annotations[api.SeccompPodAnnotationKey]; exists {
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: deprecated since v1.19, non-functional in v1.25+; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompPodAnnotationKey)))
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompPodAnnotationKey)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta
|
||||
// use of container seccomp annotation without accompanying field
|
||||
if c.SecurityContext == nil || c.SecurityContext.SeccompProfile == nil {
|
||||
if _, exists := meta.Annotations[api.SeccompContainerAnnotationKeyPrefix+c.Name]; exists {
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: deprecated since v1.19, non-functional in v1.25+; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompContainerAnnotationKeyPrefix+c.Name)))
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompContainerAnnotationKeyPrefix+c.Name)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,8 +432,8 @@ func TestWarnings(t *testing.T) {
|
||||
},
|
||||
expected: []string{
|
||||
`metadata.annotations[scheduler.alpha.kubernetes.io/critical-pod]: non-functional in v1.16+; use the "priorityClassName" field instead`,
|
||||
`metadata.annotations[seccomp.security.alpha.kubernetes.io/pod]: deprecated since v1.19, non-functional in v1.25+; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[container.seccomp.security.alpha.kubernetes.io/foo]: deprecated since v1.19, non-functional in v1.25+; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[seccomp.security.alpha.kubernetes.io/pod]: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[container.seccomp.security.alpha.kubernetes.io/foo]: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[security.alpha.kubernetes.io/sysctls]: non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
`metadata.annotations[security.alpha.kubernetes.io/unsafe-sysctls]: non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
},
|
||||
|
@ -4218,7 +4218,7 @@ func ValidatePodCreate(pod *core.Pod, opts PodValidationOptions) field.ErrorList
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateSeccompAnnotationsAndFields iterates through all containers and ensure that when both seccompProfile and seccomp annotations exist they match.
|
||||
// validateSeccompAnnotationsAndFields iterates through all containers and ensure that when both seccompProfile and seccomp annotations exist they match.
|
||||
func validateSeccompAnnotationsAndFields(objectMeta metav1.ObjectMeta, podSpec *core.PodSpec, specPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
|
@ -234,15 +234,6 @@ func fieldProfile(scmp *v1.SeccompProfile, profileRootPath string, fallbackToRun
|
||||
return ""
|
||||
}
|
||||
|
||||
func annotationProfile(profile, profileRootPath string) string {
|
||||
if strings.HasPrefix(profile, v1.SeccompLocalhostProfileNamePrefix) {
|
||||
name := strings.TrimPrefix(profile, v1.SeccompLocalhostProfileNamePrefix)
|
||||
fname := filepath.Join(profileRootPath, filepath.FromSlash(name))
|
||||
return v1.SeccompLocalhostProfileNamePrefix + fname
|
||||
}
|
||||
return profile
|
||||
}
|
||||
|
||||
func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string]string, containerName string,
|
||||
podSecContext *v1.PodSecurityContext, containerSecContext *v1.SecurityContext, fallbackToRuntimeDefault bool) string {
|
||||
// container fields are applied first
|
||||
@ -250,23 +241,11 @@ func (m *kubeGenericRuntimeManager) getSeccompProfilePath(annotations map[string
|
||||
return fieldProfile(containerSecContext.SeccompProfile, m.seccompProfileRoot, fallbackToRuntimeDefault)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// when container seccomp is not defined, try to apply from pod field
|
||||
if podSecContext != nil && podSecContext.SeccompProfile != nil {
|
||||
return fieldProfile(podSecContext.SeccompProfile, m.seccompProfileRoot, fallbackToRuntimeDefault)
|
||||
}
|
||||
|
||||
// as last resort, try to apply pod annotation (deprecated)
|
||||
if profile, ok := annotations[v1.SeccompPodAnnotationKey]; ok {
|
||||
return annotationProfile(profile, m.seccompProfileRoot)
|
||||
}
|
||||
|
||||
if fallbackToRuntimeDefault {
|
||||
return v1.SeccompProfileRuntimeDefault
|
||||
}
|
||||
|
@ -369,91 +369,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}},
|
||||
@ -500,36 +415,6 @@ 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 {
|
||||
@ -559,91 +444,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}},
|
||||
@ -690,36 +490,6 @@ 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 {
|
||||
|
@ -158,12 +158,6 @@ func newTestPod() *v1.Pod {
|
||||
|
||||
func newSeccompPod(podFieldProfile, containerFieldProfile *v1.SeccompProfile, podAnnotationProfile, containerAnnotationProfile string) *v1.Pod {
|
||||
pod := newTestPod()
|
||||
if podAnnotationProfile != "" {
|
||||
pod.Annotations = map[string]string{v1.SeccompPodAnnotationKey: podAnnotationProfile}
|
||||
}
|
||||
if containerAnnotationProfile != "" {
|
||||
pod.Annotations = map[string]string{v1.SeccompContainerAnnotationKeyPrefix + "": containerAnnotationProfile}
|
||||
}
|
||||
if podFieldProfile != nil {
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
SeccompProfile: podFieldProfile,
|
||||
|
@ -644,28 +644,20 @@ func validateContainer(container string, pod *api.Pod) (string, error) {
|
||||
|
||||
// applySeccompVersionSkew implements the version skew behavior described in:
|
||||
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/135-seccomp#version-skew-strategy
|
||||
// Note that we dropped copying the field to annotation synchronization in
|
||||
// v1.25 with the functional removal of the annotations.
|
||||
func applySeccompVersionSkew(pod *api.Pod) {
|
||||
// get possible annotation and field
|
||||
annotation, hasAnnotation := pod.Annotations[v1.SeccompPodAnnotationKey]
|
||||
field, hasField := (*api.SeccompProfile)(nil), false
|
||||
hasField := false
|
||||
|
||||
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SeccompProfile != nil {
|
||||
field = pod.Spec.SecurityContext.SeccompProfile
|
||||
hasField = true
|
||||
}
|
||||
|
||||
// sync field and annotation
|
||||
if hasField && !hasAnnotation {
|
||||
newAnnotation := podutil.SeccompAnnotationForField(field)
|
||||
|
||||
if newAnnotation != "" {
|
||||
if pod.Annotations == nil {
|
||||
pod.Annotations = map[string]string{}
|
||||
}
|
||||
pod.Annotations[v1.SeccompPodAnnotationKey] = newAnnotation
|
||||
}
|
||||
} else if hasAnnotation && !hasField {
|
||||
newField := podutil.SeccompFieldForAnnotation(annotation)
|
||||
if hasAnnotation && !hasField {
|
||||
newField := seccompFieldForAnnotation(annotation)
|
||||
|
||||
if newField != nil {
|
||||
if pod.Spec.SecurityContext == nil {
|
||||
@ -682,24 +674,14 @@ func applySeccompVersionSkew(pod *api.Pod) {
|
||||
key := api.SeccompContainerAnnotationKeyPrefix + ctr.Name
|
||||
annotation, hasAnnotation := pod.Annotations[key]
|
||||
|
||||
field, hasField := (*api.SeccompProfile)(nil), false
|
||||
hasField := false
|
||||
if ctr.SecurityContext != nil && ctr.SecurityContext.SeccompProfile != nil {
|
||||
field = ctr.SecurityContext.SeccompProfile
|
||||
hasField = true
|
||||
}
|
||||
|
||||
// sync field and annotation
|
||||
if hasField && !hasAnnotation {
|
||||
newAnnotation := podutil.SeccompAnnotationForField(field)
|
||||
|
||||
if newAnnotation != "" {
|
||||
if pod.Annotations == nil {
|
||||
pod.Annotations = map[string]string{}
|
||||
}
|
||||
pod.Annotations[key] = newAnnotation
|
||||
}
|
||||
} else if hasAnnotation && !hasField {
|
||||
newField := podutil.SeccompFieldForAnnotation(annotation)
|
||||
if hasAnnotation && !hasField {
|
||||
newField := seccompFieldForAnnotation(annotation)
|
||||
|
||||
if newField != nil {
|
||||
if ctr.SecurityContext == nil {
|
||||
@ -712,3 +694,33 @@ func applySeccompVersionSkew(pod *api.Pod) {
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// seccompFieldForAnnotation takes a pod annotation and returns the converted
|
||||
// seccomp profile field.
|
||||
func seccompFieldForAnnotation(annotation string) *api.SeccompProfile {
|
||||
// If only seccomp annotations are specified, copy the values into the
|
||||
// corresponding fields. This ensures that existing applications continue
|
||||
// to enforce seccomp, and prevents the kubelet from needing to resolve
|
||||
// annotations & fields.
|
||||
if annotation == v1.SeccompProfileNameUnconfined {
|
||||
return &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}
|
||||
}
|
||||
|
||||
if annotation == api.SeccompProfileRuntimeDefault || annotation == api.DeprecatedSeccompProfileDockerDefault {
|
||||
return &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(annotation, v1.SeccompLocalhostProfileNamePrefix) {
|
||||
localhostProfile := strings.TrimPrefix(annotation, v1.SeccompLocalhostProfileNamePrefix)
|
||||
if localhostProfile != "" {
|
||||
return &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeLocalhost,
|
||||
LocalhostProfile: &localhostProfile,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this code path if the localhostProfile name has a zero
|
||||
// length or if the annotation has an unrecognized value
|
||||
return nil
|
||||
}
|
||||
|
@ -749,7 +749,7 @@ func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type unconfined and no annotation present",
|
||||
description: "Field set and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
@ -759,55 +759,6 @@ func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 1)
|
||||
require.Equal(t, v1.SeccompProfileNameUnconfined, pod.Annotations[api.SeccompPodAnnotationKey])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type default and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 1)
|
||||
require.Equal(t, v1.SeccompProfileRuntimeDefault, pod.Annotations[v1.SeccompPodAnnotationKey])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type localhost and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeLocalhost,
|
||||
LocalhostProfile: &testProfile,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 1)
|
||||
require.Equal(t, "localhost/test", pod.Annotations[v1.SeccompPodAnnotationKey])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type localhost but profile is nil",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeLocalhost,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
@ -911,7 +862,7 @@ func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type unconfined and no annotation present (container)",
|
||||
description: "Field set and no annotation present (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
@ -927,51 +878,7 @@ func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 1)
|
||||
require.Equal(t, v1.SeccompProfileNameUnconfined, pod.Annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type runtime/default and no annotation present (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
SecurityContext: &api.SecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 1)
|
||||
require.Equal(t, v1.SeccompProfileRuntimeDefault, pod.Annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field type localhost and no annotation present (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
SecurityContext: &api.SecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeLocalhost,
|
||||
LocalhostProfile: &testProfile,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 1)
|
||||
require.Equal(t, "localhost/test", pod.Annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName])
|
||||
require.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1002,9 +909,7 @@ func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 2)
|
||||
require.Equal(t, v1.SeccompProfileNameUnconfined, pod.Annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName+"1"])
|
||||
require.Equal(t, v1.SeccompProfileRuntimeDefault, pod.Annotations[v1.SeccompContainerAnnotationKeyPrefix+containerName+"3"])
|
||||
require.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -626,13 +626,10 @@ func (a *Admission) PolicyToEvaluate(labels map[string]string) (api.Policy, fiel
|
||||
}
|
||||
|
||||
// isSignificantPodUpdate determines whether a pod update should trigger a policy evaluation.
|
||||
// Relevant mutable pod fields as of 1.21 are image and seccomp annotations:
|
||||
// Relevant mutable pod fields as of 1.21 are image annotations:
|
||||
// * https://github.com/kubernetes/kubernetes/blob/release-1.21/pkg/apis/core/validation/validation.go#L3947-L3949
|
||||
func isSignificantPodUpdate(pod, oldPod *corev1.Pod) bool {
|
||||
// TODO: invert this logic to only allow specific update types.
|
||||
if pod.Annotations[corev1.SeccompPodAnnotationKey] != oldPod.Annotations[corev1.SeccompPodAnnotationKey] {
|
||||
return true
|
||||
}
|
||||
if len(pod.Spec.Containers) != len(oldPod.Spec.Containers) {
|
||||
return true
|
||||
}
|
||||
@ -672,6 +669,7 @@ func isSignificantContainerUpdate(container, oldContainer *corev1.Container, ann
|
||||
if container.Image != oldContainer.Image {
|
||||
return true
|
||||
}
|
||||
// TODO(saschagrunert): Remove this logic in 1.27.
|
||||
seccompKey := corev1.SeccompContainerAnnotationKeyPrefix + container.Name
|
||||
return annotations[seccompKey] != oldAnnotations[seccompKey]
|
||||
}
|
||||
|
@ -165,27 +165,27 @@ var _ = SIGDescribe("Security Context", func() {
|
||||
pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeUnconfined}}
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}}
|
||||
pod.Spec.Containers[0].Command = []string{"grep", "ecc", "/proc/self/status"}
|
||||
f.TestContainerOutput(v1.SeccompPodAnnotationKey, pod, 0, []string{"0"}) // seccomp disabled
|
||||
f.TestContainerOutput("seccomp unconfined container", pod, 0, []string{"0"}) // seccomp disabled
|
||||
})
|
||||
|
||||
ginkgo.It("should support seccomp unconfined on the pod [LinuxOnly]", func() {
|
||||
pod := scTestPod(false, false)
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeUnconfined}}
|
||||
pod.Spec.Containers[0].Command = []string{"grep", "ecc", "/proc/self/status"}
|
||||
f.TestContainerOutput(v1.SeccompPodAnnotationKey, pod, 0, []string{"0"}) // seccomp disabled
|
||||
f.TestContainerOutput("seccomp unconfined pod", pod, 0, []string{"0"}) // seccomp disabled
|
||||
})
|
||||
|
||||
ginkgo.It("should support seccomp runtime/default [LinuxOnly]", func() {
|
||||
pod := scTestPod(false, false)
|
||||
pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{SeccompProfile: &v1.SeccompProfile{Type: v1.SeccompProfileTypeRuntimeDefault}}
|
||||
pod.Spec.Containers[0].Command = []string{"grep", "ecc", "/proc/self/status"}
|
||||
f.TestContainerOutput(v1.SeccompPodAnnotationKey, pod, 0, []string{"2"}) // seccomp filtered
|
||||
f.TestContainerOutput("seccomp runtime/default", pod, 0, []string{"2"}) // seccomp filtered
|
||||
})
|
||||
|
||||
ginkgo.It("should support seccomp default which is unconfined [LinuxOnly]", func() {
|
||||
pod := scTestPod(false, false)
|
||||
pod.Spec.Containers[0].Command = []string{"grep", "ecc", "/proc/self/status"}
|
||||
f.TestContainerOutput(v1.SeccompPodAnnotationKey, pod, 0, []string{"0"}) // seccomp disabled
|
||||
f.TestContainerOutput("seccomp default unconfined", pod, 0, []string{"0"}) // seccomp disabled
|
||||
})
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user