AAP 2.6 Credential Management: Vaults, External Secrets, and Machine Credentials
By Luca Berton · Published 2024-01-01 · Category: events
Master credential management in AAP 2.6: machine credentials, vault passwords, cloud credentials, custom credential types, external secret backends (HashiCorp.
Why Credential Management Matters in AAP
Automation at enterprise scale means managing hundreds of credentials: SSH keys, API tokens, cloud provider secrets, database passwords, and vault passwords. AAP 2.6's credential system provides: • Centralized storage — one place for all automation credentials • RBAC-controlled access — teams see only the credentials they need • External secret backends — pull secrets at runtime from HashiCorp Vault, CyberArk, AWS Secrets Manager • Audit logging — track who used which credential and when • No plaintext exposure — credentials never appear in job output or logs
See also: Integrating HashiCorp Vault with Event-Driven Ansible in AAP 2.6
Built-in Credential Types
AAP 2.6 ships with credential types for common use cases:
| Credential Type | Purpose | Key Fields | |----------------|---------|------------| | Machine | SSH/WinRM access to managed hosts | username, password, SSH key, privilege escalation | | Source Control | Git/SVN repository access | username, password/token, SSH key | | Vault | Ansible Vault decryption | vault password | | Amazon Web Services | AWS API access | access key, secret key, STS token | | Microsoft Azure Resource Manager | Azure API access | subscription, client ID, secret, tenant | | Google Compute Engine | GCP API access | service account JSON, project | | VMware vCenter | vSphere API access | host, username, password | | Red Hat Satellite | Satellite 6 API access | host, username, password | | Container Registry | Pull EE images | host, username, password | | Galaxy/Automation Hub API Token | Collection access | URL, token |
Creating Machine Credentials
- name: Create SSH machine credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Production SSH Key"
organization: "Operations"
credential_type: "Machine"
inputs:
username: ansible
ssh_key_data: "{{ lookup('file', '/path/to/id_rsa') }}"
become_method: sudo
become_username: root
state: present
Creating Cloud Credentials
- name: Create AWS credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "AWS Production"
organization: "Cloud Team"
credential_type: "Amazon Web Services"
inputs:
username: "{{ aws_access_key }}"
password: "{{ aws_secret_key }}"
state: present
- name: Create Azure credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Azure Production"
organization: "Cloud Team"
credential_type: "Microsoft Azure Resource Manager"
inputs:
subscription: "{{ azure_subscription_id }}"
client: "{{ azure_client_id }}"
secret: "{{ azure_client_secret }}"
tenant: "{{ azure_tenant_id }}"
state: present
External Secret Backends
Instead of storing secrets in AAP's database, pull them at runtime from external secret management systems.
HashiCorp Vault
# Step 1: Create HashiCorp Vault credential
- name: Create Vault lookup credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "HashiCorp Vault Lookup"
organization: "Operations"
credential_type: "HashiCorp Vault Secret Lookup"
inputs:
url: "https://vault.example.com:8200"
token: "{{ vault_token }}"
api_version: "v2"
state: present
# Step 2: Create machine credential that pulls from Vault
- name: Create Vault-backed machine credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Production SSH - Vault Backed"
organization: "Operations"
credential_type: "Machine"
inputs:
username: ansible
input_sources:
- input_field_name: "password"
source_credential: "HashiCorp Vault Lookup"
metadata:
secret_path: "secret/data/ansible/production"
secret_key: "ssh_password"
- input_field_name: "become_password"
source_credential: "HashiCorp Vault Lookup"
metadata:
secret_path: "secret/data/ansible/production"
secret_key: "become_password"
state: present
CyberArk
- name: Create CyberArk lookup credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "CyberArk Central Credential Provider"
organization: "Security"
credential_type: "CyberArk Central Credential Provider Lookup"
inputs:
url: "https://cyberark.example.com"
app_id: "AnsibleAutomation"
verify: true
state: present
AWS Secrets Manager
- name: Create AWS Secrets Manager lookup
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "AWS Secrets Manager Lookup"
organization: "Cloud Team"
credential_type: "AWS Secrets Manager Lookup"
inputs:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
region: "us-east-1"
state: present
Azure Key Vault
- name: Create Azure Key Vault lookup
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Azure Key Vault Lookup"
organization: "Cloud Team"
credential_type: "Microsoft Azure Key Vault"
inputs:
url: "https://my-keyvault.vault.azure.net/"
client: "{{ azure_client_id }}"
secret: "{{ azure_client_secret }}"
tenant: "{{ azure_tenant_id }}"
state: present
See also: HashiCorp Vault Integration with Ansible Automation Platform: Credential Management at Scale
Custom Credential Types
Create custom credential types for services not covered by built-in types:
Example: Database Credential Type
# Step 1: Define the credential type
- name: Create database credential type
ansible.platform.credential_type:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Database Credential"
kind: "cloud"
inputs:
fields:
- id: db_host
type: string
label: "Database Host"
- id: db_port
type: string
label: "Database Port"
default: "5432"
- id: db_name
type: string
label: "Database Name"
- id: db_username
type: string
label: "Username"
- id: db_password
type: string
label: "Password"
secret: true
required:
- db_host
- db_name
- db_username
- db_password
injectors:
extra_vars:
database_host: "{% raw %}{{ db_host }}{% endraw %}"
database_port: "{% raw %}{{ db_port }}{% endraw %}"
database_name: "{% raw %}{{ db_name }}{% endraw %}"
database_user: "{% raw %}{{ db_username }}{% endraw %}"
database_pass: "{% raw %}{{ db_password }}{% endraw %}"
state: present
# Step 2: Create a credential using the custom type
- name: Create production database credential
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Production PostgreSQL"
organization: "Database Team"
credential_type: "Database Credential"
inputs:
db_host: "db-prod.example.com"
db_port: "5432"
db_name: "application"
db_username: "app_user"
db_password: "{{ vault_db_password }}"
state: present
Injector Types
Credential injectors control how secrets are passed to playbooks:
| Injector | Method | Use Case |
|----------|--------|----------|
| extra_vars | Extra variables | Most common — playbook accesses as variables |
| env | Environment variables | Cloud SDKs (AWS_ACCESS_KEY_ID, etc.) |
| file | Temporary file | SSH keys, certificates, kubeconfig |
injectors:
# As extra variables
extra_vars:
api_token: "{% raw %}{{ token }}{% endraw %}"
# As environment variables
env:
API_TOKEN: "{% raw %}{{ token }}{% endraw %}"
API_URL: "{% raw %}{{ url }}{% endraw %}"
# As a temporary file
file:
template: |
[default]
token = {% raw %}{{ token }}{% endraw %}
url = {% raw %}{{ url }}{% endraw %}
extra_vars:
config_file: "{% raw %}{{ tower.filename.config }}{% endraw %}"
Multi-Credential Job Templates
AAP 2.6 supports assigning multiple credentials to a single job template:
- name: Create multi-credential job template
ansible.platform.job_template:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Full Stack Deployment"
organization: "DevOps"
project: "infrastructure"
playbook: "deploy.yml"
inventory: "Production"
credentials:
- "Production SSH Key" # Machine credential
- "AWS Production" # Cloud credential
- "Production PostgreSQL" # Custom database credential
- "Ansible Vault - Prod" # Vault credential
- "Private Hub Registry" # Container registry
state: present
The playbook can access all credential values through extra variables and environment variables simultaneously.
See also: Ansible Secrets Management: Best Practices for Enterprise Credential Security
Credential RBAC
Control who can use, view, and manage credentials:
| Permission | Can View | Can Use in Jobs | Can Edit | Can Admin | |-----------|---------|-----------------|---------|----------| | Read | ✅ | ❌ | ❌ | ❌ | | Use | ✅ | ✅ | ❌ | ❌ | | Admin | ✅ | ✅ | ✅ | ✅ |
- name: Grant credential use to team
ansible.platform.role:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
role: "Use"
credential: "Production SSH Key"
team: "Operations"
state: present
Team members with Use permission can attach the credential to job templates but cannot view the actual secret values.
Credential Rotation Best Practices
Automated Rotation with External Backends
When using external secret backends (HashiCorp Vault, CyberArk), rotation happens externally: External system rotates the secret on its schedule AAP pulls the fresh secret at job runtime No credential updates needed in AAP
This is the recommended approach for production.
Manual Rotation Playbook
For credentials stored directly in AAP:
- name: Rotate machine credential password
ansible.platform.credential:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Production SSH Key"
credential_type: "Machine"
inputs:
username: ansible
password: "{{ new_password }}"
become_method: sudo
become_password: "{{ new_become_password }}"
state: present
- name: Verify credential works
ansible.platform.ad_hoc_command:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
inventory: "Production Servers"
credential: "Production SSH Key"
module_name: ping
limit: "test-host.example.com"
FAQ
Are credentials encrypted at rest in AAP?
Yes. Credentials are encrypted in the PostgreSQL database using Fernet symmetric encryption. The encryption key is stored separately from the database. Even database administrators cannot read credential values without the encryption key.
Can I export credentials from AAP?
No. By design, AAP does not allow exporting credential secret values. You can export credential metadata (name, type, organization) but not the actual secrets. This prevents credential exfiltration.
Which external secret backend should I use?
Use whatever your organization already has. HashiCorp Vault is the most common in Ansible environments. CyberArk is common in enterprises with existing PAM infrastructure. AWS Secrets Manager / Azure Key Vault are natural choices for cloud-heavy organizations.
Can job output expose credentials?
AAP automatically redacts credential values from job output. If a playbook prints a variable that contains a credential value, AAP replaces it with $encrypted$ in the output. However, be careful with no_log: false on tasks that handle secrets.
How many credentials can a job template use?
There is no hard limit. A job template can use multiple credentials of different types simultaneously. The only constraint is that you can have at most one Machine credential and one Vault credential per job template.
Conclusion
Credential management is the security foundation of AAP 2.6. By combining built-in credential types, external secret backends, custom credential types, and RBAC-controlled access, you can manage secrets at scale without compromising security. The key principle: secrets should be managed externally and pulled at runtime, never stored in playbooks or version control.
Related Articles
• AAP 2.6 Security Best Practices • AAP 2.6 RBAC and Gateway API • HashiCorp Vault Integration with Ansible Automation Platform • AAP 2.6 HashiCorp Vault Integration with EDA • AAP 2.6 Architecture and Components: Complete GuideCategory: events