Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions providers/k8s/resources/applications.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package resources

import (
"slices"
"sort"

"go.mondoo.com/cnquery/v11/llx"
"go.mondoo.com/cnquery/v11/providers-sdk/v1/util/convert"
"go.mondoo.com/cnquery/v11/types"
)

const (
// https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
K8sApplicationName = "app.kubernetes.io/name"
K8sApplicationInstance = "app.kubernetes.io/instance"
K8sApplicationVersion = "app.kubernetes.io/version"
K8sApplicationComponent = "app.kubernetes.io/component"
K8sApplicationPartOf = "app.kubernetes.io/part-of"
K8sApplicationManagedBy = "app.kubernetes.io/managed-by"
)

func (k *mqlK8s) apps() ([]interface{}, error) {
apps := map[string]k8sapp{}

// fetch deployment resources
deployments := k.GetDeployments()
if deployments.Error != nil {
return nil, deployments.Error
}

for i := range deployments.Data {
d := deployments.Data[i].(*mqlK8sDeployment)
labels := d.GetLabels().Data
extractApp(apps, labels)
}

// fetch daemonset resources
daemonsets := k.GetDaemonsets()
if daemonsets.Error != nil {
return nil, daemonsets.Error
}

for i := range daemonsets.Data {
d := daemonsets.Data[i].(*mqlK8sDaemonset)
labels := d.GetLabels().Data
extractApp(apps, labels)
}

// return k8s app list
appList := []interface{}{}
for _, app := range apps {
r, err := CreateResource(k.MqlRuntime, "k8s.app", map[string]*llx.RawData{
"__id": llx.StringData(app.name + "/" + app.instance),
"name": llx.StringData(app.name),
"version": llx.StringData(app.version),
"instance": llx.StringData(app.instance),
"managedBy": llx.StringData(app.managedBy),
"partOf": llx.StringData(app.partOf),
"components": llx.ArrayData(convert.SliceAnyToInterface(app.components), types.String),
})
if err != nil {
return nil, err
}

appList = append(appList, r)
}

return appList, nil
}

type k8sapp struct {
name string
version string
instance string
components []string
partOf string
managedBy string
}

func extractApp(apps map[string]k8sapp, labels map[string]interface{}) {
name, nameOk := labels[K8sApplicationName]
instance, instanceOK := labels[K8sApplicationInstance]
version, versionOK := labels[K8sApplicationVersion]
component, componentOK := labels[K8sApplicationComponent]
partOf, partOfOK := labels[K8sApplicationPartOf]
managedBy, managedByOK := labels[K8sApplicationManagedBy]

if !nameOk {
// if the name is not set, we cannot create an app
return
}

app := k8sapp{
name: name.(string),
}
if instanceOK {
app.instance = instance.(string)
}
if versionOK {
app.version = version.(string)
}
if componentOK {
app.components = []string{component.(string)}
}
if partOfOK {
app.partOf = partOf.(string)
}
if managedByOK {
app.managedBy = managedBy.(string)
}

key := app.name + app.instance
if existing, ok := apps[key]; ok {
// if the app already exists, we need to merge the components
components := append(existing.components, app.components...)
sort.Strings(components)
components = slices.Compact(components)
existing.components = components
apps[app.name+app.instance] = existing
} else {
apps[app.name+app.instance] = app
}
}
19 changes: 19 additions & 0 deletions providers/k8s/resources/k8s.lr
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ k8s {
customresources() []k8s.customresource
// Kubernetes admission webhook configurations
validatingWebhookConfigurations() []k8s.admission.validatingwebhookconfiguration
// Kubernetes applications
apps() []k8s.app
}

// Kubernetes API resources
Expand Down Expand Up @@ -865,6 +867,7 @@ private k8s.userinfo @defaults("username") {
uid string
}

// Kubernetes Validating Webhook Configuration
private k8s.admission.validatingwebhookconfiguration @defaults("name") {
// Mondoo ID for the Kubernetes object
id string
Expand All @@ -886,4 +889,20 @@ private k8s.admission.validatingwebhookconfiguration @defaults("name") {
manifest() dict
// Webhooks configuration
webhooks() []dict
}

// Kubernetes Application
private k8s.app {
// Application name
name string
// Application version
version string
// Application instance
instance string
// Managed by
managedBy string
// Name of the higher-level application
partOf string
// Components
components []string
}
143 changes: 143 additions & 0 deletions providers/k8s/resources/k8s.lr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions providers/k8s/resources/k8s.lr.manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ resources:
k8s:
fields:
apiResources: {}
apps:
min_mondoo_version: 9.0.0
clusterrolebindings:
min_mondoo_version: 5.31.0
clusterroles:
Expand Down Expand Up @@ -120,6 +122,19 @@ resources:
platform:
name:
- kubernetes
k8s.app:
fields:
components: {}
instance: {}
managedBy: {}
name: {}
partOf: {}
version: {}
is_private: true
min_mondoo_version: 9.0.0
platform:
name:
- kubernetes
k8s.configmap:
fields:
annotations: {}
Expand Down
Loading