HashiCorp Vault Integration with Ansible Automation Platform: Credential Management at Scale
By Luca Berton · Published 2024-01-01 · Category: installation
How to integrate HashiCorp Vault with Ansible Automation Platform for enterprise credential management.
Introduction
Managing credentials at scale is one of the biggest challenges in enterprise automation. Hard-coded passwords in playbooks, shared SSH keys, and static API tokens create security vulnerabilities that grow with your infrastructure. HashiCorp Vault solves this by providing centralized secret management with dynamic credentials, automatic rotation, and detailed audit logging.
When integrated with Ansible Automation Platform (AAP), Vault becomes the single source of truth for all automation credentials — from database passwords to cloud provider tokens to SSH keys.
See also: Ansible Zero Trust Security: Implement Zero Trust Architecture for Enterprise Infrastructure
Why Vault + AAP?
Traditional credential management breaks down at scale. Teams share static passwords through encrypted Ansible Vault files, but these still require manual rotation and offer no audit trail of who accessed what. HashiCorp Vault introduces dynamic secrets — credentials generated on-demand with automatic expiration.
Key benefits of the integration: • Dynamic credentials — Database passwords, AWS keys, and SSH certificates generated per-job with automatic expiration • Centralized policy — Fine-grained access control based on team, project, and environment • Complete audit trail — Every secret access logged with timestamp, identity, and source IP • Zero-trust model — No long-lived credentials stored anywhere in the automation pipeline • Automatic rotation — Vault handles credential lifecycle; no manual intervention needed
Architecture
The integration works through AAP's credential plugin system and Ansible's hashi_vault lookup plugin: AAP authenticates to Vault using AppRole (machine-to-machine auth) At job launch, AAP fetches required secrets from Vault Secrets are injected as extra vars or environment variables Playbooks use dynamic credentials — never stored on disk After job completion, dynamic credentials expire automatically
See also: Ansible AAP as OIDC Authentication Provider for HashiCorp Vault: Zero Trust Workflow
Setup Vault for AAP
Enable AppRole Authentication
# Enable AppRole auth method
vault auth enable approle
# Create policy for AAP with least-privilege access
vault policy write aap-automation - <<POLICY
# Read secrets from KV store
path "secret/data/ansible/*" {
capabilities = ["read", "list"]
}
# Generate dynamic database credentials
path "database/creds/ansible-role" {
capabilities = ["read"]
}
# Generate dynamic AWS credentials
path "aws/creds/ansible-role" {
capabilities = ["read"]
}
# Sign SSH certificates
path "ssh-client-signer/sign/ansible-role" {
capabilities = ["create", "update"]
}
POLICY
# Create AppRole for AAP
vault write auth/approle/role/aap \
token_policies="aap-automation" \
token_ttl=1h \
token_max_ttl=4h \
secret_id_ttl=720h
# Retrieve credentials for AAP configuration
vault read auth/approle/role/aap/role-id
vault write -f auth/approle/role/aap/secret-id
Store Static Secrets
# Enable KV v2 secrets engine
vault secrets enable -path=secret kv-v2
# Store automation credentials
vault kv put secret/ansible/database \
username="ansible_svc" \
password="SecureDbP@ss!"
vault kv put secret/ansible/api-keys \
github_token="ghp_xxxxxxxxxxxx" \
slack_webhook="https://hooks.slack.com/xxx"
Configure AAP Credential Type
Create a custom credential type in AAP to store Vault connection details:
# Input Configuration
fields:
- id: vault_url
type: string
label: Vault URL
- id: vault_role_id
type: string
label: Vault Role ID
- id: vault_secret_id
type: string
label: Vault Secret ID
secret: true
- id: vault_path
type: string
label: Secret Path
# Injector Configuration
extra_vars:
vault_url: "{{ vault_url }}"
vault_secret_path: "{{ vault_path }}"
env:
VAULT_ADDR: "{{ vault_url }}"
VAULT_ROLE_ID: "{{ vault_role_id }}"
VAULT_SECRET_ID: "{{ vault_secret_id }}"
See also: Ansible Automation Platform and HashiCorp Vault: End-to-End Trusted Automation (Integration Guide)
Ansible Playbook with Vault Lookup
Install the Collection
ansible-galaxy collection install community.hashi_vault
pip install hvac # HashiCorp Vault Python client
Read Static Secrets
---
- name: Deploy application with Vault credentials
hosts: webservers
become: true
vars:
vault_addr: "{{ lookup('env', 'VAULT_ADDR') }}"
db_creds: "{{ lookup('community.hashi_vault.hashi_vault',
'secret/data/ansible/database',
url=vault_addr,
auth_method='approle',
role_id=lookup('env', 'VAULT_ROLE_ID'),
secret_id=lookup('env', 'VAULT_SECRET_ID')
) }}"
tasks:
- name: Deploy database configuration
ansible.builtin.template:
src: db-config.j2
dest: /etc/myapp/database.conf
mode: '0600'
vars:
db_user: "{{ db_creds.data.username }}"
db_pass: "{{ db_creds.data.password }}"
no_log: true
Dynamic Database Credentials
- name: Use dynamic database credentials
hosts: appservers
vars:
dynamic_creds: "{{ lookup('community.hashi_vault.hashi_vault',
'database/creds/ansible-role',
url=vault_addr,
auth_method='approle',
role_id=lookup('env', 'VAULT_ROLE_ID'),
secret_id=lookup('env', 'VAULT_SECRET_ID')
) }}"
tasks:
- name: Configure application
ansible.builtin.template:
src: app-config.j2
dest: /etc/myapp/config.yml
vars:
db_username: "{{ dynamic_creds.username }}"
db_password: "{{ dynamic_creds.password }}"
no_log: true
# Credentials auto-expire after TTL!
Dynamic AWS Credentials
- name: Provision AWS with dynamic credentials
hosts: localhost
connection: local
vars:
aws_creds: "{{ lookup('community.hashi_vault.hashi_vault',
'aws/creds/ansible-role',
url=vault_addr,
auth_method='approle',
role_id=lookup('env', 'VAULT_ROLE_ID'),
secret_id=lookup('env', 'VAULT_SECRET_ID')
) }}"
tasks:
- name: Launch EC2 instance
amazon.aws.ec2_instance:
name: web-server
instance_type: t3.micro
image_id: ami-0abcdef1234567890
aws_access_key: "{{ aws_creds.access_key }}"
aws_secret_key: "{{ aws_creds.secret_key }}"
security_token: "{{ aws_creds.security_token }}"
no_log: true
SSH Certificate Signing
- name: Sign SSH key with Vault CA
hosts: localhost
connection: local
tasks:
- name: Sign SSH public key
community.hashi_vault.vault_write:
url: "{{ vault_addr }}"
path: ssh-client-signer/sign/ansible-role
data:
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
valid_principals: deploy
ttl: 30m
register: signed_key
no_log: true
- name: Write signed certificate
ansible.builtin.copy:
content: "{{ signed_key.data.signed_key }}"
dest: ~/.ssh/id_rsa-cert.pub
mode: '0600'
Vault Secret Engines for Ansible
| Engine | Use Case | Credential Type | |--------|----------|----------------| | KV v2 | Static secrets | Passwords, API keys, tokens | | Database | Database access | Dynamic username/password (PostgreSQL, MySQL, MongoDB) | | AWS | Cloud provisioning | Dynamic IAM credentials with STS | | SSH | Server access | Signed SSH certificates (short-lived) | | PKI | TLS/mTLS | Dynamic X.509 certificates | | Azure | Azure resources | Dynamic service principals | | GCP | GCP resources | Dynamic service account keys |
Best Practices
Use dynamic credentials whenever possible — Short-lived secrets that auto-expire eliminate the rotation burden entirely Always useno_log: true — On every task that handles Vault data to prevent secrets in job output
Scope Vault policies tightly — Each AAP team/project gets its own Vault policy with minimum required permissions
Use AppRole for machine authentication — Not human user tokens; AppRole is designed for automated workflows
Enable audit logging — Every secret access should be logged: vault audit enable file file_path=/var/log/vault-audit.log
Rotate AppRole Secret IDs — Automate Secret ID rotation on a regular schedule
Separate environments — Use different Vault paths or namespaces for dev/staging/production
Test with --check mode — Vault lookups still execute in check mode; plan accordingly
Troubleshooting
"Permission denied" from Vault
# Check current token policies
vault token lookup
# Verify path access directly
vault kv get secret/ansible/database
# Check AppRole role configuration
vault read auth/approle/role/aap
"hvac module not found"
pip install hvac
# On AAP: Add hvac to your execution environment requirements
FAQ
Can I use this with ansible-playbook CLI (not AAP)?
Yes — set VAULT_ADDR and VAULT_TOKEN environment variables, or pass auth_method parameters directly in the lookup plugin. AAP just wraps this in its credential system.
HashiCorp Vault vs Ansible Vault?
Ansible Vault encrypts files at rest (symmetric encryption). HashiCorp Vault is a full secret management platform with dynamic credentials, rotation, access policies, and audit logging. They complement each other — use Ansible Vault to encrypt the Vault connection details.
Vault Community vs Enterprise?
Community (free) works fully with AAP. Enterprise adds namespaces (multi-tenancy), cross-datacenter replication, HSM auto-unseal, and Sentinel policies for governance.
Conclusion
Integrating HashiCorp Vault with Ansible Automation Platform transforms credential management from a security liability into a competitive advantage. Dynamic secrets, automatic rotation, and comprehensive audit logging enable true zero-trust automation at enterprise scale.
Related Articles
• Ansible Vault Complete Guide • Ansible AWX • Ansible AWS Complete GuideCategory: installation