diff --git a/go.mod b/go.mod index b65f3ddb..dc51dc1d 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,11 @@ require ( github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d // indirect + github.com/aquasecurity/table v1.8.0 // indirect + github.com/aquasecurity/tml v0.6.1 // indirect + github.com/aquasecurity/trivy v0.53.0 // indirect github.com/aquasecurity/trivy-checks v0.13.0 // indirect + github.com/aquasecurity/trivy-db v0.0.0-20231020043206-3770774790ce // indirect github.com/aws/aws-sdk-go-v2 v1.32.3 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 // indirect github.com/aws/smithy-go v1.22.0 // indirect @@ -203,10 +207,6 @@ require ( github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/aquasecurity/table v1.8.0 // indirect - github.com/aquasecurity/tml v0.6.1 // indirect - github.com/aquasecurity/trivy v0.53.0 // indirect - github.com/aquasecurity/trivy-db v0.0.0-20231020043206-3770774790ce // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index c3ad08cf..16b20251 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -23,7 +23,6 @@ import ( "github.com/k8sgpt-ai/k8sgpt/pkg/common" "github.com/k8sgpt-ai/k8sgpt/pkg/integration/keda" "github.com/k8sgpt-ai/k8sgpt/pkg/integration/prometheus" - "github.com/k8sgpt-ai/k8sgpt/pkg/integration/trivy" "github.com/k8sgpt-ai/k8sgpt/pkg/util" "github.com/spf13/viper" ) @@ -49,7 +48,6 @@ type Integration struct { } var integrations = map[string]IIntegration{ - "trivy": trivy.NewTrivy(), "prometheus": prometheus.NewPrometheus(), "aws": aws.NewAWS(), "keda": keda.NewKeda(), diff --git a/pkg/integration/trivy/analyzer.go b/pkg/integration/trivy/analyzer.go deleted file mode 100644 index 344d0920..00000000 --- a/pkg/integration/trivy/analyzer.go +++ /dev/null @@ -1,175 +0,0 @@ -/* -Copyright 2023 The K8sGPT Authors. -Licensed 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. -*/ - -package trivy - -import ( - "fmt" - "strings" - - ctrl "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/aquasecurity/trivy-operator/pkg/apis/aquasecurity/v1alpha1" - "github.com/k8sgpt-ai/k8sgpt/pkg/common" - "github.com/k8sgpt-ai/k8sgpt/pkg/util" -) - -type TrivyAnalyzer struct { - vulernabilityReportAnalysis bool - configAuditReportAnalysis bool -} - -func (TrivyAnalyzer) analyzeVulnerabilityReports(a common.Analyzer) ([]common.Result, error) { - // Get all trivy VulnerabilityReports - result := &v1alpha1.VulnerabilityReportList{} - - client := a.Client.CtrlClient - err := v1alpha1.AddToScheme(client.Scheme()) - if err != nil { - return nil, err - } - if err := client.List(a.Context, result, &ctrl.ListOptions{}); err != nil { - return nil, err - } - - // Find criticals and get CVE - var preAnalysis = map[string]common.PreAnalysis{} - - for _, report := range result.Items { - - // For each pod there may be multiple vulnerabilities - var failures []common.Failure - distinctFailures := make(map[string]common.Failure) - for _, vuln := range report.Report.Vulnerabilities { - if vuln.Severity == "CRITICAL" { - // get the vulnerability ID - // get the vulnerability description - text := fmt.Sprintf("critical Vulnerability found ID: %s (learn more at: %s)", vuln.VulnerabilityID, vuln.PrimaryLink) - distinctFailures[text] = common.Failure{ - Text: text, - Sensitive: []common.Sensitive{}, - } - } - } - for _, v := range distinctFailures { - failures = append(failures, v) - } - if len(failures) > 0 { - preAnalysis[fmt.Sprintf("%s/%s", report.Namespace, - report.Name)] = common.PreAnalysis{ - TrivyVulnerabilityReport: report, - FailureDetails: failures, - } - } - } - - for key, value := range preAnalysis { - var currentAnalysis = common.Result{ - Kind: "VulnerabilityReport", - Name: key, - Error: value.FailureDetails, - } - - parent, _ := util.GetParent(a.Client, value.TrivyVulnerabilityReport.ObjectMeta) - currentAnalysis.ParentObject = parent - a.Results = append(a.Results, currentAnalysis) - } - - return a.Results, nil - -} - -func (t TrivyAnalyzer) analyzeConfigAuditReports(a common.Analyzer) ([]common.Result, error) { - // Get all trivy ConfigAuditReports - result := &v1alpha1.ConfigAuditReportList{} - - client := a.Client.CtrlClient - err := v1alpha1.AddToScheme(client.Scheme()) - if err != nil { - return nil, err - } - if err := client.List(a.Context, result, &ctrl.ListOptions{}); err != nil { - return nil, err - } - - // Find criticals and get CVE - var preAnalysis = map[string]common.PreAnalysis{} - - for _, report := range result.Items { - - // For each k8s resources there may be multiple checks - var failures []common.Failure - for _, check := range report.Report.Checks { - if check.Severity == "MEDIUM" || check.Severity == "HIGH" || check.Severity == "CRITICAL" { - failures = append(failures, common.Failure{ - Text: fmt.Sprintf("Config issue with severity \"%s\" found: %s", check.Severity, strings.Join(check.Messages, "")), - Sensitive: []common.Sensitive{ - { - Unmasked: report.Labels["trivy-operator.resource.name"], - Masked: util.MaskString(report.Labels["trivy-operator.resource.name"]), - }, - { - Unmasked: report.Labels["trivy-operator.resource.namespace"], - Masked: util.MaskString(report.Labels["trivy-operator.resource.namespace"]), - }, - }, - }) - } - } - - if len(failures) > 0 { - preAnalysis[fmt.Sprintf("%s/%s", report.Namespace, - report.Name)] = common.PreAnalysis{ - TrivyConfigAuditReport: report, - FailureDetails: failures, - } - } - } - - for key, value := range preAnalysis { - var currentAnalysis = common.Result{ - Kind: "ConfigAuditReport", - Name: key, - Error: value.FailureDetails, - } - - parent, _ := util.GetParent(a.Client, value.TrivyConfigAuditReport.ObjectMeta) - currentAnalysis.ParentObject = parent - a.Results = append(a.Results, currentAnalysis) - } - - return a.Results, nil -} - -func (t TrivyAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) { - - if t.vulernabilityReportAnalysis { - common := make([]common.Result, 0) - vresult, err := t.analyzeVulnerabilityReports(a) - if err != nil { - return nil, err - } - common = append(common, vresult...) - return common, nil - } - if t.configAuditReportAnalysis { - common := make([]common.Result, 0) - cresult, err := t.analyzeConfigAuditReports(a) - if err != nil { - return nil, err - } - common = append(common, cresult...) - return common, nil - } - return make([]common.Result, 0), nil -} diff --git a/pkg/integration/trivy/trivy.go b/pkg/integration/trivy/trivy.go deleted file mode 100644 index c4a602e1..00000000 --- a/pkg/integration/trivy/trivy.go +++ /dev/null @@ -1,199 +0,0 @@ -/* -Copyright 2023 The K8sGPT Authors. -Licensed 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. -*/ - -package trivy - -import ( - "context" - "fmt" - "os" - - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/fatih/color" - "github.com/k8sgpt-ai/k8sgpt/pkg/common" - "github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes" - helmclient "github.com/mittwald/go-helm-client" - "github.com/spf13/viper" - "helm.sh/helm/v3/pkg/repo" -) - -var ( - Repo = getEnv("TRIVY_REPO", "https://aquasecurity.github.io/helm-charts/") - Version = getEnv("TRIVY_VERSION", "0.13.0") - ChartName = getEnv("TRIVY_CHART_NAME", "trivy-operator") - RepoShortName = getEnv("TRIVY_REPO_SHORT_NAME", "aqua") - ReleaseName = getEnv("TRIVY_RELEASE_NAME", "trivy-operator-k8sgpt") -) - -type Trivy struct { - helm helmclient.Client -} - -func getEnv(key, defaultValue string) string { - value := os.Getenv(key) - if value == "" { - return defaultValue - } - return value -} - -func NewTrivy() *Trivy { - helmClient, err := helmclient.New(&helmclient.Options{}) - if err != nil { - panic(err) - } - return &Trivy{ - helm: helmClient, - } -} - -func (t *Trivy) GetAnalyzerName() []string { - return []string{ - "VulnerabilityReport", - "ConfigAuditReport", - } -} - -// This doesnt work -func (t *Trivy) GetNamespace() (string, error) { - releases, err := t.helm.ListDeployedReleases() - if err != nil { - return "", err - } - for _, rel := range releases { - if rel.Name == ReleaseName { - return rel.Namespace, nil - } - } - return "", status.Error(codes.NotFound, "trivy release not found") -} - -func (t *Trivy) OwnsAnalyzer(analyzer string) bool { - - for _, a := range t.GetAnalyzerName() { - if analyzer == a { - return true - } - } - return false -} -func (t *Trivy) Deploy(namespace string) error { - - // Add the repository - chartRepo := repo.Entry{ - Name: RepoShortName, - URL: Repo, - } - // Add a chart-repository to the client. - if err := t.helm.AddOrUpdateChartRepo(chartRepo); err != nil { - panic(err) - } - - chartSpec := helmclient.ChartSpec{ - ReleaseName: ReleaseName, - ChartName: fmt.Sprintf("%s/%s", RepoShortName, ChartName), - Namespace: namespace, - - //TODO: All of this should be configurable - UpgradeCRDs: true, - Wait: false, - Timeout: 300, - CreateNamespace: true, - } - - // Install a chart release. - // Note that helmclient.Options.Namespace should ideally match the namespace in chartSpec.Namespace. - if _, err := t.helm.InstallOrUpgradeChart(context.Background(), &chartSpec, nil); err != nil { - return err - } - - return nil -} - -func (t *Trivy) UnDeploy(namespace string) error { - chartSpec := helmclient.ChartSpec{ - ReleaseName: ReleaseName, - ChartName: fmt.Sprintf("%s/%s", RepoShortName, ChartName), - Namespace: namespace, - UpgradeCRDs: true, - Wait: false, - Timeout: 300, - } - // Uninstall the chart release. - // Note that helmclient.Options.Namespace should ideally match the namespace in chartSpec.Namespace. - if err := t.helm.UninstallRelease(&chartSpec); err != nil { - return err - } - return nil -} - -func (t *Trivy) isDeployed() bool { - // check if aquasec apigroup is available as a marker if trivy is installed on the cluster - kubecontext := viper.GetString("kubecontext") - kubeconfig := viper.GetString("kubeconfig") - client, err := kubernetes.NewClient(kubecontext, kubeconfig) - if err != nil { - // TODO: better error handling - color.Red("Error initialising kubernetes client: %v", err) - os.Exit(1) - } - groups, _, err := client.Client.Discovery().ServerGroupsAndResources() - if err != nil { - // TODO: better error handling - color.Red("Error initialising discovery client: %v", err) - os.Exit(1) - } - - for _, group := range groups { - if group.Name == "aquasecurity.github.io" { - return true - } - } - - return false -} - -func (t *Trivy) isFilterActive() bool { - activeFilters := viper.GetStringSlice("active_filters") - - for _, filter := range t.GetAnalyzerName() { - for _, af := range activeFilters { - if af == filter { - return true - } - } - } - - return false -} - -func (t *Trivy) IsActivate() bool { - if t.isFilterActive() && t.isDeployed() { - return true - } else { - return false - } -} - -func (t *Trivy) AddAnalyzer(mergedMap *map[string]common.IAnalyzer) { - - (*mergedMap)["VulnerabilityReport"] = &TrivyAnalyzer{ - vulernabilityReportAnalysis: true, - } - (*mergedMap)["ConfigAuditReport"] = &TrivyAnalyzer{ - configAuditReportAnalysis: true, - } - -}