Helm Chart Review
Purpose
Provide comprehensive review checklists and automated validation for ensuring Helm charts meet production quality and security standards before deployment.
Complete Review Workflow
Step 1: Run Automated Validation
# Lint checks
helm lint ./charts/mychart
# Template rendering validation
helm template mychart ./charts/mychart --debug
# Test with different value files
helm template mychart ./charts/mychart -f values-prod.yaml
# Dry run installation
helm install test ./charts/mychart --dry-run --debug --namespace test
Step 2: Security Review Checklist
Critical security items (must pass):
- [ ] No hardcoded secrets in values.yaml or templates
- [ ] Image tags are specific (no
:latesttag) - [ ] Security contexts are defined and restrictive:
securityContext: runAsNonRoot: true runAsUser: 1000 readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: - ALL - [ ] RBAC is properly configured with least privilege
- [ ] Resource limits are set for all containers
- [ ] Service accounts are explicitly created (not using default)
- [ ] Secrets use external secret management (not inline)
Security red flags:
# ❌ NEVER allow these
securityContext:
privileged: true # Unacceptable
runAsUser: 0 # Root user - requires justification
allowPrivilegeEscalation: true # Security risk
image:
tag: latest # Non-deterministic
# Hardcoded secrets
password: "hardcoded123" # NEVER hardcode secrets
Step 3: Structure Review Checklist
- [ ] Chart.yaml has all required fields:
apiVersion: v2name,description,typeversion(follows SemVer2)appVersionmaintainerswith contact info
- [ ] Version follows SemVer2 format (MAJOR.MINOR.PATCH)
- [ ] Dependencies use version ranges (~)
- [ ] One resource per file in templates/
- [ ] Template helpers are properly namespaced
- [ ] File naming follows conventions (lowercase, dashes)
- [ ] NOTES.txt provides useful post-install information
- [ ] README.md exists with usage documentation
Step 4: Values Review Checklist
- [ ] All values are documented with clear comments
- [ ] Naming is consistent (camelCase throughout)
- [ ] Types are explicit (strings quoted:
tag: "1.0") - [ ] Flat structure preferred over deep nesting
- [ ] Defaults are secure and production-ready
- [ ] Environment-specific values separated (values-{env}.yaml)
- [ ] Boolean values use lowercase (
true/false) - [ ] Resource requests/limits have realistic values
Good vs bad values:
# ✅ Good
replicaCount: 2 # Documented, reasonable default
image:
repository: myapp
pullPolicy: IfNotPresent
tag: "" # Empty, uses appVersion
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 250m
memory: 128Mi
# ❌ Bad
replicas: 1 # Undocumented, single point of failure
ImageTag: latest # Wrong case, non-specific tag
database:
password: "changeme" # Hardcoded secret
Step 5: Template Review Checklist
- [ ] Labels are consistent and follow k8s recommendations:
app.kubernetes.io/nameapp.kubernetes.io/instanceapp.kubernetes.io/versionapp.kubernetes.io/managed-by
- [ ] Nil checks for nested values (prevent nil pointer errors)
- [ ] Whitespace properly managed (
{{-and-}}used correctly) - [ ] Helper functions used for repeated logic
- [ ] Conditionals properly structured
- [ ] Resources can be disabled via values
- [ ] Image tags default to Chart.AppVersion
- [ ] ConfigMap/Secret changes trigger pod restarts (checksum annotations)
- [ ] Names truncated to 63 characters
Template quality patterns:
# ✅ Good
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- if .Values.ingress.enabled }}
# ... conditional resource
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
# Safe nil handling
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
# ❌ Bad
name: my-app-{{ .Release.Name }} # Hardcoded
image: {{ .Values.image }}:latest # Hardcoded latest
{{ .Values.nested.value }} # No nil check
Step 6: Testing Review Checklist
- [ ] helm lint passes without errors or warnings
- [ ] helm template renders correctly
- [ ] Dry run succeeds
- [ ] Unit tests exist and pass (helm-unittest)
- [ ] All conditional paths tested (enabled/disabled features)
- [ ] Multiple environments tested (dev, staging, prod values)
Security Scanning Integration
Kubesec Analysis
# Scan rendered templates for security issues
helm template mychart ./charts/mychart | kubesec scan -
# Look for:
# - Missing security contexts
# - Privileged containers
# - Host path mounts
# - Host network usage
Trivy Image Scanning
# Extract images from chart
helm template mychart ./charts/mychart | grep "image:" | sort -u
# Scan each image for vulnerabilities
trivy image myapp:1.0.0
Common Review Findings and Fixes
Finding: Missing Resource Limits
# ❌ Problem
containers:
- name: app
image: myapp:1.0
# ✅ Solution
containers:
- name: app
image: myapp:1.0
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 250m
memory: 128Mi
Finding: Insecure Security Context
# ❌ Problem
securityContext: {}
# ✅ Solution
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
Finding: Latest Image Tag
# ❌ Problem
image: myapp:latest
# ✅ Solution
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
Finding: No Liveness/Readiness Probes
# ❌ Problem
containers:
- name: app
image: myapp:1.0
# ✅ Solution
containers:
- name: app
image: myapp:1.0
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
Review Severity Levels
BLOCKER (must fix before merge):
- Hardcoded secrets
- Missing security contexts
- Privileged containers
- No resource limits
- Use of
:latesttag
CRITICAL (must fix before production):
- Missing liveness/readiness probes
- Single replica without PDB
- No pod disruption budget
- Incorrect RBAC (too permissive)
MAJOR (should fix):
- Undocumented values
- Missing tests
- Incomplete README
- No CHANGELOG entry
MINOR (nice to have):
- Improved comments
- Additional examples
- Optimization opportunities
Pre-Release Checklist
Before releasing chart:
- [ ] All security review items pass
- [ ] All structure review items pass
- [ ] All tests pass (lint, unit, integration, dry-run)
- [ ] Security scanning completed (kubesec, trivy)
- [ ] Documentation updated and accurate
- [ ] CHANGELOG.md updated with version notes
- [ ] Version bumped appropriately (major/minor/patch)
- [ ] Tested in staging environment
- [ ] Rollback procedure documented
- [ ] Resource quotas validated
- [ ] Network policies tested
- [ ] Monitoring/alerting configured
CI/CD Quality Gates
Example pipeline checks:
# GitLab CI / GitHub Actions
helm-lint:
stage: test
script:
- helm lint ./charts/*
helm-unittest:
stage: test
script:
- helm unittest ./charts/*
helm-security-scan:
stage: test
script:
- helm template ./charts/* | kubesec scan -
- helm template ./charts/* | trivy config -
helm-dry-run:
stage: test
script:
- helm install test ./charts/mychart --dry-run --debug
Documentation Review
README.md must include:
- [ ] Chart description and purpose
- [ ] Prerequisites and dependencies
- [ ] Installation instructions
- [ ] Configuration options (values) table
- [ ] Usage examples
- [ ] Upgrade instructions
CHANGELOG.md must track:
- [ ] Version number and date
- [ ] Added features
- [ ] Changed behavior
- [ ] Deprecated features
- [ ] Removed features
- [ ] Fixed bugs
- [ ] Security fixes
Resources
Related Agent
For comprehensive Helm/Kubernetes guidance that coordinates this and other Helm skills, use the helm-kubernetes-expert agent.