HashiCorp Vault — Agent Injector Deep Dive
Advanced patterns for the Vault Agent Injector — multi-secret injection, JSON configs, dynamic secrets, and troubleshooting.
Multi-Secret Injection
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp"
# Database credentials
vault.hashicorp.com/agent-inject-secret-db.env: "secret/data/myapp/db"
vault.hashicorp.com/agent-inject-template-db.env: |
{{ with secret "secret/data/myapp/db" -}}
DB_HOST={{ .Data.data.host }}
DB_PORT={{ .Data.data.port }}
DB_USER={{ .Data.data.username }}
DB_PASS={{ .Data.data.password }}
{{- end }}
# Redis credentials
vault.hashicorp.com/agent-inject-secret-redis.env: "secret/data/myapp/redis"
vault.hashicorp.com/agent-inject-template-redis.env: |
{{ with secret "secret/data/myapp/redis" -}}
REDIS_URL=redis://:{{ .Data.data.password }}@{{ .Data.data.host }}:{{ .Data.data.port }}
{{- end }}
# TLS certificate
vault.hashicorp.com/agent-inject-secret-tls.crt: "pki_int/issue/web-server"
vault.hashicorp.com/agent-inject-template-tls.crt: |
{{ with secret "pki_int/issue/web-server" "common_name=myapp.default.svc" "ttl=24h" -}}
{{ .Data.certificate }}
{{ .Data.issuing_ca }}
{{- end }}
vault.hashicorp.com/agent-inject-secret-tls.key: "pki_int/issue/web-server"
vault.hashicorp.com/agent-inject-template-tls.key: |
{{ with secret "pki_int/issue/web-server" "common_name=myapp.default.svc" "ttl=24h" -}}
{{ .Data.private_key }}
{{- end }}
Files rendered at:
/vault/secrets/db.env/vault/secrets/redis.env/vault/secrets/tls.crt/vault/secrets/tls.key
JSON Configuration Template
vault.hashicorp.com/agent-inject-secret-config.json: "secret/data/myapp/config"
vault.hashicorp.com/agent-inject-template-config.json: |
{{ with secret "secret/data/myapp/config" -}}
{
"database": {
"host": "{{ .Data.data.db_host }}",
"port": {{ .Data.data.db_port }},
"username": "{{ .Data.data.db_user }}",
"password": "{{ .Data.data.db_pass }}"
},
"redis": {
"url": "{{ .Data.data.redis_url }}"
},
"log_level": "{{ .Data.data.log_level }}"
}
{{- end }}
Dynamic Database Credentials
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp"
vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/myapp-role"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{ with secret "database/creds/myapp-role" -}}
PGHOST=db.internal
PGPORT=5432
PGDATABASE=mydb
PGUSER={{ .Data.username }}
PGPASSWORD={{ .Data.password }}
{{- end }}
The sidecar agent automatically renews the dynamic credential lease.
Resource Tuning
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp"
# Resource limits for the sidecar
vault.hashicorp.com/agent-limits-cpu: "100m"
vault.hashicorp.com/agent-limits-mem: "128Mi"
vault.hashicorp.com/agent-requests-cpu: "50m"
vault.hashicorp.com/agent-requests-mem: "64Mi"
# Run agent as specific user
vault.hashicorp.com/agent-run-as-user: "1000"
vault.hashicorp.com/agent-run-as-group: "1000"
# Vault connection settings
vault.hashicorp.com/tls-skip-verify: "false"
vault.hashicorp.com/ca-cert: "/vault/tls/ca.crt"
Init-Only vs Sidecar
# Init-only: fetch secrets once, no sidecar stays running
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/role: "myapp"
vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config"
Use init-only when:
- Secrets don’t change during pod lifetime
- You want minimal resource usage
- No dynamic secrets (which need renewal)
Troubleshooting
Check Injector Logs
kubectl -n vault logs -l app.kubernetes.io/name=vault-agent-injector
Check Sidecar Logs
# List containers in the pod
kubectl get pod myapp-xyz -o jsonpath='{.spec.containers[*].name}'
# Check agent sidecar logs
kubectl logs myapp-xyz -c vault-agent
# Check init container logs
kubectl logs myapp-xyz -c vault-agent-init
Common Issues
| Issue | Cause | Fix |
|---|---|---|
| Pod stuck in Init | Agent can’t authenticate | Check SA name matches role |
permission denied |
Policy doesn’t match | Verify policy paths |
| No sidecar injected | Annotations missing or webhook not running | Check injector pods |
| Secret file empty | Template error | Check agent logs |
service account not allowed |
SA/namespace mismatch | Check role bindings |
Verify Injector Webhook
# Check mutating webhook configuration
kubectl get mutatingwebhookconfigurations
# Verify the injector is running
kubectl -n vault get pods -l app.kubernetes.io/name=vault-agent-injector
Quick Reference
| Annotation | Purpose |
|---|---|
agent-inject: "true" |
Enable injection |
agent-pre-populate-only: "true" |
Init-only, no sidecar |
agent-inject-secret-NAME: "PATH" |
Inject secret as file |
agent-inject-template-NAME: "TPL" |
Custom template |
agent-limits-cpu/mem |
Sidecar resources |
Next: CSI Provider