At Red Hat Tech Day Netherlands 2026 in Bunnik, Fred van Zwieten and Ismail Dhaoui demoed the new Automation Portal in AAP 2.7, a self-service template gallery where operators click "Start" without knowing where a playbook lives or how it's configured. One catalog entry, "Cloud - Request Azure Resource Group," provisions an Azure resource group with appropriate RBAC. Here's a runnable playbook that models what that template does.
Playbook
---
- name: "Cloud - Request Azure Resource Group"
hosts: localhost
connection: local
gather_facts: false
vars:
resource_group_name: "rg-app-payments-prod"
resource_group_location: "westeurope"
resource_group_tags:
environment: "production"
cost_center: "payments"
requested_by: "{{ lookup('env', 'USER') }}"
rbac_assignments:
- principal_id: "11111111-2222-3333-4444-555555555555"
role_definition_name: "Contributor"
- principal_id: "66666666-7777-8888-9999-000000000000"
role_definition_name: "Reader"
tasks:
- name: Create the Azure resource group
azure.azcollection.azure_rm_resourcegroup:
name: "{{ resource_group_name }}"
location: "{{ resource_group_location }}"
tags: "{{ resource_group_tags }}"
register: rg_result
- name: Assign RBAC roles on the new resource group
azure.azcollection.azure_rm_roleassignment:
scope: "{{ rg_result.state.id }}"
assignee_object_id: "{{ item.principal_id }}"
role_definition_id: "{{ item.role_definition_name }}"
loop: "{{ rbac_assignments }}"
loop_control:
label: "{{ item.role_definition_name }} -> {{ item.principal_id }}"
- name: Report resource group details
ansible.builtin.debug:
msg: >-
Resource group {{ rg_result.state.name }} created in
{{ rg_result.state.location }} with
{{ rbac_assignments | length }} role assignment(s).
What it does
The playbook takes two inputs a requester would normally supply through the Automation Portal's form-based survey: a resource group name/location/tags, and a list of RBAC assignments (who gets which role). It runs in two steps:
azure_rm_resourcegroupcreates the resource group if it doesn't exist, and is idempotent — re-running the playbook against an existing group only reconciles tags and location, it won't fail or duplicate anything.azure_rm_roleassignmentloops overrbac_assignmentsand grants each principal (a user, group, or service principal object ID) the requested built-in role, scoped to the resource group's resource ID returned by the first task.
This mirrors the point of the "Cloud - Request Azure Resource Group" template shown in the demo: the requester never edits YAML or touches credentials directly — they fill in a short form, and the underlying job template (built from a playbook like this one) does the provisioning and access wiring behind a single "Start" button.
Notes / Gotchas
- Requires the
azure.azcollectioncollection and its Python SDK dependencies (azure-mgmt-resource,azure-identity, etc.) installed on the execution environment. - Authentication is normally handled by an Azure credential attached to the AAP job template (service principal or managed identity) rather than inline
vars— don't hardcode secrets in the playbook. role_definition_nameaccepts built-in role names likeContributororReader; for custom roles, userole_definition_idwith the full resource ID instead.- Scoping the role assignment to the resource group (not subscription) keeps access tightly bound to what was actually requested — worth enforcing as policy if you template this for self-service.
- Tag values feeding cost allocation or ownership reports (like the "Branch - After Hours Access Report" template in the same catalog) should be validated or defaulted, since a missing tag breaks downstream reporting.
A resource group plus scoped RBAC in one idempotent playbook is exactly the kind of task worth hiding behind a self-service "Start" button rather than a ticket queue.
Related Articles
- Ansible Playbook Example: Create an S3 Bucket with Encryption
- Ansible Playbook Example: Provision an EC2 Instance with Standard Tags
- Ansible azure.azcollection Example: Provision Azure ML and Storage Resources