Group Managed Service Account Playbook Usage Guide
Requirements
- The target host must be a Windows Server with the RSAT-AD-PowerShell feature available. The playbook will install it automatically if it is not already present.
Prerequisites
- A domain account with permissions to create security groups and service accounts in Active Directory must be available.
- The playbook must be run against a single Windows host using
--limit. The host does not need to be a domain controller, but must be domain-joined. - Define your gMSA definitions in
extra_vars/gmsas.yml. See Sample Variables below. - The following variables must be defined. The variables should be all uppercase when defined as environment variables, but all lowercase when defined in
host_vars,group_vars, or an Ansible vault.
Usage
- Define your gMSA definitions in
extra_vars/gmsas.ymlusing the sample variables below. - Run the
playbooks/create-gmsa.ymlplaybook against a single domain-joined Windows host. The playbook will create the AD security group, add the specified members, and create the gMSA with the group as the allowed principal to retrieve the password.
Optional Variables
The following optional variables can be passed to override default AD paths and group ownership:
| Variable | Description |
|---|---|
security_group_path |
OU path for the security group (e.g. OU=Groups,DC=sapphire,DC=dev) |
service_account_path |
OU path for the gMSA (e.g. OU=Service Accounts,DC=sapphire,DC=dev) |
managed_by |
AD identity to set as the group's Managed By attribute |
Inventory Groups and the Constructed Plugin
When using members_group, the group name must match an Ansible inventory group. The ansible.builtin.constructed inventory plugin is the recommended way to create these groups from hostname naming conventions — no manual maintenance required as hosts are added or removed.
This repo includes inventory.constructed.yml as a ready-to-use example. It creates groups in two ways:
keyed_groups— auto-derives a group from the role segment of the hostname (e.g.epic-kpr-*→role_kpr,epic-msql-*→role_msql). Any new host matching the naming convention is grouped automatically.groups— explicit named groups using Jinja2 hostname pattern matching (e.g.epic_kpr,epic_msql).
plugin: constructed
keyed_groups:
- key: inventory_hostname.split('.')[0].split('-')[1] if inventory_hostname.split('.')[0].split('-') | length > 1 else 'ungrouped'
prefix: "role"
separator: "_"
groups:
epic: "'epic-' in inventory_hostname"
epic_kpr: "'epic-kpr' in inventory_hostname"
epic_msql: "'epic-msql' in inventory_hostname"
epic_cog: "'epic-cog' in inventory_hostname"
epic_smtp: "'epic-smtp' in inventory_hostname"
epic_sp: "'epic-sp' in inventory_hostname"
To verify the groups that will be available to use in members_group, run:
Sample Variables
extra_vars/gmsas.yml defines the gMSAs to create. Each entry requires a name (the gMSA account name), a group (the AD security group that controls which hosts can retrieve the password), and at least one of members or members_group to populate that group.
Specifying Members
members and members_group can be used independently or combined — duplicates are automatically removed.
members_group— an Ansible inventory group; short hostnames are derived automatically (e.g. hosts inepic_kprresolve toepic-kpr-sapph1,epic-kpr-sapph2)members— an explicit list of short AD computer names (without the trailing$)
# gmsa_definitions supports two ways to specify members (combinable):
# members: explicit list of short AD computer names
# members_group: an Ansible inventory group; short names are derived automatically
gmsa_definitions:
- name: kuiper-gmsa
group: KuiperAllowedHosts
members_group: epic_kpr
# Mix both: group provides the base, members adds extras not in inventory
# - name: kuiper-gmsa
# group: KuiperAllowedHosts
# members_group: epic_kpr
# members:
# - some-extra-host
# Manual-only
# - name: wbs-gmsa
# group: WbsAllowedHosts
# members:
# - epic-msql-sapph