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

Built-in Credential Types

AAP 2.6 ships with credential types for common use cases:

Credential TypePurposeKey Fields
MachineSSH/WinRM access to managed hostsusername, password, SSH key, privilege escalation
Source ControlGit/SVN repository accessusername, password/token, SSH key
VaultAnsible Vault decryptionvault password
Amazon Web ServicesAWS API accessaccess key, secret key, STS token
Microsoft Azure Resource ManagerAzure API accesssubscription, client ID, secret, tenant
Google Compute EngineGCP API accessservice account JSON, project
VMware vCentervSphere API accesshost, username, password
Red Hat SatelliteSatellite 6 API accesshost, username, password
Container RegistryPull EE imageshost, username, password
Galaxy/Automation Hub API TokenCollection accessURL, 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

See also: hashicorp.vault Ansible Collection: Complete Guide for AAP 2.7

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

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:

InjectorMethodUse Case
extra_varsExtra variablesMost common — playbook accesses as variables
envEnvironment variablesCloud SDKs (AWS_ACCESS_KEY_ID, etc.)
fileTemporary fileSSH 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 %}"

See also: AAP 2.7 Workload Identity: Configure OIDC Credential Types for HashiCorp Vault (Step-by-Step)

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.

Credential RBAC

Control who can use, view, and manage credentials:

PermissionCan ViewCan Use in JobsCan EditCan 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.

See also: Ansible OIDC Integration with HashiCorp Vault: Zero Trust Credential Management (Complete Guide)

Credential Rotation Best Practices

Automated Rotation with External Backends

When using external secret backends (HashiCorp Vault, CyberArk), rotation happens externally:

  1. External system rotates the secret on its schedule
  2. AAP pulls the fresh secret at job runtime
  3. 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.

Category: events

Browse all Ansible tutorials · AnsiblePilot Home