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
6 changes: 5 additions & 1 deletion controllers/container_image/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,16 @@ func Inventory(integrationMRN, clusterUID string, m v1alpha2.MondooAuditConfig,
}
}

// Add user-defined annotations to all assets
// Add user-defined annotations first, then operator-managed annotations.
// Operator annotations go last so they cannot be overwritten by user values.
if len(m.Spec.Annotations) > 0 {
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(m.Spec.Annotations)
}
}
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(constants.AuditConfigAnnotations(m.Name, m.Namespace))
}

invBytes, err := yaml.Marshal(inv)
if err != nil {
Expand Down
14 changes: 12 additions & 2 deletions controllers/k8s_scan/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,12 +995,16 @@ func Inventory(integrationMRN, clusterUID string, m v1alpha2.MondooAuditConfig,
}
}

// Add user-defined annotations to all assets
// Add user-defined annotations first, then operator-managed annotations.
// Operator annotations go last so they cannot be overwritten by user values.
if len(m.Spec.Annotations) > 0 {
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(m.Spec.Annotations)
}
}
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(constants.AuditConfigAnnotations(m.Name, m.Namespace))
}

invBytes, err := yaml.Marshal(inv)
if err != nil {
Expand Down Expand Up @@ -1065,12 +1069,18 @@ func ExternalClusterInventory(integrationMRN, operatorClusterUID string, cluster
}
}

// Add user-defined annotations to all assets
// Add user-defined annotations first, then operator-managed annotations.
// Operator annotations go last so they cannot be overwritten by user values.
if len(m.Spec.Annotations) > 0 {
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(m.Spec.Annotations)
}
}
operatorAnnotations := constants.AuditConfigAnnotations(m.Name, m.Namespace)
operatorAnnotations[constants.MondooClusterNameAnnotation] = cluster.Name
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(operatorAnnotations)
}

invBytes, err := yaml.Marshal(inv)
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion controllers/nodes/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,12 +401,16 @@ func Inventory(integrationMRN, clusterUID string, m v1alpha2.MondooAuditConfig)
}
}

// Add user-defined annotations to all assets
// Add user-defined annotations first, then operator-managed annotations.
// Operator annotations go last so they cannot be overwritten by user values.
if len(m.Spec.Annotations) > 0 {
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(m.Spec.Annotations)
}
}
for i := range inv.Spec.Assets {
inv.Spec.Assets[i].AddAnnotations(constants.AuditConfigAnnotations(m.Name, m.Namespace))
}

invBytes, err := yaml.Marshal(inv)
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,19 @@ const (
// MondooAssetsIntegrationLabel is the label we set for any assets whenever the consoleIntegration is enabled
// (for consistency with other integrations, the integration tag will not use the 'k8s' prefix)
MondooAssetsIntegrationLabel = "mondoo.com/" + "integration-mrn"

// Operator-managed asset annotations propagated to all discovered assets for routing.
MondooAuditConfigAnnotation = "mondoo.com/audit-config/name"
MondooAuditConfigNamespaceAnnotation = "mondoo.com/audit-config/namespace"
MondooClusterNameAnnotation = "mondoo.com/audit-config/cluster-name"
)

// AuditConfigAnnotations returns operator-managed annotations identifying the
// MondooAuditConfig that owns the scan. These are propagated to all discovered
// assets so that server-side routing rules can match on them.
func AuditConfigAnnotations(name, namespace string) map[string]string {
return map[string]string{
MondooAuditConfigAnnotation: name,
MondooAuditConfigNamespaceAnnotation: namespace,
}
}
8 changes: 8 additions & 0 deletions pkg/utils/mondoo/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ func GarbageCollectAssets(
req.SpaceMrn = SpaceMrnFromServiceAccountMrn(sa.Mrn)
}
}

// Org-level service accounts without spaceId have no determinable space for GC.
// This happens when asset routing is used (server-side routing, no operator-side space).
if req.SpaceMrn == "" {
logger.Info("Skipping garbage collection: no space MRN determinable (org-level SA without spaceId)")
return nil
Comment thread
mondoo-code-review[bot] marked this conversation as resolved.
}

logger.Info("Preparing GarbageCollectAssets request", "spaceMrn", req.SpaceMrn, "managedBy", req.ManagedBy)

opts := mondooclient.MondooClientOptions{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright Mondoo, Inc. 2026
# SPDX-License-Identifier: BUSL-1.1

# MondooAuditConfig for scanning the LOCAL cluster (Autopilot — no nodes).
# No spaceId — server-side asset routing rules determine destination spaces.
apiVersion: k8s.mondoo.com/v1alpha2
kind: MondooAuditConfig
metadata:
name: mondoo-scanner
namespace: ${NAMESPACE}
spec:
mondooCredsSecretRef:
name: mondoo-client
filtering:
namespaces:
exclude:
- kube-system
- gke-managed-system
- gke-managed-cim
kubernetesResources:
enable: true
schedule: "*/5 * * * *"
containers:
enable: true
schedule: "*/5 * * * *"
nodes:
enable: false
---
# MondooAuditConfig for scanning the REMOTE (target) cluster.
# No spaceId — server-side asset routing rules determine destination spaces.
# enable: false prevents local cluster scanning; externalClusters reconciles independently.
apiVersion: k8s.mondoo.com/v1alpha2
kind: MondooAuditConfig
metadata:
name: mondoo-target
namespace: ${NAMESPACE}
spec:
mondooCredsSecretRef:
name: mondoo-client
filtering:
namespaces:
exclude:
- kube-system
- gke-managed-system
- gke-managed-cim
kubernetesResources:
enable: false
schedule: "*/5 * * * *"
externalClusters:
- name: target-cluster
kubeconfigSecretRef:
name: target-kubeconfig
containers:
enable: false
nodes:
enable: false
58 changes: 58 additions & 0 deletions tests/e2e/gke/manifests/mondoo-audit-config-asset-routing.yaml.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright Mondoo, Inc. 2026
# SPDX-License-Identifier: BUSL-1.1

# MondooAuditConfig for scanning the LOCAL cluster.
# No spaceId — server-side asset routing rules determine destination spaces.
apiVersion: k8s.mondoo.com/v1alpha2
kind: MondooAuditConfig
metadata:
name: mondoo-scanner
namespace: ${NAMESPACE}
spec:
mondooCredsSecretRef:
name: mondoo-client
filtering:
namespaces:
exclude:
- kube-system
- gke-managed-system
- gke-managed-cim
kubernetesResources:
enable: true
schedule: "*/5 * * * *"
containers:
enable: true
schedule: "*/5 * * * *"
nodes:
enable: true
style: cronjob
schedule: "*/5 * * * *"
---
# MondooAuditConfig for scanning the REMOTE (target) cluster.
# No spaceId — server-side asset routing rules determine destination spaces.
# enable: false prevents local cluster scanning; externalClusters reconciles independently.
apiVersion: k8s.mondoo.com/v1alpha2
kind: MondooAuditConfig
metadata:
name: mondoo-target
namespace: ${NAMESPACE}
spec:
mondooCredsSecretRef:
name: mondoo-client
filtering:
namespaces:
exclude:
- kube-system
- gke-managed-system
- gke-managed-cim
kubernetesResources:
enable: false
schedule: "*/5 * * * *"
externalClusters:
- name: target-cluster
kubeconfigSecretRef:
name: target-kubeconfig
containers:
enable: false
nodes:
enable: false
48 changes: 46 additions & 2 deletions tests/e2e/gke/terraform/mondoo.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,59 @@ resource "mondoo_service_account" "e2e" {
################################################################################

resource "mondoo_space" "target" {
count = var.enable_space_splitting_test ? 1 : 0
count = (var.enable_space_splitting_test || var.enable_asset_routing_test) ? 1 : 0
name = "e2e-target-${local.name_prefix}"
org_id = var.mondoo_org_id
}

resource "mondoo_service_account" "org" {
count = var.enable_space_splitting_test ? 1 : 0
count = (var.enable_space_splitting_test || var.enable_asset_routing_test) ? 1 : 0
name = "e2e-org-sa"
description = "Org-level service account for space splitting e2e test"
roles = ["//iam.api.mondoo.app/roles/agent"]
org_id = var.mondoo_org_id
}

################################################################################
# Asset Routing Test: developers space + routing table
################################################################################

resource "mondoo_space" "developers" {
count = var.enable_asset_routing_test ? 1 : 0
name = "e2e-developers-${local.name_prefix}"
org_id = var.mondoo_org_id
}

resource "mondoo_asset_routing_table" "e2e" {
count = var.enable_asset_routing_test ? 1 : 0
org_mrn = "//captain.api.mondoo.app/organizations/${var.mondoo_org_id}"

# Priority 1: k8s workload label app=nginx-developers → developers space
rule {
target_space_mrn = mondoo_space.developers[0].mrn
condition {
field = "LABEL"
key = "app"
operator = "EQUAL"
values = ["nginx-developers"]
}
}

# Priority 2: external cluster annotation (set by operator) → target space
rule {
target_space_mrn = mondoo_space.target[0].mrn
condition {
field = "LABEL"
key = "mondoo.com/audit-config/cluster-name"
operator = "EQUAL"
values = ["target-cluster"]
}
}

# Catch-all → default e2e space
rule {
target_space_mrn = mondoo_space.e2e.mrn
}

depends_on = [mondoo_space.developers, mondoo_space.target, mondoo_space.e2e]
}
14 changes: 11 additions & 3 deletions tests/e2e/gke/terraform/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,22 @@ output "scanner_space_id" {
}

output "target_space_id" {
value = var.enable_space_splitting_test ? mondoo_space.target[0].id : ""
value = (var.enable_space_splitting_test || var.enable_asset_routing_test) ? mondoo_space.target[0].id : ""
}

output "target_space_mrn" {
value = var.enable_space_splitting_test ? mondoo_space.target[0].mrn : ""
value = (var.enable_space_splitting_test || var.enable_asset_routing_test) ? mondoo_space.target[0].mrn : ""
}

output "org_credentials_b64" {
value = var.enable_space_splitting_test ? mondoo_service_account.org[0].credential : ""
value = (var.enable_space_splitting_test || var.enable_asset_routing_test) ? mondoo_service_account.org[0].credential : ""
sensitive = true
}

output "enable_asset_routing_test" {
value = var.enable_asset_routing_test
}

output "developers_space_id" {
value = var.enable_asset_routing_test ? mondoo_space.developers[0].id : ""
}
19 changes: 16 additions & 3 deletions tests/e2e/gke/terraform/terraform.example.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,22 @@

project_id = "your-gcp-project-id"
mondoo_org_id = "your-mondoo-organization-id"
region = "europe-west3"
autopilot = true

# Set to true to provision a mirror AR repo for registry mirroring/imagePullSecrets tests
# Create a second GKE cluster as a scan target for external cluster testing
enable_target_cluster = false

# Create a mirror AR repo for registry mirroring/imagePullSecrets tests
enable_mirror_test = false
# Set to true to also provision a Squid proxy VM for proxy tests (requires enable_mirror_test)
enable_proxy_test = false
# Provision a Squid proxy VM for proxy tests (requires enable_mirror_test)
enable_proxy_test = false

# Enable GKE Workload Identity Federation for external cluster scanning
enable_wif_test = false

# Test org-level SA with spaceId routing (requires enable_target_cluster)
enable_space_splitting_test = false

# Test server-side asset routing rules (requires enable_target_cluster)
enable_asset_routing_test = false
6 changes: 6 additions & 0 deletions tests/e2e/gke/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@ variable "enable_space_splitting_test" {
type = bool
default = false
}

variable "enable_asset_routing_test" {
description = "Create spaces and routing rules for server-side asset routing tests"
type = bool
default = false
}
25 changes: 25 additions & 0 deletions tests/e2e/manifests/nginx-developers-workload.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright Mondoo, Inc. 2026
# SPDX-License-Identifier: BUSL-1.1

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-developers
namespace: developers
labels:
app: nginx-developers
spec:
replicas: 1
selector:
matchLabels:
app: nginx-developers
template:
metadata:
labels:
app: nginx-developers
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
Loading
Loading