Trivy can scan Helm charts for misconfigurations before you deploy them, saving you from chasing down runtime errors.
Let’s see Trivy in action. Imagine you have a Helm chart for a simple Nginx deployment.
# nginx-chart/Chart.yaml
apiVersion: v2
name: nginx
version: 0.1.0
description: A simple Nginx chart
# nginx-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
This chart is pretty basic, but it’s a good starting point. Now, let’s scan it with Trivy.
trivy config ./nginx-chart
Trivy will output something like this, pointing out potential issues:
nginx-chart/templates/deployment.yaml
[WARN] Container "nginx" is using the "latest" tag.
[INFO] Container "nginx" is running as root user.
This tells us two things:
- We’re using the
latesttag for the Nginx image. This is bad becauselatestcan change unexpectedly, leading to unreproducible deployments or even breaking changes. - The Nginx container is running as the root user. This is a security risk, as it gives the process elevated privileges within the container.
Trivy’s config command works by parsing the Helm chart’s Chart.yaml and all files within the templates/ directory. It then analyzes the Kubernetes manifest files generated by Helm before they are rendered. It’s not actually rendering the chart with helm template; instead, it understands the structure and common patterns of Kubernetes YAML and Helm templating language to identify potential issues. It looks for known insecure configurations, best practice violations, and potential security vulnerabilities that can be introduced at the configuration level.
The core problem Trivy solves here is shifting security and configuration checks "left," meaning earlier in the development lifecycle. Instead of discovering that your deployment is insecure after it’s running in production, you catch it when you’re writing the Helm chart. This is significantly cheaper and less disruptive.
To fix the issues Trivy found:
First, pin the image tag to a specific, known version. It’s best practice to use a specific version, not latest. For example, nginx:1.23.3.
# nginx-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.3 # Changed from nginx:latest
ports:
- containerPort: 80
Second, configure the container to run as a non-root user. You can do this by adding a securityContext to the container definition. Nginx can be configured to run as a specific user, often nginx or user ID 101.
# nginx-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.3
ports:
- containerPort: 80
securityContext:
runAsUser: 101 # Added to run as non-root
runAsGroup: 101 # Added to run as non-root group
Now, if you re-run Trivy:
trivy config ./nginx-chart
You should see no configuration warnings for this specific chart.
One of the more subtle but powerful aspects of Trivy’s config command is its ability to understand Helm’s templating logic to a degree. It doesn’t just parse static YAML; it can evaluate common templating functions and variable substitutions found in values.yaml files and within the template files themselves. This means it can catch misconfigurations that are dependent on how your Helm chart is configured, not just hardcoded values. For instance, if you have a values.yaml that specifies imageTag: latest, Trivy can flag that, even though imageTag is a variable.
The next step after ensuring your configurations are secure and well-formed is to scan the container images themselves for vulnerabilities.