Export and import Ansible Automation Platform (AAP) 2.5+ configuration to/from Git using upstream infra.aap_configuration and infra.aap_configuration_extended.
| Playbook | Purpose |
|---|---|
config-controller-export.yaml |
Export AAP → Git (aap-export/) |
config-controller-filetree.yaml |
Import Git (aap-export/) → AAP |
Both playbooks use the same tree: export writes aap-export/, import reads it. This public template ships an empty aap-export/ — run export against your AAP to populate it (prefer a private working repo for environment-specific data).
flowchart LR
AAP["AAP Platform"]
ExportPB["Export playbook"]
Git["Git repo / aap-export"]
ImportPB["Import playbook"]
AAP -->|"filetree_create"| ExportPB
ExportPB -->|"git push"| Git
Git -->|"git clone"| ImportPB
ImportPB -->|"filetree_read + dispatch"| AAP
- AAP 2.5+ (Gateway API:
/api/gateway/v1/tokens/) - Admin user (or equivalent) that can manage Controller, Gateway, Hub, and EDA objects you intend to CaC
- Network access from the Execution Environment to:
- AAP Gateway URL
- GitHub (HTTPS)
Install these into your EE (see collections/requirements.yml). Keep certified collection versions aligned with your AAP release.
| Collection | Version | Role |
|---|---|---|
infra.aap_configuration |
>=4.7.0 |
dispatch and object roles (Controller, Gateway, Hub, EDA) |
infra.aap_configuration_extended |
4.8.0 (pinned) |
filetree_create, filetree_read |
ansible.platform |
>=2.5.0 |
Gateway / platform API modules (dependency of the infra collections) |
ansible.controller |
>=4.6.0 |
Controller API modules |
ansible.hub |
>=1.0.0 |
Automation Hub / PAH modules |
ansible.eda |
>=2.5.0 |
Event-Driven Ansible modules |
infra.aap_configuration declares ansible.platform, ansible.controller, ansible.hub, and ansible.eda as dependencies; list them explicitly in the EE so builds and air-gapped installs do not miss them.
Also ensure the EE has the git CLI.
Example EE requirements snippet:
collections:
- name: infra.aap_configuration
version: ">=4.7.0"
- name: infra.aap_configuration_extended
version: "4.8.0"
- name: ansible.platform
version: ">=2.5.0"
- name: ansible.controller
version: ">=4.6.0"
- name: ansible.hub
version: ">=1.0.0"
- name: ansible.eda
version: ">=2.5.0"- A Git repository for this CaC content (this repo)
- A Personal Access Token (PAT) with
reposcope- Export needs write
- Import needs read (write not required)
vars/aap_vars.yamlis expected to be ansible-vault encrypted (contains AAP password)- An AAP credential of type Vault with the same vault password, attached to both Job Templates
- Optionally encrypt
vars/vault_secrets.yamlwhen you enable vault-backed credential/user import
Without the Vault credential on the JT, jobs fail with:
Decryption failed (no vault secrets were found that could decrypt) on .../vars/aap_vars.yaml
cp vars/aap_vars.yaml.example vars/aap_vars.yaml
cp vars/git_vars.yaml.example vars/git_vars.yamlEdit:
| File | Required settings |
|---|---|
vars/aap_vars.yaml |
aap_hostname (full Gateway URL, e.g. https://aap.example.com), aap_username, aap_password, aap_validate_certs |
vars/git_vars.yaml |
github_repo_url, github_branch (usually main), github_export_dir_name (aap-export) |
Encrypt AAP credentials:
ansible-vault encrypt vars/aap_vars.yamlgit_vars.yaml does not need encryption unless you later store a PAT there. Git auth is normally supplied by the Job Template survey.
Keep vars/aap_vars.yaml, vars/git_vars.yaml, and filled vars/vault_secrets.yaml local (they are gitignored). For AAP Project sync, either use a private fork/working repo that holds your real aap-export/ and connection vars, or inject credentials via Job Template surveys / credentials instead of committing secrets.
- Automation Execution → Infrastructure → Credentials → Create
- Credential type: Vault
- Vault Password: the password used with
ansible-vault encrypt - Leave Vault Identifier empty (default vault)
- Save
- Projects → Create
- SCM type Git → this repository URL
- SCM branch:
main(or your working branch) - Attach a Source Control credential if the repo is private
- Enable Update Revision on Launch
- If a force-push ever breaks sync (
non-fast-forwardon fetch), temporarily enable Delete on Update, sync once, then disable it again
Create two Job Templates on the Project from step 3. Both use the same credentials and survey; only the playbook differs.
| Job Template (suggested name) | Playbook | Direction |
|---|---|---|
| CaC Export | config-controller-export.yaml |
AAP → Git (aap-export/) |
| CaC Import | config-controller-filetree.yaml |
Git (aap-export/) → AAP |
- Automation Execution → Templates → Create → Job Template
- Name: as in the table above (or your own names)
- Job type: Run
- Inventory: any inventory the job can run against (localhost / a dummy inventory is fine; the playbooks talk to AAP via API, not via inventory hosts)
- Project: the Project from step 3
- Execution Environment: an EE that includes
infra.aap_configuration,infra.aap_configuration_extended, and thegitCLI (see Prerequisites) - Credentials: attach the Vault credential from step 2 (required to decrypt
vars/aap_vars.yaml) - Enable Survey (Prompt on launch) with these questions:
| Variable name | Question / prompt | Type | Required | Notes |
|---|---|---|---|---|
github_user |
GitHub username | Text | Yes | Used in the HTTPS clone/push URL |
github_password |
GitHub PAT | Password | Yes | PAT with repo scope (write for Export, read for Import) |
github_branch |
Git branch | Text | No | Optional; overrides vars/git_vars.yaml |
- Save
- Create a Job Template with the shared settings above
- Set Playbook to
config-controller-export.yaml - Save
- Launch once to verify: enter survey values → job should push an updated
aap-export/(and regeneratevars/vault_secrets.yamlplaceholders) togithub_branch
- Create a second Job Template with the same shared settings
- Set Playbook to
config-controller-filetree.yaml - Save
- Launch after
aap-export/has content: enter survey values → job applies the filetree to AAP (credentials / EDA credentials / Gateway users stay skipped until you enable vault-backed import)
- Sync/update the Project if needed
- Launch the Export Job Template
- Enter survey values (
github_user/github_password) - On success, the job:
- Authenticates to AAP Gateway
- Clones/updates the Git repo
- Runs
filetree_createinto a temp dir - Copies into
aap-export/ - Filters out
aap_operator_service_account - Regenerates
vars/vault_secrets.yamlplaceholders for anyvaulted_*refs - Commits and pushes to
github_branch
- Launch the Import Job Template
- Enter survey values
- On success, the job:
- Clones the Git repo
- Discovers orgs from
controller_organization.yaml(+ORGANIZATIONLESSif present) - Runs
filetree_read+dispatchper org, then at root
Default import behavior: Controller credentials, EDA credentials, and Gateway users are skipped until you fill/encrypt vars/vault_secrets.yaml and enable them (see below). Everything else in the export tree is applied, minus runtime/ephemeral exclusions.
Export writes secret fields as Jinja references, for example:
password: "{{ vaulted_controller_credentials_github_scm_password }}"and generates placeholders in vars/vault_secrets.yaml (see vars/vault_secrets.yaml.example for the shape):
vaulted_controller_credentials_github_scm_password: "changeme"
vaulted_gateway_users_admin_password: "changeme"Those objects are not imported until vault-backed import is enabled. They do not need to be pre-created manually in AAP once vault import is on — import creates/updates them from Git.
- Replace every
"changeme"invars/vault_secrets.yamlwith real values - Encrypt:
ansible-vault encrypt vars/vault_secrets.yaml- Use the same AAP Vault credential password (or rekey everything to one password)
- Toggle the import paths with the helper (recommended):
bash helper/toggle_vault_import.shOr edit by hand in tasks/import_org.yml and tasks/import_root.yml:
- Uncomment the
filetree_*paths for credentials/users - Remove from
aap_configuration_dispatcher_exclude_roles:controller_credentialscontroller_credential_input_sourceseda_credentialsgateway_users
- Load
vars/vault_secrets.yamlfromconfig-controller-filetree.yamlvars_files
- Commit, push, sync the Project, run Import
Interactive script that comments / uncomments the vault-backed import wiring for you.
bash helper/toggle_vault_import.shIt asks:
- ENABLE or DISABLE
- Which object groups to change:
- Controller credentials (+ input sources)
- EDA credentials
- Gateway users
| Mode | What it does |
|---|---|
| Enable | Uncomments filetree_* paths, removes roles from aap_configuration_dispatcher_exclude_roles, adds vars/vault_secrets.yaml to the import playbook vars_files |
| Disable | Comments those paths (sets /dev/null), adds roles back to exclusions, stops loading vault_secrets.yaml |
Always commit the script’s file changes before running Import from AAP.
Playbooks load:
vars_files:
- vars/aap_vars.yaml
- vars/git_vars.yaml| Variable | Source | Notes |
|---|---|---|
aap_hostname |
vars/aap_vars.yaml |
Full Gateway URL with https:// |
aap_username / aap_password |
vars/aap_vars.yaml |
Encrypt this file |
aap_validate_certs |
vars/aap_vars.yaml |
true in production with valid certs |
github_repo_url |
vars/git_vars.yaml |
HTTPS clone/push URL |
github_branch |
vars/git_vars.yaml or survey |
Target branch for clone/push |
github_export_dir_name |
vars/git_vars.yaml |
Directory name in repo (aap-export) |
github_user / github_password |
JT survey | GitHub user + PAT |
| Scope | Resources |
|---|---|
| Controller | Orgs, projects, inventories, sources, hosts, groups, job/workflow templates, credentials (vaulted_*), labels, teams, schedules, credential types, instance groups, EEs, settings, roles |
| Gateway | Authenticators/maps, HTTP ports, services, settings, orgs, users (vaulted_*), teams, routes, service clusters/keys/nodes, role definitions/assignments |
| Hub | Namespaces, collection remotes/repos, collection metadata, EE registries/repos/images |
| EDA | Custom credential types, credentials (vaulted_*), decision environments, event streams, projects, rulebook activations |
| Role | Reason |
|---|---|
controller_inventory_source_update |
Runtime sync |
controller_job_launch / controller_workflow_launch |
Launch actions |
controller_instances / controller_instance_groups |
Ephemeral pod hostnames |
hub_collection |
Content comes from remotes |
hub_ee_registry_index / hub_ee_registry_sync |
Sync/index triggers |
hub_collection_repository_sync / hub_ee_repository_sync |
Sync triggers |
eda_controller_tokens |
Runtime tokens |
controller_credentials, controller_credential_input_sources, eda_credentials, gateway_users
- Managed EDA credential types:
Postgres,Red Hat Ansible Automation Platform - Gateway user
aap_operator_service_account(operator-managed; never CaC’d)
aap-configuration-as-code/
├── config-controller-export.yaml # Export playbook
├── config-controller-filetree.yaml # Import playbook
├── collections/requirements.yml # EE collection pins
├── tasks/
│ ├── aap_auth.yml
│ ├── aap_auth_cleanup.yml
│ ├── git_clone.yml
│ ├── filter_gateway_users.yml
│ ├── import_org.yml
│ └── import_root.yml
├── vars/
│ ├── *.example # Templates (tracked)
│ ├── aap_vars.yaml # Local only — vault-encrypt (AAP login)
│ ├── git_vars.yaml # Local only — repo URL / branch
│ └── vault_secrets.yaml # Local / export-generated; fill to import secrets
├── helper/toggle_vault_import.sh # Comment/uncomment vault import wiring
├── tests/ # CI checks
└── aap-export/ # Created by export (empty in this template)
| Symptom | What to check |
|---|---|
Decryption failed ... vars/aap_vars.yaml |
Vault credential attached to JT; password matches ansible-vault encrypt |
Project update non-fast-forward / fetch rejected |
Enable Delete on Update, sync once (common after force-push) |
| Git push/clone auth errors | Survey PAT has repo scope; not expired |
undefined variable: vaulted_* on import |
Vault-backed objects enabled without filled/loaded vault_secrets.yaml — run helper to disable, or complete vault setup |
| Missing modules / roles | Rebuild EE from collections/requirements.yml |
| Import stops mid-dispatch | Fail-fast by design; fix object data or add role to exclusions |