From 052c042dac0b73a0fd66a79c2e8f0c2ab0c07017 Mon Sep 17 00:00:00 2001 From: rcohencyberarmor <84019060+rcohencyberarmor@users.noreply.github.com> Date: Sun, 22 Oct 2023 15:10:08 +0300 Subject: [PATCH] Support backend access key (#1404) Support backend access key Signed-off-by: Amir Malka --- cmd/config/set.go | 1 + cmd/download/download.go | 1 + cmd/list/list.go | 1 + cmd/rootutils.go | 3 +- core/cautils/customerloader.go | 235 +++++++++++------- core/cautils/getter/kscloudapi_test.go | 2 +- core/cautils/scaninfo.go | 1 + core/core/cachedconfig.go | 10 +- core/core/download.go | 10 +- core/core/initutils.go | 2 +- core/core/list.go | 6 +- core/core/scan.go | 2 +- core/meta/datastructures/v1/config.go | 1 + core/meta/datastructures/v1/download.go | 1 + core/meta/datastructures/v1/listpolicies.go | 1 + .../reporter/v2/reporteventreceiver.go | 44 ++-- .../reporter/v2/reporteventreceiver_test.go | 57 ++++- go.mod | 16 +- go.sum | 30 +-- httphandler/config/config.go | 29 +++ httphandler/config/credentials.go | 20 ++ httphandler/go.mod | 10 +- httphandler/go.sum | 15 +- .../v1/requestshandlerutil_test.go | 20 ++ .../handlerequests/v1/requestshandlerutils.go | 4 +- httphandler/main.go | 83 +++++-- 26 files changed, 413 insertions(+), 192 deletions(-) create mode 100644 httphandler/config/config.go create mode 100644 httphandler/config/credentials.go diff --git a/cmd/config/set.go b/cmd/config/set.go index 9662e943..b6692eaa 100644 --- a/cmd/config/set.go +++ b/cmd/config/set.go @@ -33,6 +33,7 @@ func getSetCmd(ks meta.IKubescape) *cobra.Command { } var supportConfigSet = map[string]func(*metav1.SetConfig, string){ + "accessKey": func(s *metav1.SetConfig, accessKey string) { s.AccessKey = accessKey }, "accountID": func(s *metav1.SetConfig, account string) { s.Account = account }, "cloudAPIURL": func(s *metav1.SetConfig, cloudAPIURL string) { s.CloudAPIURL = cloudAPIURL }, "cloudReportURL": func(s *metav1.SetConfig, cloudReportURL string) { s.CloudReportURL = cloudReportURL }, diff --git a/cmd/download/download.go b/cmd/download/download.go index 4ff92d1f..b037da05 100644 --- a/cmd/download/download.go +++ b/cmd/download/download.go @@ -84,6 +84,7 @@ func GetDownloadCmd(ks meta.IKubescape) *cobra.Command { } downloadCmd.PersistentFlags().StringVarP(&downloadInfo.AccountID, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache") + downloadCmd.PersistentFlags().StringVarP(&downloadInfo.AccessKey, "accessKey", "", "", "Kubescape SaaS access key. Default will load access key from cache") downloadCmd.PersistentFlags().MarkDeprecated("client-id", "Client ID is no longer supported. Feel free to contact the Kubescape maintainers for more information.") downloadCmd.PersistentFlags().MarkDeprecated("secret-key", "Secret Key is no longer supported. Feel free to contact the Kubescape maintainers for more information.") downloadCmd.Flags().StringVarP(&downloadInfo.Path, "output", "o", "", "Output file. If not specified, will save in `~/.kubescape/.json`") diff --git a/cmd/list/list.go b/cmd/list/list.go index 961f2193..4c390aa2 100644 --- a/cmd/list/list.go +++ b/cmd/list/list.go @@ -64,6 +64,7 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command { }, } listCmd.PersistentFlags().StringVarP(&listPolicies.AccountID, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache") + listCmd.PersistentFlags().StringVarP(&listPolicies.AccessKey, "accessKey", "", "", "Kubescape SaaS access key. Default will load access key from cache") listCmd.PersistentFlags().StringVar(&listPolicies.Format, "format", "pretty-print", "output format. supported: 'pretty-print'/'json'") listCmd.PersistentFlags().MarkDeprecated("id", "Control ID's are included in list outputs") diff --git a/cmd/rootutils.go b/cmd/rootutils.go index 8fe0fc35..fc823c52 100644 --- a/cmd/rootutils.go +++ b/cmd/rootutils.go @@ -83,7 +83,7 @@ func initEnvironment() { logger.L().Debug("configuring service discovery URLs", helpers.String("cloudAPIURL", services.GetApiServerUrl()), helpers.String("cloudReportURL", services.GetReportReceiverHttpUrl())) - tenant := cautils.GetTenantConfig("", "", "", nil) + tenant := cautils.GetTenantConfig("", "", "", "", nil) if services.GetApiServerUrl() != "" { tenant.GetConfigObj().CloudAPIURL = services.GetApiServerUrl() } @@ -99,6 +99,7 @@ func initEnvironment() { services.GetApiServerUrl(), services.GetReportReceiverHttpUrl(), "", + "", ) if err != nil { logger.L().Fatal("failed to create KS Cloud client", helpers.Error(err)) diff --git a/core/cautils/customerloader.go b/core/cautils/customerloader.go index 2243493b..7259401b 100644 --- a/core/cautils/customerloader.go +++ b/core/cautils/customerloader.go @@ -21,19 +21,21 @@ import ( ) const ( - configFileName string = "config" - kubescapeNamespace string = "kubescape" - kubescapeConfigMapName string = "kubescape-config" - kubescapeCloudConfigMapName string = "ks-cloud-config" + configFileName string = "config" + kubescapeNamespace string = "kubescape" + + kubescapeConfigMapName string = "kubescape-config" // deprecated - for backward compatibility + kubescapeCloudConfigMapName string = "ks-cloud-config" // deprecated - for backward compatibility + + cloudConfigMapLabelSelector string = "kubescape.io/infra=config" + credsLabelSelectors string = "kubescape.io/infra=credentials" //nolint:gosec // env vars - defaultConfigMapNameEnvVar string = "KS_DEFAULT_CONFIGMAP_NAME" - defaultCloudConfigMapNameEnvVar string = "KS_DEFAULT_CLOUD_CONFIGMAP_NAME" defaultConfigMapNamespaceEnvVar string = "KS_DEFAULT_CONFIGMAP_NAMESPACE" accountIdEnvVar string = "KS_ACCOUNT_ID" + accessKeyEnvVar string = "KS_ACCESS_KEY" cloudApiUrlEnvVar string = "KS_CLOUD_API_URL" cloudReportUrlEnvVar string = "KS_CLOUD_REPORT_URL" - storageEnabledEnvVar string = "KS_STORAGE_ENABLED" ) func ConfigFileFullPath() string { return getter.GetDefaultPath(configFileName + ".json") } @@ -47,7 +49,7 @@ type ConfigObj struct { ClusterName string `json:"clusterName,omitempty"` CloudReportURL string `json:"cloudReportURL,omitempty"` CloudAPIURL string `json:"cloudAPIURL,omitempty"` - StorageEnabled bool `json:"storageEnabled,omitempty"` + AccessKey string `json:"accessKey,omitempty"` } // Config - convert ConfigObj to config file @@ -92,15 +94,15 @@ type ITenantConfig interface { UpdateCachedConfig() error DeleteCachedConfig(ctx context.Context) error GenerateAccountID() (string, error) - DeleteAccountID() error + DeleteCredentials() error // getters GetContextName() string GetAccountID() string + GetAccessKey() string GetConfigObj() *ConfigObj GetCloudReportURL() string GetCloudAPIURL() string - IsStorageEnabled() bool } // ====================================================================================== @@ -114,7 +116,7 @@ type LocalConfig struct { configObj *ConfigObj } -func NewLocalConfig(accountID, clusterName string, customClusterName string) *LocalConfig { +func NewLocalConfig(accountID, accessKey, clusterName, customClusterName string) *LocalConfig { lc := &LocalConfig{ configObj: &ConfigObj{}, } @@ -123,9 +125,8 @@ func NewLocalConfig(accountID, clusterName string, customClusterName string) *Lo loadConfigFromFile(lc.configObj) } - updateAccountID(lc.configObj, accountID) + updateCredentials(lc.configObj, accountID, accessKey) updateCloudURLs(lc.configObj) - updateStorageEnabled(lc.configObj) // If a custom cluster name is provided then set that name, else use the cluster's original name if customClusterName != "" { @@ -145,7 +146,7 @@ func (lc *LocalConfig) GetAccountID() string { return lc.configObj.AccountI func (lc *LocalConfig) GetContextName() string { return lc.configObj.ClusterName } func (lc *LocalConfig) GetCloudReportURL() string { return lc.configObj.CloudReportURL } func (lc *LocalConfig) GetCloudAPIURL() string { return lc.configObj.CloudAPIURL } -func (lc *LocalConfig) IsStorageEnabled() bool { return lc.configObj.StorageEnabled } +func (lc *LocalConfig) GetAccessKey() string { return lc.configObj.AccessKey } func (lc *LocalConfig) GenerateAccountID() (string, error) { lc.configObj.AccountID = uuid.NewString() @@ -153,7 +154,8 @@ func (lc *LocalConfig) GenerateAccountID() (string, error) { return lc.configObj.AccountID, err } -func (lc *LocalConfig) DeleteAccountID() error { +func (lc *LocalConfig) DeleteCredentials() error { + lc.configObj.AccessKey = "" lc.configObj.AccountID = "" return lc.UpdateCachedConfig() } @@ -189,20 +191,16 @@ KS_CACHE // path to cached files var _ ITenantConfig = &ClusterConfig{} type ClusterConfig struct { - k8s *k8sinterface.KubernetesApi - configObj *ConfigObj - configMapNamespace string - ksConfigMapName string - ksCloudConfigMapName string + k8s *k8sinterface.KubernetesApi + configObj *ConfigObj + configMapNamespace string } -func NewClusterConfig(k8s *k8sinterface.KubernetesApi, accountID, clusterName string, customClusterName string) *ClusterConfig { +func NewClusterConfig(k8s *k8sinterface.KubernetesApi, accountID, accessKey, clusterName, customClusterName string) *ClusterConfig { c := &ClusterConfig{ - k8s: k8s, - configObj: &ConfigObj{}, - ksConfigMapName: getKubescapeConfigMapName(), - ksCloudConfigMapName: getKubescapeCloudConfigMapName(), - configMapNamespace: GetConfigMapNamespace(), + k8s: k8s, + configObj: &ConfigObj{}, + configMapNamespace: GetConfigMapNamespace(), } // first, load from file @@ -210,19 +208,14 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, accountID, clusterName st loadConfigFromFile(c.configObj) } - // second, load from configMap - if c.existsConfigMap(c.ksConfigMapName) { - c.updateConfigEmptyFieldsFromKubescapeConfigMap() - } + // second, load urls from config map + c.updateConfigEmptyFieldsFromKubescapeConfigMap() - // third, load urls from cloudConfigMap - if c.existsConfigMap(c.ksCloudConfigMapName) { - c.updateConfigEmptyFieldsFromKubescapeCloudConfigMap() - } + // third, credentials from secret + c.updateConfigEmptyFieldsFromCredentialsSecret() - updateAccountID(c.configObj, accountID) + updateCredentials(c.configObj, accountID, accessKey) updateCloudURLs(c.configObj) - updateStorageEnabled(c.configObj) // If a custom cluster name is provided then set that name, else use the cluster's original name if customClusterName != "" { @@ -246,7 +239,7 @@ func (c *ClusterConfig) GetDefaultNS() string { return c.configMapNamespace func (c *ClusterConfig) GetAccountID() string { return c.configObj.AccountID } func (c *ClusterConfig) GetCloudReportURL() string { return c.configObj.CloudReportURL } func (c *ClusterConfig) GetCloudAPIURL() string { return c.configObj.CloudAPIURL } -func (c *ClusterConfig) IsStorageEnabled() bool { return c.configObj.StorageEnabled } +func (c *ClusterConfig) GetAccessKey() string { return c.configObj.AccessKey } func (c *ClusterConfig) UpdateCachedConfig() error { logger.L().Debug("updating cached config", helpers.Interface("configObj", c.configObj)) @@ -272,42 +265,78 @@ func (c *ClusterConfig) ToMapString() map[string]interface{} { } func (c *ClusterConfig) updateConfigEmptyFieldsFromKubescapeConfigMap() error { - configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.ksConfigMapName, metav1.GetOptions{}) + configMaps, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: cloudConfigMapLabelSelector, + }) if err != nil { return err } - - tempCO := ConfigObj{} - if jsonConf, ok := configMap.Data["config.json"]; ok { - if err = json.Unmarshal([]byte(jsonConf), &tempCO); err != nil { - return err - } - return c.configObj.updateEmptyFields(&tempCO) + var ksConfigMap *corev1.ConfigMap + var urlsConfigMap *corev1.ConfigMap + if len(configMaps.Items) == 0 { + // try to find configmaps by name (for backward compatibility) + ksConfigMap, _ = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), kubescapeConfigMapName, metav1.GetOptions{}) + urlsConfigMap, _ = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), kubescapeCloudConfigMapName, metav1.GetOptions{}) + } else { + // use the first configmap with the label + ksConfigMap = &configMaps.Items[0] + urlsConfigMap = &configMaps.Items[0] } + + if ksConfigMap != nil { + if jsonConf, ok := ksConfigMap.Data["clusterData"]; ok { + tempCO := ConfigObj{} + if err = json.Unmarshal([]byte(jsonConf), &tempCO); err != nil { + return err + } + c.configObj.updateEmptyFields(&tempCO) + } + } + + if urlsConfigMap != nil { + if jsonConf, ok := urlsConfigMap.Data["services"]; ok { + services, err := servicediscovery.GetServices( + servicediscoveryv1.NewServiceDiscoveryStreamV1([]byte(jsonConf)), + ) + if err != nil { + return err + } + + if services.GetApiServerUrl() != "" { + c.configObj.CloudAPIURL = services.GetApiServerUrl() + } + if services.GetReportReceiverHttpUrl() != "" { + c.configObj.CloudReportURL = services.GetReportReceiverHttpUrl() + } + } + } + return err } -func (c *ClusterConfig) updateConfigEmptyFieldsFromKubescapeCloudConfigMap() error { - configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.ksCloudConfigMapName, metav1.GetOptions{}) +func (c *ClusterConfig) updateConfigEmptyFieldsFromCredentialsSecret() error { + secrets, err := c.k8s.KubernetesClient.CoreV1().Secrets(c.configMapNamespace).List(context.Background(), + metav1.ListOptions{LabelSelector: credsLabelSelectors}) if err != nil { return err } - if jsonConf, ok := configMap.Data["services"]; ok { - services, err := servicediscovery.GetServices( - servicediscoveryv1.NewServiceDiscoveryStreamV1([]byte(jsonConf)), - ) - if err != nil { - return err - } + if len(secrets.Items) == 0 { + return nil + } - if services.GetApiServerUrl() != "" { - c.configObj.CloudAPIURL = services.GetApiServerUrl() - } - if services.GetReportReceiverHttpUrl() != "" { - c.configObj.CloudReportURL = services.GetReportReceiverHttpUrl() + if jsonConf, ok := secrets.Items[0].Data["account"]; ok { + if account := string(jsonConf); account != "" { + c.configObj.AccountID = account } } + + if jsonConf, ok := secrets.Items[0].Data["accessKey"]; ok { + if accessKey := string(jsonConf); accessKey != "" { + c.configObj.AccessKey = accessKey + } + } + return nil } @@ -323,11 +352,6 @@ func loadConfigFromData(co *ConfigObj, data map[string]string) error { return e } -func (c *ClusterConfig) existsConfigMap(name string) bool { - _, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), name, metav1.GetOptions{}) - return err == nil -} - func existsConfigFile() bool { _, err := os.ReadFile(ConfigFileFullPath()) return err == nil @@ -349,8 +373,9 @@ func (c *ClusterConfig) GenerateAccountID() (string, error) { return c.configObj.AccountID, err } -func (c *ClusterConfig) DeleteAccountID() error { +func (c *ClusterConfig) DeleteCredentials() error { c.configObj.AccountID = "" + c.configObj.AccessKey = "" return c.UpdateCachedConfig() } @@ -396,21 +421,6 @@ func AdoptClusterName(clusterName string) string { return re.ReplaceAllString(clusterName, "-") } -func getKubescapeConfigMapName() string { - if n := os.Getenv(defaultConfigMapNameEnvVar); n != "" { - return n - } - return kubescapeConfigMapName -} - -func getKubescapeCloudConfigMapName() string { - if n := os.Getenv(defaultCloudConfigMapNameEnvVar); n != "" { - return n - } - - return kubescapeCloudConfigMapName -} - // GetConfigMapNamespace returns the namespace of the cluster config, which is the same for all in-cluster components func GetConfigMapNamespace() string { if n := os.Getenv(defaultConfigMapNamespaceEnvVar); n != "" { @@ -419,7 +429,15 @@ func GetConfigMapNamespace() string { return kubescapeNamespace } -func updateAccountID(configObj *ConfigObj, accountID string) { +func updateCredentials(configObj *ConfigObj, accountID, accessKey string) { + if accessKey != "" { + configObj.AccessKey = accessKey + } + + if envAccessKey := os.Getenv(accessKeyEnvVar); envAccessKey != "" { + configObj.AccessKey = envAccessKey + } + if accountID != "" { configObj.AccountID = accountID } @@ -429,10 +447,6 @@ func updateAccountID(configObj *ConfigObj, accountID string) { } } -func updateStorageEnabled(configObj *ConfigObj) { - configObj.StorageEnabled, _ = ParseBoolEnvVar(storageEnabledEnvVar, configObj.StorageEnabled) -} - func getCloudURLsFromEnv(cloudURLs *CloudURLs) { // load from env if cloudAPIURL := os.Getenv(cloudApiUrlEnvVar); cloudAPIURL != "" { @@ -460,18 +474,53 @@ func updateCloudURLs(configObj *ConfigObj) { } func initializeCloudAPI(c ITenantConfig) *v1.KSCloudAPI { - logger.L().Debug("initializing KS Cloud API from config", helpers.String("accountID", c.GetAccountID()), helpers.String("cloudAPIURL", c.GetCloudAPIURL()), helpers.String("cloudReportURL", c.GetCloudReportURL())) - cloud, err := v1.NewKSCloudAPI(c.GetCloudAPIURL(), c.GetCloudReportURL(), c.GetAccountID()) - if err != nil { - logger.L().Fatal("failed to create KS Cloud client", helpers.Error(err)) + if ksCloud := getter.GetKSCloudAPIConnector(); ksCloud != nil { + logger.L().Debug("KS Cloud API already initialized") + + if val := c.GetCloudAPIURL(); val != "" && val != ksCloud.GetCloudAPIURL() { + logger.L().Debug("updating KS Cloud API from config", helpers.String("old", ksCloud.GetCloudAPIURL()), helpers.String("new", val)) + ksCloud.SetCloudAPIURL(val) + } + if val := c.GetCloudReportURL(); val != "" && val != ksCloud.GetCloudReportURL() { + logger.L().Debug("updating KS Cloud Report from config", helpers.String("old", ksCloud.GetCloudReportURL()), helpers.String("new", val)) + ksCloud.SetCloudReportURL(val) + } + if val := c.GetAccountID(); val != "" && val != ksCloud.GetAccountID() { + logger.L().Debug("updating Account ID from config", helpers.String("old", ksCloud.GetAccountID()), helpers.String("new", val)) + ksCloud.SetAccountID(val) + } + if val := c.GetAccessKey(); val != "" && val != ksCloud.GetAccessKey() { + logger.L().Debug("updating Access Key from config", helpers.Int("old (len)", len(ksCloud.GetAccessKey())), helpers.Int("new (len)", len(val))) + ksCloud.SetAccessKey(val) + } + getter.SetKSCloudAPIConnector(ksCloud) + } else { + logger.L().Debug("initializing KS Cloud API from config", helpers.String("accountID", c.GetAccountID()), helpers.String("cloudAPIURL", c.GetCloudAPIURL()), helpers.String("cloudReportURL", c.GetCloudReportURL())) + cloud, err := v1.NewKSCloudAPI( + c.GetCloudAPIURL(), + c.GetCloudReportURL(), + c.GetAccountID(), + c.GetAccessKey()) + if err != nil { + logger.L().Fatal("failed to create KS Cloud client", helpers.Error(err)) + } + getter.SetKSCloudAPIConnector(cloud) } - getter.SetKSCloudAPIConnector(cloud) + return getter.GetKSCloudAPIConnector() } -func GetTenantConfig(accountID, clusterName, customClusterName string, k8s *k8sinterface.KubernetesApi) ITenantConfig { +func GetTenantConfig(accountID, accessKey, clusterName, customClusterName string, k8s *k8sinterface.KubernetesApi) ITenantConfig { if !k8sinterface.IsConnectedToCluster() || k8s == nil { - return NewLocalConfig(accountID, clusterName, customClusterName) + return NewLocalConfig(accountID, accessKey, clusterName, customClusterName) } - return NewClusterConfig(k8s, accountID, clusterName, customClusterName) + return NewClusterConfig(k8s, accountID, accessKey, clusterName, customClusterName) +} + +// firstNonEmpty returns the first non-empty string +func firstNonEmpty(s1, s2 string) string { + if s1 != "" { + return s1 + } + return s2 } diff --git a/core/cautils/getter/kscloudapi_test.go b/core/cautils/getter/kscloudapi_test.go index 1fdff370..978f734f 100644 --- a/core/cautils/getter/kscloudapi_test.go +++ b/core/cautils/getter/kscloudapi_test.go @@ -39,7 +39,7 @@ func TestGlobalKSCloudAPIConnector(t *testing.T) { }) t.Run("initialized global connector should yield the same pointer", func(t *testing.T) { - ksCloud, _ := v1.NewKSCloudAPI("test-123", "test-456", "account") + ksCloud, _ := v1.NewKSCloudAPI("test-123", "test-456", "account", "token") SetKSCloudAPIConnector(ksCloud) client := GetKSCloudAPIConnector() diff --git a/core/cautils/scaninfo.go b/core/cautils/scaninfo.go index 2326b51f..276aa95a 100644 --- a/core/cautils/scaninfo.go +++ b/core/cautils/scaninfo.go @@ -129,6 +129,7 @@ type ScanInfo struct { HostSensorYamlPath string // Path to hostsensor file Local bool // Do not submit results AccountID string // account ID + AccessKey string // access key FrameworkScan bool // false if scanning control ScanAll bool // true if scan all frameworks OmitRawResources bool // true if omit raw resources from the output diff --git a/core/core/cachedconfig.go b/core/core/cachedconfig.go index b1514eae..331dd828 100644 --- a/core/core/cachedconfig.go +++ b/core/core/cachedconfig.go @@ -9,11 +9,15 @@ import ( ) func (ks *Kubescape) SetCachedConfig(setConfig *metav1.SetConfig) error { - tenant := cautils.GetTenantConfig("", "", "", nil) + tenant := cautils.GetTenantConfig("", "", "", "", nil) if setConfig.Account != "" { tenant.GetConfigObj().AccountID = setConfig.Account } + if setConfig.AccessKey != "" { + tenant.GetConfigObj().AccessKey = setConfig.AccessKey + } + if setConfig.CloudAPIURL != "" { tenant.GetConfigObj().CloudAPIURL = setConfig.CloudAPIURL } @@ -26,13 +30,13 @@ func (ks *Kubescape) SetCachedConfig(setConfig *metav1.SetConfig) error { // View cached configurations func (ks *Kubescape) ViewCachedConfig(viewConfig *metav1.ViewConfig) error { - tenant := cautils.GetTenantConfig("", "", "", getKubernetesApi()) // change k8sinterface + tenant := cautils.GetTenantConfig("", "", "", "", getKubernetesApi()) // change k8sinterface fmt.Fprintf(viewConfig.Writer, "%s\n", tenant.GetConfigObj().Config()) return nil } func (ks *Kubescape) DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error { - tenant := cautils.GetTenantConfig("", "", "", nil) // change k8sinterface + tenant := cautils.GetTenantConfig("", "", "", "", nil) // change k8sinterface return tenant.DeleteCachedConfig(ctx) } diff --git a/core/core/download.go b/core/core/download.go index 7319d63e..e89052d5 100644 --- a/core/core/download.go +++ b/core/core/download.go @@ -92,7 +92,7 @@ func downloadArtifacts(ctx context.Context, downloadInfo *metav1.DownloadInfo) e } func downloadConfigInputs(ctx context.Context, downloadInfo *metav1.DownloadInfo) error { - tenant := cautils.GetTenantConfig(downloadInfo.AccountID, "", "", getKubernetesApi()) + tenant := cautils.GetTenantConfig(downloadInfo.AccountID, downloadInfo.AccessKey, "", "", getKubernetesApi()) controlsInputsGetter := getConfigInputsGetter(ctx, downloadInfo.Identifier, tenant.GetAccountID(), nil) controlInputs, err := controlsInputsGetter.GetControlsInputs(tenant.GetContextName()) @@ -115,7 +115,7 @@ func downloadConfigInputs(ctx context.Context, downloadInfo *metav1.DownloadInfo } func downloadExceptions(ctx context.Context, downloadInfo *metav1.DownloadInfo) error { - tenant := cautils.GetTenantConfig(downloadInfo.AccountID, "", "", getKubernetesApi()) + tenant := cautils.GetTenantConfig(downloadInfo.AccountID, downloadInfo.AccessKey, "", "", getKubernetesApi()) exceptionsGetter := getExceptionsGetter(ctx, "", tenant.GetAccountID(), nil) exceptions, err := exceptionsGetter.GetExceptions(tenant.GetContextName()) @@ -137,7 +137,7 @@ func downloadExceptions(ctx context.Context, downloadInfo *metav1.DownloadInfo) func downloadAttackTracks(ctx context.Context, downloadInfo *metav1.DownloadInfo) error { var err error - tenant := cautils.GetTenantConfig(downloadInfo.AccountID, "", "", getKubernetesApi()) + tenant := cautils.GetTenantConfig(downloadInfo.AccountID, downloadInfo.AccessKey, "", "", getKubernetesApi()) attackTracksGetter := getAttackTracksGetter(ctx, "", tenant.GetAccountID(), nil) @@ -161,7 +161,7 @@ func downloadAttackTracks(ctx context.Context, downloadInfo *metav1.DownloadInfo func downloadFramework(ctx context.Context, downloadInfo *metav1.DownloadInfo) error { - tenant := cautils.GetTenantConfig(downloadInfo.AccountID, "", "", getKubernetesApi()) + tenant := cautils.GetTenantConfig(downloadInfo.AccountID, downloadInfo.AccessKey, "", "", getKubernetesApi()) g := getPolicyGetter(ctx, nil, tenant.GetAccountID(), true, nil) @@ -203,7 +203,7 @@ func downloadFramework(ctx context.Context, downloadInfo *metav1.DownloadInfo) e func downloadControl(ctx context.Context, downloadInfo *metav1.DownloadInfo) error { - tenant := cautils.GetTenantConfig(downloadInfo.AccountID, "", "", getKubernetesApi()) + tenant := cautils.GetTenantConfig(downloadInfo.AccountID, downloadInfo.AccessKey, "", "", getKubernetesApi()) g := getPolicyGetter(ctx, nil, tenant.GetAccountID(), false, nil) diff --git a/core/core/initutils.go b/core/core/initutils.go index b8d7b124..5c1247f5 100644 --- a/core/core/initutils.go +++ b/core/core/initutils.go @@ -68,7 +68,7 @@ func getReporter(ctx context.Context, tenantConfig cautils.ITenantConfig, report if scanInfo.GetScanningContext() != cautils.ContextCluster { submitData = reporterv2.SubmitContextRepository } - return reporterv2.NewReportEventReceiver(tenantConfig, reportID, submitData) + return reporterv2.NewReportEventReceiver(tenantConfig, reportID, submitData, getter.GetKSCloudAPIConnector()) } if tenantConfig.GetAccountID() == "" { // Add link only when scanning a cluster using a framework diff --git a/core/core/list.go b/core/core/list.go index b9f61449..1e2ab2bb 100644 --- a/core/core/list.go +++ b/core/core/list.go @@ -54,14 +54,14 @@ func (ks *Kubescape) List(ctx context.Context, listPolicies *metav1.ListPolicies } func listFrameworks(ctx context.Context, listPolicies *metav1.ListPolicies) ([]string, error) { - tenant := cautils.GetTenantConfig(listPolicies.AccountID, "", "", getKubernetesApi()) // change k8sinterface + tenant := cautils.GetTenantConfig(listPolicies.AccountID, listPolicies.AccessKey, "", "", getKubernetesApi()) // change k8sinterface policyGetter := getPolicyGetter(ctx, nil, tenant.GetAccountID(), true, nil) return listFrameworksNames(policyGetter), nil } func listControls(ctx context.Context, listPolicies *metav1.ListPolicies) ([]string, error) { - tenant := cautils.GetTenantConfig(listPolicies.AccountID, "", "", getKubernetesApi()) // change k8sinterface + tenant := cautils.GetTenantConfig(listPolicies.AccountID, listPolicies.AccessKey, "", "", getKubernetesApi()) // change k8sinterface policyGetter := getPolicyGetter(ctx, nil, tenant.GetAccountID(), false, nil) return policyGetter.ListControls() @@ -69,7 +69,7 @@ func listControls(ctx context.Context, listPolicies *metav1.ListPolicies) ([]str func listExceptions(ctx context.Context, listPolicies *metav1.ListPolicies) ([]string, error) { // load tenant metav1 - tenant := cautils.GetTenantConfig(listPolicies.AccountID, "", "", getKubernetesApi()) + tenant := cautils.GetTenantConfig(listPolicies.AccountID, listPolicies.AccessKey, "", "", getKubernetesApi()) var exceptionsNames []string ksCloudAPI := getExceptionsGetter(ctx, "", tenant.GetAccountID(), nil) diff --git a/core/core/scan.go b/core/core/scan.go index 220610ea..29584e52 100644 --- a/core/core/scan.go +++ b/core/core/scan.go @@ -49,7 +49,7 @@ func getInterfaces(ctx context.Context, scanInfo *cautils.ScanInfo) componentInt } // ================== setup tenant object ====================================== - tenantConfig := cautils.GetTenantConfig(scanInfo.AccountID, k8sinterface.GetContextName(), scanInfo.CustomClusterName, k8s) + tenantConfig := cautils.GetTenantConfig(scanInfo.AccountID, scanInfo.AccessKey, k8sinterface.GetContextName(), scanInfo.CustomClusterName, k8s) // Set submit behavior AFTER loading tenant config setSubmitBehavior(scanInfo, tenantConfig) diff --git a/core/meta/datastructures/v1/config.go b/core/meta/datastructures/v1/config.go index 0eeaaed7..771222a5 100644 --- a/core/meta/datastructures/v1/config.go +++ b/core/meta/datastructures/v1/config.go @@ -4,6 +4,7 @@ import "io" type SetConfig struct { Account string + AccessKey string CloudReportURL string CloudAPIURL string } diff --git a/core/meta/datastructures/v1/download.go b/core/meta/datastructures/v1/download.go index a4680756..901577ac 100644 --- a/core/meta/datastructures/v1/download.go +++ b/core/meta/datastructures/v1/download.go @@ -6,4 +6,5 @@ type DownloadInfo struct { Target string // type of artifact to download Identifier string // identifier of artifact to download AccountID string + AccessKey string } diff --git a/core/meta/datastructures/v1/listpolicies.go b/core/meta/datastructures/v1/listpolicies.go index 79b3471f..862044c1 100644 --- a/core/meta/datastructures/v1/listpolicies.go +++ b/core/meta/datastructures/v1/listpolicies.go @@ -4,6 +4,7 @@ type ListPolicies struct { Target string Format string AccountID string + AccessKey string } type ListResponse struct { diff --git a/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go b/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go index a17ebbff..7ac63884 100644 --- a/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go +++ b/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go @@ -4,8 +4,6 @@ import ( "context" "encoding/json" "fmt" - "net/http" - "net/url" "os" "strings" "time" @@ -39,18 +37,17 @@ var _ reporter.IReport = &ReportEventReceiver{} type ReportEventReceiver struct { reportTime time.Time - httpClient *http.Client + client *client.KSCloudAPI tenantConfig cautils.ITenantConfig - eventReceiverURL *url.URL message string reportID string submitContext SubmitContext accountIdGenerated bool } -func NewReportEventReceiver(tenantConfig cautils.ITenantConfig, reportID string, submitContext SubmitContext) *ReportEventReceiver { +func NewReportEventReceiver(tenantConfig cautils.ITenantConfig, reportID string, submitContext SubmitContext, client *client.KSCloudAPI) *ReportEventReceiver { return &ReportEventReceiver{ - httpClient: &http.Client{}, + client: client, tenantConfig: tenantConfig, reportID: reportID, submitContext: submitContext, @@ -69,6 +66,8 @@ func (report *ReportEventReceiver) Submit(ctx context.Context, opaSessionObj *ca return err } report.accountIdGenerated = true + report.client.SetAccountID(accountID) + getter.SetKSCloudAPIConnector(report.client) logger.L().Debug("generated account ID", helpers.String("account ID", accountID)) } @@ -78,7 +77,7 @@ func (report *ReportEventReceiver) Submit(ctx context.Context, opaSessionObj *ca } if err := report.prepareReport(opaSessionObj); err != nil { - return fmt.Errorf("failed to submit scan results. url: '%s', reason: %s", report.eventReceiverURL, err.Error()) + return fmt.Errorf("failed to submit scan results. url: '%s', reason: %s", report.getReportUrl(), err.Error()) } logger.L().Debug("", helpers.String("account ID", report.GetAccountID())) @@ -113,18 +112,20 @@ func (report *ReportEventReceiver) prepareReport(opaSessionObj *cautils.OPASessi }() } - var err error - report.eventReceiverURL, err = client.GetPostureReportUrl(getter.GetKSCloudAPIConnector().GetCloudReportURL(), report.GetAccountID(), report.GetClusterName(), report.reportID) - if err != nil { - return err - } - cautils.StartSpinner() defer cautils.StopSpinner() return report.sendResources(opaSessionObj) } +func (report *ReportEventReceiver) getReportUrl() string { + url, err := client.GetPostureReportUrl(report.client.GetCloudReportURL(), report.GetAccountID(), report.GetClusterName(), report.reportID) + if err != nil { + return "" + } + return url.String() +} + func (report *ReportEventReceiver) sendResources(opaSessionObj *cautils.OPASessionObj) error { splittedPostureReport := report.setSubReport(opaSessionObj) @@ -234,19 +235,22 @@ func (report *ReportEventReceiver) sendReport(postureReport *reporthandlingv2.Po ReportNumber: counter, IsLastReport: isLastReport, } - reqBody, err := json.Marshal(postureReport) - if err != nil { - return fmt.Errorf("in 'sendReport' failed to json.Marshal, reason: %v", err) - } - strResponse, err := getter.HttpPost(report.httpClient, report.eventReceiverURL.String(), nil, reqBody) + logger.L().Debug("sending report", + helpers.String("url", report.getReportUrl()), + helpers.String("account", report.client.GetAccountID()), + helpers.Int("accessKey length", len(report.client.GetAccessKey())), + helpers.Int("reportNumber", counter), + ) + + strResponse, err := report.client.SubmitReport(postureReport) if err != nil { // in case of error, we need to revert the generated account ID // otherwise the next run will fail using a non existing account ID if report.accountIdGenerated { - report.tenantConfig.DeleteAccountID() + report.tenantConfig.DeleteCredentials() } - return fmt.Errorf("%s, %v:%s", report.eventReceiverURL.String(), err, strResponse) + return fmt.Errorf("%s, %v:%s", report.getReportUrl(), err, strResponse) } // message is taken only from last report diff --git a/core/pkg/resultshandling/reporter/v2/reporteventreceiver_test.go b/core/pkg/resultshandling/reporter/v2/reporteventreceiver_test.go index 2e30684a..abcd8426 100644 --- a/core/pkg/resultshandling/reporter/v2/reporteventreceiver_test.go +++ b/core/pkg/resultshandling/reporter/v2/reporteventreceiver_test.go @@ -8,9 +8,11 @@ import ( "sync" "testing" + v1 "github.com/kubescape/backend/pkg/client/v1" logger "github.com/kubescape/go-logger" "github.com/kubescape/go-logger/prettylogger" "github.com/kubescape/kubescape/v2/core/cautils" + "github.com/kubescape/kubescape/v2/core/cautils/getter" reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,6 +24,7 @@ var mxStdio sync.Mutex type TenantConfigMock struct { clusterName string accountID string + accessKey string } const testGeneratedAccountIDString = "6a1ff233-5297-4193-bb51-5d67bc841cbf" @@ -59,11 +62,16 @@ func (tcm *TenantConfigMock) GenerateAccountID() (string, error) { return testGeneratedAccountIDString, nil } -func (tcm *TenantConfigMock) DeleteAccountID() error { +func (tcm *TenantConfigMock) DeleteCredentials() error { tcm.accountID = "" + tcm.accessKey = "" return nil } +func (tcm *TenantConfigMock) GetAccessKey() string { + return tcm.accessKey +} + func TestDisplayMessage(t *testing.T) { t.Parallel() @@ -77,6 +85,7 @@ func TestDisplayMessage(t *testing.T) { }, "", SubmitContextScan, + getter.GetKSCloudAPIConnector(), ) capture, clean := captureStderr(t) @@ -101,6 +110,7 @@ func TestDisplayMessage(t *testing.T) { }, "", SubmitContextScan, + getter.GetKSCloudAPIConnector(), ) reporter.setMessage("message returned from server") @@ -142,6 +152,7 @@ func TestPrepareReport(t *testing.T) { }, "", SubmitContextScan, + getter.GetKSCloudAPIConnector(), ) for _, tc := range testCases { @@ -171,25 +182,44 @@ func TestSubmit(t *testing.T) { srv := mockAPIServer(t) t.Cleanup(srv.Close) + const account = "1e3ae7c4-a8bb-4d7c-9bdf-eb86bc25e6bb" + const accessKey = "ef871116-b4c9-4dbc-9abb-f422f025429f" + t.Run("should submit simple report", func(t *testing.T) { + ksCloud, err := v1.NewKSCloudAPI( + srv.Root(), + srv.Root(), + account, + accessKey, + v1.WithHTTPClient(hijackedClient(t, srv))) // re-route the http client to our mock server, as this is not easily configurable in the reporter. + require.NoError(t, err) + reporter := NewReportEventReceiver( &TenantConfigMock{ clusterName: "test", - accountID: "1e3ae7c4-a8bb-4d7c-9bdf-eb86bc25e6bb", + accountID: account, + accessKey: accessKey, }, "cbabd56f-bac6-416a-836b-b815ef347647", SubmitContextScan, + ksCloud, ) opaSession := mockOPASessionObj(t) - reporter.httpClient = hijackedClient(t, srv) // re-route the http client to our mock server, as this is not easily configurable in the reporter. - require.NoError(t, reporter.Submit(ctx, opaSession), ) }) - t.Run("should generate new customerGUID when no customerGUID", func(t *testing.T) { + t.Run("should generate new account if account is empty", func(t *testing.T) { + ksCloud, err := v1.NewKSCloudAPI( + srv.Root(), + srv.Root(), + "", + "", + v1.WithHTTPClient(hijackedClient(t, srv))) // re-route the http client to our mock server, as this is not easily configurable in the reporter. + require.NoError(t, err) + reporter := NewReportEventReceiver( &TenantConfigMock{ clusterName: "test", @@ -197,10 +227,10 @@ func TestSubmit(t *testing.T) { }, "cbabd56f-bac6-416a-836b-b815ef347647", SubmitContextScan, + ksCloud, ) opaSession := mockOPASessionObj(t) - reporter.httpClient = hijackedClient(t, srv) capture, clean := captureStderr(t) if pretty, ok := logger.L().(*prettylogger.PrettyLogger); ok { @@ -222,20 +252,28 @@ func TestSubmit(t *testing.T) { }) t.Run("should warn when no cluster name", func(t *testing.T) { + ksCloud, err := v1.NewKSCloudAPI( + srv.Root(), + srv.Root(), + account, + accessKey, + v1.WithHTTPClient(hijackedClient(t, srv))) // re-route the http client to our mock server, as this is not easily configurable in the reporter. + require.NoError(t, err) + reporter := NewReportEventReceiver( &TenantConfigMock{ clusterName: "", - accountID: "1e3ae7c4-a8bb-4d7c-9bdf-eb86bc25e6bb", + accountID: account, + accessKey: accessKey, }, "cbabd56f-bac6-416a-836b-b815ef347647", SubmitContextScan, + ksCloud, ) opaSession := mockOPASessionObj(t) opaSession.Metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Cluster - reporter.httpClient = hijackedClient(t, srv) - capture, clean := captureStderr(t) if pretty, ok := logger.L().(*prettylogger.PrettyLogger); ok { pretty.SetWriter(capture) @@ -275,6 +313,7 @@ func TestSetters(t *testing.T) { }, "cbabd56f-bac6-416a-836b-b815ef347647", SubmitContextScan, + getter.GetKSCloudAPIConnector(), ) t.Run("should set tenantConfig", func(t *testing.T) { diff --git a/go.mod b/go.mod index 9c08ab4a..0248d31f 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/anchore/stereoscope v0.0.0-20230727211946-d1f3d766295e github.com/anchore/syft v0.86.1 github.com/armosec/armoapi-go v0.0.256 - github.com/armosec/utils-go v0.0.20 - github.com/armosec/utils-k8s-go v0.0.17 + github.com/armosec/utils-go v0.0.40 + github.com/armosec/utils-k8s-go v0.0.18 github.com/briandowns/spinner v1.23.0 github.com/distribution/distribution v2.8.3+incompatible github.com/docker/distribution v2.8.2+incompatible @@ -17,11 +17,11 @@ require ( github.com/francoispqt/gojay v1.2.13 github.com/go-git/go-git/v5 v5.8.1 github.com/google/go-containerregistry v0.16.1 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/johnfercher/maroto v0.42.0 github.com/json-iterator/go v1.1.12 github.com/jwalton/gchalk v1.3.0 - github.com/kubescape/backend v0.0.2 + github.com/kubescape/backend v0.0.11 github.com/kubescape/go-git-url v0.0.25 github.com/kubescape/go-logger v0.0.21 github.com/kubescape/k8s-interface v0.0.142 @@ -224,7 +224,7 @@ require ( github.com/go-restruct/restruct v1.2.0-alpha // indirect github.com/go-test/deep v1.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/goccy/go-json v0.9.11 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-yaml v1.9.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -366,7 +366,7 @@ require ( github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect - github.com/ulikunitz/xz v0.5.10 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.2.2 // indirect github.com/uptrace/opentelemetry-go-extra/otelzap v0.2.2 // indirect github.com/uptrace/uptrace-go v1.18.0 // indirect @@ -404,8 +404,8 @@ require ( go.step.sm/crypto v0.32.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.13.0 // indirect diff --git a/go.sum b/go.sum index e4640563..0a213413 100644 --- a/go.sum +++ b/go.sum @@ -611,10 +611,10 @@ github.com/armosec/armoapi-go v0.0.256 h1:eV8WWQ1r+2D0KHhLA6ux6lx67+uqkYe/uVHrOU github.com/armosec/armoapi-go v0.0.256/go.mod h1:CJT5iH5VF30zjdQYXaQhsAm8IEHtM1T87HcFVXeLX54= github.com/armosec/gojay v1.2.15 h1:sSB2vnAvacUNkw9nzUYZKcPzhJOyk6/5LK2JCNdmoZY= github.com/armosec/gojay v1.2.15/go.mod h1:vzVAaay2TWJAngOpxu8aqLbye9jMgoKleuAOK+xsOts= -github.com/armosec/utils-go v0.0.20 h1:bvr+TMumEYdMsGFGSsaQysST7K02nNROFvuajNuKPlw= -github.com/armosec/utils-go v0.0.20/go.mod h1:ZEFiSv8KpTFNT19jHis1IengiF/BGDvg7tHmXo+cwxs= -github.com/armosec/utils-k8s-go v0.0.17 h1:HUntJGR0/PHt7bp8S0zLhVcJ6sDz061Hc9mAM9ha1lA= -github.com/armosec/utils-k8s-go v0.0.17/go.mod h1:FJRG/MRz7jT4ExSEYHIFsilVsAF11M+GJRhLl4PFZ4s= +github.com/armosec/utils-go v0.0.40 h1:FdH8TxRG0SH3heKLrZ0Mj0eq5dNgk5go8/mteSCg2wY= +github.com/armosec/utils-go v0.0.40/go.mod h1:pDaq3SNKQ8wliAAOq4B8re9MWmT0bX9di2Jn1jZI7lE= +github.com/armosec/utils-k8s-go v0.0.18 h1:SBmj+j/5JrROVQVLjlHsoMcPZKK/AKWEK1SMMf3hd1U= +github.com/armosec/utils-k8s-go v0.0.18/go.mod h1:FJRG/MRz7jT4ExSEYHIFsilVsAF11M+GJRhLl4PFZ4s= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -1021,8 +1021,8 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -1148,8 +1148,9 @@ github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= @@ -1352,8 +1353,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubescape/backend v0.0.2 h1:s/aQ5/U9lLXBcVTuGz9vxGtD/koem6eojRTA3lRiyYo= -github.com/kubescape/backend v0.0.2/go.mod h1:rEkxLNQdOGQNKAZekZBn0z/r8FIymBRSmwLFqkUenAQ= +github.com/kubescape/backend v0.0.11 h1:M8AgIBUkAkSgx20604GW/uvnzQNhG7JxPyyIJQtJu1w= +github.com/kubescape/backend v0.0.11/go.mod h1:ug9NFmmxT4DcQx3sgdLRzlLPWMKGHE/fpbcYUm5G5Qo= github.com/kubescape/go-git-url v0.0.25 h1:i7SSSC1+1m/Dg+4LV3erp0YklnWj1Z0cVlRxCT3Zy/0= github.com/kubescape/go-git-url v0.0.25/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM= github.com/kubescape/go-logger v0.0.21 h1:4ZRIEw3UGUH6BG/cH3yiqFipzQSfGAoCrxlsZuk37ys= @@ -1807,8 +1808,9 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/uptrace/opentelemetry-go-extra/otelutil v0.2.2 h1:CNznWHkrbA6o1q2H/BsH4tIHf4zbKNtndeoV+AH8z0U= github.com/uptrace/opentelemetry-go-extra/otelutil v0.2.2/go.mod h1:7YSrHCmYPHIXjTWnKSU7EGT0TFEcm3WwSeQquwCGg38= github.com/uptrace/opentelemetry-go-extra/otelzap v0.2.2 h1:uyrW06oJi4iWvhjPLVfk4qrSP2Zm0AMozKKDmp6i4pE= @@ -1980,8 +1982,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2107,8 +2109,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= diff --git a/httphandler/config/config.go b/httphandler/config/config.go new file mode 100644 index 00000000..37df0794 --- /dev/null +++ b/httphandler/config/config.go @@ -0,0 +1,29 @@ +package config + +import ( + "github.com/spf13/viper" +) + +type Config struct { + Namespace string `mapstructure:"namespace"` + ClusterName string `mapstructure:"clusterName"` + ContinuousPostureScan bool `mapstructure:"continuousPostureScan"` +} + +// LoadConfig reads configuration from file or environment variables. +func LoadConfig(path string) (Config, error) { + viper.AddConfigPath(path) + viper.SetConfigName("clusterData") + viper.SetConfigType("json") + + viper.AutomaticEnv() + + err := viper.ReadInConfig() + if err != nil { + return Config{}, err + } + + var config Config + err = viper.Unmarshal(&config) + return config, err +} diff --git a/httphandler/config/credentials.go b/httphandler/config/credentials.go new file mode 100644 index 00000000..584921e6 --- /dev/null +++ b/httphandler/config/credentials.go @@ -0,0 +1,20 @@ +package config + +var accessKey string +var account string + +func SetAccessKey(key string) { + accessKey = key +} + +func GetAccessKey() string { + return accessKey +} + +func SetAccount(accountId string) { + account = accountId +} + +func GetAccount() string { + return account +} diff --git a/httphandler/go.mod b/httphandler/go.mod index 14ea12aa..ee3d2527 100644 --- a/httphandler/go.mod +++ b/httphandler/go.mod @@ -6,17 +6,18 @@ replace github.com/kubescape/kubescape/v2 => ../ require ( github.com/armosec/armoapi-go v0.0.256 - github.com/armosec/utils-go v0.0.20 + github.com/armosec/utils-go v0.0.40 github.com/go-openapi/runtime v0.26.0 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/schema v1.2.0 - github.com/kubescape/backend v0.0.2 + github.com/kubescape/backend v0.0.11 github.com/kubescape/go-logger v0.0.21 github.com/kubescape/k8s-interface v0.0.144 github.com/kubescape/kubescape/v2 v2.0.0-00010101000000-000000000000 github.com/kubescape/opa-utils v0.0.270 github.com/kubescape/storage v0.0.20 + github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0 go.opentelemetry.io/otel v1.19.0 @@ -111,7 +112,7 @@ require ( github.com/aquasecurity/trivy v0.44.1 // indirect github.com/aquasecurity/trivy-db v0.0.0-20230726112157-167ba4f2faeb // indirect github.com/armosec/gojay v1.2.15 // indirect - github.com/armosec/utils-k8s-go v0.0.17 // indirect + github.com/armosec/utils-k8s-go v0.0.18 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.44.312 // indirect github.com/aws/aws-sdk-go-v2 v1.20.0 // indirect @@ -358,7 +359,6 @@ require ( github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.16.0 // indirect github.com/spiffe/go-spiffe/v2 v2.1.6 // indirect github.com/stripe/stripe-go/v74 v74.28.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect diff --git a/httphandler/go.sum b/httphandler/go.sum index 869c06c6..4c1a47c1 100644 --- a/httphandler/go.sum +++ b/httphandler/go.sum @@ -611,10 +611,10 @@ github.com/armosec/armoapi-go v0.0.256 h1:eV8WWQ1r+2D0KHhLA6ux6lx67+uqkYe/uVHrOU github.com/armosec/armoapi-go v0.0.256/go.mod h1:CJT5iH5VF30zjdQYXaQhsAm8IEHtM1T87HcFVXeLX54= github.com/armosec/gojay v1.2.15 h1:sSB2vnAvacUNkw9nzUYZKcPzhJOyk6/5LK2JCNdmoZY= github.com/armosec/gojay v1.2.15/go.mod h1:vzVAaay2TWJAngOpxu8aqLbye9jMgoKleuAOK+xsOts= -github.com/armosec/utils-go v0.0.20 h1:bvr+TMumEYdMsGFGSsaQysST7K02nNROFvuajNuKPlw= -github.com/armosec/utils-go v0.0.20/go.mod h1:ZEFiSv8KpTFNT19jHis1IengiF/BGDvg7tHmXo+cwxs= -github.com/armosec/utils-k8s-go v0.0.17 h1:HUntJGR0/PHt7bp8S0zLhVcJ6sDz061Hc9mAM9ha1lA= -github.com/armosec/utils-k8s-go v0.0.17/go.mod h1:FJRG/MRz7jT4ExSEYHIFsilVsAF11M+GJRhLl4PFZ4s= +github.com/armosec/utils-go v0.0.40 h1:FdH8TxRG0SH3heKLrZ0Mj0eq5dNgk5go8/mteSCg2wY= +github.com/armosec/utils-go v0.0.40/go.mod h1:pDaq3SNKQ8wliAAOq4B8re9MWmT0bX9di2Jn1jZI7lE= +github.com/armosec/utils-k8s-go v0.0.18 h1:SBmj+j/5JrROVQVLjlHsoMcPZKK/AKWEK1SMMf3hd1U= +github.com/armosec/utils-k8s-go v0.0.18/go.mod h1:FJRG/MRz7jT4ExSEYHIFsilVsAF11M+GJRhLl4PFZ4s= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -1149,8 +1149,9 @@ github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= @@ -1355,8 +1356,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubescape/backend v0.0.2 h1:s/aQ5/U9lLXBcVTuGz9vxGtD/koem6eojRTA3lRiyYo= -github.com/kubescape/backend v0.0.2/go.mod h1:rEkxLNQdOGQNKAZekZBn0z/r8FIymBRSmwLFqkUenAQ= +github.com/kubescape/backend v0.0.11 h1:M8AgIBUkAkSgx20604GW/uvnzQNhG7JxPyyIJQtJu1w= +github.com/kubescape/backend v0.0.11/go.mod h1:ug9NFmmxT4DcQx3sgdLRzlLPWMKGHE/fpbcYUm5G5Qo= github.com/kubescape/go-git-url v0.0.25 h1:i7SSSC1+1m/Dg+4LV3erp0YklnWj1Z0cVlRxCT3Zy/0= github.com/kubescape/go-git-url v0.0.25/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM= github.com/kubescape/go-logger v0.0.21 h1:4ZRIEw3UGUH6BG/cH3yiqFipzQSfGAoCrxlsZuk37ys= diff --git a/httphandler/handlerequests/v1/requestshandlerutil_test.go b/httphandler/handlerequests/v1/requestshandlerutil_test.go index cdc419ed..a0ba92d1 100644 --- a/httphandler/handlerequests/v1/requestshandlerutil_test.go +++ b/httphandler/handlerequests/v1/requestshandlerutil_test.go @@ -3,6 +3,7 @@ package v1 import ( "testing" + "github.com/kubescape/kubescape/v2/httphandler/config" apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1" utilsmetav1 "github.com/kubescape/opa-utils/httpserver/meta/v1" "github.com/stretchr/testify/assert" @@ -14,6 +15,7 @@ func TestDefaultScanInfo(t *testing.T) { assert.Equal(t, "", s.AccountID) assert.Equal(t, "v2", s.FormatVersion) assert.Equal(t, "json", s.Format) + assert.Equal(t, "", s.AccessKey) assert.False(t, s.HostSensorEnabled.GetBool()) assert.False(t, s.Local) assert.False(t, s.Submit) @@ -28,6 +30,24 @@ func TestGetScanCommand(t *testing.T) { assert.Equal(t, "abc", s.ScanID) assert.Equal(t, "v2", s.FormatVersion) assert.Equal(t, "json", s.Format) + assert.Equal(t, "", s.AccessKey) + assert.False(t, s.HostSensorEnabled.GetBool()) + assert.False(t, s.Local) + assert.False(t, s.Submit) +} + +func TestGetScanCommandWithAccessKey(t *testing.T) { + config.SetAccessKey("test-123") + + req := utilsmetav1.PostScanRequest{ + TargetType: apisv1.KindFramework, + } + s := getScanCommand(&req, "abc") + assert.Equal(t, "", s.AccountID) + assert.Equal(t, "abc", s.ScanID) + assert.Equal(t, "v2", s.FormatVersion) + assert.Equal(t, "json", s.Format) + assert.Equal(t, "test-123", s.AccessKey) assert.False(t, s.HostSensorEnabled.GetBool()) assert.False(t, s.Local) assert.False(t, s.Submit) diff --git a/httphandler/handlerequests/v1/requestshandlerutils.go b/httphandler/handlerequests/v1/requestshandlerutils.go index f957e681..752e801e 100644 --- a/httphandler/handlerequests/v1/requestshandlerutils.go +++ b/httphandler/handlerequests/v1/requestshandlerutils.go @@ -14,6 +14,7 @@ import ( "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/cautils/getter" "github.com/kubescape/kubescape/v2/core/core" + "github.com/kubescape/kubescape/v2/httphandler/config" "github.com/kubescape/kubescape/v2/httphandler/storage" utilsapisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1" utilsmetav1 "github.com/kubescape/opa-utils/httpserver/meta/v1" @@ -168,7 +169,8 @@ func defaultScanInfo() *cautils.ScanInfo { scanInfo := &cautils.ScanInfo{} scanInfo.FailThreshold = 100 scanInfo.ComplianceThreshold = 0 - scanInfo.AccountID = envToString("KS_ACCOUNT", "") // publish results to Kubescape SaaS + scanInfo.AccountID = envToString("KS_ACCOUNT_ID", config.GetAccount()) // publish results to Kubescape SaaS + scanInfo.AccessKey = envToString("KS_ACCESS_KEY", config.GetAccessKey()) // publish results to Kubescape SaaS scanInfo.ExcludedNamespaces = envToString("KS_EXCLUDE_NAMESPACES", "") // namespaces to exclude scanInfo.IncludeNamespaces = envToString("KS_INCLUDE_NAMESPACES", "") // namespaces to include scanInfo.HostSensorYamlPath = envToString("KS_HOST_SCAN_YAML", "") // path to host scan YAML diff --git a/httphandler/main.go b/httphandler/main.go index 204b8837..717bb34f 100644 --- a/httphandler/main.go +++ b/httphandler/main.go @@ -5,20 +5,21 @@ import ( "net/url" "os" + v1 "github.com/kubescape/backend/pkg/client/v1" + "github.com/kubescape/backend/pkg/servicediscovery" + servicediscoveryv1 "github.com/kubescape/backend/pkg/servicediscovery/v1" + "github.com/kubescape/backend/pkg/utils" logger "github.com/kubescape/go-logger" + "github.com/kubescape/go-logger/helpers" + "github.com/kubescape/go-logger/zaplogger" "github.com/kubescape/k8s-interface/k8sinterface" "github.com/kubescape/kubescape/v2/core/cautils" + "github.com/kubescape/kubescape/v2/core/cautils/getter" + "github.com/kubescape/kubescape/v2/httphandler/config" _ "github.com/kubescape/kubescape/v2/httphandler/docs" "github.com/kubescape/kubescape/v2/httphandler/listener" "github.com/kubescape/kubescape/v2/httphandler/storage" "k8s.io/client-go/rest" - - v1 "github.com/kubescape/backend/pkg/client/v1" - "github.com/kubescape/backend/pkg/servicediscovery" - servicediscoveryv1 "github.com/kubescape/backend/pkg/servicediscovery/v1" - "github.com/kubescape/go-logger/helpers" - "github.com/kubescape/go-logger/zaplogger" - "github.com/kubescape/kubescape/v2/core/cautils/getter" ) const ( @@ -27,12 +28,22 @@ const ( func main() { ctx := context.Background() + + cfg, err := config.LoadConfig("/etc/config") + if err != nil { + logger.L().Ctx(ctx).Error("load config error", helpers.Error(err)) + } + + loadAndSetCredentials() + + clusterName := getClusterName(cfg) + // to enable otel, set OTEL_COLLECTOR_SVC=otel-collector:4317 if otelHost, present := os.LookupEnv("OTEL_COLLECTOR_SVC"); present { ctx = logger.InitOtel("kubescape", os.Getenv(cautils.BuildNumber), - os.Getenv("ACCOUNT_ID"), - os.Getenv("CLUSTER_NAME"), + config.GetAccount(), + clusterName, url.URL{Host: otelHost}) defer logger.ShutdownOtel(ctx) } @@ -43,21 +54,19 @@ func main() { initializeLoggerName() initializeLoggerLevel() initializeSaaSEnv() - initializeStorage() - + initializeStorage(cfg) // traces will be created by otelmux.Middleware in SetupHTTPListener() logger.L().Ctx(ctx).Fatal(listener.SetupHTTPListener().Error()) } -func initializeStorage() { - if !cautils.GetTenantConfig("", "", "", nil).IsStorageEnabled() { - logger.L().Debug("storage disabled - skipping initialization") +func initializeStorage(cfg config.Config) { + if !cfg.ContinuousPostureScan { + logger.L().Debug("continuous posture scan - skipping storage initialization") return } - - namespace := getNamespace() - logger.L().Debug("storage enabled", helpers.String("namespace", namespace)) + namespace := getNamespace(cfg) + logger.L().Debug("initializing storage", helpers.String("namespace", namespace)) // for local storage, use the k8s config var config *rest.Config @@ -119,17 +128,51 @@ func initializeSaaSEnv() { return } - if ksCloud, err := v1.NewKSCloudAPI(backendServices.GetReportReceiverHttpUrl(), backendServices.GetApiServerUrl(), ""); err != nil { + if ksCloud, err := v1.NewKSCloudAPI(backendServices.GetReportReceiverHttpUrl(), backendServices.GetApiServerUrl(), config.GetAccount(), config.GetAccessKey()); err != nil { logger.L().Fatal("failed to initialize cloud api", helpers.Error(err)) } else { getter.SetKSCloudAPIConnector(ksCloud) } - } -func getNamespace() string { +func getClusterName(cfg config.Config) string { + if clusterName, ok := os.LookupEnv("CLUSTER_NAME"); ok { + return clusterName + } + return cfg.ClusterName +} + +func getNamespace(cfg config.Config) string { if ns, ok := os.LookupEnv("NAMESPACE"); ok { return ns } + if cfg.Namespace != "" { + return cfg.Namespace + } + return defaultNamespace } + +func loadAndSetCredentials() { + credentialsPath := "/etc/credentials" + if envVar := os.Getenv("KS_CREDENTIALS_SECRET_PATH"); envVar != "" { + credentialsPath = envVar + } + + credentials, err := utils.LoadCredentialsFromFile(credentialsPath) + if err != nil { + logger.L().Error("failed to load credentials", helpers.Error(err)) + // fallback (backward compatibility) + config.SetAccount(os.Getenv("ACCOUNT_ID")) + + return + } + + logger.L().Info("credentials loaded from path", + helpers.String("path", credentialsPath), + helpers.Int("accessKeyLength", len(credentials.AccessKey)), + helpers.Int("accountLength", len(credentials.Account))) + + config.SetAccessKey(credentials.AccessKey) + config.SetAccount(credentials.Account) +}