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
10 changes: 7 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ func main() {
// Create clients
logger.L().Info("Kubernetes mode is true")
k8sClient := k8sinterface.NewKubernetesApi()

// Fetch cluster UID from kube-system namespace
clusterUID := utils.GetClusterUID(k8sClient.GetKubernetesClient())

storageClient, err := storage.CreateStorage(clusterData.Namespace)
if err != nil {
logger.L().Ctx(ctx).Fatal("error creating the storage client", helpers.Error(err))
Expand Down Expand Up @@ -282,7 +286,7 @@ func main() {

if cfg.EnableRuntimeDetection {
// create exporter
exporter := exporters.InitExporters(cfg.Exporters, clusterData.ClusterName, cfg.NodeName, cloudMetadata)
exporter := exporters.InitExporters(cfg.Exporters, clusterData.ClusterName, cfg.NodeName, cloudMetadata, clusterUID)
dWatcher.AddAdaptor(ruleBindingCache)

ruleBindingNotify = make(chan rulebinding.RuleBindingNotify, 100)
Expand Down Expand Up @@ -348,7 +352,7 @@ func main() {
var malwareManager malwaremanager.MalwareManagerClient
if cfg.EnableMalwareDetection {
// create exporter
exporter := exporters.InitExporters(cfg.Exporters, clusterData.ClusterName, cfg.NodeName, cloudMetadata)
exporter := exporters.InitExporters(cfg.Exporters, clusterData.ClusterName, cfg.NodeName, cloudMetadata, clusterUID)
malwareManager, err = malwaremanagerv1.CreateMalwareManager(cfg, k8sClient, cfg.NodeName, clusterData.ClusterName, exporter, prometheusExporter, k8sObjectCache)
if err != nil {
logger.L().Ctx(ctx).Fatal("error creating MalwareManager", helpers.Error(err))
Expand Down Expand Up @@ -385,7 +389,7 @@ func main() {
if cfg.EnableFIM {
// Initialize FIM-specific exporters
fimExportersConfig := cfg.FIM.GetFIMExportersConfig()
fimExporter := exporters.InitExporters(fimExportersConfig, clusterData.ClusterName, cfg.NodeName, cloudMetadata)
fimExporter := exporters.InitExporters(fimExportersConfig, clusterData.ClusterName, cfg.NodeName, cloudMetadata, clusterUID)

fimManager, err = fimmanager.NewFIMManager(cfg, clusterData.ClusterName, fimExporter, cloudMetadata)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/Masterminds/semver/v3 v3.4.0
github.com/anchore/syft v1.32.0
github.com/aquilax/truncate v1.0.0
github.com/armosec/armoapi-go v0.0.671
github.com/armosec/armoapi-go v0.0.672
github.com/armosec/utils-k8s-go v0.0.35
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cenkalti/backoff/v4 v4.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -761,8 +761,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/armosec/armoapi-go v0.0.671 h1:amHT4tTa1h/z4hf/F/DO5VkdrEtvckOpwwMos36LT3o=
github.com/armosec/armoapi-go v0.0.671/go.mod h1:9jAH0g8ZsryhiBDd/aNMX4+n10bGwTx/doWCyyjSxts=
github.com/armosec/armoapi-go v0.0.672 h1:Js3yvV3GnqYCw3Dyq5HHo9br1mCthgrVwHuWCzNX/2w=
github.com/armosec/armoapi-go v0.0.672/go.mod h1:9jAH0g8ZsryhiBDd/aNMX4+n10bGwTx/doWCyyjSxts=
github.com/armosec/gojay v1.2.17 h1:VSkLBQzD1c2V+FMtlGFKqWXNsdNvIKygTKJI9ysY8eM=
github.com/armosec/gojay v1.2.17/go.mod h1:vuvX3DlY0nbVrJ0qCklSS733AWMoQboq3cFyuQW9ybc=
github.com/armosec/utils-go v0.0.58 h1:g9RnRkxZAmzTfPe2ruMo2OXSYLwVSegQSkSavOfmaIE=
Expand Down
4 changes: 2 additions & 2 deletions pkg/exporters/exporters_bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type ExporterBus struct {
}

// InitExporters initializes all exporters.
func InitExporters(exportersConfig ExportersConfig, clusterName string, nodeName string, cloudMetadata *armotypes.CloudMetadata) *ExporterBus {
func InitExporters(exportersConfig ExportersConfig, clusterName string, nodeName string, cloudMetadata *armotypes.CloudMetadata, clusterUID string) *ExporterBus {
var exporters []Exporter
for _, url := range exportersConfig.AlertManagerExporterUrls {
alertMan := InitAlertManagerExporter(url)
Expand All @@ -56,7 +56,7 @@ func InitExporters(exportersConfig ExportersConfig, clusterName string, nodeName
}
}
if exportersConfig.HTTPExporterConfig != nil {
httpExporter, err := NewHTTPExporter(*exportersConfig.HTTPExporterConfig, clusterName, nodeName, cloudMetadata)
httpExporter, err := NewHTTPExporter(*exportersConfig.HTTPExporterConfig, clusterName, nodeName, cloudMetadata, clusterUID)
if err == nil {
exporters = append(exporters, httpExporter)
} else {
Expand Down
7 changes: 6 additions & 1 deletion pkg/exporters/http_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type HTTPExporter struct {
host string
nodeName string
clusterName string
clusterUID string
httpClient *http.Client
alertMetrics *alertMetrics
cloudMetadata *apitypes.CloudMetadata
Expand Down Expand Up @@ -94,7 +95,7 @@ type HTTPAlertsListSpec struct {
}

// NewHTTPExporter creates a new HTTPExporter instance
func NewHTTPExporter(config HTTPExporterConfig, clusterName, nodeName string, cloudMetadata *apitypes.CloudMetadata) (*HTTPExporter, error) {
func NewHTTPExporter(config HTTPExporterConfig, clusterName, nodeName string, cloudMetadata *apitypes.CloudMetadata, clusterUID string) (*HTTPExporter, error) {
if err := config.Validate(); err != nil {
return nil, fmt.Errorf("invalid config: %w", err)
}
Expand All @@ -103,6 +104,7 @@ func NewHTTPExporter(config HTTPExporterConfig, clusterName, nodeName string, cl
config: config,
nodeName: nodeName,
clusterName: clusterName,
clusterUID: clusterUID,
httpClient: &http.Client{
Timeout: time.Duration(config.TimeoutSeconds) * time.Second,
},
Expand Down Expand Up @@ -315,9 +317,11 @@ func (e *HTTPExporter) createRuleAlert(failedRule types.RuleFailure) apitypes.Ru
k8sDetails := failedRule.GetRuntimeAlertK8sDetails()
k8sDetails.NodeName = e.nodeName
k8sDetails.ClusterName = e.clusterName
k8sDetails.ClusterUID = e.clusterUID

httpDetails := failedRule.GetHttpRuleAlert()
httpDetails.SourcePodInfo.ClusterName = e.clusterName
httpDetails.SourcePodInfo.ClusterUID = e.clusterUID

return apitypes.RuntimeAlert{
Message: failedRule.GetRuleAlert().RuleDescription,
Expand All @@ -336,6 +340,7 @@ func (e *HTTPExporter) createMalwareAlert(result malwaremanager.MalwareResult) a
k8sDetails := result.GetRuntimeAlertK8sDetails()
k8sDetails.NodeName = e.nodeName
k8sDetails.ClusterName = e.clusterName
k8sDetails.ClusterUID = e.clusterUID

return apitypes.RuntimeAlert{
Message: fmt.Sprintf("Malware detected: %s", result.GetBasicRuntimeAlert().AlertName),
Expand Down
15 changes: 8 additions & 7 deletions pkg/exporters/http_exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestSendRuleAlert(t *testing.T) {
// Create an HTTPExporter with the mock server URL
exporter, err := NewHTTPExporter(HTTPExporterConfig{
URL: server.URL,
}, "", "", nil)
}, "", "", nil, "")
assert.NoError(t, err)

// Create a mock rule failure
Expand Down Expand Up @@ -93,7 +93,7 @@ func TestSendRuleAlertRateReached(t *testing.T) {
exporter, err := NewHTTPExporter(HTTPExporterConfig{
URL: server.URL,
MaxAlertsPerMinute: 1,
}, "", "", nil)
}, "", "", nil, "")
assert.NoError(t, err)

// Create a mock rule failure
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestSendMalwareAlertHTTPExporter(t *testing.T) {
// Create an HTTPExporter with the mock server URL
exporter, err := NewHTTPExporter(HTTPExporterConfig{
URL: server.URL,
}, "", "", nil)
}, "", "", nil, "")
assert.NoError(t, err)

// Create a mock malware description
Expand Down Expand Up @@ -213,20 +213,21 @@ func TestSendMalwareAlertHTTPExporter(t *testing.T) {

func TestValidateHTTPExporterConfig(t *testing.T) {
// Test case: URL is empty
_, err := NewHTTPExporter(HTTPExporterConfig{}, "", "", nil)
_, err := NewHTTPExporter(HTTPExporterConfig{}, "", "", nil, "")
assert.Error(t, err)

// Test case: URL is not empty
exp, err := NewHTTPExporter(HTTPExporterConfig{
URL: "http://localhost:9093",
}, "cluster", "node", nil)
}, "cluster", "node", nil, "test-cluster-uid")
assert.NoError(t, err)
assert.Equal(t, "POST", exp.config.Method)
assert.Equal(t, 5, exp.config.TimeoutSeconds)
assert.Equal(t, 100, exp.config.MaxAlertsPerMinute)
assert.Equal(t, []HTTPKeyValues{}, exp.config.Headers)
assert.Equal(t, "cluster", exp.clusterName)
assert.Equal(t, "node", exp.nodeName)
assert.Equal(t, "test-cluster-uid", exp.clusterUID)

// Test case: Method is PUT
exp, err = NewHTTPExporter(HTTPExporterConfig{
Expand All @@ -240,7 +241,7 @@ func TestValidateHTTPExporterConfig(t *testing.T) {
Value: "Bearer token",
},
},
}, "", "", nil)
}, "", "", nil, "")
assert.NoError(t, err)
assert.Equal(t, "PUT", exp.config.Method)
assert.Equal(t, 2, exp.config.TimeoutSeconds)
Expand All @@ -251,6 +252,6 @@ func TestValidateHTTPExporterConfig(t *testing.T) {
_, err = NewHTTPExporter(HTTPExporterConfig{
URL: "http://localhost:9093",
Method: "DELETE",
}, "", "", nil)
}, "", "", nil, "")
assert.Error(t, err)
}
27 changes: 27 additions & 0 deletions pkg/utils/clusteruid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package utils

import (
"context"
"time"

"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

// GetClusterUID retrieves the UID of the kube-system namespace to use as a stable cluster identifier.
// If the namespace cannot be accessed (e.g., due to RBAC restrictions), it returns an empty string and logs a warning.
func GetClusterUID(k8sClient kubernetes.Interface) string {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
namespace, err := k8sClient.CoreV1().Namespaces().Get(ctx, "kube-system", metav1.GetOptions{})
if err != nil {
logger.L().Ctx(ctx).Warning("failed to get kube-system namespace for ClusterUID", helpers.Error(err))
return ""
}

clusterUID := string(namespace.UID)
logger.L().Ctx(ctx).Info("successfully retrieved ClusterUID", helpers.String("clusterUID", clusterUID))
return clusterUID
}
Loading