From 36d98fbd6176b3d2f61def083854eb80602597d9 Mon Sep 17 00:00:00 2001 From: Oleg Sucharevich Date: Thu, 15 Dec 2022 16:07:26 +0200 Subject: [PATCH] feat: validate benchmark type --- beater/cloudbeat.go | 3 +- beater/validator.go | 2 +- config/benchmark.go | 29 +++++++++++++ config/config.go | 38 +++++++++++++---- config/config_test.go | 42 +++++++++++++++++++ launcher/launcher.go | 6 +++ resources/fetchersManager/factory.go | 2 +- resources/fetchersManager/factory_aws_test.go | 2 +- resources/providers/cluster_provider.go | 5 ++- resources/providers/cluster_provider_test.go | 9 ++-- scripts/common.sh | 7 ++-- 11 files changed, 122 insertions(+), 23 deletions(-) create mode 100644 config/benchmark.go diff --git a/beater/cloudbeat.go b/beater/cloudbeat.go index 622503ce34..f114776939 100644 --- a/beater/cloudbeat.go +++ b/beater/cloudbeat.go @@ -20,9 +20,10 @@ package beater import ( "context" "fmt" - "github.com/elastic/cloudbeat/resources/providers" "time" + "github.com/elastic/cloudbeat/resources/providers" + "github.com/elastic/cloudbeat/config" "github.com/elastic/cloudbeat/dataprovider" "github.com/elastic/cloudbeat/evaluator" diff --git a/beater/validator.go b/beater/validator.go index d2bcf0ed7a..955acdbd42 100644 --- a/beater/validator.go +++ b/beater/validator.go @@ -32,7 +32,7 @@ type validator struct{} func (v *validator) Validate(cfg *agentconfig.C) error { c, err := config.New(cfg) if err != nil { - return fmt.Errorf("could not parse reconfiguration %v, skipping with error: %v", cfg.FlattenedKeys(), err) + return fmt.Errorf("could not parse reconfiguration %v, skipping with error: %w", cfg.FlattenedKeys(), err) } if c.RuntimeCfg == nil { diff --git a/config/benchmark.go b/config/benchmark.go new file mode 100644 index 0000000000..b39c1bcc0a --- /dev/null +++ b/config/benchmark.go @@ -0,0 +1,29 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package config + +// https://github.com/elastic/integrations/tree/main/packages/cloud_security_posture/data_stream/findings/agent/stream +const ( + CIS_K8S = "cis_k8s" + CIS_EKS = "cis_eks" + CIS_AWS = "cis_aws" +) + +var SupportedCIS = []string{CIS_AWS, CIS_K8S, CIS_EKS} diff --git a/config/config.go b/config/config.go index 1068a6a73c..72ac206e62 100644 --- a/config/config.go +++ b/config/config.go @@ -22,11 +22,14 @@ package config import ( "context" - "github.com/elastic/elastic-agent-libs/logp" + "errors" + "fmt" "os" "path/filepath" "time" + "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/beats/v7/libbeat/processors" "github.com/elastic/beats/v7/x-pack/libbeat/common/aws" "github.com/elastic/elastic-agent-libs/config" @@ -38,11 +41,7 @@ const DefaultNamespace = "default" const ResultsDatastreamIndexPrefix = "logs-cloud_security_posture.findings" -const ( - InputTypeVanillaK8s = "cloudbeat/cis_k8s" - InputTypeEks = "cloudbeat/cis_eks" - InputTypeAws = "cloudbeat/cis_aws" -) +var ErrBenchmarkNotSupported = errors.New("benchmark is not supported") type Fetcher struct { Name string `config:"name"` // Name of the fetcher @@ -57,6 +56,7 @@ type Config struct { Period time.Duration `config:"period"` Processors processors.PluginConfig `config:"processors"` BundlePath string `config:"bundle_path"` + Benchmark *string `config:"config.v1.benchmark"` } type RuntimeConfig struct { @@ -79,8 +79,15 @@ func New(cfg *config.C) (*Config, error) { return nil, err } - if c.RuntimeCfg != nil && c.RuntimeCfg.ActivatedRules != nil && len(c.RuntimeCfg.ActivatedRules.CisEks) > 0 { - c.Type = InputTypeEks + if c.Benchmark != nil { + if !isSupportedBenchmark(*c.Benchmark) { + return c, ErrBenchmarkNotSupported + } + c.Type = buildConfigType(*c.Benchmark) + } else { + if c.RuntimeCfg != nil && c.RuntimeCfg.ActivatedRules != nil && len(c.RuntimeCfg.ActivatedRules.CisEks) > 0 { + c.Type = buildConfigType(CIS_EKS) + } } return c, nil } @@ -88,7 +95,7 @@ func New(cfg *config.C) (*Config, error) { func defaultConfig() (*Config, error) { ret := &Config{ Period: 4 * time.Hour, - Type: InputTypeVanillaK8s, + Type: buildConfigType(CIS_K8S), } bundle, err := getBundlePath() @@ -120,3 +127,16 @@ func Datastream(namespace string, indexPrefix string) string { type AwsConfigProvider interface { InitializeAWSConfig(ctx context.Context, cfg aws.ConfigAWS, log *logp.Logger) (awssdk.Config, error) } + +func isSupportedBenchmark(benchmark string) bool { + for _, s := range SupportedCIS { + if benchmark == s { + return true + } + } + return false +} + +func buildConfigType(benchmark string) string { + return fmt.Sprintf("cloudbeat/%s", benchmark) +} diff --git a/config/config_test.go b/config/config_test.go index 79b794ffb8..4fe289fdb4 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -170,6 +170,48 @@ not_runtime_cfg: } } +func (s *ConfigTestSuite) TestBenchmarkType() { + tests := []struct { + config string + expected string + wantError bool + }{ + { + ` +config: + v1: + benchmark: cis_eks +`, + "cis_eks", + false, + }, + { + ` +config: + v1: + benchmark: cis_gcp +`, + "", + true, + }, + } + + for i, test := range tests { + s.Run(fmt.Sprint(i), func() { + cfg, err := config.NewConfigFrom(test.config) + s.NoError(err) + + c, err := New(cfg) + if test.wantError { + s.Error(err) + return + } + s.NoError(err) + s.Equal(test.expected, *c.Benchmark) + }) + } +} + func (s *ConfigTestSuite) TestRuntimeConfig() { tests := []struct { config string diff --git a/launcher/launcher.go b/launcher/launcher.go index b8ba86691c..9c3a67a0c8 100644 --- a/launcher/launcher.go +++ b/launcher/launcher.go @@ -21,11 +21,14 @@ package launcher import ( + "errors" "fmt" "sync" "time" "github.com/elastic/beats/v7/libbeat/beat" + "github.com/elastic/beats/v7/libbeat/management" + cloudbeat_config "github.com/elastic/cloudbeat/config" "github.com/elastic/elastic-agent-libs/config" "github.com/elastic/elastic-agent-libs/logp" "github.com/elastic/go-ucfg" @@ -239,6 +242,9 @@ func (l *launcher) reconfigureWait(timeout time.Duration) (*config.C, error) { err := l.validator.Validate(update) if err != nil { l.log.Errorf("Config update validation failed: %v", err) + if errors.Is(err, cloudbeat_config.ErrBenchmarkNotSupported) { + l.beat.Manager.UpdateStatus(management.Degraded, cloudbeat_config.ErrBenchmarkNotSupported.Error()) + } continue } } diff --git a/resources/fetchersManager/factory.go b/resources/fetchersManager/factory.go index 20c52c9e19..3725d02935 100644 --- a/resources/fetchersManager/factory.go +++ b/resources/fetchersManager/factory.go @@ -94,7 +94,7 @@ func (fa *factories) parseConfigFetcher(log *logp.Logger, fcfg *agentconfig.C, c // This function takes the configuration file provided by the integration the `cfg` file // and depending on the input type, extract the relevant credentials and add them to the fetcher config func addCredentialsToFetcherConfiguration(log *logp.Logger, cfg *config.Config, fcfg *agentconfig.C) { - if cfg.Type == config.InputTypeEks || cfg.Type == config.InputTypeAws { + if cfg.Type == config.CIS_EKS || cfg.Type == config.CIS_AWS { err := fcfg.Merge(cfg.AWSConfig) if err != nil { log.Errorf("Failed to merge aws configuration to fetcher configuration: %v", err) diff --git a/resources/fetchersManager/factory_aws_test.go b/resources/fetchersManager/factory_aws_test.go index 76bacae7eb..8af83bafff 100644 --- a/resources/fetchersManager/factory_aws_test.go +++ b/resources/fetchersManager/factory_aws_test.go @@ -169,7 +169,7 @@ func (s *FactoriesTestSuite) TestRegisterFetchersWithAwsCredentials() { func createEksAgentConfig(s *FactoriesTestSuite, awsConfig aws.ConfigAWS, fetcherName string) *config.Config { conf := &config.Config{ - Type: config.InputTypeEks, + Type: config.CIS_EKS, AWSConfig: awsConfig, RuntimeCfg: nil, Fetchers: []*agentconfig.C{agentconfig.MustNewConfigFrom(fmt.Sprint("name: ", fetcherName))}, diff --git a/resources/providers/cluster_provider.go b/resources/providers/cluster_provider.go index ef5c2816ab..1635ce4501 100644 --- a/resources/providers/cluster_provider.go +++ b/resources/providers/cluster_provider.go @@ -20,6 +20,7 @@ package providers import ( "context" "fmt" + "github.com/elastic/cloudbeat/config" "github.com/elastic/cloudbeat/resources/providers/awslib" "github.com/elastic/elastic-agent-libs/logp" @@ -40,10 +41,10 @@ type ClusterNameProvider struct { func (provider ClusterNameProvider) GetClusterName(ctx context.Context, cfg *config.Config, log *logp.Logger) (string, error) { switch cfg.Type { - case config.InputTypeVanillaK8s: + case config.CIS_K8S: log.Debugf("Trying to identify Kubernetes Vanilla cluster name") return provider.KubernetesClusterNameProvider.GetClusterName(cfg, provider.KubeClient) - case config.InputTypeEks: + case config.CIS_EKS: log.Debugf("Trying to identify EKS cluster name") awsConfig, err := provider.AwsConfigProvider.InitializeAWSConfig(ctx, cfg.AWSConfig, log) if err != nil { diff --git a/resources/providers/cluster_provider_test.go b/resources/providers/cluster_provider_test.go index d1bee0820b..52c58b28d7 100644 --- a/resources/providers/cluster_provider_test.go +++ b/resources/providers/cluster_provider_test.go @@ -19,13 +19,14 @@ package providers import ( "context" + "testing" + awssdk "github.com/aws/aws-sdk-go-v2/aws" "github.com/elastic/beats/v7/x-pack/libbeat/common/aws" "github.com/elastic/cloudbeat/config" "github.com/elastic/cloudbeat/resources/providers/awslib" "github.com/stretchr/testify/mock" k8sfake "k8s.io/client-go/kubernetes/fake" - "testing" "github.com/elastic/elastic-agent-libs/logp" "github.com/stretchr/testify/suite" @@ -49,7 +50,7 @@ func TestClusterProviderTestSuite(t *testing.T) { } func (s *ClusterProviderTestSuite) TestGetClusterName() { - var tests = []struct { + tests := []struct { config config.Config vanillaClusterName string eksClusterName string @@ -57,7 +58,7 @@ func (s *ClusterProviderTestSuite) TestGetClusterName() { }{ { config.Config{ - Type: config.InputTypeVanillaK8s, + Type: config.CIS_K8S, KubeConfig: "", }, "vanilla-cluster", @@ -66,7 +67,7 @@ func (s *ClusterProviderTestSuite) TestGetClusterName() { }, { config.Config{ - Type: config.InputTypeEks, + Type: config.CIS_EKS, AWSConfig: aws.ConfigAWS{}, }, "vanilla-cluster", diff --git a/scripts/common.sh b/scripts/common.sh index 011564799e..608c6cc38c 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -57,8 +57,7 @@ copy_to_agents() { } restart_agents() { - echo "Agent restart is not supported yet" - # for P in $(get_agents); do - # exec_pod $POD "elastic-agent restart" # https://github.com/elastic/cloudbeat/pull/458#issuecomment-1308837098 - # done + for P in $(get_agents); do + exec_pod $POD "elastic-agent restart" # https://github.com/elastic/cloudbeat/pull/458#issuecomment-1308837098 + done }