External Secret Managers
External secret managers provide centralized, auditable secret storage with automated rotation and fine-grained access control. This guide shows how to integrate Expanso Edge with popular enterprise secret management systems.
Assumption
This guide assumes your secret manager (Vault, AWS Secrets Manager, etc.) is already provisioned and configured. Examples focus on fetching and using secrets, not on secret manager setup.
Why Use External Secret Managers?
Benefits
- Automated Rotation: Credentials expire and renew without manual intervention
- Audit Trails: Track who accessed which secrets and when
- Centralized Management: Single source of truth for all credentials
- Dynamic Secrets: Generate short-lived credentials on demand
- Access Control: Fine-grained policies per service/user
- Compliance: Meet SOC 2, HIPAA, PCI-DSS requirements
When to Use
- Production deployments with compliance requirements
- Multi-environment setups (dev/staging/prod)
- Large-scale deployments (10+ edge nodes)
- Regulated industries (finance, healthcare)
- Environments requiring secret rotation
Integration Patterns
All external secret managers follow a similar pattern:
- Fetch secrets at edge agent startup or runtime
- Inject as environment variables or write to local files
- Reference in pipeline config using interpolation (
${VAR_NAME})
HashiCorp Vault
Architecture
┌─────────────────┐
│ Vault Server │
│ (Pre-existing) │
└────────┬────────┘
│ Vault Agent (sidecar)
│ fetches secrets
↓
┌─────────────────┐
│ Edge Agent │
│ (reads from │
│ env vars) │
└─────────────────┘
Using Vault Agent Sidecar
Vault Agent runs alongside the edge agent, automatically fetching and refreshing secrets.
Vault Agent config:
vault-agent.hcl
pid_file = "/tmp/vault-agent.pid"
vault {
address = "https://vault.example.com:8200"
}
auto_auth {
method {
type = "kubernetes" # or "aws", "gcp", "azure"
config = {
role = "expanso-edge"
}
}
sink {
type = "file"
config = {
path = "/etc/expanso/secrets.env"
mode = 0600
}
}
}
template {
source = "/etc/vault/templates/pipeline.env.tpl"
destination = "/etc/expanso/pipeline.env"
perms = "0600"
}
Template file:
pipeline.env.tpl
{{ with secret "secret/data/expanso/pipeline" }}
KAFKA_USERNAME={{ .Data.data.kafka_username }}
KAFKA_PASSWORD={{ .Data.data.kafka_password }}
API_TOKEN={{ .Data.data.api_token }}
DB_PASSWORD={{ .Data.data.db_password }}
{{ end }}
Docker Compose example:
docker-compose.yml
version: '3.8'
services:
vault-agent:
image: hashicorp/vault:latest
command: agent -config=/vault/config/vault-agent.hcl
volumes:
- ./vault-agent.hcl:/vault/config/vault-agent.hcl:ro
- ./pipeline.env.tpl:/etc/vault/templates/pipeline.env.tpl:ro
- secrets:/etc/expanso
environment:
VAULT_ADDR: https://vault.example.com:8200
expanso-edge:
image: ghcr.io/expanso-io/expanso-edge:latest
command: run --config /etc/expanso/pipeline.yaml
volumes:
- ./pipeline.yaml:/etc/expanso/pipeline.yaml:ro
- secrets:/etc/expanso
depends_on:
- vault-agent
# Reload env vars on change
env_file:
- /etc/expanso/pipeline.env
volumes:
secrets:
Using Vault Init Container (Kubernetes)
Kubernetes example:
Create the ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: expanso-edge
namespace: expanso-system
Create the Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: expanso-edge
namespace: expanso-system
spec:
replicas: 1
selector:
matchLabels:
app: expanso-edge
template:
metadata:
labels:
app: expanso-edge
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-pipeline.env: "secret/data/expanso/pipeline"
vault.hashicorp.com/agent-inject-template-pipeline.env: |
{{- with secret "secret/data/expanso/pipeline" -}}
export KAFKA_USERNAME="{{ .Data.data.kafka_username }}"
export KAFKA_PASSWORD="{{ .Data.data.kafka_password }}"
export API_TOKEN="{{ .Data.data.api_token }}"
{{- end }}
vault.hashicorp.com/role: "expanso-edge"
spec:
serviceAccountName: expanso-edge
containers:
- name: expanso-edge
image: ghcr.io/expanso-io/expanso-edge:latest
command:
- /bin/sh
- -c
- |
source /vault/secrets/pipeline.env
expanso-edge run --config /etc/expanso/pipeline.yaml
volumeMounts:
- name: pipeline-config
mountPath: /etc/expanso
readOnly: true
volumes:
- name: pipeline-config
configMap:
name: expanso-pipeline
AWS Secrets Manager
Architecture