go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/discovery/k8s/common.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package k8s 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/rs/zerolog/log" 11 "go.mondoo.com/cnquery" 12 "go.mondoo.com/cnquery/motor/asset" 13 "go.mondoo.com/cnquery/motor/discovery/common" 14 "go.mondoo.com/cnquery/motor/providers" 15 "go.mondoo.com/cnquery/motor/providers/k8s" 16 ) 17 18 type K8sResourceIdentifier struct { 19 Type string 20 Namespace string 21 Name string 22 } 23 24 // addSeparateAssets Depending on config options it will search for additional assets which should be listed separately. 25 func addSeparateAssets( 26 tc *providers.Config, 27 p k8s.KubernetesProvider, 28 nsFilter NamespaceFilterOpts, 29 resourcesFilter map[string][]K8sResourceIdentifier, 30 clusterIdentifier string, 31 od *k8s.PlatformIdOwnershipDirectory, 32 features cnquery.Features, 33 ) ([]*asset.Asset, error) { 34 resolved := []*asset.Asset{} 35 36 // discover deployments 37 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryDeployments) { 38 // fetch deployment information 39 log.Debug().Strs("namespace", nsFilter.include).Msg("search for deployments") 40 connection := tc.Clone() 41 deployments, err := ListDeployments(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 42 if err != nil { 43 log.Error().Err(err).Msg("could not fetch k8s deployments") 44 return nil, err 45 } 46 resolved = append(resolved, deployments...) 47 } 48 49 // discover k8s pods 50 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryPods) { 51 // fetch pod information 52 log.Debug().Strs("namespace", nsFilter.include).Msg("search for pods") 53 connection := tc.Clone() 54 pods, err := ListPods(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 55 if err != nil { 56 log.Error().Err(err).Msg("could not fetch k8s pods") 57 return nil, err 58 } 59 resolved = append(resolved, pods...) 60 } 61 62 // discover k8s pod images 63 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, DiscoveryContainerImages) { 64 // fetch pod information 65 log.Debug().Strs("namespace", nsFilter.include).Msg("search for pods images") 66 containerimages, err := ListPodImages(p, nsFilter, od) 67 if err != nil { 68 log.Error().Err(err).Msg("could not fetch k8s pods images") 69 return nil, err 70 } 71 resolved = append(resolved, containerimages...) 72 } 73 74 // discovery k8s daemonsets 75 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryDaemonSets) { 76 log.Debug().Strs("namespace", nsFilter.include).Msg("search for daemonsets") 77 connection := tc.Clone() 78 daemonsets, err := ListDaemonSets(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 79 if err != nil { 80 log.Error().Err(err).Msg("could not fetch k8s daemonsets") 81 return nil, err 82 } 83 resolved = append(resolved, daemonsets...) 84 } 85 86 // discover cronjobs 87 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryCronJobs) { 88 log.Debug().Strs("namespace", nsFilter.include).Msg("search for cronjobs") 89 connection := tc.Clone() 90 cronjobs, err := ListCronJobs(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 91 if err != nil { 92 log.Error().Err(err).Msg("could not fetch k8s cronjobs") 93 return nil, err 94 } 95 resolved = append(resolved, cronjobs...) 96 } 97 98 // discover jobs 99 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryJobs, DiscoveryJobs) { 100 log.Debug().Strs("namespace", nsFilter.include).Msg("search for jobs") 101 connection := tc.Clone() 102 jobs, err := ListJobs(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 103 if err != nil { 104 log.Error().Err(err).Msg("could not fetch k8s jobs") 105 return nil, err 106 } 107 resolved = append(resolved, jobs...) 108 } 109 110 // discover statefulsets 111 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryStatefulSets) { 112 log.Debug().Strs("namespace", nsFilter.include).Msg("search for statefulsets") 113 connection := tc.Clone() 114 statefulsets, err := ListStatefulSets(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 115 if err != nil { 116 log.Error().Err(err).Msg("could not fetch k8s statefulsets") 117 return nil, err 118 } 119 resolved = append(resolved, statefulsets...) 120 } 121 122 // discover replicasets 123 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryReplicaSets) { 124 log.Debug().Strs("namespace", nsFilter.include).Msg("search for replicasets") 125 connection := tc.Clone() 126 replicasets, err := ListReplicaSets(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 127 if err != nil { 128 log.Error().Err(err).Msg("could not fetch k8s replicasets") 129 return nil, err 130 } 131 resolved = append(resolved, replicasets...) 132 } 133 134 // discover admissionreviews 135 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, DiscoveryAdmissionReviews) { 136 log.Debug().Msg("search for admissionreviews") 137 connection := tc.Clone() 138 admissionReviews, err := ListAdmissionReviews(p, connection, clusterIdentifier, od) 139 if err != nil { 140 log.Error().Err(err).Msg("could not fetch k8s admissionreviews") 141 return nil, err 142 } 143 resolved = append(resolved, admissionReviews...) 144 } 145 146 // discover ingresses 147 if tc.IncludesOneOfDiscoveryTarget(common.DiscoveryAll, common.DiscoveryAuto, DiscoveryIngresses) { 148 log.Debug().Msg("search for ingresses") 149 connection := tc.Clone() 150 ingresses, err := ListIngresses(p, connection, clusterIdentifier, nsFilter, resourcesFilter, od) 151 if err != nil { 152 log.Error().Err(err).Msg("could not fetch k8s ingresses") 153 } 154 resolved = append(resolved, ingresses...) 155 } 156 157 // build a lookup on the k8s uid to look up individual assets to link 158 platformIdToAssetMap := map[string]*asset.Asset{} 159 for _, assetObj := range resolved { 160 for _, platformId := range assetObj.PlatformIds { 161 platformIdToAssetMap[platformId] = assetObj 162 } 163 } 164 165 for id, a := range platformIdToAssetMap { 166 ownedBy := od.OwnedBy(id) 167 for _, ownerPlatformId := range ownedBy { 168 if aa, ok := platformIdToAssetMap[ownerPlatformId]; ok { 169 a.RelatedAssets = append(a.RelatedAssets, aa) 170 } else { 171 // If the owner object is not scanned we can still add an asset as we know most of the information 172 // from the ownerReference field 173 if platformEntry, ok := od.GetKubernetesObjectData(ownerPlatformId); ok { 174 platformData, err := createPlatformData(platformEntry.Kind, providers.RUNTIME_KUBERNETES_CLUSTER) 175 if err != nil || (!features.IsActive(cnquery.K8sNodeDiscovery) && platformData.Name == "k8s-node") { 176 continue 177 } 178 a.RelatedAssets = append(a.RelatedAssets, &asset.Asset{ 179 PlatformIds: []string{ownerPlatformId}, 180 Platform: platformData, 181 Name: platformEntry.Namespace + "/" + platformEntry.Name, 182 }) 183 } 184 } 185 } 186 } 187 return resolved, nil 188 } 189 190 // resourceFilters parses the resource filters from the provider config 191 func resourceFilters(tc *providers.Config) (map[string][]K8sResourceIdentifier, error) { 192 resourcesFilter := make(map[string][]K8sResourceIdentifier) 193 if fOpt, ok := tc.Options["k8s-resources"]; ok { 194 fs := strings.Split(fOpt, ",") 195 for _, f := range fs { 196 ids := strings.Split(strings.TrimSpace(f), ":") 197 resType := ids[0] 198 var ns, name string 199 if _, ok := resourcesFilter[resType]; !ok { 200 resourcesFilter[resType] = []K8sResourceIdentifier{} 201 } 202 203 switch len(ids) { 204 case 3: 205 // Namespaced resources have the format type:ns:name 206 ns = ids[1] 207 name = ids[2] 208 case 2: 209 // Non-namespaced resources have the format type:name 210 name = ids[1] 211 default: 212 return nil, fmt.Errorf("invalid k8s resource filter: %s", f) 213 } 214 215 resourcesFilter[resType] = append(resourcesFilter[resType], K8sResourceIdentifier{Type: resType, Namespace: ns, Name: name}) 216 } 217 } 218 return resourcesFilter, nil 219 }