Authentication¶
Configure secure authentication for your vaults.
Note: The generic HTTP adapter only supports
bearer,basic,oauth2,api_key, andcustomauth methods. If you use managed identity, AppRole, Kubernetes auth, IAM, or other provider-specific flows, obtain a token externally and pass it via headers or OAuth2 configuration.
Authentication Overview¶
vaults-syncer uses a generic HTTP adapter. Supported auth methods are: bearer, basic, oauth2, api_key, and custom. Obtain provider-specific tokens (Azure AD, Vault, etc.) externally and pass them via headers or OAuth2.
Quick Reference¶
| Vault Type | Recommended Auth | Alternative Methods |
|---|---|---|
| Azure Key Vault | Bearer Token (Azure AD) | OAuth2 (client credentials) |
| Bitwarden | OAuth2 | API Key |
| HashiCorp Vault | Custom header (X-Vault-Token) | Bearer token |
| AWS Secrets Manager | Custom header / Proxy | Bearer token |
| Generic REST | Bearer Token | Basic Auth, API Key, OAuth2 |
Azure Key Vault Authentication¶
1. Managed Identity (Recommended)¶
Use when: Running on Azure resources (VMs, App Service, AKS, Functions, Container Instances)
Advantages: - ✅ No credentials to manage - ✅ Automatic token rotation - ✅ Best security practice - ✅ No password expiration
Configuration:
vaults:
- id: akv-prod
type: azure
endpoint: "https://myvault.vault.azure.net/secrets"
auth:
method: bearer
headers:
token: "${AZURE_ACCESS_TOKEN}"
field_names:
name_field: "name"
value_field: "value"
Setup for different Azure resources:
Azure VM¶
# Enable system-assigned managed identity
az vm identity assign \
--resource-group myResourceGroup \
--name myVM
# Then grant permissions to Key Vault
az keyvault set-policy \
--name myKeyVault \
--object-id $(az vm show -d -g myResourceGroup -n myVM --query systemAssignedIdentity -o tsv) \
--secret-permissions get list
Azure App Service¶
# Enable system-assigned managed identity in Azure Portal
# Settings → Identity → System assigned → On
# Then grant permissions
az keyvault set-policy \
--name myKeyVault \
--object-id <app-service-principal-id> \
--secret-permissions get list
Azure Kubernetes Service (AKS)¶
# Create service account and workload identity
kubectl create serviceaccount sync-daemon -n akv-sync
# Create federated credential
az identity federated-credential create \
--name sync-federated \
--identity-name sync-identity \
--resource-group myResourceGroup \
--issuer "https://oidc.prod.workload.identity.azure.com/$(AZ_SUBSCRIPTION_ID).dfs.core.windows.net/akv-sync/" \
--subject "system:serviceaccount:akv-sync:sync-daemon"
# Configure workload identity on pod
# See Kubernetes deployment example
Container Instances¶
# Assign managed identity to container
az container create \
--resource-group myResourceGroup \
--name akv-sync \
--image ghcr.io/pacorreia/vaults-syncer:latest \
--assign-identity /subscriptions/{sub}/resourcegroups/{rg}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{name}
2. Service Principal¶
Use when: Non-Azure environments, CI/CD pipelines, or testing
Advantages: - ✅ Works anywhere - ✅ Fine-grained permissions - ✅ Easy to test
Disadvantages: - ❌ Must manage credentials - ❌ Credentials can expire - ❌ Must refresh tokens manually
Configuration:
vaults:
- id: akv-sp
type: azure
endpoint: "https://myvault.vault.azure.net/secrets"
auth:
method: oauth2
oauth:
token_endpoint: "https://login.microsoftonline.com/${AZURE_TENANT_ID}/oauth2/v2.0/token"
client_id: "${AZURE_CLIENT_ID}"
client_secret: "${AZURE_CLIENT_SECRET}"
scope: "https://vault.azure.net/.default"
field_names:
name_field: "name"
value_field: "value"
Setup:
# Create service principal
az ad sp create-for-rbac \
--name "akv-sync-sp" \
--role "Key Vault Secrets Officer" \
--scope /subscriptions/{subscription-id}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{vault-name}
# Output:
# {
# "appId": "12345678-1234-1234-1234-123456789012",
# "displayName": "akv-sync-sp",
# "password": "...",
# "tenant": "abcdef12-1234-1234-1234-abcdef123456"
# }
# Set environment variables
export AZURE_TENANT_ID="abcdef12-..."
export AZURE_CLIENT_ID="12345678-..."
export AZURE_CLIENT_SECRET="..."
RBAC Roles:
# Option 1: Use built-in role (recommended)
az role assignment create \
--assignee {client-id} \
--role "Key Vault Secrets Officer" \
--scope {key-vault-resource-id}
# Option 2: For read-only access
az role assignment create \
--assignee {client-id} \
--role "Key Vault Secrets User" \
--scope {key-vault-resource-id}
# Option 3: Custom role - read-only
az role definition create --role-definition @custom-role.json
Example custom role file:
{
"Name": "Key Vault Secrets Reader",
"Description": "Read-only access to Key Vault secrets",
"Type": "CustomRole",
"Actions": [
"Microsoft.KeyVault/vaults/secrets/read",
"Microsoft.KeyVault/vaults/read"
],
"NotActions": [],
"AssignableScopes": [
"/subscriptions/{subscription-id}"
]
}
3. Client Certificate¶
Use when: Certificate-based authentication required
Configuration:
vaults:
- id: akv-cert
type: azure
endpoint: "https://myvault.vault.azure.net/secrets"
auth:
method: bearer
headers:
token: "${AZURE_ACCESS_TOKEN}"
field_names:
name_field: "name"
value_field: "value"
Setup:
# Generate certificate
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
# Create PKCS12 file
openssl pkcs12 -export -in cert.pem -inkey key.pem -out client.p12
# Upload to Azure AD application certificate
az ad app credential reset \
--id {client-id} \
--cert @cert.pem
4. User Authentication¶
Use when: Local development with user principal
Configuration:
vaults:
- id: akv-user
type: azure
endpoint: "https://myvault.vault.azure.net/secrets"
auth:
method: bearer
headers:
token: "${AZURE_ACCESS_TOKEN}"
field_names:
name_field: "name"
value_field: "value"
Setup:
# Login with Azure CLI
az login
# Verify access
az keyvault secret list --vault-name myvault
Bitwarden Authentication¶
OAuth2¶
Configuration:
vaults:
- id: bitwarden
type: bitwarden
endpoint: "https://vault.example.com/api/ciphers"
auth:
method: oauth2
oauth:
client_id: "${BITWARDEN_CLIENT_ID}"
client_secret: "${BITWARDEN_CLIENT_SECRET}"
scope: "api"
field_names:
name_field: "name"
value_field: "login"
Setup:
- Access Bitwarden admin panel as administrator
- Navigate to Settings → Integrations → API/OAuth2
- Enable API access if required
- Create new OAuth2 application:
- Application name: "akv-sync"
- Grant type: Client credentials
- Scopes needed:
cipher:readcipher:writefolder:readfolder:write
- Copy the generated credentials
Scope Reference:
| Scope | Permission | Use Case |
|---|---|---|
cipher:read |
Read ciphers (items) | Reading secrets from Bitwarden |
cipher:write |
Create/modify ciphers | Writing secrets to Bitwarden |
folder:read |
List folders | Organizing synced secrets |
folder:write |
Create/modify folders | Creating folder structure |
collection:read |
List collections | Filtering by collection |
collection:write |
Modify collections | Assigning to collections |
API Key (Alternative)¶
vaults:
- id: bitwarden-api
type: bitwarden
endpoint: "https://vault.example.com/api/ciphers"
auth:
method: api_key
headers:
api_key: "${BITWARDEN_API_KEY}"
field_names:
name_field: "name"
value_field: "login"
HashiCorp Vault Authentication¶
Token Authentication¶
vaults:
- id: vault-token
type: vault
endpoint: "https://vault.example.com:8200"
auth:
method: token
token: "${VAULT_TOKEN}"
AppRole Authentication¶
vaults:
- id: vault-approle
type: vault
endpoint: "https://vault.example.com:8200/v1/secret/data"
auth:
method: custom
headers:
X-Vault-Token: "${VAULT_TOKEN}"
field_names:
name_field: "name"
value_field: "value"
Setup:
# Enable AppRole auth method
vault auth enable approle
# Create AppRole
vault write auth/approle/role/sync-role \
token_num_uses=0 \
token_ttl=1h
# Get role ID
vault read auth/approle/role/sync-role/role-id
# Get secret ID
vault write -f auth/approle/role/sync-role/secret-id
Kubernetes Authentication¶
vaults:
- id: vault-k8s
type: vault
endpoint: "https://vault.example.com:8200/v1/secret/data"
auth:
method: custom
headers:
X-Vault-Token: "${VAULT_TOKEN}"
field_names:
name_field: "name"
value_field: "value"
AWS Secrets Manager Authentication¶
IAM Role (Recommended)¶
vaults:
- id: aws-sm
type: aws
endpoint: "https://secretsmanager.us-east-1.amazonaws.com"
auth:
method: custom
headers:
X-Amz-Security-Token: "${AWS_SESSION_TOKEN}"
field_names:
name_field: "Name"
value_field: "SecretString"
Works with: - EC2 instance roles - ECS task roles - Lambda execution roles
IAM User Keys¶
vaults:
- id: aws-sm-keys
type: aws
endpoint: "https://secretsmanager.us-east-1.amazonaws.com"
auth:
method: custom
headers:
X-Amz-Security-Token: "${AWS_SESSION_TOKEN}"
field_names:
name_field: "Name"
value_field: "SecretString"
Generic REST API Authentication¶
Bearer Token¶
vaults:
- id: rest-bearer
type: generic
endpoint: "https://api.example.com"
auth:
method: bearer
headers:
token: "${API_TOKEN}"
field_names:
name_field: "name"
value_field: "value"
Basic Authentication¶
vaults:
- id: rest-basic
type: generic
endpoint: "https://api.example.com"
auth:
method: basic
headers:
username: "${API_USER}"
password: "${API_PASSWORD}"
field_names:
name_field: "name"
value_field: "value"
API Key¶
vaults:
- id: rest-apikey
type: generic
endpoint: "https://api.example.com"
auth:
method: api_key
headers:
api_key: "${API_KEY}"
field_names:
name_field: "name"
value_field: "value"
OAuth2¶
vaults:
- id: rest-oauth2
type: generic
endpoint: "https://api.example.com"
auth:
method: oauth2
oauth:
token_endpoint: "https://auth.example.com/oauth/token"
client_id: "${CLIENT_ID}"
client_secret: "${CLIENT_SECRET}"
scope: "api"
field_names:
name_field: "name"
value_field: "value"
Credential Management¶
Using Environment Variables¶
Best practice for secrets:
vaults:
- id: secure-vault
type: bitwarden
endpoint: "https://vault.example.com"
auth:
method: oauth2
client_id: ${BITWARDEN_CLIENT_ID}
client_secret: ${BITWARDEN_CLIENT_SECRET}
Setting variables:
# Linux/macOS
export BITWARDEN_CLIENT_ID="..."
export BITWARDEN_CLIENT_SECRET="..."
./sync-daemon -config config.yaml
# Docker with env file
echo 'BITWARDEN_CLIENT_ID=...' > .env
echo 'BITWARDEN_CLIENT_SECRET=...' >> .env
docker run --env-file .env ...
# Docker Compose
environment:
- BITWARDEN_CLIENT_ID=${BITWARDEN_CLIENT_ID}
- BITWARDEN_CLIENT_SECRET=${BITWARDEN_CLIENT_SECRET}
Using Azure Key Vault for Credentials¶
Store credentials in Azure Key Vault and reference them:
# Store credential
az keyvault secret set \
--vault-name mykeyvault \
--name "bitwarden-client-id" \
--value "actual-client-id"
# Use in configuration (requires special setup)
# See advanced documentation for details
Using HashiCorp Vault¶
# Store in HashiCorp Vault
vault kv put secret/sync/bitwarden \
client_id="..." \
client_secret="..."
# Reference in config
auth:
method: oauth2
client_id: vault://secret/sync/bitwarden:client_id
client_secret: vault://secret/sync/bitwarden:client_secret
Certificate and Key Rotation¶
Azure Service Principal¶
# Replace expiring credential
az ad sp credential reset \
--name akv-sync-sp \
--credential-description "new-key"
# Update environment variables
export AZURE_CLIENT_SECRET="new-secret"
API Tokens¶
# Generate new token
BITWARDEN_CLIENT_ID=new-id
BITWARDEN_CLIENT_SECRET=new-secret
# Update without downtime (rolling deployment)
docker-compose up -d # Pulls new config
Security Best Practices¶
✅ Do: - Use managed identities on cloud platforms (no credential management) - Rotate credentials regularly (every 90 days recommended) - Use least-privilege permissions - Store credentials in environment variables or secret stores - Enable audit logging for authentication events - Use TLS 1.2+ for all connections - Restrict network access to vaults
❌ Don't: - Hardcode credentials in configuration files - Commit credentials to version control - Share credentials across multiple applications - Use overly permissive authentication roles - Skip certificate validation in production - Log authentication tokens or secrets - Disable SSL/TLS for "convenience"
Troubleshooting¶
"Authentication Failed"¶
- Verify credentials are correct
- Check credential expiration (especially for time-limited tokens)
- Verify required permissions in the vault
- Check network connectivity to vault endpoint
- Review vault audit logs for permission errors
"Token Expired"¶
- Regenerate the token/credential
- Update environment variables or configuration
- Restart the daemon
"Permission Denied"¶
- Verify the authentication principal has required permissions
- Check vault RBAC configuration
- Verify correct scope/role assignment
- Review vault audit logs