diff --git a/providers/k8s/connection/manifest/connection_test.go b/providers/k8s/connection/manifest/connection_test.go index eb573c7d17..75c48d8c7c 100644 --- a/providers/k8s/connection/manifest/connection_test.go +++ b/providers/k8s/connection/manifest/connection_test.go @@ -153,7 +153,7 @@ func TestOperatorManifest(t *testing.T) { } inv, err := resources.Discover(pluginRuntime, cnquery.Features{}) require.NoError(t, err) - require.Len(t, inv.Spec.Assets, 2) + require.Len(t, inv.Spec.Assets, 3) require.Len(t, inv.Spec.Assets[1].PlatformIds, 1) @@ -175,7 +175,7 @@ func TestOperatorManifest(t *testing.T) { require.NotEqual(t, inv.Spec.Assets[0].PlatformIds[0], inv.Spec.Assets[1].PlatformIds[0]) require.Equal(t, "//platformid.api.mondoo.app/runtime/k8s/uid/"+manifestHash, inv.Spec.Assets[0].PlatformIds[0]) - require.Equal(t, "//platformid.api.mondoo.app/runtime/k8s/uid/"+manifestHash+"/namespace/mondoo-operator/deployments/name/mondoo-operator-controller-manager", inv.Spec.Assets[1].PlatformIds[0]) + require.Equal(t, "//platformid.api.mondoo.app/runtime/k8s/uid/"+manifestHash+"/namespace/mondoo-operator/deployments/name/mondoo-operator-controller-manager", inv.Spec.Assets[2].PlatformIds[0]) } func TestOperatorManifestWithNamespaceFilter(t *testing.T) { @@ -210,7 +210,7 @@ func TestOperatorManifestWithNamespaceFilter(t *testing.T) { } inv, err := resources.Discover(pluginRuntime, cnquery.Features{}) require.NoError(t, err) - require.Len(t, inv.Spec.Assets, 2) + require.Len(t, inv.Spec.Assets, 3) require.Len(t, inv.Spec.Assets[1].PlatformIds, 1) @@ -224,7 +224,7 @@ func TestOperatorManifestWithNamespaceFilter(t *testing.T) { } require.NotEqual(t, inv.Spec.Assets[0].PlatformIds[0], inv.Spec.Assets[1].PlatformIds[0]) require.Equal(t, "//platformid.api.mondoo.app/runtime/k8s/uid/namespace/mondoo-operator", inv.Spec.Assets[0].PlatformIds[0]) - require.Equal(t, "//platformid.api.mondoo.app/runtime/k8s/uid/namespace/mondoo-operator/deployments/name/mondoo-operator-controller-manager", inv.Spec.Assets[1].PlatformIds[0]) + require.Equal(t, "//platformid.api.mondoo.app/runtime/k8s/uid/namespace/mondoo-operator/deployments/name/mondoo-operator-controller-manager", inv.Spec.Assets[2].PlatformIds[0]) } func TestManifestNoObjects(t *testing.T) { @@ -258,7 +258,7 @@ func TestManifestNoObjects(t *testing.T) { } inv, err := resources.Discover(pluginRuntime, cnquery.Features{}) require.NoError(t, err) - require.Len(t, inv.Spec.Assets, 1) + require.Len(t, inv.Spec.Assets, 2) require.Len(t, inv.Spec.Assets[0].PlatformIds, 1) @@ -304,7 +304,7 @@ func TestManifestDir(t *testing.T) { } inv, err := resources.Discover(pluginRuntime, cnquery.Features{}) require.NoError(t, err) - require.Len(t, inv.Spec.Assets, 3) + require.Len(t, inv.Spec.Assets, 5) for i := range inv.Spec.Assets { asset := inv.Spec.Assets[i] diff --git a/providers/k8s/resources/discovery.go b/providers/k8s/resources/discovery.go index 34924d2b99..d13dc0c39c 100644 --- a/providers/k8s/resources/discovery.go +++ b/providers/k8s/resources/discovery.go @@ -40,6 +40,7 @@ const ( DiscoveryAdmissionReviews = "admissionreviews" DiscoveryIngresses = "ingresses" DiscoveryNamespaces = "namespaces" + DiscoveryServices = "services" ) type NamespaceFilterOpts struct { @@ -202,6 +203,13 @@ func discoverAssets( } assets = append(assets, list...) } + if target == DiscoveryServices || target == DiscoveryAuto || target == DiscoveryAll { + list, err = discoverServices(conn, invConfig, clusterId, k8s, od, nsFilter, resFilters) + if err != nil { + return nil, err + } + assets = append(assets, list...) + } if target == DiscoveryStatefulSets || target == DiscoveryAuto || target == DiscoveryAll { list, err = discoverStatefulSets(conn, invConfig, clusterId, k8s, od, nsFilter, resFilters) if err != nil { @@ -372,6 +380,61 @@ func discoverJobs( return assetList, nil } +func discoverServices( + conn shared.Connection, + invConfig *inventory.Config, + clusterId string, + k8s *mqlK8s, + od *PlatformIdOwnershipIndex, + nsFilter NamespaceFilterOpts, + resFilter *ResourceFilters, +) ([]*inventory.Asset, error) { + cjs := k8s.GetServices() + if cjs.Error != nil { + return nil, cjs.Error + } + + // If there is a resources filter we should only retrieve the workloads that are in the filter. + if !resFilter.IsEmpty() && resFilter.IsEmptyForType("service") { + return []*inventory.Asset{}, nil + } + + assetList := make([]*inventory.Asset, 0, len(cjs.Data)) + for _, cj := range cjs.Data { + serv := cj.(*mqlK8sService) + + if skip := nsFilter.skipNamespace(serv.Namespace.Data); skip { + continue + } + + if !resFilter.IsEmpty() && !resFilter.Match("service", serv.Name.Data, serv.Namespace.Data) { + continue + } + + labels := map[string]string{} + for k, v := range serv.GetLabels().Data { + labels[k] = v.(string) + } + addMondooAssetLabels(labels, &serv.obj.ObjectMeta, clusterId) + platform, err := createPlatformData(serv.Kind.Data, conn.Runtime()) + if err != nil { + return nil, err + } + assetList = append(assetList, &inventory.Asset{ + PlatformIds: []string{ + shared.NewWorkloadPlatformId(clusterId, "service", serv.Namespace.Data, serv.Name.Data, serv.Uid.Data), + }, + Name: assetName(serv.Namespace.Data, serv.Name.Data), + Platform: platform, + Labels: labels, + Connections: []*inventory.Config{invConfig.Clone(inventory.WithoutDiscovery(), inventory.WithParentConnectionId(invConfig.Id))}, // pass-in the parent connection config + Category: conn.Asset().Category, + }) + od.Add(serv.obj) + } + return assetList, nil +} + func discoverCronJobs( conn shared.Connection, invConfig *inventory.Config, @@ -961,6 +1024,10 @@ func createPlatformData(objectKind, runtime string) (*inventory.Platform, error) platformData.Family = append(platformData.Family, "k8s-ingress") platformData.Name = "k8s-ingress" platformData.Title = "Kubernetes Ingress" + case "Service": + platformData.Family = append(platformData.Family, "k8s-service") + platformData.Name = "k8s-service" + platformData.Title = "Kubernetes Service" case "Namespace": platformData.Family = append(platformData.Family, "k8s-namespace") platformData.Name = "k8s-namespace"