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-in | Custom |
|---|---|
| Machine (SSH) | Internal REST APIs |
| AWS, Azure, GCP | Custom cloud providers |
| Vault (HashiCorp) | Database admin credentials |
| SCM (Git) | LDAP bind credentials |
| Container Registry | Monitoring systems (Datadog, Splunk) |
Create a Custom Credential Type
Via AWX UI
- Navigate to Administration → Credential Types
- Click Add
- Define Input Configuration (what users fill in)
- 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
| Issue | Solution |
|---|---|
| Credential field not available in playbook | Check 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 injector | Validate YAML syntax; use quotes around Jinja2 expressions |
| File injector path unknown | Use {{ tower.filename }} to reference the temp file path |
| Credential type won't delete | Remove all credentials using this type first |
Best Practices
- Use
secret: truefor any sensitive field — masks in UI and logs - Prefer
extra_varsoverenv— more explicit in playbooks - Use
envfor tools that read environment (kubectl, terraform, psql) - Use
fileinjector for certificates and kubeconfigs - Name consistently — prefix with service name (e.g., "Datadog API", "Internal CMDB")
- Document required fields — use
help_textfor each input field - 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.