Helm Security
Helm Security Challenges
Helm simplifies Kubernetes deployments but introduces security concerns: untrusted charts, unprotected secrets, and supply chain risks.
Chart Signing
Sign charts with GPG to verify authenticity:
# Generate signing key
gpg --full-generate-key
gpg --list-secret-keys
# Sign a chart
helm package mychart/
helm sign mychart-1.0.0.tgz --key "developer@example.com"
# Verify a chart
helm verify mychart-1.0.0.tgz
# With custom public key
gpg --export developer@example.com > pubkey.asc
helm verify mychart-1.0.0.tgz --keyring pubkey.asc
Provenance Files
Provenance files contain the chart hash and signature:
# mychart-1.0.0.tgz.prov
apiVersion: v1
files:
- mychart-1.0.0.tgz
chart: |
sha256: a1b2c3d4...
signature: |
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEE...
-----END PGP SIGNATURE-----
Automated Verification in CI
# CI pipeline chart verification
pipeline:
- name: verify-charts
commands:
# Import trusted keys
- gpg --import trusted-keys.asc
# Verify all charts
- for chart in charts/*.tgz; do
helm verify "$chart" --keyring trusted-keys.asc || exit 1
done
# Scan for vulnerabilities
- trivy fs charts/
# Lint charts
- helm lint charts/*
# Check for deprecated APIs
- pluto detect-files -d charts/
Secrets Management
Never store secrets in values files:
# BAD: Secrets in values
apiKey: "sk-1234567890"
dbPassword: "password123"
# GOOD: Reference external secret
apiKey: "{{ .Values.externalSecrets.apiKey }}"
dbPassword: "{{ .Values.externalSecrets.dbPassword }}"
Use external secrets operator:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: app-secret
data:
- secretKey: api-key
remoteRef:
key: secret/data/app
property: api-key
- secretKey: db-password
remoteRef:
key: secret/data/app
property: db-password
Values Security
Validate values with JSON Schema:
{
"$schema": "https://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"image": {
"type": "object",
"properties": {
"repository": { "type": "string" },
"tag": { "type": "string", "pattern": "^[a-zA-Z0-9._-]+$" },
"pullPolicy": {
"type": "string",
"enum": ["Always", "IfNotPresent", "Never"]
}
},
"required": ["repository"]
},
"securityContext": {
"type": "object",
"required": ["runAsNonRoot"],
"properties": {
"runAsNonRoot": { "type": "boolean", "const": true },
"runAsUser": { "type": "integer", "minimum": 1000 }
}
}
}
}
RBAC for Helm Operations
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: helm-deployer
rules:
- apiGroups: ["apps", "extensions"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list", "create", "update", "patch"]
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["get", "list", "create"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "create", "delete"]
Conclusion
Secure Helm deployments with chart signing and provenance verification. Use external secrets management instead of storing secrets in values files. Validate values with JSON Schema. Restrict Helm RBAC to specific operations. Scan charts for vulnerabilities before deployment. Always verify chart signatures from third-party repositories.