Secure Agent Environment Variable Injection with Encrypted Vaults
Best practices for safely injecting sensitive environment variables into AI agents using HashiCorp Vault and other encrypted secret management systems.
AI agents operating in production environments need access to sensitive credentials—API keys, database passwords, encryption keys, and more. But embedding these secrets in code, configuration files, or environment variables at deployment time is a security antipattern that violates the principle of least privilege and leaves your agent infrastructure vulnerable to credential leakage.
This post explores how to implement secure environment variable injection for AI agents using encrypted vault systems, ensuring secrets remain encrypted until the moment an agent needs them, and never at rest in your codebase or container images.
The Problem: Secrets in Plain Sight
Traditional deployment workflows often handle secrets carelessly:
- Secrets in Dockerfiles or base images: Once built, they're immutable and visible to anyone with image access.
- Secrets in CI/CD logs: Unmasked environment variable output exposes credentials to anyone reviewing pipelines.
- Secrets in configuration files: YAML, JSON, or
.envfiles checked into version control are a liability, even in private repos. - Long-lived tokens: Static credentials with no expiration create a large attack surface if compromised.
When an agent receives these secrets, they often sit in memory, environment variables, or process listings—places where attackers or other processes on the same host can find them.
The Solution: Vault-Based Secret Injection
A secrets management system like HashiCorp Vault acts as a single source of truth for sensitive data, providing:
- Encryption at rest: Secrets stored in encrypted form, protected by master keys.
- Just-in-time delivery: Secrets are retrieved only when needed, never baked into artifacts.
- Audit trails: Every access to secrets is logged, creating accountability and forensic capability.
- Rotation and expiration: Secrets can be rotated automatically; time-limited credentials reduce blast radius.
- Role-based access control: Fine-grained policies ensure agents only access the secrets they need.
Implementation Patterns
1. Vault Agent Caching
Vault Agent runs as a proxy on the same host as your AI agent, handling authentication and secret retrieval:
// Agent initialization with Vault Agent proxy
import http from 'node:http';
async function getSecret(path) {
const response = await fetch('http://127.0.0.1:8200/v1/secret/data/' + path, {
headers: { 'X-Vault-Token': process.env.VAULT_TOKEN }
});
const data = await response.json();
return data.data.data; // Vault v2 secrets engine structure
}
const dbCreds = await getSecret('database/prod');
const agent = new AIAgent({
database: {
host: dbCreds.host,
password: dbCreds.password,
username: dbCreds.username
}
});
Vault Agent caches secrets locally for a configurable TTL, reducing load on Vault while ensuring secrets remain short-lived. The cache is protected by Vault Agent's own authentication and can be restricted to only the agent process.
2. Init Container Pattern (Kubernetes)
In Kubernetes, use an init container to fetch secrets before the agent container starts:
apiVersion: v1
kind: Pod
metadata:
name: ai-agent
spec:
serviceAccountName: agent-sa
initContainers:
- name: vault-init
image: vault:latest
env:
- name: VAULT_ADDR
value: "https://vault.default.svc.cluster.local:8200"
- name: VAULT_ROLE
value: "ai-agent"
volumeMounts:
- name: secrets
mountPath: /secrets
command:
- sh
- -c
- |
VAULT_TOKEN=$(vault write -field=token auth/kubernetes/login role=$VAULT_ROLE jwt=$(<${VAULT_SA_TOKEN_PATH:-/var/run/secrets/kubernetes.io/serviceaccount/token}))
vault kv get -format=json secret/ai-agent > /secrets/config.json
chmod 400 /secrets/config.json
containers:
- name: agent
image: my-agent:latest
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
env:
- name: AGENT_SECRETS_PATH
value: /secrets/config.json
volumes:
- name: secrets
emptyDir: {}
The init container runs with elevated privileges, retrieves secrets, and writes them to a temporary volume. The agent container then reads the secrets with restricted permissions. The volume is ephemeral—secrets never persist beyond pod lifetime.
3. Lambda / Serverless with Vault Lambda Auth
For serverless agents, use Vault's Lambda auth method to authenticate based on AWS Lambda role:
import crypto from 'node:crypto';
import https from 'node:https';
async function vaultLambdaAuth() {
// Get AWS SigV4 signature for Vault auth
const request = await fetch('http://169.254.169.254/latest/api/token', {
headers: { 'X-aws-ec2-metadata-token-ttl-seconds': '21600' }
});
const token = await request.text();
const response = await fetch('http://169.254.169.254/latest/dynamic/instance-identity/document', {
headers: { 'X-aws-ec2-metadata-token': token }
});
const identity = await response.json();
// Sign and send to Vault Lambda auth endpoint
const vaultResponse = await fetch(
'https://vault.example.com/v1/auth/aws/login',
{
method: 'POST',
body: JSON.stringify({
role: 'ai-agent-lambda',
iam_http_request_method: 'POST',
iam_request_body: JSON.stringify(identity),
iam_request_url: Buffer.from('https://sts.amazonaws.com/').toString('base64')
})
}
);
const { auth } = await vaultResponse.json();
return auth.client_token;
}
// In handler:
export async function handler(event) {
const vaultToken = await vaultLambdaAuth();
const secrets = await fetch('https://vault.example.com/v1/secret/data/lambda-agent', {
headers: { 'X-Vault-Token': vaultToken }
}).then(r => r.json());
// Agent runs with fresh secrets
}
This approach ensures each Lambda invocation gets fresh, short-lived credentials derived from the Lambda's IAM role—no static tokens or hardcoded secrets.
4. Environment Variable Templating
Use Vault to dynamically generate environment variables at runtime:
#!/bin/bash
# vault-env-setup.sh
export VAULT_ADDR="https://vault.internal:8200"
export VAULT_TOKEN=$(vault login -method=oidc -path=oidc role=ai-agent -token-only)
# Fetch all secrets and export as variables
vault kv list secret/ai-agent | grep -v '^secrets' | while read secret; do
value=$(vault kv get -field=value secret/ai-agent/$secret)
export "AGENT_$(echo $secret | tr '[:lower:]' '[:upper:]')"="$value"
done
# Start agent with populated environment
exec node agent.js
This script fetches all secrets from Vault, sets them as environment variables with a safe prefix, then launches the agent. Secrets exist only in the shell environment and the agent process—they're never written to disk or logs.
Best Practices
1. Principle of least privilege: Grant each agent role access only to the secrets it actually needs. Use Vault policies to enforce this:
path "secret/data/ai-agent/*" {
capabilities = ["read", "list"]
}
path "secret/data/other-team/*" {
capabilities = [] # Explicitly denied
}
2. Use dynamic secrets when possible: Rather than static credentials, request time-limited secrets from Vault:
// Every agent request fetches fresh creds
const dbCreds = await fetch('https://vault.internal:8200/v1/database/creds/agent-role', {
headers: { 'X-Vault-Token': vaultToken }
}).then(r => r.json());
// Credentials expire automatically after 1 hour
const agent = new DatabaseClient(dbCreds.data);
3. Encrypt secrets in logs: Even when logging is enabled, ensure any credential that appears in logs is redacted or encrypted:
const logger = pino({
redact: {
paths: ['*.password', '*.api_key', '*.token', 'AGENT_*'],
censor: '[REDACTED]'
}
});
4. Audit secret access: Review Vault audit logs regularly to catch unauthorized retrieval attempts or anomalous access patterns.
5. Rotate credentials regularly: Set automatic rotation schedules for long-lived secrets, and use Vault's rotation endpoints for managed secrets like database passwords.
Conclusion
Secure environment variable injection transforms how AI agents handle sensitive credentials. By deferring secret retrieval to runtime, using short-lived credentials, and implementing audit trails, you eliminate entire classes of credential-leakage vulnerabilities. Combined with proper RBAC, encryption at rest, and regular rotation, this approach provides defense-in-depth for agent infrastructure in production.
Start with Vault Agent or Kubernetes init containers—both are battle-tested patterns that integrate smoothly into existing deployment pipelines while significantly improving your security posture.