diff --git a/documentation/docs/getting-started/upgrading.md b/documentation/docs/getting-started/upgrading.md index 327a82babf..0d74ee91c3 100644 --- a/documentation/docs/getting-started/upgrading.md +++ b/documentation/docs/getting-started/upgrading.md @@ -26,6 +26,13 @@ If you maintain a custom deployment that directly references `manager-role` or ` ➡️ [Reference: #3002](https://github.com/secureCodeBox/secureCodeBox/pull/3002) +### Changes to trivy k8s scope (namespace / cluster) + +The `kubeauditScope` on the `trivy` ScanType chart was renamed to `k8sScanScope` Scope. The previous name was used for consistency with the `kubeaudit` ScanType, but it never really made sense and was confusing. +The default `k8sScanScope` scope was also changed from `cluster` to `namespace`, The cluster mode needs cluster wide permissions, which makes the trivy chart hard to install in properly locked down RBAC setups. + +➡️ [Reference: #3025](https://github.com/secureCodeBox/secureCodeBox/pull/3025) + ## From 3.X to 4.X ### Renamed the docker images of demo-targets to include a "demo-target-" prefix diff --git a/scanners/trivy/Makefile b/scanners/trivy/Makefile index 2eb284ee54..89985fe040 100644 --- a/scanners/trivy/Makefile +++ b/scanners/trivy/Makefile @@ -9,3 +9,13 @@ include_guard = set scanner = trivy include ../../scanners.mk + +.PHONY: deploy-without-scanner +deploy-without-scanner: + @echo ".: 💾 Deploying '$(name)' $(scanner-prefix) HelmChart with the docker tag '$(IMG_TAG)' into kind namespace 'integration-tests'." + helm -n integration-tests upgrade --install $(name) ./ --wait \ + --set="parser.image.repository=docker.io/$(IMG_NS)/$(parser-prefix)-$(name)" \ + --set="parser.image.tag=$(IMG_TAG)" \ + --set="parser.env[0].name=CRASH_ON_FAILED_VALIDATION" \ + --set-string="parser.env[0].value=true" \ + --set="k8sScanScope=cluster" \ No newline at end of file diff --git a/scanners/trivy/README.md b/scanners/trivy/README.md index 7e0b756010..9831462612 100644 --- a/scanners/trivy/README.md +++ b/scanners/trivy/README.md @@ -133,7 +133,7 @@ Kubernetes: `>=v1.11.0-0` | cascadingRules.enabled | bool | `false` | Enables or disables the installation of the default cascading rules for this scanner | | createAutoDiscoveryScanType | bool | `false` | Creates a `trivy-image-autodiscovery` scanType with its own ServiceAccount for the SCB AutoDiscovery, enabled to scan images from both public & private registries. | | imagePullSecrets | list | `[]` | Define imagePullSecrets when a private registry is used (see: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) | -| kubeauditScope | string | `"cluster"` | Automatically sets up rbac roles for kubeaudit to access the resources it scans. Can be either "cluster" (ClusterRole) or "namespace" (Role) | +| k8sScanScope | string | `"cluster"` | Automatically sets up rbac roles for trivy to access the resources it scans. Can be either "cluster" (ClusterRole) or "namespace" (Role) | | parser.affinity | object | `{}` | Optional affinity settings that control how the parser job is scheduled (see: https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | | parser.env | list | `[]` | Optional environment variables mapped into each parseJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) | | parser.image.pullPolicy | string | `"IfNotPresent"` | Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images | diff --git a/scanners/trivy/docs/README.ArtifactHub.md b/scanners/trivy/docs/README.ArtifactHub.md index fb5b92c202..2a27261e21 100644 --- a/scanners/trivy/docs/README.ArtifactHub.md +++ b/scanners/trivy/docs/README.ArtifactHub.md @@ -140,7 +140,7 @@ Kubernetes: `>=v1.11.0-0` | cascadingRules.enabled | bool | `false` | Enables or disables the installation of the default cascading rules for this scanner | | createAutoDiscoveryScanType | bool | `false` | Creates a `trivy-image-autodiscovery` scanType with its own ServiceAccount for the SCB AutoDiscovery, enabled to scan images from both public & private registries. | | imagePullSecrets | list | `[]` | Define imagePullSecrets when a private registry is used (see: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) | -| kubeauditScope | string | `"cluster"` | Automatically sets up rbac roles for kubeaudit to access the resources it scans. Can be either "cluster" (ClusterRole) or "namespace" (Role) | +| k8sScanScope | string | `"cluster"` | Automatically sets up rbac roles for trivy to access the resources it scans. Can be either "cluster" (ClusterRole) or "namespace" (Role) | | parser.affinity | object | `{}` | Optional affinity settings that control how the parser job is scheduled (see: https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/) | | parser.env | list | `[]` | Optional environment variables mapped into each parseJob (see: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) | | parser.image.pullPolicy | string | `"IfNotPresent"` | Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images | diff --git a/scanners/trivy/examples/k8s-cluster/README.md b/scanners/trivy/examples/k8s-cluster/README.md new file mode 100644 index 0000000000..58058ce3b3 --- /dev/null +++ b/scanners/trivy/examples/k8s-cluster/README.md @@ -0,0 +1,13 @@ + + +This example shows how to use the `trivy k8s` scan with the secureCodeBox to scan an entire cluster with trivy. + +Note: To scan the entire cluster you need to set the `k8sScanScope=cluster` for the trivy ScanType, otherwise the scanner doesn't have sufficient RBAC permissions to access all resources. + +```bash +helm upgrade --install trivy oci://ghcr.io/securecodebox/helm/trivy --set="k8sScanScope=cluster" +``` diff --git a/scanners/trivy/examples/k8s-cluster/scan.yaml b/scanners/trivy/examples/k8s-cluster/scan.yaml new file mode 100644 index 0000000000..ebe21884c4 --- /dev/null +++ b/scanners/trivy/examples/k8s-cluster/scan.yaml @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: the secureCodeBox authors +# +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: "execution.securecodebox.io/v1" +kind: Scan +metadata: + name: "trivy-k8s" +spec: + scanType: "trivy-k8s" + parameters: [] # to can the entire cluster you need no parameters diff --git a/scanners/trivy/examples/k8s/README.md b/scanners/trivy/examples/k8s-namespace/README.md similarity index 80% rename from scanners/trivy/examples/k8s/README.md rename to scanners/trivy/examples/k8s-namespace/README.md index eeea8e97dd..27423366eb 100644 --- a/scanners/trivy/examples/k8s/README.md +++ b/scanners/trivy/examples/k8s-namespace/README.md @@ -4,4 +4,4 @@ SPDX-FileCopyrightText: the secureCodeBox authors SPDX-License-Identifier: Apache-2.0 --> -This example shows how to use the `trivy k8s` scan with the secureCodeBox. +This example shows how to use the `trivy k8s` scan with the secureCodeBox to scan a single namespace. diff --git a/scanners/trivy/examples/k8s/scan.yaml b/scanners/trivy/examples/k8s-namespace/scan.yaml similarity index 77% rename from scanners/trivy/examples/k8s/scan.yaml rename to scanners/trivy/examples/k8s-namespace/scan.yaml index e9824a7f80..efb60c9cfd 100644 --- a/scanners/trivy/examples/k8s/scan.yaml +++ b/scanners/trivy/examples/k8s-namespace/scan.yaml @@ -9,4 +9,5 @@ metadata: spec: scanType: "trivy-k8s" parameters: - - "cluster" + - "--include-namespaces" + - default # can be any namespace diff --git a/scanners/trivy/templates/trivy-rbac.yaml b/scanners/trivy/templates/trivy-rbac.yaml index 87e663aa06..f49c15b361 100644 --- a/scanners/trivy/templates/trivy-rbac.yaml +++ b/scanners/trivy/templates/trivy-rbac.yaml @@ -70,7 +70,7 @@ roleRef: kind: Role name: lurker --- - {{- if eq .Values.kubeauditScope "namespace" }} +{{- if eq .Values.k8sScanScope "namespace" }} kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -82,7 +82,11 @@ rules: - pods - podtemplates - replicationcontrollers - - namespaces + - serviceaccounts + - services + - configmaps + - resourcequotas + - limitranges verbs: ["get", "list"] - apiGroups: ["apps"] resources: @@ -90,12 +94,19 @@ rules: - statefulsets - deployments verbs: ["get", "list"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: + - rolebindings + - roles + verbs: ["get", "list"] - apiGroups: ["batch"] resources: + - jobs - cronjobs verbs: ["get", "list"] - - apiGroups: ["networking"] + - apiGroups: ["networking.k8s.io"] resources: + - ingresses - networkpolicies verbs: ["get", "list"] --- @@ -112,8 +123,8 @@ roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: trivy-k8s - {{- end }} - {{- if eq .Values.kubeauditScope "cluster" }} +{{- end }} +{{- if eq .Values.k8sScanScope "cluster" }} kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -121,10 +132,15 @@ metadata: rules: - apiGroups: [""] resources: + - namespaces - pods - podtemplates - replicationcontrollers - - namespaces + - serviceaccounts + - services + - configmaps + - resourcequotas + - limitranges verbs: ["get", "list"] - apiGroups: ["apps"] resources: @@ -132,13 +148,20 @@ rules: - statefulsets - deployments verbs: ["get", "list"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: + - rolebindings + - roles + verbs: ["get", "list"] - apiGroups: ["batch"] resources: + - jobs - cronjobs verbs: ["get", "list"] - - apiGroups: ["networking"] + - apiGroups: ["networking.k8s.io"] resources: - networkpolicies + - ingresses verbs: ["get", "list"] --- kind: ClusterRoleBinding @@ -153,4 +176,4 @@ roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin - {{- end }} +{{- end }} diff --git a/scanners/trivy/tests/__snapshot__/scanner_test.yaml.snap b/scanners/trivy/tests/__snapshot__/scanner_test.yaml.snap index 6cccc2d109..79eb4605cd 100644 --- a/scanners/trivy/tests/__snapshot__/scanner_test.yaml.snap +++ b/scanners/trivy/tests/__snapshot__/scanner_test.yaml.snap @@ -107,9 +107,10 @@ matches the snapshot: namespace: NAMESPACE 6: | apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole + kind: Role metadata: name: trivy-k8s + namespace: NAMESPACE rules: - apiGroups: - "" @@ -117,7 +118,11 @@ matches the snapshot: - pods - podtemplates - replicationcontrollers - - namespaces + - serviceaccounts + - services + - configmaps + - resourcequotas + - limitranges verbs: - get - list @@ -130,29 +135,40 @@ matches the snapshot: verbs: - get - list + - apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + - roles + verbs: + - get + - list - apiGroups: - batch resources: + - jobs - cronjobs verbs: - get - list - apiGroups: - - networking + - networking.k8s.io resources: + - ingresses - networkpolicies verbs: - get - list 7: | apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding + kind: RoleBinding metadata: name: trivy-k8s + namespace: NAMESPACE roleRef: apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin + kind: Role + name: trivy-k8s subjects: - kind: ServiceAccount name: trivy-k8s @@ -370,3 +386,342 @@ matches the snapshot: tolerations: - foo: bar volumes: [] +works properly in k8sScanScope=cluster: + 1: | + apiVersion: v1 + kind: Service + metadata: + labels: + app: trivy-database + name: trivy-database + spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: trivy-database + type: ClusterIP + 2: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app: trivy-database + name: trivy-database + spec: + replicas: 1 + selector: + matchLabels: + app: trivy-database + template: + metadata: + labels: + app: trivy-database + spec: + containers: + - args: + - server + - --listen + - 0.0.0.0:8080 + image: docker.io/aquasec/trivy:0.0.0 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 10 + httpGet: + path: /healthz + port: trivy-http + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + name: trivy-database + ports: + - containerPort: 8080 + name: trivy-http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: trivy-http + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + 3: | + apiVersion: execution.securecodebox.io/v1 + kind: ParseDefinition + metadata: + name: trivy-json + spec: + affinity: {} + env: [] + image: docker.io/securecodebox/parser-trivy:0.0.0 + imagePullPolicy: IfNotPresent + scopeLimiterAliases: {} + tolerations: [] + ttlSecondsAfterFinished: null + 4: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: trivy-k8s + namespace: NAMESPACE + 5: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: trivy-k8s-lurker + namespace: NAMESPACE + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: lurker + subjects: + - kind: ServiceAccount + name: trivy-k8s + namespace: NAMESPACE + 6: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: trivy-k8s + rules: + - apiGroups: + - "" + resources: + - namespaces + - pods + - podtemplates + - replicationcontrollers + - serviceaccounts + - services + - configmaps + - resourcequotas + - limitranges + verbs: + - get + - list + - apiGroups: + - apps + resources: + - daemonsets + - statefulsets + - deployments + verbs: + - get + - list + - apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + - roles + verbs: + - get + - list + - apiGroups: + - batch + resources: + - jobs + - cronjobs + verbs: + - get + - list + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + - ingresses + verbs: + - get + - list + 7: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: trivy-k8s + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin + subjects: + - kind: ServiceAccount + name: trivy-k8s + namespace: NAMESPACE + 8: | + apiVersion: execution.securecodebox.io/v1 + kind: ScanType + metadata: + name: trivy-image + spec: + extractResults: + location: /home/securecodebox/trivy-results.json + type: trivy-json + jobTemplate: + spec: + backoffLimit: 3 + template: + spec: + affinity: {} + containers: + - command: + - trivy + - image + - --no-progress + - --server + - http://trivy-database.NAMESPACE.svc:8080 + - --format + - json + - --output + - /home/securecodebox/trivy-results.json + env: [] + image: docker.io/aquasec/trivy:0.0.0 + imagePullPolicy: IfNotPresent + name: trivy + resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: false + volumeMounts: [] + restartPolicy: OnFailure + securityContext: {} + tolerations: [] + volumes: [] + 9: | + apiVersion: execution.securecodebox.io/v1 + kind: ScanType + metadata: + name: trivy-filesystem + spec: + extractResults: + location: /home/securecodebox/trivy-results.json + type: trivy-json + jobTemplate: + spec: + backoffLimit: 3 + suspend: false + template: + spec: + affinity: {} + containers: + - command: + - trivy + - filesystem + - --no-progress + - --server + - http://trivy-database.NAMESPACE.svc:8080 + - --format + - json + - --output + - /home/securecodebox/trivy-results.json + env: [] + image: docker.io/aquasec/trivy:0.0.0 + imagePullPolicy: IfNotPresent + name: trivy + resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: false + volumeMounts: [] + restartPolicy: OnFailure + tolerations: [] + volumes: [] + 10: | + apiVersion: execution.securecodebox.io/v1 + kind: ScanType + metadata: + name: trivy-repo + spec: + extractResults: + location: /home/securecodebox/trivy-results.json + type: trivy-json + jobTemplate: + spec: + backoffLimit: 3 + suspend: false + template: + spec: + affinity: {} + containers: + - command: + - trivy + - repo + - --no-progress + - --server + - http://trivy-database.NAMESPACE.svc:8080 + - --format + - json + - --output + - /home/securecodebox/trivy-results.json + env: [] + image: docker.io/aquasec/trivy:0.0.0 + imagePullPolicy: IfNotPresent + name: trivy + resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: false + volumeMounts: [] + restartPolicy: OnFailure + tolerations: [] + volumes: [] + 11: | + apiVersion: execution.securecodebox.io/v1 + kind: ScanType + metadata: + name: trivy-k8s + spec: + extractResults: + location: /home/securecodebox/trivy-results.json + type: trivy-json + jobTemplate: + spec: + backoffLimit: 3 + template: + spec: + affinity: {} + containers: + - command: + - trivy + - k8s + - --no-progress + - --format + - json + - --report + - all + - --output + - /home/securecodebox/trivy-results.json + env: [] + image: docker.io/aquasec/trivy:0.0.0 + imagePullPolicy: IfNotPresent + name: trivy + resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: false + volumeMounts: [] + restartPolicy: OnFailure + serviceAccountName: trivy-k8s + tolerations: [] + volumes: [] diff --git a/scanners/trivy/tests/scanner_test.yaml b/scanners/trivy/tests/scanner_test.yaml index c5b3b49c3a..a95464c242 100644 --- a/scanners/trivy/tests/scanner_test.yaml +++ b/scanners/trivy/tests/scanner_test.yaml @@ -8,7 +8,7 @@ tests: - it: matches the snapshot chart: version: 0.0.0 - appVersion: 0.0.0 + appVersion: 0.0.0 set: cascadingRules.enabled: true imagePullSecrets: [{name: foo}] @@ -28,3 +28,11 @@ tests: tolerations: [{foo: bar}] asserts: - matchSnapshot: {} + - it: works properly in k8sScanScope=cluster + chart: + version: 0.0.0 + appVersion: 0.0.0 + set: + k8sScanScope: cluster + asserts: + - matchSnapshot: {} diff --git a/scanners/trivy/values.yaml b/scanners/trivy/values.yaml index 1afbf80af0..806e62fc41 100644 --- a/scanners/trivy/values.yaml +++ b/scanners/trivy/values.yaml @@ -109,8 +109,8 @@ scanner: # -- if set to true the scan job will be suspended after creation. You can then resume the job using `kubectl resume ` or using a job scheduler like kueue suspend: false -# kubeauditScope -- Automatically sets up rbac roles for kubeaudit to access the resources it scans. Can be either "cluster" (ClusterRole) or "namespace" (Role) -kubeauditScope: "cluster" +# -- Automatically sets up rbac roles for trivy to access the resources it scans. Can be either "cluster" (ClusterRole) or "namespace" (Role) +k8sScanScope: "namespace" trivyDatabaseCache: # -- Enables or disables the use of trivy server in another pod to cache the vulnerability database for all scans.