go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/discovery/k8s/container_utils.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package k8s 5 6 import ( 7 "strings" 8 9 "go.mondoo.com/cnquery/types" 10 v1 "k8s.io/api/core/v1" 11 ) 12 13 const DockerPullablePrefix = "docker-pullable://" 14 15 type ContainerImage struct { 16 image string 17 resolvedImage string 18 pullSecrets []v1.Secret 19 } 20 21 func ResolveUniqueContainerImages(cs []v1.Container, ps []v1.Secret) map[string]ContainerImage { 22 imagesSet := make(map[string]ContainerImage) 23 for _, c := range cs { 24 imagesSet[c.Image] = ContainerImage{image: c.Image, resolvedImage: c.Image, pullSecrets: ps} 25 } 26 return imagesSet 27 } 28 29 func ResolveUniqueContainerImagesFromStatus(cs []v1.ContainerStatus, ps []v1.Secret) map[string]ContainerImage { 30 imagesSet := make(map[string]ContainerImage) 31 for _, c := range cs { 32 image, resolvedImage := ResolveContainerImageFromStatus(c) 33 imagesSet[resolvedImage] = ContainerImage{image: image, resolvedImage: resolvedImage, pullSecrets: ps} 34 } 35 return imagesSet 36 } 37 38 func ResolveContainerImageFromStatus(containerStatus v1.ContainerStatus) (string, string) { 39 image := containerStatus.Image 40 resolvedImage := containerStatus.ImageID 41 if strings.HasPrefix(resolvedImage, DockerPullablePrefix) { 42 resolvedImage = strings.TrimPrefix(resolvedImage, DockerPullablePrefix) 43 } 44 45 // stopped pods may not include the resolved image 46 // pods with imagePullPolicy: Never do not have a proper ImageId value as it contains only the 47 // sha but not the repository. If we use that value, it will cause issues later because we will 48 // eventually try to pull an image by providing just the sha without a repo. 49 if len(resolvedImage) == 0 || !strings.Contains(resolvedImage, "@") { 50 resolvedImage = containerStatus.Image 51 } 52 53 return image, resolvedImage 54 } 55 56 // UniqueImagesForPod returns the unique container images for a pod. Images are compared based on their digest 57 // if that is available in the pod status. If there is no pod status set, the container image tag is used. 58 func UniqueImagesForPod(pod v1.Pod, credsStore *credsStore) map[string]ContainerImage { 59 imagesSet := make(map[string]ContainerImage) 60 61 pullSecrets := make([]v1.Secret, 0, len(pod.Spec.ImagePullSecrets)) 62 for _, ps := range pod.Spec.ImagePullSecrets { 63 s, err := credsStore.Get(pod.Namespace, ps.Name) // TODO: figure out if we want to do anything with the error here 64 if err == nil { 65 pullSecrets = append(pullSecrets, *s) 66 } 67 } 68 69 // it is best to read the image from the container status since it is resolved 70 // and more accurate, for static file scan we also need to fall-back to pure spec 71 // since the status will not be set 72 imagesSet = types.MergeMaps(imagesSet, ResolveUniqueContainerImagesFromStatus(pod.Status.InitContainerStatuses, pullSecrets)) 73 74 // fall-back to spec 75 if len(pod.Spec.InitContainers) > 0 && len(pod.Status.InitContainerStatuses) == 0 { 76 imagesSet = types.MergeMaps(imagesSet, ResolveUniqueContainerImages(pod.Spec.InitContainers, pullSecrets)) 77 } 78 79 imagesSet = types.MergeMaps(imagesSet, ResolveUniqueContainerImagesFromStatus(pod.Status.ContainerStatuses, pullSecrets)) 80 81 // fall-back to spec 82 if len(pod.Spec.Containers) > 0 && len(pod.Status.ContainerStatuses) == 0 { 83 imagesSet = types.MergeMaps(imagesSet, ResolveUniqueContainerImages(pod.Spec.Containers, pullSecrets)) 84 } 85 return imagesSet 86 }