Introduction

AWX includes built-in credential types for SSH, AWS, Azure, and other common services. But when you need to authenticate against internal APIs, custom cloud endpoints, or third-party services, you create custom credential types. This guide covers the full workflow: defining input fields, configuring injectors, and using custom credentials in playbooks.

Built-in vs Custom Credential Types

Built-inCustom
Machine (SSH)Internal REST APIs
AWS, Azure, GCPCustom cloud providers
Vault (HashiCorp)Database admin credentials
SCM (Git)LDAP bind credentials
Container RegistryMonitoring systems (Datadog, Splunk)

Create a Custom Credential Type

Via AWX UI

  1. Navigate to Administration → Credential Types
  2. Click Add
  3. Define Input Configuration (what users fill in)
  4. Define Injector Configuration (how it's exposed to playbooks)

Input Configuration

# Defines the form fields users see when creating credentials
fields:
  - id: api_url
    type: string
    label: API URL
    help_text: Base URL for the service API
  - id: api_token
    type: string
    label: API Token
    secret: true
    help_text: Authentication token
  - id: api_version
    type: string
    label: API Version
    default: "v2"
required:
  - api_url
  - api_token

Injector Configuration

# How credential values are exposed to playbooks
# Option 1: Environment variables
env:
  MY_API_URL: "{{ api_url }}"
  MY_API_TOKEN: "{{ api_token }}"
  MY_API_VERSION: "{{ api_version }}"

# Option 2: Extra variables
extra_vars:
  my_api_url: "{{ api_url }}"
  my_api_token: "{{ api_token }}"

# Option 3: File (for certificates, keys)
file:
  template: |
    [default]
    url = {{ api_url }}
    token = {{ api_token }}

Common Custom Credential Examples

REST API Service

# Input
fields:
  - id: base_url
    type: string
    label: Service URL
  - id: username
    type: string
    label: Username
  - id: password
    type: string
    label: Password
    secret: true
required:
  - base_url
  - username
  - password

# Injector
extra_vars:
  service_url: "{{ base_url }}"
  service_user: "{{ username }}"
  service_pass: "{{ password }}"

Kubernetes Kubeconfig

# Input
fields:
  - id: kubeconfig
    type: string
    label: Kubeconfig Content
    secret: true
    multiline: true
required:
  - kubeconfig

# Injector
file:
  template: "{{ kubeconfig }}"
env:
  KUBECONFIG: "{{ tower.filename }}"

Database Admin

# Input
fields:
  - id: db_host
    type: string
    label: Database Host
  - id: db_port
    type: string
    label: Port
    default: "5432"
  - id: db_admin_user
    type: string
    label: Admin Username
  - id: db_admin_pass
    type: string
    label: Admin Password
    secret: true
required:
  - db_host
  - db_admin_user
  - db_admin_pass

# Injector
env:
  PGHOST: "{{ db_host }}"
  PGPORT: "{{ db_port }}"
  PGUSER: "{{ db_admin_user }}"
  PGPASSWORD: "{{ db_admin_pass }}"
extra_vars:
  db_host: "{{ db_host }}"
  db_port: "{{ db_port }}"
  db_admin_user: "{{ db_admin_user }}"

HashiCorp Consul

# Input
fields:
  - id: consul_url
    type: string
    label: Consul URL
  - id: consul_token
    type: string
    label: ACL Token
    secret: true
  - id: consul_datacenter
    type: string
    label: Datacenter
    default: "dc1"
required:
  - consul_url
  - consul_token

# Injector
env:
  CONSUL_HTTP_ADDR: "{{ consul_url }}"
  CONSUL_HTTP_TOKEN: "{{ consul_token }}"
extra_vars:
  consul_datacenter: "{{ consul_datacenter }}"

Use Custom Credentials in Playbooks

---
- name: Call internal API using custom credential
  hosts: localhost
  connection: local
  # AWX injects extra_vars from credential automatically
  tasks:
    - name: Query service API
      ansible.builtin.uri:
        url: "{{ service_url }}/api/v1/status"
        method: GET
        headers:
          Authorization: "Bearer {{ service_pass }}"
        validate_certs: true
      register: api_response

    - name: Display result
      ansible.builtin.debug:
        var: api_response.json
---
- name: Database maintenance with custom credential
  hosts: db_servers
  # db_host, db_admin_user injected by AWX credential
  tasks:
    - name: Run database backup
      community.postgresql.postgresql_db:
        name: production
        state: dump
        target: /backups/prod-{{ ansible_date_time.date }}.sql
        login_host: "{{ db_host }}"
        login_user: "{{ db_admin_user }}"
        # Password from PGPASSWORD env var (injected)

AWX API: Create Credential Types Programmatically

---
- name: Create custom credential type via AWX API
  hosts: localhost
  vars:
    awx_host: https://awx.example.com
    awx_token: "{{ lookup('env', 'AWX_TOKEN') }}"
  tasks:
    - name: Create API credential type
      ansible.builtin.uri:
        url: "{{ awx_host }}/api/v2/credential_types/"
        method: POST
        headers:
          Authorization: "Bearer {{ awx_token }}"
          Content-Type: application/json
        body_format: json
        body:
          name: "Internal API Service"
          description: "Credentials for internal microservices"
          kind: cloud
          inputs:
            fields:
              - id: api_url
                type: string
                label: API URL
              - id: api_token
                type: string
                label: API Token
                secret: true
            required:
              - api_url
              - api_token
          injectors:
            extra_vars:
              api_url: "{% raw %}{{ api_url }}{% endraw %}"
              api_token: "{% raw %}{{ api_token }}{% endraw %}"
        status_code: [200, 201]

Troubleshooting

IssueSolution
Credential field not available in playbookCheck injector uses extra_vars (not just env)
Secret value shows as $encrypted$Expected — AWX never displays secrets; they're injected at runtime
YAML parse error in injectorValidate YAML syntax; use quotes around Jinja2 expressions
File injector path unknownUse {{ tower.filename }} to reference the temp file path
Credential type won't deleteRemove all credentials using this type first

Best Practices

  1. Use secret: true for any sensitive field — masks in UI and logs
  2. Prefer extra_vars over env — more explicit in playbooks
  3. Use env for tools that read environment (kubectl, terraform, psql)
  4. Use file injector for certificates and kubeconfigs
  5. Name consistently — prefix with service name (e.g., "Datadog API", "Internal CMDB")
  6. Document required fields — use help_text for each input field
  7. Version control definitions — store input/injector YAML in Git, create via API

Conclusion

Custom credential types extend AWX to authenticate against any service. Define input fields (what users provide), configure injectors (how values reach playbooks), and attach credentials to job templates. Use extra_vars for playbook access, env for CLI tools, and file for certificates. Store credential type definitions in Git and create them via the AWX API for reproducibility.