mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-08-15 22:43:07 +00:00
feat: removal of trivy integration
Signed-off-by: AlexsJones <alexsimonjones@gmail.com>
This commit is contained in:
parent
d956f32e1e
commit
443fe95fe1
8
go.mod
8
go.mod
@ -85,7 +85,11 @@ require (
|
|||||||
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v15 v15.0.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/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-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 v1.32.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 // indirect
|
||||||
github.com/aws/smithy-go v1.22.0 // 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/semver/v3 v3.3.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||||
github.com/Masterminds/squirrel v1.5.4 // 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/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/common"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/integration/keda"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/integration/keda"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/integration/prometheus"
|
"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/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
@ -49,7 +48,6 @@ type Integration struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var integrations = map[string]IIntegration{
|
var integrations = map[string]IIntegration{
|
||||||
"trivy": trivy.NewTrivy(),
|
|
||||||
"prometheus": prometheus.NewPrometheus(),
|
"prometheus": prometheus.NewPrometheus(),
|
||||||
"aws": aws.NewAWS(),
|
"aws": aws.NewAWS(),
|
||||||
"keda": keda.NewKeda(),
|
"keda": keda.NewKeda(),
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user