From 960921a0489533a3933d13a500719e82b8795369 Mon Sep 17 00:00:00 2001 From: Matheus Moraes Date: Mon, 11 Mar 2024 11:53:16 -0300 Subject: [PATCH] OpenShift support (#250) * set SSL_CERT_DIR environment variable for trivy * set a different cache directory for trivy * add insecure helm parameter for trivy * identify openshift as provider * add missing target _blank in doc links * don't set runAsUser and runAsGroup by default (just runAsNonRoot is enough) * docs: add page for private registries * bump trivy to 0.49.1 * bump Zora Helm chart version to 0.8.4-rc1 * rename doc page to Authenticated Registries --- charts/zora/Chart.yaml | 4 +-- charts/zora/README.md | 9 ++--- charts/zora/templates/plugins/trivy.yaml | 6 ++++ charts/zora/values.yaml | 7 ++-- .../samples/zora_v1alpha1_plugin_trivy.yaml | 5 ++- .../configuration/authenticated-registries.md | 33 +++++++++++++++++++ .../{ => private-registries}/acr.md | 4 +-- .../ecr.md} | 4 +-- docs/index.md | 4 +-- docs/plugins/index.md | 2 +- docs/plugins/trivy.md | 2 +- mkdocs.yml | 8 +++-- pkg/discovery/cluster_labels.go | 3 +- pkg/discovery/discovery.go | 2 +- pkg/discovery/discovery_test.go | 24 ++++++++++++++ 15 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 docs/configuration/authenticated-registries.md rename docs/configuration/{ => private-registries}/acr.md (94%) rename docs/configuration/{aws-elastic-container-registry.md => private-registries/ecr.md} (61%) diff --git a/charts/zora/Chart.yaml b/charts/zora/Chart.yaml index bea193f1..b3d8b7ee 100644 --- a/charts/zora/Chart.yaml +++ b/charts/zora/Chart.yaml @@ -17,7 +17,7 @@ name: zora description: A multi-plugin solution that reports misconfigurations and vulnerabilities by scanning your cluster at scheduled times. icon: https://zora-docs.undistro.io/v0.7/assets/logo.svg type: application -version: 0.8.3 -appVersion: "v0.8.3" +version: 0.8.4-rc1 +appVersion: "v0.8.4-rc1" sources: - https://github.com/undistro/zora diff --git a/charts/zora/README.md b/charts/zora/README.md index 4a8d43bc..623d252e 100644 --- a/charts/zora/README.md +++ b/charts/zora/README.md @@ -1,6 +1,6 @@ # Zora Helm Chart -![Version: 0.8.3](https://img.shields.io/badge/Version-0.8.3-informational?style=flat-square&color=3CA9DD) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square&color=3CA9DD) ![AppVersion: v0.8.3](https://img.shields.io/badge/AppVersion-v0.8.3-informational?style=flat-square&color=3CA9DD) +![Version: 0.8.4-rc1](https://img.shields.io/badge/Version-0.8.4--rc1-informational?style=flat-square&color=3CA9DD) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square&color=3CA9DD) ![AppVersion: v0.8.4-rc1](https://img.shields.io/badge/AppVersion-v0.8.4--rc1-informational?style=flat-square&color=3CA9DD) A multi-plugin solution that reports misconfigurations and vulnerabilities by scanning your cluster at scheduled times. @@ -13,7 +13,7 @@ helm repo add undistro https://charts.undistro.io --force-update helm repo update undistro helm upgrade --install zora undistro/zora \ -n zora-system \ - --version 0.8.3 \ + --version 0.8.4-rc1 \ --create-namespace \ --wait \ --set clusterName="$(kubectl config current-context)" @@ -75,7 +75,7 @@ The following table lists the configurable parameters of the Zora chart and thei | operator.rbac.serviceAccount.annotations | object | `{}` | Annotations to be added to service account | | operator.rbac.serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | | operator.podAnnotations | object | `{"kubectl.kubernetes.io/default-container":"manager"}` | Annotations to be added to pods | -| operator.podSecurityContext | object | `{"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532}` | [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context) to add to the pod | +| operator.podSecurityContext | object | `{"runAsNonRoot":true}` | [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context) to add to the pod | | operator.securityContext | object | `{"allowPrivilegeEscalation":false,"readOnlyRootFilesystem":true}` | [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context) to add to `manager` container | | operator.metricsService.type | string | `"ClusterIP"` | Type of metrics service | | operator.metricsService.port | int | `8443` | Port of metrics service | @@ -115,10 +115,11 @@ The following table lists the configurable parameters of the Zora chart and thei | scan.plugins.trivy.resources | object | `{}` | [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `trivy` container | | scan.plugins.trivy.podAnnotations | object | `{}` | Annotations added to the trivy pods | | scan.plugins.trivy.image.repository | string | `"ghcr.io/aquasecurity/trivy"` | trivy plugin image repository | -| scan.plugins.trivy.image.tag | string | `"0.48.2"` | trivy plugin image tag | +| scan.plugins.trivy.image.tag | string | `"0.49.1"` | trivy plugin image tag | | scan.plugins.trivy.env | list | `[]` | List of environment variables to set in trivy container. | | scan.plugins.trivy.envFrom | list | `[]` | List of sources to populate environment variables in trivy container. | | scan.plugins.trivy.timeout | string | `"10m"` | Trivy timeout | +| scan.plugins.trivy.insecure | bool | `false` | Allow insecure server connections for Trivy | | scan.plugins.popeye.skipInternalResources | bool | `false` | Specifies whether the following resources should be skipped by `popeye` scans. 1. resources from `kube-system`, `kube-public` and `kube-node-lease` namespaces; 2. kubernetes system reserved RBAC (prefixed with `system:`); 3. `kube-root-ca.crt` configmaps; 4. `default` namespace; 5. `default` serviceaccounts; 6. Helm secrets (prefixed with `sh.helm.release`); 7. Zora components. See `popeye` configuration file that is used for this case: https://github.com/undistro/zora/blob/main/charts/zora/templates/plugins/popeye-config.yaml | | scan.plugins.popeye.resources | object | `{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `popeye` container | | scan.plugins.popeye.podAnnotations | object | `{}` | Annotations added to the popeye pods | diff --git a/charts/zora/templates/plugins/trivy.yaml b/charts/zora/templates/plugins/trivy.yaml index 22dd5800..c3082359 100644 --- a/charts/zora/templates/plugins/trivy.yaml +++ b/charts/zora/templates/plugins/trivy.yaml @@ -35,6 +35,8 @@ spec: env: - name: TRIVY_IGNORE_VULN_DESCRIPTIONS value: {{ .Values.scan.plugins.trivy.ignoreDescriptions | quote }} + - name: SSL_CERT_DIR + value: "/etc/ssl/:/run/secrets/kubernetes.io/serviceaccount/" {{- with .Values.scan.plugins.trivy.env }} {{- toYaml . | nindent 4 }} {{- end }} @@ -58,6 +60,10 @@ spec: --all-namespaces \ --scanners=vuln \ -f=json \ + --cache-dir=/tmp/trivy-cache \ + {{- if .Values.scan.plugins.trivy.insecure }} + --insecure \ + {{- end }} {{- if .Values.scan.plugins.trivy.ignoreUnfixed }} --ignore-unfixed \ {{- end }} diff --git a/charts/zora/values.yaml b/charts/zora/values.yaml index 338d0441..479ec920 100644 --- a/charts/zora/values.yaml +++ b/charts/zora/values.yaml @@ -82,8 +82,6 @@ operator: # -- [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context) to add to the pod podSecurityContext: runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 # -- [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context) to add to `manager` container securityContext: allowPrivilegeEscalation: false @@ -211,7 +209,7 @@ scan: # -- trivy plugin image repository repository: ghcr.io/aquasecurity/trivy # -- trivy plugin image tag - tag: 0.48.2 + tag: 0.49.1 # -- List of environment variables to set in trivy container. env: [] # - name: AWS_REGION @@ -228,6 +226,9 @@ scan: # name: trivy-credentials # -- Trivy timeout timeout: 10m + # -- Allow insecure server connections for Trivy + insecure: false + popeye: # -- Specifies whether the following resources should be skipped by `popeye` scans. # 1. resources from `kube-system`, `kube-public` and `kube-node-lease` namespaces; diff --git a/config/samples/zora_v1alpha1_plugin_trivy.yaml b/config/samples/zora_v1alpha1_plugin_trivy.yaml index 6c392499..7f426ed7 100644 --- a/config/samples/zora_v1alpha1_plugin_trivy.yaml +++ b/config/samples/zora_v1alpha1_plugin_trivy.yaml @@ -10,12 +10,14 @@ metadata: name: trivy spec: type: vulnerability - image: ghcr.io/aquasecurity/trivy:0.48.2 + image: ghcr.io/aquasecurity/trivy:0.49.1 securityContext: allowPrivilegeEscalation: false env: - name: TRIVY_IGNORE_VULN_DESCRIPTIONS value: "false" + - name: SSL_CERT_DIR + value: "/etc/ssl/:/run/secrets/kubernetes.io/serviceaccount/" command: - /bin/sh - -c @@ -26,6 +28,7 @@ spec: --all-namespaces \ --scanners=vuln \ -f=json \ + --cache-dir=/tmp/trivy-cache \ -o $(DONE_DIR)/results.json \ cluster diff --git a/docs/configuration/authenticated-registries.md b/docs/configuration/authenticated-registries.md new file mode 100644 index 00000000..5ca66c93 --- /dev/null +++ b/docs/configuration/authenticated-registries.md @@ -0,0 +1,33 @@ +# Authenticated Registries + +Trivy plugin is able to scan images from registries that require authentication. + +It's necessary to create a secret containing authentication credentials as pairs, like the command below. + +!!! note + For [AWS ECR](private-registries/ecr.md) and [Azure ACR](private-registries/acr.md) registries, please refer to the specific pages. + +```shell +kubectl create secret generic trivy-credentials -n zora-system \ + --from-literal=TRIVY_USERNAME="," \ + --from-literal=TRIVY_PASSWORD="," +``` + +!!! note + Please note that the number of usernames and passwords must be the same. + +Once the secret is created, it needs to be referenced in the Helm chart parameters as the following `values.yaml` file: + +```yaml hl_lines="6" +scan: + plugins: + trivy: + envFrom: + - secretRef: + name: trivy-credentials + optional: true +``` + +Then provide this file in `helm upgrade --install` command with `-f values.yaml` flag. + +This ensures that Trivy can authenticate with the private registries using the provided credentials. diff --git a/docs/configuration/acr.md b/docs/configuration/private-registries/acr.md similarity index 94% rename from docs/configuration/acr.md rename to docs/configuration/private-registries/acr.md index 59e20e12..d00c1064 100644 --- a/docs/configuration/acr.md +++ b/docs/configuration/private-registries/acr.md @@ -1,12 +1,12 @@ # Azure Container Registry (ACR) -If you are running within Azure, and making use of a private [Azure Container Registry (ACR)](https://learn.microsoft.com/en-us/azure/container-registry/) +If you are running within Azure, and making use of a private [Azure Container Registry (ACR)](https://learn.microsoft.com/en-us/azure/container-registry/){:target="_blank"} to host your application images, then the Trivy plugin will be unable to scan those images unless access is granted to the registry through a service principal with `AcrPull` role assigned. ## Creating service principal -The following [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/) command creates a service principal +The following [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/){:target="_blank"} command creates a service principal with `AcrPull` role assigned, and stores the output including the credentials into `SP_DATA` environment variable. !!! note diff --git a/docs/configuration/aws-elastic-container-registry.md b/docs/configuration/private-registries/ecr.md similarity index 61% rename from docs/configuration/aws-elastic-container-registry.md rename to docs/configuration/private-registries/ecr.md index 7b753d95..2969b207 100644 --- a/docs/configuration/aws-elastic-container-registry.md +++ b/docs/configuration/private-registries/ecr.md @@ -1,6 +1,6 @@ -# AWS Elastic Container Registry +# AWS Elastic Container Registry (ECR) -If you are running within AWS, and making use of a private [Elastic Container Registry (ECR)](https://aws.amazon.com/ecr/) to host your application images, then the Trivy plugin will be unable to scan those images unless access is granted to the registry through an [Identity and Access Managemnent (IAM)](https://aws.amazon.com/iam/) role assigned to the service account running the Trivy plugins. +If you are running within AWS, and making use of a private [Elastic Container Registry (ECR)](https://aws.amazon.com/ecr/){:target="_blank"} to host your application images, then the Trivy plugin will be unable to scan those images unless access is granted to the registry through an [Identity and Access Managemnent (IAM)](https://aws.amazon.com/iam/){:target="_blank"} role assigned to the service account running the Trivy plugins. Once an IAM role granting access to the ECR has been created, this can be assigned to the service account by including the following additional parameter when running the `helm upgrade --install` command. diff --git a/docs/index.md b/docs/index.md index f99c784b..33d10dfa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -40,7 +40,7 @@ and [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-se #### :octicons-sliders-16: Custom checks Enabled by the [Marvin](https://github.com/undistro/marvin){:target="_blank"} plugin, Zora offers a declarative way to create your own -checks by using [CEL](https://github.com/google/cel-spec){:target="_blank"} expressions to define validation rules. +checks by using [Common Expression Language (CEL)](https://github.com/google/cel-spec){:target="_blank"} expressions to define validation rules. #### :simple-kubernetes: Kubernetes-native @@ -71,7 +71,7 @@ The origin of the name Borg refers to the cybernetic life form existing in the S that worked as a collective of individuals with a single mind and the same purpose, as well as a "[cluster](https://pt.wikipedia.org/wiki/Cluster){:target="_blank"}". As good nerds as we are and wishing to honor our Kubernetes' -[predecessor](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/) (Borg) we named our project +[predecessor](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/){:target="_blank"} (Borg) we named our project Zora. In Star Trek, Zora is the Artificial Intelligence that controls the ship U.S.S Discovery. diff --git a/docs/plugins/index.md b/docs/plugins/index.md index 5bde7f65..107654c8 100644 --- a/docs/plugins/index.md +++ b/docs/plugins/index.md @@ -17,7 +17,7 @@ kubectl get plugins -n zora-system NAME IMAGE TYPE AGE marvin ghcr.io/undistro/marvin:v0.2.1 misconfiguration 14m popeye ghcr.io/undistro/popeye:v0.11.3 misconfiguration 14m -trivy ghcr.io/aquasecurity/trivy:0.48.2 vulnerability 14m +trivy ghcr.io/aquasecurity/trivy:0.49.1 vulnerability 14m ``` Each item listed above is an instance of `Plugin` CRD and represents the execution configuration of a plugin. diff --git a/docs/plugins/trivy.md b/docs/plugins/trivy.md index 880d23d0..5a69177a 100644 --- a/docs/plugins/trivy.md +++ b/docs/plugins/trivy.md @@ -11,7 +11,7 @@ in different targets like containers, code repositories and **Kubernetes cluster :octicons-codescan-24: **Type**: `vulnerability` -:simple-docker: **Image**: `ghcr.io/aquasecurity/trivy:0.48.2` +:simple-docker: **Image**: `ghcr.io/aquasecurity/trivy:0.49.1` :simple-github: **GitHub repository**: [https://github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy){:target="_blank"} diff --git a/mkdocs.yml b/mkdocs.yml index f256c690..80c93e9a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -86,11 +86,13 @@ nav: - Compute resources: configuration/resources.md - Suspending scans: configuration/suspend-scan.md - Retain issues: configuration/retain-issues.md + - HTTPS proxy: configuration/https-proxy.md - Ignore unfixed vulnerabilities: plugins/trivy/#large-vulnerability-reports - - HTTPS Proxy: configuration/https-proxy.md - - Scanning Images hosted in AWS ECR: configuration/aws-elastic-container-registry.md - - Scanning Images hosted in Azure ACR: configuration/acr.md - Vulnerability scan timeout: plugins/trivy/#scan-timeout + - Authenticated registries: configuration/authenticated-registries.md + - Private registries: + - AWS ECR: configuration/private-registries/ecr.md + - Azure ACR: configuration/private-registries/acr.md - "🔌 Plugins": - Overview: plugins/index.md - Misconfiguration: diff --git a/pkg/discovery/cluster_labels.go b/pkg/discovery/cluster_labels.go index 4285e723..9bd6dfd0 100644 --- a/pkg/discovery/cluster_labels.go +++ b/pkg/discovery/cluster_labels.go @@ -18,10 +18,11 @@ const ( RegionLabel = "topology.kubernetes.io/region" ) -var ClusterSourcePrefixes = map[string]string{ +var providerPrefixes = map[string]string{ "cloud.google.com/gke": "gcp", "eks.amazonaws.com/": "aws", "kubernetes.azure.com/": "azure", "doks.digitalocean.com/": "digitalocean", "oke.oraclecloud.com/": "oraclecloud", + "node.openshift.io/": "openshift", } diff --git a/pkg/discovery/discovery.go b/pkg/discovery/discovery.go index c4d43e19..26cb255b 100644 --- a/pkg/discovery/discovery.go +++ b/pkg/discovery/discovery.go @@ -85,7 +85,7 @@ func (r *clusterDiscovery) Resources(ctx context.Context) (ClusterResources, err func (r *clusterDiscovery) provider(nodes []corev1.Node) string { for _, node := range nodes { for l := range node.Labels { - for pref, p := range ClusterSourcePrefixes { + for pref, p := range providerPrefixes { if strings.HasPrefix(l, pref) { return p } diff --git a/pkg/discovery/discovery_test.go b/pkg/discovery/discovery_test.go index 8bb14b63..9695ec38 100644 --- a/pkg/discovery/discovery_test.go +++ b/pkg/discovery/discovery_test.go @@ -384,6 +384,30 @@ func TestProvider(t *testing.T) { }}}, want: "oraclecloud", }, + { + name: "openshift", + args: args{[]corev1.Node{{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/instance-type": "m5.xlarge", + "beta.kubernetes.io/os": "linux", + "failure-domain.beta.kubernetes.io/region": "us-east-1", + "failure-domain.beta.kubernetes.io/zone": "us-east-1a", + "kubernetes.io/arch": "amd64", + "kubernetes.io/hostname": "ip-10-0-41-28.ec2.internal", + "kubernetes.io/os": "linux", + "node-role.kubernetes.io/worker": "", + "node.kubernetes.io/instance-type": "m5.xlarge", + "node.openshift.io/os_id": "rhcos", + "topology.ebs.csi.aws.com/zone": "us-east-1a", + "topology.kubernetes.io/region": "us-east-1", + "topology.kubernetes.io/zone": "us-east-1a", + }, + }, + }}}, + want: "openshift", + }, { name: "kind", args: args{[]corev1.Node{{