BREAKING: support exclude kinds/namespaces and include kinds/namespaces (#6323)

Signed-off-by: chenk <hen.keinan@gmail.com>
This commit is contained in:
chenk
2024-04-27 17:30:17 +03:00
committed by GitHub
parent 2d090ef2df
commit 060d0bb641
12 changed files with 129 additions and 407 deletions

View File

@@ -2,32 +2,33 @@
[EXPERIMENTAL] Scan kubernetes cluster [EXPERIMENTAL] Scan kubernetes cluster
### Synopsis
Default context in kube configuration will be used unless specified
``` ```
trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: pods, pod/NAME } trivy kubernetes [flags] [CONTEXT]
``` ```
### Examples ### Examples
``` ```
# cluster scanning # cluster scanning
$ trivy k8s --report summary cluster $ trivy k8s --report summary
# namespace scanning: # cluster scanning with specific namespace:
$ trivy k8s -n kube-system --report summary all $ trivy k8s --include-namespaces kube-system --report summary
# cluster with specific context:
$ trivy k8s kind-kind --report summary
# resources scanning:
$ trivy k8s --report=summary deploy
$ trivy k8s --namespace=kube-system --report=summary deploy,configmaps
# resource scanning:
$ trivy k8s deployment/orion
``` ```
### Options ### Options
``` ```
-A, --all-namespaces fetch resources from all cluster namespaces
--burst int specify the maximum burst for throttle (default 10) --burst int specify the maximum burst for throttle (default 10)
--cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs") --cache-backend string cache backend (e.g. redis://localhost:6379) (default "fs")
--cache-ttl duration cache TTL when using redis as cache backend --cache-ttl duration cache TTL when using redis as cache backend
@@ -36,11 +37,12 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
--components strings specify which components to scan (workload,infra) (default [workload,infra]) --components strings specify which components to scan (workload,infra) (default [workload,infra])
--config-data strings specify paths from which data for the Rego policies will be recursively loaded --config-data strings specify paths from which data for the Rego policies will be recursively loaded
--config-policy strings specify the paths to the Rego policy files or to the directories containing them, applying config files --config-policy strings specify the paths to the Rego policy files or to the directories containing them, applying config files
--context string specify a context to scan
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2")
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages
--download-db-only download/update vulnerability database but don't run a scan --download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan
--exclude-kinds strings indicate the kinds exclude from scanning (example: node)
--exclude-namespaces strings indicate the namespaces excluded from scanning (example: kube-system)
--exclude-nodes strings indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev) --exclude-nodes strings indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)
--exclude-owned exclude resources that have an owner reference --exclude-owned exclude resources that have an owner reference
--exit-code int specify exit code when any security issues are found --exit-code int specify exit code when any security issues are found
@@ -58,13 +60,14 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
--ignore-unfixed display only fixed vulnerabilities --ignore-unfixed display only fixed vulnerabilities
--ignorefile string specify .trivyignore file (default ".trivyignore") --ignorefile string specify .trivyignore file (default ".trivyignore")
--image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote]) --image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote])
--include-kinds strings indicate the kinds included in scanning (example: node)
--include-namespaces strings indicate the namespaces included in scanning (example: kube-system)
--include-non-failures include successes and exceptions, available with '--scanners misconfig' --include-non-failures include successes and exceptions, available with '--scanners misconfig'
--java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1")
--k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0)
--kubeconfig string specify the kubeconfig file path to use --kubeconfig string specify the kubeconfig file path to use
--list-all-pkgs enabling the option will output all packages regardless of vulnerability --list-all-pkgs enabling the option will output all packages regardless of vulnerability
--misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot])
-n, --namespace string specify a namespace to scan
--no-progress suppress progress bar --no-progress suppress progress bar
--node-collector-imageref string indicate the image reference for the node-collector scan job (default "ghcr.io/aquasecurity/node-collector:0.0.9") --node-collector-imageref string indicate the image reference for the node-collector scan job (default "ghcr.io/aquasecurity/node-collector:0.0.9")
--node-collector-namespace string specify the namespace in which the node-collector job should be deployed (default "trivy-temp") --node-collector-namespace string specify the namespace in which the node-collector job should be deployed (default "trivy-temp")

22
go.mod
View File

@@ -26,7 +26,7 @@ require (
github.com/aquasecurity/trivy-aws v0.8.0 github.com/aquasecurity/trivy-aws v0.8.0
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
github.com/aquasecurity/trivy-kubernetes v0.6.3 github.com/aquasecurity/trivy-kubernetes v0.6.6
github.com/aquasecurity/trivy-policies v0.10.0 github.com/aquasecurity/trivy-policies v0.10.0
github.com/aws/aws-sdk-go-v2 v1.26.1 github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2/config v1.27.10 github.com/aws/aws-sdk-go-v2/config v1.27.10
@@ -50,8 +50,8 @@ require (
github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/strfmt v0.23.0
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/protobuf v1.5.3 github.com/golang/protobuf v1.5.4
github.com/google/go-containerregistry v0.19.0 github.com/google/go-containerregistry v0.19.1
github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/google/wire v0.6.0 github.com/google/wire v0.6.0
@@ -105,7 +105,7 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 github.com/xeipuuv/gojsonschema v1.2.0
github.com/xlab/treeprint v1.2.0 github.com/xlab/treeprint v1.2.0
go.etcd.io/bbolt v1.3.9 go.etcd.io/bbolt v1.3.9
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
golang.org/x/mod v0.16.0 golang.org/x/mod v0.16.0
golang.org/x/net v0.23.0 golang.org/x/net v0.23.0
@@ -115,7 +115,7 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
google.golang.org/protobuf v1.33.0 google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.29.1 k8s.io/api v0.29.3
k8s.io/utils v0.0.0-20231127182322-b307cd553661 k8s.io/utils v0.0.0-20231127182322-b307cd553661
modernc.org/sqlite v1.29.7 modernc.org/sqlite v1.29.7
) )
@@ -177,7 +177,7 @@ require (
github.com/antchfx/xpath v1.2.3 // indirect github.com/antchfx/xpath v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.49.21 // indirect github.com/aws/aws-sdk-go v1.51.16 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
@@ -411,14 +411,14 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiextensions-apiserver v0.29.0 // indirect k8s.io/apiextensions-apiserver v0.29.0 // indirect
k8s.io/apimachinery v0.29.1 // indirect k8s.io/apimachinery v0.29.3 // indirect
k8s.io/apiserver v0.29.0 // indirect k8s.io/apiserver v0.29.0 // indirect
k8s.io/cli-runtime v0.29.0 // indirect k8s.io/cli-runtime v0.29.3 // indirect
k8s.io/client-go v0.29.0 // indirect k8s.io/client-go v0.29.3 // indirect
k8s.io/component-base v0.29.0 // indirect k8s.io/component-base v0.29.3 // indirect
k8s.io/klog/v2 v2.120.0 // indirect k8s.io/klog/v2 v2.120.0 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
k8s.io/kubectl v0.29.0 // indirect k8s.io/kubectl v0.29.3 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.49.3 // indirect modernc.org/libc v1.49.3 // indirect
modernc.org/mathutil v1.6.0 // indirect modernc.org/mathutil v1.6.0 // indirect

40
go.sum
View File

@@ -349,8 +349,8 @@ github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d h1:fjI9mkoTU
github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d/go.mod h1:cj9/QmD9N3OZnKQMp+/DvdV+ym3HyIkd4e+F0ZM3ZGs= github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d/go.mod h1:cj9/QmD9N3OZnKQMp+/DvdV+ym3HyIkd4e+F0ZM3ZGs=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
github.com/aquasecurity/trivy-kubernetes v0.6.3 h1:Hmo0pefXRsyVYsii62WUQyt3xMHjm37ipPESeWM/LNA= github.com/aquasecurity/trivy-kubernetes v0.6.6 h1:90Y3FH7Mrh+M06+RyLhl26HA06kWbhvTWwKWpt9jE0M=
github.com/aquasecurity/trivy-kubernetes v0.6.3/go.mod h1:v6B8SO2ep718ccGbbjhpzMn6p27IijS+dMb+MeYz3jQ= github.com/aquasecurity/trivy-kubernetes v0.6.6/go.mod h1:+NJBTgQErUmq21Ag71q/EuXZKIP+/OJvBAR0G+YUkKo=
github.com/aquasecurity/trivy-policies v0.10.0 h1:QONOsIFi6+WyB+7NGMBQeCgMFcRg6RV9dTBBpeOFDxU= github.com/aquasecurity/trivy-policies v0.10.0 h1:QONOsIFi6+WyB+7NGMBQeCgMFcRg6RV9dTBBpeOFDxU=
github.com/aquasecurity/trivy-policies v0.10.0/go.mod h1:7WU0GTUqtQxqQ+FV3JAy7lskQQZU6lp7Mz1i8GEapFw= github.com/aquasecurity/trivy-policies v0.10.0/go.mod h1:7WU0GTUqtQxqQ+FV3JAy7lskQQZU6lp7Mz1i8GEapFw=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
@@ -366,8 +366,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.49.21 h1:Rl8KW6HqkwzhATwvXhyr7vD4JFUMi7oXGAw9SrxxIFY= github.com/aws/aws-sdk-go v1.51.16 h1:vnWKK8KjbftEkuPX8bRj3WHsLy1uhotn0eXptpvrxJI=
github.com/aws/aws-sdk-go v1.49.21/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go v1.51.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
@@ -948,8 +948,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -981,8 +981,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw= github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw=
github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic= github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@@ -2476,32 +2476,32 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw=
k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0=
k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc=
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU=
k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU=
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o= k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o=
k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM= k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM=
k8s.io/cli-runtime v0.29.0 h1:q2kC3cex4rOBLfPOnMSzV2BIrrQlx97gxHJs21KxKS4= k8s.io/cli-runtime v0.29.3 h1:r68rephmmytoywkw2MyJ+CxjpasJDQY7AGc3XY2iv1k=
k8s.io/cli-runtime v0.29.0/go.mod h1:VKudXp3X7wR45L+nER85YUzOQIru28HQpXr0mTdeCrk= k8s.io/cli-runtime v0.29.3/go.mod h1:aqVUsk86/RhaGJwDhHXH0jcdqBrgdF3bZWk4Z9D4mkM=
k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo=
k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio=
k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
@@ -2514,8 +2514,8 @@ k8s.io/klog/v2 v2.120.0/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/kubectl v0.29.0 h1:Oqi48gXjikDhrBF67AYuZRTcJV4lg2l42GmvsP7FmYI= k8s.io/kubectl v0.29.3 h1:RuwyyIU42MAISRIePaa8Q7A3U74Q9P4MoJbDFz9o3us=
k8s.io/kubectl v0.29.0/go.mod h1:0jMjGWIcMIQzmUaMgAzhSELv5WtHo2a8pq67DtviAJs= k8s.io/kubectl v0.29.3/go.mod h1:yCxfY1dbwgVdEt2zkJ6d5NNLOhhWgTyrqACIoFhpdd4=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI=

View File

@@ -31,7 +31,7 @@ func TestK8s(t *testing.T) {
"--cache-dir", "--cache-dir",
cacheDir, cacheDir,
"k8s", "k8s",
"cluster", "kind-kind-test",
"--report", "--report",
"summary", "summary",
"-q", "-q",
@@ -39,10 +39,6 @@ func TestK8s(t *testing.T) {
"5m0s", "5m0s",
"--format", "--format",
"json", "json",
"--components",
"workload",
"--context",
"kind-kind-test",
"--output", "--output",
outputFile, outputFile,
} }
@@ -79,12 +75,10 @@ func TestK8s(t *testing.T) {
outputFile := filepath.Join(t.TempDir(), "output.json") outputFile := filepath.Join(t.TempDir(), "output.json")
osArgs := []string{ osArgs := []string{
"k8s", "k8s",
"cluster", "kind-kind-test",
"--format", "--format",
"cyclonedx", "cyclonedx",
"-q", "-q",
"--context",
"kind-kind-test",
"--output", "--output",
outputFile, outputFile,
} }
@@ -111,51 +105,5 @@ func TestK8s(t *testing.T) {
assert.True(t, lo.SomeBy(*got.Dependencies, func(r cdx.Dependency) bool { assert.True(t, lo.SomeBy(*got.Dependencies, func(r cdx.Dependency) bool {
return len(*r.Dependencies) > 0 return len(*r.Dependencies) > 0
})) }))
})
t.Run("specific resource scan", func(t *testing.T) {
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
osArgs := []string{
"k8s",
"-n",
"default",
"deployments/nginx-deployment",
"-q",
"--timeout",
"5m0s",
"--format",
"json",
"--components",
"workload",
"--context",
"kind-kind-test",
"--output",
outputFile,
}
// Run Trivy
err := execute(osArgs)
require.NoError(t, err)
var got report.Report
f, err := os.Open(outputFile)
require.NoError(t, err)
defer f.Close()
err = json.NewDecoder(f).Decode(&got)
require.NoError(t, err)
// Flatten findings
results := lo.FlatMap(got.Resources, func(resource report.Resource, _ int) []types.Result {
return resource.Results
})
// Has vulnerabilities
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Vulnerabilities) > 0
}))
}) })
} }

View File

@@ -934,22 +934,21 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
VulnerabilityFlagGroup: flag.NewVulnerabilityFlagGroup(), VulnerabilityFlagGroup: flag.NewVulnerabilityFlagGroup(),
} }
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "kubernetes [flags] { cluster | all | specific resources like kubectl. eg: pods, pod/NAME }", Use: "kubernetes [flags] [CONTEXT]",
Aliases: []string{"k8s"}, Aliases: []string{"k8s"},
GroupID: groupScanning, GroupID: groupScanning,
Short: "[EXPERIMENTAL] Scan kubernetes cluster", Short: "[EXPERIMENTAL] Scan kubernetes cluster",
Long: `Default context in kube configuration will be used unless specified`,
Example: ` # cluster scanning Example: ` # cluster scanning
$ trivy k8s --report summary cluster $ trivy k8s --report summary
# namespace scanning: # cluster scanning with specific namespace:
$ trivy k8s -n kube-system --report summary all $ trivy k8s --include-namespaces kube-system --report summary
# cluster with specific context:
$ trivy k8s kind-kind --report summary
# resources scanning:
$ trivy k8s --report=summary deploy
$ trivy k8s --namespace=kube-system --report=summary deploy,configmaps
# resource scanning:
$ trivy k8s deployment/orion
`, `,
PreRunE: func(cmd *cobra.Command, args []string) error { PreRunE: func(cmd *cobra.Command, args []string) error {
if err := k8sFlags.Bind(cmd); err != nil { if err := k8sFlags.Bind(cmd); err != nil {
@@ -1236,7 +1235,7 @@ func validateArgs(cmd *cobra.Command, args []string) error {
return nil return nil
} }
if len(args) == 0 && viper.GetString(flag.InputFlag.ConfigName) == "" { if len(args) == 0 && viper.GetString(flag.InputFlag.ConfigName) == "" && cmd.Name() != "kubernetes" {
if err := cmd.Help(); err != nil { if err := cmd.Help(); err != nil {
return err return err
} }

View File

@@ -10,20 +10,6 @@ import (
) )
var ( var (
ClusterContextFlag = Flag[string]{
Name: "context",
ConfigName: "kubernetes.context",
Usage: "specify a context to scan",
Aliases: []Alias{
{Name: "ctx"},
},
}
K8sNamespaceFlag = Flag[string]{
Name: "namespace",
ConfigName: "kubernetes.namespace",
Shorthand: "n",
Usage: "specify a namespace to scan",
}
KubeConfigFlag = Flag[string]{ KubeConfigFlag = Flag[string]{
Name: "kubeconfig", Name: "kubeconfig",
ConfigName: "kubernetes.kubeconfig", ConfigName: "kubernetes.kubeconfig",
@@ -52,12 +38,6 @@ var (
ConfigName: "kubernetes.tolerations", ConfigName: "kubernetes.tolerations",
Usage: "specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule)", Usage: "specify node-collector job tolerations (example: key1=value1:NoExecute,key2=value2:NoSchedule)",
} }
AllNamespaces = Flag[bool]{
Name: "all-namespaces",
ConfigName: "kubernetes.all-namespaces",
Shorthand: "A",
Usage: "fetch resources from all cluster namespaces",
}
NodeCollectorNamespace = Flag[string]{ NodeCollectorNamespace = Flag[string]{
Name: "node-collector-namespace", Name: "node-collector-namespace",
ConfigName: "kubernetes.node-collector.namespace", ConfigName: "kubernetes.node-collector.namespace",
@@ -80,6 +60,27 @@ var (
ConfigName: "kubernetes.exclude.nodes", ConfigName: "kubernetes.exclude.nodes",
Usage: "indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)", Usage: "indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)",
} }
ExcludeKinds = Flag[[]string]{
Name: "exclude-kinds",
ConfigName: "kubernetes.excludeKinds",
Usage: "indicate the kinds exclude from scanning (example: node)",
}
IncludeKinds = Flag[[]string]{
Name: "include-kinds",
ConfigName: "kubernetes.includeKinds",
Usage: "indicate the kinds included in scanning (example: node)",
}
ExcludeNamespaces = Flag[[]string]{
Name: "exclude-namespaces",
ConfigName: "kubernetes.excludeNamespaces",
Usage: "indicate the namespaces excluded from scanning (example: kube-system)",
}
IncludeNamespaces = Flag[[]string]{
Name: "include-namespaces",
ConfigName: "kubernetes.includeNamespaces",
Usage: "indicate the namespaces included in scanning (example: kube-system)",
}
QPS = Flag[float64]{ QPS = Flag[float64]{
Name: "qps", Name: "qps",
ConfigName: "kubernetes.qps", ConfigName: "kubernetes.qps",
@@ -95,49 +96,52 @@ var (
) )
type K8sFlagGroup struct { type K8sFlagGroup struct {
ClusterContext *Flag[string]
Namespace *Flag[string]
KubeConfig *Flag[string] KubeConfig *Flag[string]
Components *Flag[[]string] Components *Flag[[]string]
K8sVersion *Flag[string] K8sVersion *Flag[string]
Tolerations *Flag[[]string] Tolerations *Flag[[]string]
NodeCollectorImageRef *Flag[string] NodeCollectorImageRef *Flag[string]
AllNamespaces *Flag[bool]
NodeCollectorNamespace *Flag[string] NodeCollectorNamespace *Flag[string]
ExcludeOwned *Flag[bool] ExcludeOwned *Flag[bool]
ExcludeNodes *Flag[[]string] ExcludeNodes *Flag[[]string]
ExcludeKinds *Flag[[]string]
IncludeKinds *Flag[[]string]
ExcludeNamespaces *Flag[[]string]
IncludeNamespaces *Flag[[]string]
QPS *Flag[float64] QPS *Flag[float64]
Burst *Flag[int] Burst *Flag[int]
} }
type K8sOptions struct { type K8sOptions struct {
ClusterContext string
Namespace string
KubeConfig string KubeConfig string
Components []string Components []string
K8sVersion string K8sVersion string
Tolerations []corev1.Toleration Tolerations []corev1.Toleration
NodeCollectorImageRef string NodeCollectorImageRef string
AllNamespaces bool
NodeCollectorNamespace string NodeCollectorNamespace string
ExcludeOwned bool ExcludeOwned bool
ExcludeNodes map[string]string ExcludeNodes map[string]string
ExcludeKinds []string
IncludeKinds []string
ExcludeNamespaces []string
IncludeNamespaces []string
QPS float32 QPS float32
Burst int Burst int
} }
func NewK8sFlagGroup() *K8sFlagGroup { func NewK8sFlagGroup() *K8sFlagGroup {
return &K8sFlagGroup{ return &K8sFlagGroup{
ClusterContext: ClusterContextFlag.Clone(),
Namespace: K8sNamespaceFlag.Clone(),
KubeConfig: KubeConfigFlag.Clone(), KubeConfig: KubeConfigFlag.Clone(),
Components: ComponentsFlag.Clone(), Components: ComponentsFlag.Clone(),
K8sVersion: K8sVersionFlag.Clone(), K8sVersion: K8sVersionFlag.Clone(),
Tolerations: TolerationsFlag.Clone(), Tolerations: TolerationsFlag.Clone(),
AllNamespaces: AllNamespaces.Clone(),
NodeCollectorNamespace: NodeCollectorNamespace.Clone(), NodeCollectorNamespace: NodeCollectorNamespace.Clone(),
ExcludeOwned: ExcludeOwned.Clone(), ExcludeOwned: ExcludeOwned.Clone(),
ExcludeNodes: ExcludeNodes.Clone(), ExcludeNodes: ExcludeNodes.Clone(),
ExcludeKinds: ExcludeKinds.Clone(),
IncludeKinds: IncludeKinds.Clone(),
ExcludeNamespaces: ExcludeNamespaces.Clone(),
IncludeNamespaces: IncludeNamespaces.Clone(),
NodeCollectorImageRef: NodeCollectorImageRef.Clone(), NodeCollectorImageRef: NodeCollectorImageRef.Clone(),
QPS: QPS.Clone(), QPS: QPS.Clone(),
Burst: Burst.Clone(), Burst: Burst.Clone(),
@@ -150,17 +154,18 @@ func (f *K8sFlagGroup) Name() string {
func (f *K8sFlagGroup) Flags() []Flagger { func (f *K8sFlagGroup) Flags() []Flagger {
return []Flagger{ return []Flagger{
f.ClusterContext,
f.Namespace,
f.KubeConfig, f.KubeConfig,
f.Components, f.Components,
f.K8sVersion, f.K8sVersion,
f.Tolerations, f.Tolerations,
f.AllNamespaces,
f.NodeCollectorNamespace, f.NodeCollectorNamespace,
f.ExcludeOwned, f.ExcludeOwned,
f.ExcludeNodes, f.ExcludeNodes,
f.NodeCollectorImageRef, f.NodeCollectorImageRef,
f.ExcludeKinds,
f.IncludeKinds,
f.ExcludeNamespaces,
f.IncludeNamespaces,
f.QPS, f.QPS,
f.Burst, f.Burst,
} }
@@ -185,20 +190,27 @@ func (f *K8sFlagGroup) ToOptions() (K8sOptions, error) {
} }
exludeNodeLabels[excludeNodeParts[0]] = excludeNodeParts[1] exludeNodeLabels[excludeNodeParts[0]] = excludeNodeParts[1]
} }
if len(f.ExcludeNamespaces.Value()) > 0 && len(f.IncludeNamespaces.Value()) > 0 {
return K8sOptions{}, fmt.Errorf("include-namespaces and exclude-namespaces flags cannot be used together")
}
if len(f.ExcludeKinds.Value()) > 0 && len(f.IncludeKinds.Value()) > 0 {
return K8sOptions{}, fmt.Errorf("include-kinds and exclude-kinds flags cannot be used together")
}
return K8sOptions{ return K8sOptions{
ClusterContext: f.ClusterContext.Value(),
Namespace: f.Namespace.Value(),
KubeConfig: f.KubeConfig.Value(), KubeConfig: f.KubeConfig.Value(),
Components: f.Components.Value(), Components: f.Components.Value(),
K8sVersion: f.K8sVersion.Value(), K8sVersion: f.K8sVersion.Value(),
Tolerations: tolerations, Tolerations: tolerations,
AllNamespaces: f.AllNamespaces.Value(),
NodeCollectorNamespace: f.NodeCollectorNamespace.Value(), NodeCollectorNamespace: f.NodeCollectorNamespace.Value(),
ExcludeOwned: f.ExcludeOwned.Value(), ExcludeOwned: f.ExcludeOwned.Value(),
ExcludeNodes: exludeNodeLabels, ExcludeNodes: exludeNodeLabels,
NodeCollectorImageRef: f.NodeCollectorImageRef.Value(), NodeCollectorImageRef: f.NodeCollectorImageRef.Value(),
QPS: float32(f.QPS.Value()), QPS: float32(f.QPS.Value()),
ExcludeKinds: f.ExcludeKinds.Value(),
IncludeKinds: f.IncludeKinds.Value(),
ExcludeNamespaces: f.ExcludeNamespaces.Value(),
IncludeNamespaces: f.IncludeNamespaces.Value(),
Burst: f.Burst.Value(), Burst: f.Burst.Value(),
}, nil }, nil
} }

View File

@@ -3,7 +3,6 @@ package commands
import ( import (
"context" "context"
"go.uber.org/zap"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@@ -16,9 +15,6 @@ import (
// clusterRun runs scan on kubernetes cluster // clusterRun runs scan on kubernetes cluster
func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) error { func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) error {
// TODO: replace with log.Logger
logger, _ := zap.NewProduction()
if err := validateReportArguments(opts); err != nil { if err := validateReportArguments(opts); err != nil {
return err return err
} }
@@ -26,13 +22,20 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err
var err error var err error
switch opts.Format { switch opts.Format {
case types.FormatCycloneDX: case types.FormatCycloneDX:
artifacts, err = trivyk8s.New(cluster, logger.Sugar()).ListClusterBomInfo(ctx) artifacts, err = trivyk8s.New(cluster).ListClusterBomInfo(ctx)
if err != nil { if err != nil {
return xerrors.Errorf("get k8s artifacts with node info error: %w", err) return xerrors.Errorf("get k8s artifacts with node info error: %w", err)
} }
case types.FormatJSON, types.FormatTable: case types.FormatJSON, types.FormatTable:
k8sOpts := []trivyk8s.K8sOption{
trivyk8s.WithExcludeNamespaces(opts.ExcludeNamespaces),
trivyk8s.WithIncludeNamespaces(opts.IncludeNamespaces),
trivyk8s.WithExcludeKinds(opts.ExcludeKinds),
trivyk8s.WithIncludeKinds(opts.IncludeKinds),
trivyk8s.WithExcludeOwned(opts.ExcludeOwned),
}
if opts.Scanners.AnyEnabled(types.MisconfigScanner) && slices.Contains(opts.Components, "infra") { if opts.Scanners.AnyEnabled(types.MisconfigScanner) && slices.Contains(opts.Components, "infra") {
artifacts, err = trivyk8s.New(cluster, logger.Sugar(), trivyk8s.WithExcludeOwned(opts.ExcludeOwned)).ListArtifactAndNodeInfo(ctx, artifacts, err = trivyk8s.New(cluster, k8sOpts...).ListArtifactAndNodeInfo(ctx,
trivyk8s.WithScanJobNamespace(opts.NodeCollectorNamespace), trivyk8s.WithScanJobNamespace(opts.NodeCollectorNamespace),
trivyk8s.WithIgnoreLabels(opts.ExcludeNodes), trivyk8s.WithIgnoreLabels(opts.ExcludeNodes),
trivyk8s.WithScanJobImageRef(opts.NodeCollectorImageRef), trivyk8s.WithScanJobImageRef(opts.NodeCollectorImageRef),
@@ -41,7 +44,7 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err
return xerrors.Errorf("get k8s artifacts with node info error: %w", err) return xerrors.Errorf("get k8s artifacts with node info error: %w", err)
} }
} else { } else {
artifacts, err = trivyk8s.New(cluster, logger.Sugar()).ListArtifacts(ctx) artifacts, err = trivyk8s.New(cluster, k8sOpts...).ListArtifacts(ctx)
if err != nil { if err != nil {
return xerrors.Errorf("get k8s artifacts error: %w", err) return xerrors.Errorf("get k8s artifacts error: %w", err)
} }

View File

@@ -1,44 +0,0 @@
package commands
import (
"context"
"go.uber.org/zap"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
"github.com/aquasecurity/trivy-kubernetes/pkg/trivyk8s"
"github.com/aquasecurity/trivy/pkg/flag"
)
// namespaceRun runs scan on kubernetes cluster
func namespaceRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) error {
// TODO: replace with slog.Logger
logger, _ := zap.NewProduction()
if err := validateReportArguments(opts); err != nil {
return err
}
var trivyk trivyk8s.TrivyK8S
if opts.AllNamespaces {
trivyk = trivyk8s.New(cluster, logger.Sugar()).AllNamespaces()
} else {
trivyk = trivyk8s.New(cluster, logger.Sugar()).Namespace(getNamespace(opts, cluster.GetCurrentNamespace()))
}
artifacts, err := trivyk.ListArtifacts(ctx)
if err != nil {
return xerrors.Errorf("get k8s artifacts error: %w", err)
}
runner := newRunner(opts, cluster.GetCurrentContext())
return runner.run(ctx, artifacts)
}
func getNamespace(opts flag.Options, currentNamespace string) string {
if opts.K8sOptions.Namespace != "" {
return opts.K8sOptions.Namespace
}
return currentNamespace
}

View File

@@ -1,47 +0,0 @@
package commands
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aquasecurity/trivy/pkg/flag"
)
func Test_getNamespace(t *testing.T) {
tests := []struct {
name string
currentNamespace string
opts flag.Options
want string
}{
{
name: "--namespace=custom",
currentNamespace: "default",
opts: flag.Options{
K8sOptions: flag.K8sOptions{
Namespace: "custom",
},
},
want: "custom",
},
{
name: "no namespaces passed",
currentNamespace: "default",
opts: flag.Options{
K8sOptions: flag.K8sOptions{
Namespace: "",
},
},
want: "default",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := getNamespace(test.opts, test.currentNamespace)
assert.Equal(t, test.want, got)
})
}
}

View File

@@ -1,73 +0,0 @@
package commands
import (
"context"
"strings"
"go.uber.org/zap"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
"github.com/aquasecurity/trivy-kubernetes/pkg/trivyk8s"
"github.com/aquasecurity/trivy/pkg/flag"
)
// resourceRun runs scan on kubernetes cluster
func resourceRun(ctx context.Context, args []string, opts flag.Options, cluster k8s.Cluster) error {
kind, name, err := extractKindAndName(args)
if err != nil {
return err
}
runner := newRunner(opts, cluster.GetCurrentContext())
var trivyk trivyk8s.TrivyK8S
// TODO: replace with slog.Logger
logger, _ := zap.NewProduction()
trivyk = trivyk8s.New(cluster, logger.Sugar(), trivyk8s.WithExcludeOwned(opts.ExcludeOwned))
if opts.AllNamespaces {
trivyk = trivyk.AllNamespaces()
} else {
trivyk = trivyk.Namespace(getNamespace(opts, cluster.GetCurrentNamespace()))
}
if name == "" { // pods or configmaps etc
if err = validateReportArguments(opts); err != nil {
return err
}
targets, err := trivyk.Resources(kind).ListArtifacts(ctx)
if err != nil {
return err
}
return runner.run(ctx, targets)
}
// pod/NAME or pod NAME etc
artifact, err := trivyk.GetArtifact(ctx, kind, name)
if err != nil {
return err
}
return runner.run(ctx, []*artifacts.Artifact{artifact})
}
func extractKindAndName(args []string) (string, string, error) {
switch len(args) {
case 1:
s := strings.Split(args[0], "/")
if len(s) != 2 {
return args[0], "", nil
}
return s[0], s[1], nil
case 2:
return args[0], args[1], nil
}
return "", "", xerrors.Errorf("can't parse arguments %v. Please run `trivy k8s` for usage.", args)
}

View File

@@ -1,61 +0,0 @@
package commands
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_extractKindAndName(t *testing.T) {
tests := []struct {
name string
args []string
expectedKind string
expectedName string
expectedError string
}{
{
name: "one argument only",
args: []string{"deploy"},
expectedKind: "deploy",
expectedName: "",
},
{
name: "one argument only, multiple targets",
args: []string{"deploy,configmaps"},
expectedKind: "deploy,configmaps",
expectedName: "",
},
{
name: "bar separated",
args: []string{"deploy/orion"},
expectedKind: "deploy",
expectedName: "orion",
},
{
name: "space separated",
args: []string{"deploy", "lua"},
expectedKind: "deploy",
expectedName: "lua",
},
{
name: "multiple arguments separated",
args: []string{"test", "test", "test"},
expectedError: "can't parse arguments [test test test]. Please run `trivy k8s` for usage.",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
kind, name, err := extractKindAndName(test.args)
if len(test.expectedError) > 0 {
assert.Error(t, err, test.expectedError)
return
}
assert.Equal(t, test.expectedKind, kind)
assert.Equal(t, test.expectedName, name)
})
}
}

View File

@@ -20,48 +20,30 @@ import (
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
) )
const (
clusterArtifact = "cluster"
allArtifact = "all"
)
// Run runs a k8s scan // Run runs a k8s scan
func Run(ctx context.Context, args []string, opts flag.Options) error { func Run(ctx context.Context, args []string, opts flag.Options) error {
ctx, cancel := context.WithTimeout(ctx, opts.Timeout) clusterOptions := []k8s.ClusterOption{
defer cancel()
ctx = log.WithContextPrefix(ctx, "k8s")
cluster, err := k8s.GetCluster(
k8s.WithContext(opts.K8sOptions.ClusterContext),
k8s.WithKubeConfig(opts.K8sOptions.KubeConfig), k8s.WithKubeConfig(opts.K8sOptions.KubeConfig),
k8s.WithBurst(opts.K8sOptions.Burst), k8s.WithBurst(opts.K8sOptions.Burst),
k8s.WithQPS(opts.K8sOptions.QPS), k8s.WithQPS(opts.K8sOptions.QPS),
) }
if len(args) > 0 {
clusterOptions = append(clusterOptions, k8s.WithContext(args[0]))
}
cluster, err := k8s.GetCluster(clusterOptions...)
if err != nil { if err != nil {
return xerrors.Errorf("failed getting k8s cluster: %w", err) return xerrors.Errorf("failed getting k8s cluster: %w", err)
} }
ctx, cancel := context.WithTimeout(ctx, opts.Timeout)
defer func() { defer func() {
cancel()
if errors.Is(err, context.DeadlineExceeded) { if errors.Is(err, context.DeadlineExceeded) {
log.Warn("Increase --timeout value") log.WarnContext(ctx, "Increase --timeout value")
} }
}() }()
opts.K8sVersion = cluster.GetClusterVersion() opts.K8sVersion = cluster.GetClusterVersion()
switch args[0] {
case clusterArtifact:
return clusterRun(ctx, opts, cluster) return clusterRun(ctx, opts, cluster)
case allArtifact:
if opts.Format == types.FormatCycloneDX {
return xerrors.Errorf("KBOM with CycloneDX format is not supported for all namespace scans")
}
return namespaceRun(ctx, opts, cluster)
default: // resourceArtifact
if opts.Format == types.FormatCycloneDX {
return xerrors.Errorf("KBOM with CycloneDX format is not supported for resource scans")
}
return resourceRun(ctx, args, opts, cluster)
}
} }
type runner struct { type runner struct {
@@ -71,8 +53,8 @@ type runner struct {
func newRunner(flagOpts flag.Options, cluster string) *runner { func newRunner(flagOpts flag.Options, cluster string) *runner {
return &runner{ return &runner{
flagOpts: flagOpts, flagOpts,
cluster: cluster, cluster,
} }
} }
@@ -86,7 +68,7 @@ func (r *runner) run(ctx context.Context, artifacts []*k8sArtifacts.Artifact) er
} }
defer func() { defer func() {
if err := runner.Close(ctx); err != nil { if err := runner.Close(ctx); err != nil {
log.ErrorContext(ctx, "Failed to close runner", log.Err(err)) log.ErrorContext(ctx, "failed to close runner: %s", err)
} }
}() }()