go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/discovery/k8s/resolver_namespace.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package k8s 5 6 import ( 7 "context" 8 "fmt" 9 "regexp" 10 "strings" 11 12 "github.com/gobwas/glob" 13 "github.com/rs/zerolog/log" 14 "go.mondoo.com/cnquery" 15 "go.mondoo.com/cnquery/motor/asset" 16 "go.mondoo.com/cnquery/motor/discovery/common" 17 "go.mondoo.com/cnquery/motor/providers" 18 "go.mondoo.com/cnquery/motor/providers/k8s" 19 "go.mondoo.com/cnquery/motor/providers/k8s/resources" 20 "go.mondoo.com/cnquery/motor/vault" 21 "k8s.io/apimachinery/pkg/api/errors" 22 ) 23 24 var _ common.ContextInitializer = (*NamespaceResolver)(nil) 25 26 type NamespaceResolver struct{} 27 28 func (r *NamespaceResolver) Name() string { 29 return "Kubernetes Namespace Resolver" 30 } 31 32 func (r *NamespaceResolver) AvailableDiscoveryTargets() []string { 33 return []string{ 34 common.DiscoveryAuto, 35 common.DiscoveryAll, 36 DiscoveryClusters, 37 DiscoveryPods, 38 DiscoveryJobs, 39 DiscoveryCronJobs, 40 DiscoveryStatefulSets, 41 DiscoveryDeployments, 42 DiscoveryReplicaSets, 43 DiscoveryDaemonSets, 44 DiscoveryContainerImages, 45 DiscoveryAdmissionReviews, 46 DiscoveryIngresses, 47 } 48 } 49 50 func (r *NamespaceResolver) InitCtx(ctx context.Context) context.Context { 51 return resources.SetDiscoveryCache(ctx, resources.NewDiscoveryCache()) 52 } 53 54 func (r *NamespaceResolver) Resolve(ctx context.Context, root *asset.Asset, tc *providers.Config, credsResolver vault.Resolver, sfn common.QuerySecretFn, userIdDetectors ...providers.PlatformIdDetector) ([]*asset.Asset, error) { 55 features := cnquery.GetFeatures(ctx) 56 resolved := []*asset.Asset{} 57 58 nsFilter := NamespaceFilterOpts{} 59 includeNamespaces := tc.Options["namespaces"] 60 if len(includeNamespaces) > 0 { 61 nsFilter.include = append(nsFilter.include, strings.Split(includeNamespaces, ",")...) 62 } 63 64 p, err := k8s.New(ctx, tc) 65 if err != nil { 66 return nil, err 67 } 68 69 // Put a Warn() message if a Namespace that doesn't exist was part of the 70 // list of Namespaces to include. We can only check that if the k8s user is allowed to list the 71 // cluster namespaces. 72 clusterNamespaces, err := p.Namespaces() 73 if err != nil { 74 if errors.IsForbidden(err) { 75 // If the user does not have permissions to list the cluster namespaces, we cannot do glob matching. 76 // We can only work with exact matching in that case 77 if containsGlob, _ := regexp.MatchString(`[\*\/\\\[\]\{\}\?]`, includeNamespaces); containsGlob { 78 return nil, fmt.Errorf("glob patterns are not allowed for k8s users with no list namespace permissions") 79 } 80 log.Warn().Msg("cannot list cluster namespaces, skipping check for non-existent namespaces...") 81 } else { 82 return nil, err 83 } 84 } else { 85 for _, ns := range nsFilter.include { 86 foundNamespace := false 87 g, err := glob.Compile(ns) 88 if err != nil { 89 log.Error().Err(err).Str("namespaceFilter", ns).Msg("failed to parse Namespace filter glob") 90 return nil, err 91 } 92 for _, clusterNs := range clusterNamespaces { 93 if g.Match(clusterNs.Name) { 94 foundNamespace = true 95 break 96 } 97 } 98 if !foundNamespace { 99 log.Warn().Msgf("Namespace filter %q did not match any Namespaces in cluster", ns) 100 } 101 } 102 } 103 104 excludeNamespaces := tc.Options["namespaces-exclude"] 105 if len(excludeNamespaces) > 0 { 106 nsFilter.exclude = strings.Split(excludeNamespaces, ",") 107 } 108 109 log.Debug().Strs("namespacesIncludeFilter", nsFilter.include).Strs("namespacesExcludeFilter", nsFilter.exclude).Msg("resolve k8s assets") 110 111 resourcesFilter, err := resourceFilters(tc) 112 if err != nil { 113 return nil, err 114 } 115 116 nss, err := ListNamespaces(p, tc, "", nsFilter, resourcesFilter, nil) 117 if err != nil { 118 return nil, err 119 } 120 121 resolved = append(resolved, nss...) 122 for _, ns := range nss { 123 identifier := ns.PlatformIds[0] 124 ownershipDir := k8s.NewEmptyPlatformIdOwnershipDirectory(identifier) 125 additionalAssets, err := addSeparateAssets(tc, p, nsFilter, resourcesFilter, identifier, ownershipDir, features) 126 if err != nil { 127 return nil, err 128 } 129 resolved = append(resolved, additionalAssets...) 130 } 131 132 return resolved, nil 133 }