Match annotations against pod AppArmor field

This commit is contained in:
Tim Allclair
2024-02-29 12:06:04 -08:00
parent d25b1ded76
commit ec325b328d
4 changed files with 183 additions and 56 deletions

View File

@@ -4729,8 +4729,8 @@ func ValidateAppArmorProfileFormat(profile string) error {
return nil
}
// validateAppArmorAnnotationsAndFields validates that AppArmor fields and annotations are consistent.
func validateAppArmorAnnotationsAndFields(objectMeta metav1.ObjectMeta, podSpec *core.PodSpec, specPath *field.Path) field.ErrorList {
// validateAppArmorAnnotationsAndFieldsMatchOnCreate validates that AppArmor fields and annotations are consistent.
func validateAppArmorAnnotationsAndFieldsMatchOnCreate(objectMeta metav1.ObjectMeta, podSpec *core.PodSpec, specPath *field.Path) field.ErrorList {
if podSpec.OS != nil && podSpec.OS.Name == core.Windows {
// Skip consistency check for windows pods.
return nil
@@ -4738,22 +4738,41 @@ func validateAppArmorAnnotationsAndFields(objectMeta metav1.ObjectMeta, podSpec
allErrs := field.ErrorList{}
var podProfile *core.AppArmorProfile
if podSpec.SecurityContext != nil {
podProfile = podSpec.SecurityContext.AppArmorProfile
}
podshelper.VisitContainersWithPath(podSpec, specPath, func(c *core.Container, cFldPath *field.Path) bool {
var field *core.AppArmorProfile
if c.SecurityContext != nil {
field = c.SecurityContext.AppArmorProfile
containerProfile := podProfile
if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil {
containerProfile = c.SecurityContext.AppArmorProfile
}
if field == nil {
if containerProfile == nil {
return true
}
key := core.AppArmorContainerAnnotationKeyPrefix + c.Name
if annotation, found := objectMeta.Annotations[key]; found {
apparmorPath := cFldPath.Child("securityContext").Child("appArmorProfile")
err := validateAppArmorAnnotationsAndFieldsMatch(annotation, field, apparmorPath)
if err != nil {
allErrs = append(allErrs, err)
switch containerProfile.Type {
case core.AppArmorProfileTypeUnconfined:
if annotation != core.AppArmorProfileNameUnconfined {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
}
case core.AppArmorProfileTypeRuntimeDefault:
if annotation != core.AppArmorProfileRuntimeDefault {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
}
case core.AppArmorProfileTypeLocalhost:
if !strings.HasPrefix(annotation, core.AppArmorProfileLocalhostPrefix) {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("type"), "apparmor type in annotation and field must match"))
} else if containerProfile.LocalhostProfile == nil || strings.TrimPrefix(annotation, core.AppArmorProfileLocalhostPrefix) != *containerProfile.LocalhostProfile {
allErrs = append(allErrs, field.Forbidden(apparmorPath.Child("localhostProfile"), "apparmor profile in annotation and field must match"))
}
}
}
return true
@@ -4762,33 +4781,6 @@ func validateAppArmorAnnotationsAndFields(objectMeta metav1.ObjectMeta, podSpec
return allErrs
}
func validateAppArmorAnnotationsAndFieldsMatch(annotationValue string, apparmorField *core.AppArmorProfile, fldPath *field.Path) *field.Error {
if apparmorField == nil {
return nil
}
switch apparmorField.Type {
case core.AppArmorProfileTypeUnconfined:
if annotationValue != core.AppArmorProfileNameUnconfined {
return field.Forbidden(fldPath.Child("type"), "apparmor type in annotation and field must match")
}
case core.AppArmorProfileTypeRuntimeDefault:
if annotationValue != core.AppArmorProfileRuntimeDefault {
return field.Forbidden(fldPath.Child("type"), "apparmor type in annotation and field must match")
}
case core.AppArmorProfileTypeLocalhost:
if !strings.HasPrefix(annotationValue, core.AppArmorProfileLocalhostPrefix) {
return field.Forbidden(fldPath.Child("type"), "apparmor type in annotation and field must match")
} else if apparmorField.LocalhostProfile == nil || strings.TrimPrefix(annotationValue, core.AppArmorProfileLocalhostPrefix) != *apparmorField.LocalhostProfile {
return field.Forbidden(fldPath.Child("localhostProfile"), "apparmor profile in annotation and field must match")
}
}
return nil
}
func podSpecHasContainer(spec *core.PodSpec, containerName string) bool {
var hasContainer bool
podshelper.VisitContainersWithPath(spec, field.NewPath("spec"), func(c *core.Container, _ *field.Path) bool {
@@ -4943,7 +4935,7 @@ func ValidatePodCreate(pod *core.Pod, opts PodValidationOptions) field.ErrorList
allErrs = append(allErrs, field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared"))
}
allErrs = append(allErrs, validateSeccompAnnotationsAndFields(pod.ObjectMeta, &pod.Spec, fldPath)...)
allErrs = append(allErrs, validateAppArmorAnnotationsAndFields(pod.ObjectMeta, &pod.Spec, fldPath)...)
allErrs = append(allErrs, validateAppArmorAnnotationsAndFieldsMatchOnCreate(pod.ObjectMeta, &pod.Spec, fldPath)...)
return allErrs
}