AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

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 PracticesAAP 2.6 RBAC and Gateway APIHashiCorp Vault Integration with Ansible Automation PlatformAAP 2.6 HashiCorp Vault Integration with EDAAAP 2.6 Architecture and Components: Complete Guide

Category: events

Browse all Ansible tutorials · AnsiblePilot Home