Helm Security Best Practices
A comprehensive guide to Helm security best practices covering secrets management, RBAC, chart signing, provenance, and securing Helm deployments in production.
Helm charts can contain sensitive information and have the power to deploy arbitrary resources in your Kubernetes cluster. Without proper security controls, Helm can become a significant attack vector.
Key security areas for Helm include:
- Secrets Management: Handling sensitive data securely
- RBAC: Limiting who can deploy and manage releases
- Chart Signing: Ensuring chart authenticity
- Provenance: Verifying chart integrity
- Supply Chain Security: Securing the chart distribution pipeline
- Values Security: Protecting configuration data
Never store secrets in Helm charts or values files. Use external secret management solutions for production deployments.
# Bad Practice: Secrets in values.yaml
# NEVER DO THIS
database:
username: admin
password: supersecretpassword # NEVER store secrets in values.yaml
host: db.example.com
# Bad Practice: Secrets in --set
# Visible in process list and shell history
helm install my-release ./my-chart --set database.password=supersecret
# Good Practice: External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-store
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
auth:
kubernetes:
mountPath: "kubernetes"
role: "my-app-role"
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
secretStoreRef:
name: vault-store
kind: SecretStore
target:
name: db-credentials
data:
- secretKey: username
remoteRef:
key: app/db
property: username
- secretKey: password
remoteRef:
key: app/db
property: password
# Good Practice: Sealed Secrets
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
spec:
encryptedData:
username: AgBy... # Encrypted
password: AgBy... # Encrypted
# Good Practice: Helm Secrets Plugin
# Install plugin
helm plugin install https://github.com/jkroepke/helm-secrets
# Encrypt values file
helm secrets enc secrets.yaml
# Use encrypted values
helm secrets install my-release ./my-chart -f secrets.yaml
# Decrypt for inspection
helm secrets dec secrets.yaml
# Good Practice: SOPS with Helm
# Install SOPS
helm plugin install https://github.com/jkroepke/helm-secrets
# Encrypt with SOPS
sops --encrypt --in-place secrets.yaml
# Use with Helm
helm secrets install my-release ./my-chart -f secrets.yaml
External Secrets Operator
Sealed Secrets
Helm Secrets Plugin
Cloud Secret Managers
--set, secrets are visible in process lists and shell history.
Helm uses the Kubernetes RBAC system. Control who can install, upgrade, and delete releases with fine-grained permissions.
# Tiller (Helm v2) - ClusterAdmin (not recommended)
# Helm v3 uses the user's kubeconfig credentials
# Good Practice: Namespaced RBAC for Helm
apiVersion: v1
kind: ServiceAccount
metadata:
name: helm-user
namespace: default
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: helm-user-role
namespace: default
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: helm-user-binding
namespace: default
subjects:
- kind: ServiceAccount
name: helm-user
namespace: default
roleRef:
kind: Role
name: helm-user-role
apiGroup: rbac.authorization.k8s.io
# Good Practice: Restrict Helm to specific namespaces
# Users can only deploy to their own namespaces
# Good Practice: Use separate service accounts for CI/CD
apiVersion: v1
kind: ServiceAccount
metadata:
name: helm-ci
namespace: default
# Good Practice: Limit secret access
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: helm-secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
resourceNames: ["my-app-secret"]
# Good Practice: Validate permissions
kubectl auth can-i create deployments --as=system:serviceaccount:default:helm-user
kubectl auth can-i delete secrets --as=system:serviceaccount:default:helm-user
- Use namespaced Roles instead of ClusterRoles
- Use separate service accounts for different teams
- Apply least privilege principle
- Regularly audit RBAC permissions
- Use
kubectl auth can-ito verify permissions - Implement namespace isolation
Helm supports chart signing using PGP keys. This ensures chart authenticity and integrity.
# Generate a PGP key pair
gpg --full-generate-key
# List GPG keys
gpg --list-keys
# Export public key
gpg --export --armor "Your Name" > public-key.asc
# Export private key (keep secure!)
gpg --export-secret-keys --armor "Your Name" > private-key.asc
# Sign a chart during packaging
helm package ./my-chart --sign --key "Your Name" --keyring ~/.gnupg/secring.gpg
# This creates:
# - my-chart-1.0.0.tgz (the chart)
# - my-chart-1.0.0.tgz.prov (the provenance file)
# Verify a signed chart
helm verify my-chart-1.0.0.tgz
# Verify with keyring
helm verify --keyring ~/.gnupg/pubring.gpg my-chart-1.0.0.tgz
# Install a signed chart (verifies automatically)
helm install my-release my-chart-1.0.0.tgz
# Pull and verify a chart
helm pull my-repo/my-chart --verify
# View provenance file
cat my-chart-1.0.0.tgz.prov
# Import public key for verification
gpg --import public-key.asc
# Check signature
gpg --verify my-chart-1.0.0.tgz.prov
- Chart name and version
- Chart SHA256 hash
- Signature from the chart author
- Timestamp of signing
- PGP key information
Chart Signing
Provenance
Verification
Key Management
- Sign all production charts
- Store private keys securely (HSM, Vault)
- Use strong PGP keys (4096-bit RSA)
- Rotate keys regularly
- Publish public keys for verification
- Verify signatures in CI/CD pipelines
# 1. Use trusted repositories
helm repo add bitnami https://charts.bitnami.com/bitnami # Official
helm repo add my-company https://charts.mycompany.com # Private
# 2. Verify chart signatures
helm pull my-company/my-chart --verify
# 3. Scan charts for vulnerabilities
# Install Trivy plugin
helm plugin install https://github.com/aquasecurity/helm-trivy
# Scan chart
helm trivy scan ./my-chart
# Or use trivy directly
trivy config ./my-chart
# 4. Validate Kubernetes manifests
helm template my-release ./my-chart | kubeconform -strict
# 5. Use OPA/Gatekeeper for policy enforcement
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRegistries
metadata:
name: allowed-registries
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
registries:
- "myregistry.azurecr.io/"
- "gcr.io/"
- "docker.io/"
# 6. Use immutable tags for images
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: myregistry.azurecr.io/my-app:v1.2.3 # Specific tag
imagePullPolicy: Always
# 7. Implement SBOM generation
# Generate SBOM for chart
syft ./my-chart -o spdx-json > sbom.json
# 8. Use dependency scanning
helm dependency list ./my-chart
trivy fs --security-checks vuln ./my-chart
Trusted Repositories
Chart Signing
Vulnerability Scanning
Policy Enforcement
SBOM Generation
Immutable Tags
# Helm Security Checklist
# ========================
# Secrets Management
☐ Never store secrets in values.yaml
☐ Use External Secrets Operator or Sealed Secrets
☐ Use helm-secrets plugin for encrypted values
☐ Rotate secrets regularly
☐ Use RBAC for secret access
# RBAC
☐ Use namespaced Roles instead of ClusterRoles
☐ Apply least privilege principle
☐ Use separate service accounts for CI/CD
☐ Regularly audit RBAC permissions
☐ Implement namespace isolation
# Chart Signing
☐ Sign all production charts
☐ Store private keys securely
☐ Use strong PGP keys
☐ Rotate keys regularly
☐ Verify signatures before installation
# Supply Chain Security
☐ Use trusted repositories only
☐ Verify chart signatures
☐ Scan charts for vulnerabilities
☐ Use OPA/Gatekeeper for policy enforcement
☐ Generate SBOMs for charts
☐ Use immutable image tags
# CI/CD Security
☐ Use secrets management in CI/CD
☐ Verify charts in pipelines
☐ Scan charts for vulnerabilities
☐ Use dedicated service accounts
☐ Implement audit logging
# Production Security
☐ Use network policies
☐ Enable pod security standards
☐ Use security contexts
☐ Implement resource quotas
☐ Monitor deployments
--set.gpg --full-generate-key, then package with helm package --sign --key "Your Name". This creates a .prov file for verification.helm verify my-chart-1.0.0.tgz with the public key imported. Or use helm pull --verify to verify while pulling.helm-secrets is a plugin that allows you to encrypt values files using SOPS, AWS KMS, GCP KMS, or Azure Key Vault. It decrypts values during installation.trivy config ./my-chart or install the helm-trivy plugin. Also scan dependencies and generated manifests.Helm security is critical for production deployments. Implement these best practices to protect your secrets, control access, and ensure chart authenticity.