k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/security/apparmor/helpers.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package apparmor 18 19 import ( 20 "strings" 21 22 v1 "k8s.io/api/core/v1" 23 utilfeature "k8s.io/apiserver/pkg/util/feature" 24 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 25 "k8s.io/kubernetes/pkg/features" 26 ) 27 28 // Checks whether app armor is required for the pod to run. AppArmor is considered required if any 29 // non-unconfined profiles are specified. 30 func isRequired(pod *v1.Pod) bool { 31 if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.AppArmorProfile != nil && 32 pod.Spec.SecurityContext.AppArmorProfile.Type != v1.AppArmorProfileTypeUnconfined { 33 return true 34 } 35 36 inUse := !podutil.VisitContainers(&pod.Spec, podutil.AllContainers, func(c *v1.Container, _ podutil.ContainerType) bool { 37 if c.SecurityContext != nil && c.SecurityContext.AppArmorProfile != nil && 38 c.SecurityContext.AppArmorProfile.Type != v1.AppArmorProfileTypeUnconfined { 39 return false // is in use; short-circuit 40 } 41 return true 42 }) 43 if inUse { 44 return true 45 } 46 47 for key, value := range pod.Annotations { 48 if strings.HasPrefix(key, v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix) { 49 return value != v1.DeprecatedAppArmorBetaProfileNameUnconfined 50 } 51 } 52 return false 53 } 54 55 // GetProfileName returns the name of the profile to use with the container. 56 func GetProfile(pod *v1.Pod, container *v1.Container) *v1.AppArmorProfile { 57 if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmorFields) { 58 return getProfileFromPodAnnotations(pod.Annotations, container.Name) 59 } 60 61 if container.SecurityContext != nil && container.SecurityContext.AppArmorProfile != nil { 62 return container.SecurityContext.AppArmorProfile 63 } 64 65 // Static pods may not have had annotations synced to fields, so fallback to annotations before 66 // the pod profile. 67 if profile := getProfileFromPodAnnotations(pod.Annotations, container.Name); profile != nil { 68 return profile 69 } 70 71 if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.AppArmorProfile != nil { 72 return pod.Spec.SecurityContext.AppArmorProfile 73 } 74 75 return nil 76 } 77 78 // getProfileFromPodAnnotations gets the AppArmor profile to use with container from 79 // (deprecated) pod annotations. 80 func getProfileFromPodAnnotations(annotations map[string]string, containerName string) *v1.AppArmorProfile { 81 val, ok := annotations[v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix+containerName] 82 if !ok { 83 return nil 84 } 85 86 switch { 87 case val == v1.DeprecatedAppArmorBetaProfileRuntimeDefault: 88 return &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeRuntimeDefault} 89 90 case val == v1.DeprecatedAppArmorBetaProfileNameUnconfined: 91 return &v1.AppArmorProfile{Type: v1.AppArmorProfileTypeUnconfined} 92 93 case strings.HasPrefix(val, v1.DeprecatedAppArmorBetaProfileNamePrefix): 94 // Note: an invalid empty localhost profile will be rejected by kubelet admission. 95 profileName := strings.TrimPrefix(val, v1.DeprecatedAppArmorBetaProfileNamePrefix) 96 return &v1.AppArmorProfile{ 97 Type: v1.AppArmorProfileTypeLocalhost, 98 LocalhostProfile: &profileName, 99 } 100 101 default: 102 // Invalid annotation. 103 return nil 104 } 105 }