diff --git a/cautils/datastructuresmethods.go b/cautils/datastructuresmethods.go index 655445bf..d6b97477 100644 --- a/cautils/datastructuresmethods.go +++ b/cautils/datastructuresmethods.go @@ -2,6 +2,7 @@ package cautils import ( pkgcautils "github.com/armosec/utils-go/utils" + "golang.org/x/mod/semver" "github.com/armosec/opa-utils/reporthandling" ) @@ -50,14 +51,15 @@ func ruleWithArmoOpaDependency(attributes map[string]interface{}) bool { func isRuleKubescapeVersionCompatible(attributes map[string]interface{}, version string) bool { if from, ok := attributes["useFromKubescapeVersion"]; ok && from != nil { if version != "" { - if from.(string) > BuildNumber { + + if semver.Compare(from.(string), BuildNumber) > 0 { return false } } } if until, ok := attributes["useUntilKubescapeVersion"]; ok && until != nil { if version != "" { - if until.(string) <= BuildNumber { + if semver.Compare(BuildNumber, until.(string)) >= 0 { return false } } else { diff --git a/cautils/versioncheck.go b/cautils/versioncheck.go index 83385df1..d5a2af5a 100644 --- a/cautils/versioncheck.go +++ b/cautils/versioncheck.go @@ -10,6 +10,7 @@ import ( "github.com/armosec/kubescape/cautils/logger" "github.com/armosec/kubescape/cautils/logger/helpers" pkgutils "github.com/armosec/utils-go/utils" + "golang.org/x/mod/semver" ) const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK" @@ -97,7 +98,7 @@ func (v *VersionCheckHandler) CheckLatestVersion(versionData *VersionCheckReques } if latestVersion.ClientUpdate != "" { - if BuildNumber != "" && BuildNumber < latestVersion.ClientUpdate { + if BuildNumber != "" && semver.Compare(BuildNumber, latestVersion.ClientUpdate) >= 0 { logger.L().Warning(warningMessage(latestVersion.ClientUpdate)) } } diff --git a/cautils/versioncheck_test.go b/cautils/versioncheck_test.go new file mode 100644 index 00000000..bb90dbe8 --- /dev/null +++ b/cautils/versioncheck_test.go @@ -0,0 +1,38 @@ +package cautils + +import ( + "testing" + + "github.com/armosec/armoapi-go/armotypes" + "github.com/armosec/opa-utils/reporthandling" + "github.com/stretchr/testify/assert" +) + +func TestGetKubernetesObjects(t *testing.T) { +} + +var rule_v1_0_131 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ + Attributes: map[string]interface{}{"useUntilKubescapeVersion": "v1.0.132"}}} +var rule_v1_0_132 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ + Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.132", "useUntilKubescapeVersion": "v1.0.133"}}} +var rule_v1_0_133 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ + Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.133", "useUntilKubescapeVersion": "v1.0.134"}}} +var rule_v1_0_134 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ + Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.134"}}} + +func TestIsRuleKubescapeVersionCompatible(t *testing.T) { + // local build- no build number + // should use only rules that don't have "until" + buildNumberMock := "" + assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock)) + assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock)) + assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock)) + assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock)) + + // should only use rules that version is in range of use + buildNumberMock = "v1.0.133" + assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock)) + assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock)) + assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock)) + assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock)) +} diff --git a/clihandler/cmd/scan.go b/clihandler/cmd/scan.go index 5a0f66eb..defe322b 100644 --- a/clihandler/cmd/scan.go +++ b/clihandler/cmd/scan.go @@ -61,7 +61,7 @@ func init() { rootCmd.AddCommand(scanCmd) - scanCmd.PersistentFlags().StringVarP(&scanInfo.Account, "account", "", "", "Armo portal account ID. Default will load account ID from configMap or config file") + scanCmd.PersistentFlags().StringVarP(&scanInfo.Account, "account", "", "", "ARMO portal account ID. Default will load account ID from configMap or config file") scanCmd.PersistentFlags().StringVarP(&scanInfo.KubeContext, "kube-context", "", "", "Kube context. Default will use the current-context") scanCmd.PersistentFlags().StringVar(&scanInfo.ControlsInputs, "controls-config", "", "Path to an controls-config obj. If not set will download controls-config from ARMO management portal") scanCmd.PersistentFlags().StringVar(&scanInfo.UseExceptions, "exceptions", "", "Path to an exceptions obj. If not set will download exceptions from ARMO management portal") @@ -70,13 +70,13 @@ func init() { scanCmd.PersistentFlags().Float32VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1") scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer","json","junit","prometheus","pdf"`) scanCmd.PersistentFlags().StringVar(&scanInfo.IncludeNamespaces, "include-namespaces", "", "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b") - scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to Armo backend. Use this flag if you ran with the '--submit' flag in the past and you do not want to submit your current scan results") + scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to ARMO backend. Use this flag if you ran with the '--submit' flag in the past and you do not want to submit your current scan results") scanCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout") scanCmd.PersistentFlags().BoolVar(&scanInfo.VerboseMode, "verbose", false, "Display all of the input resources and not only failed resources") scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local policy object from default path. If not used will download latest") scanCmd.PersistentFlags().StringSliceVar(&scanInfo.UseFrom, "use-from", nil, "Load local policy object from specified path. If not used will download latest") scanCmd.PersistentFlags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "Silent progress messages") - scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Send the scan results to Armo management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted") + scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Send the scan results to ARMO management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted") scanCmd.PersistentFlags().StringVar(&scanInfo.HostSensorYamlPath, "host-scan-yaml", "", "Override default host sensor DaemonSet. Use this flag cautiously") scanCmd.PersistentFlags().StringVar(&scanInfo.FormatVersion, "format-version", "v1", "Output object can be differnet between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'") @@ -85,7 +85,7 @@ func init() { scanCmd.PersistentFlags().MarkHidden("silent") // this flag should be deprecated since we added the --logger support // scanCmd.PersistentFlags().MarkHidden("format-version") // meant for testing different output approaches and not for common use - hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensorEnabled, "enable-host-scan", "", "Deploy ARMO K8s host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valueable data from cluster nodes for certain controls. Yaml file: https://raw.githubusercontent.com/armosec/kubescape/master/hostsensorutils/hostsensor.yaml") + hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensorEnabled, "enable-host-scan", "", "Deploy ARMO K8s host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valuable data from cluster nodes for certain controls. Yaml file: https://raw.githubusercontent.com/armosec/kubescape/master/hostsensorutils/hostsensor.yaml") hostF.NoOptDefVal = "true" hostF.DefValue = "false, for no TTY in stdin" diff --git a/go.mod b/go.mod index 5a61d8ea..fce8b07e 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/spf13/cobra v1.2.1 github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.19.1 + golang.org/x/mod v0.4.2 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.22.2 k8s.io/apimachinery v0.22.2 diff --git a/go.sum b/go.sum index 56b612fa..4e9dfab3 100644 --- a/go.sum +++ b/go.sum @@ -800,6 +800,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/opaprocessor/processorhandlerutils.go b/opaprocessor/processorhandlerutils.go index 5c89fad5..ffe1b10b 100644 --- a/opaprocessor/processorhandlerutils.go +++ b/opaprocessor/processorhandlerutils.go @@ -137,29 +137,6 @@ func ruleWithArmoOpaDependency(annotations map[string]interface{}) bool { return false } -// Checks that kubescape version is in range of use for this rule -// In local build (BuildNumber = ""): -// returns true only if rule doesn't have the "until" attribute -func isRuleKubescapeVersionCompatible(rule *reporthandling.PolicyRule) bool { - if from, ok := rule.Attributes["useFromKubescapeVersion"]; ok { - if cautils.BuildNumber != "" { - if from.(string) > cautils.BuildNumber { - return false - } - } - } - if until, ok := rule.Attributes["useUntilKubescapeVersion"]; ok { - if cautils.BuildNumber != "" { - if until.(string) <= cautils.BuildNumber { - return false - } - } else { - return false - } - } - return true -} - func removeData(obj workloadinterface.IMetadata) { if !k8sinterface.IsTypeWorkload(obj.GetObject()) { return // remove data only from kubernetes objects diff --git a/opaprocessor/processorhandlerutils_test.go b/opaprocessor/processorhandlerutils_test.go index 45a48092..3297e720 100644 --- a/opaprocessor/processorhandlerutils_test.go +++ b/opaprocessor/processorhandlerutils_test.go @@ -5,57 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "github.com/armosec/armoapi-go/armotypes" "github.com/armosec/k8s-interface/workloadinterface" - "github.com/armosec/kubescape/cautils" - "github.com/armosec/opa-utils/reporthandling" ) -func TestGetKubernetesObjects(t *testing.T) { -} - -var rule_v1_0_131 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ - Attributes: map[string]interface{}{"useUntilKubescapeVersion": "v1.0.132"}}} -var rule_v1_0_132 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ - Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.132", "useUntilKubescapeVersion": "v1.0.133"}}} -var rule_v1_0_133 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ - Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.133", "useUntilKubescapeVersion": "v1.0.134"}}} -var rule_v1_0_134 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{ - Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.134"}}} - -func TestIsRuleKubescapeVersionCompatible(t *testing.T) { - // local build- no build number - // should use only rules that don't have "until" - cautils.BuildNumber = "" - if isRuleKubescapeVersionCompatible(rule_v1_0_131) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - if isRuleKubescapeVersionCompatible(rule_v1_0_132) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - if isRuleKubescapeVersionCompatible(rule_v1_0_133) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - if !isRuleKubescapeVersionCompatible(rule_v1_0_134) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - - // should only use rules that version is in range of use - cautils.BuildNumber = "v1.0.133" - if isRuleKubescapeVersionCompatible(rule_v1_0_131) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - if isRuleKubescapeVersionCompatible(rule_v1_0_132) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - if !isRuleKubescapeVersionCompatible(rule_v1_0_133) { - t.Error("error in isRuleKubescapeVersionCompatible") - } - if isRuleKubescapeVersionCompatible(rule_v1_0_134) { - t.Error("error in isRuleKubescapeVersionCompatible") - } -} - func TestRemoveData(t *testing.T) { w := `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"demoservice-server"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"demoservice-server"}},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"demoservice-server"}},"spec":{"containers":[{"env":[{"name":"SERVER_PORT","value":"8089"},{"name":"SLEEP_DURATION","value":"1"},{"name":"DEMO_FOLDERS","value":"/app"},{"name":"ARMO_TEST_NAME","value":"auto_attach_deployment"},{"name":"CAA_ENABLE_CRASH_REPORTER","value":"1"}],"image":"quay.io/armosec/demoservice:v25","imagePullPolicy":"IfNotPresent","name":"demoservice","ports":[{"containerPort":8089,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"ClusterFirst","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"terminationGracePeriodSeconds":30}}}}` diff --git a/registryadaptors/README.md b/registryadaptors/README.md index f0de4892..ea5ea4d3 100644 --- a/registryadaptors/README.md +++ b/registryadaptors/README.md @@ -1,7 +1,7 @@ # Integrate With Vulnerability Server There are some controls that check the relation between the kubernetes manifest and vulnerabilities. -For these controls to work properly, it is necasery to +For these controls to work properly, it is necessary to ## Supported Servers * Armosec