Introduction

The ansible.builtin.group module creates, modifies, and deletes groups on Linux systems. Every server needs groups for permission management — application service accounts, deployment users, database administrators. This module handles group creation idempotently: it only makes changes when the group doesn't exist or its properties differ.

Parameters

ParameterRequiredDefaultDescription
name✅—Group name
state❌presentpresent to create, absent to delete
gid❌—Specific GID (group ID number)
system❌falseCreate as a system group (GID < 1000)
local❌falseUse lgroupadd/lgroupmod (for local groups when using LDAP)
non_unique❌falseAllow duplicate GIDs

Create a Group

---
- name: Manage groups
  hosts: all
  become: true
  tasks:
    - name: Create application group
      ansible.builtin.group:
        name: myapp
        state: present

    - name: Create group with specific GID
      ansible.builtin.group:
        name: deploy
        gid: 2000
        state: present

    - name: Create system group
      ansible.builtin.group:
        name: monitoring
        system: true
        state: present

Create Multiple Groups

---
- name: Create standard groups
  hosts: all
  become: true
  vars:
    groups:
      - { name: "developers", gid: 2001 }
      - { name: "dbadmins", gid: 2002 }
      - { name: "webmasters", gid: 2003 }
      - { name: "deployers", gid: 2004 }
      - { name: "monitoring", system: true }

  tasks:
    - name: Create all groups
      ansible.builtin.group:
        name: "{{ item.name }}"
        gid: "{{ item.gid | default(omit) }}"
        system: "{{ item.system | default(false) }}"
        state: present
      loop: "{{ groups }}"

Delete a Group

- name: Remove obsolete group
  ansible.builtin.group:
    name: oldteam
    state: absent

⚠️ You cannot delete a group that is any user's primary group. Remove or reassign users first.

Add Users to Groups

The group module only manages the group itself. To add users to groups, use the ansible.builtin.user module:

---
- name: Create groups and assign users
  hosts: all
  become: true
  tasks:
    - name: Create the groups
      ansible.builtin.group:
        name: "{{ item }}"
        state: present
      loop:
        - developers
        - docker
        - sudo

    - name: Create user and add to groups
      ansible.builtin.user:
        name: alice
        groups: developers,docker
        append: true  # Add to groups without removing from others

    - name: Add existing user to additional group
      ansible.builtin.user:
        name: bob
        groups: docker
        append: true  # CRITICAL — without append, removes from all other groups!

⚠️ The append Trap

# DANGEROUS — replaces ALL secondary groups with just "docker"
- ansible.builtin.user:
    name: bob
    groups: docker
    # append: false (default!)

# SAFE — adds "docker" to existing groups
- ansible.builtin.user:
    name: bob
    groups: docker
    append: true

Practical Patterns

Application Service Account

---
- name: Set up application service account
  hosts: appservers
  become: true
  tasks:
    - name: Create application group
      ansible.builtin.group:
        name: myapp
        gid: 3000
        state: present

    - name: Create service user
      ansible.builtin.user:
        name: myapp
        group: myapp
        system: true
        shell: /usr/sbin/nologin
        home: /opt/myapp
        create_home: true

    - name: Set directory ownership
      ansible.builtin.file:
        path: /opt/myapp
        state: directory
        owner: myapp
        group: myapp
        mode: "0755"

Shared Directory with Group Access

---
- name: Set up shared project directory
  hosts: devservers
  become: true
  tasks:
    - name: Create project group
      ansible.builtin.group:
        name: project-alpha
        state: present

    - name: Add developers to the group
      ansible.builtin.user:
        name: "{{ item }}"
        groups: project-alpha
        append: true
      loop:
        - alice
        - bob
        - charlie

    - name: Create shared directory with setgid
      ansible.builtin.file:
        path: /srv/projects/alpha
        state: directory
        group: project-alpha
        mode: "2775"  # setgid — new files inherit group

Standard Server Groups

---
- name: Create standard groups on all servers
  hosts: all
  become: true
  tasks:
    - name: Ensure standard groups exist
      ansible.builtin.group:
        name: "{{ item.name }}"
        gid: "{{ item.gid }}"
        system: "{{ item.system | default(false) }}"
        state: present
      loop:
        - { name: "sshusers", gid: 5000 }
        - { name: "sudousers", gid: 5001 }
        - { name: "appdeployers", gid: 5002 }
        - { name: "dbaccess", gid: 5003 }
        - { name: "monitoring", gid: 5004, system: true }

    - name: Restrict SSH to sshusers group
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "^AllowGroups"
        line: "AllowGroups sshusers"
      notify: Restart sshd

  handlers:
    - name: Restart sshd
      ansible.builtin.service:
        name: sshd
        state: restarted

Verify Group Exists

- name: Get group info
  ansible.builtin.getent:
    database: group
    key: docker
  register: group_info
  ignore_errors: true

- name: Report
  ansible.builtin.debug:
    msg: "{{ 'docker group exists' if group_info is succeeded else 'docker group missing' }}"

group vs user Module

TaskModule
Create/delete a groupansible.builtin.group
Set a user's primary groupansible.builtin.user (group:)
Add user to secondary groupsansible.builtin.user (groups: + append: true)
Check if group existsansible.builtin.getent

Troubleshooting

"groupdel: cannot remove the primary group of user"

A user has this group as their primary group. Change the user's primary group first:

- name: Change user's primary group
  ansible.builtin.user:
    name: alice
    group: users  # New primary group

- name: Now delete the old group
  ansible.builtin.group:
    name: oldgroup
    state: absent

"GID already exists"

Another group uses that GID. Either use a different GID or set non_unique: true (not recommended):

- name: Check existing GIDs
  ansible.builtin.command: getent group
  register: all_groups

- name: Create group with unique GID
  ansible.builtin.group:
    name: newgroup
    gid: 3001
    state: present

Group Created But User Not a Member

The group module doesn't add users. Use user with append: true:

# This ONLY creates the group — doesn't add anyone
- ansible.builtin.group:
    name: docker

# This adds the user to the group
- ansible.builtin.user:
    name: deploy
    groups: docker
    append: true

Conclusion

ansible.builtin.group manages group creation (state: present), deletion (state: absent), and GID assignment. Use system: true for service account groups. To add users to groups, use ansible.builtin.user with groups: and always set append: true to avoid removing the user from existing groups. The most common pattern: create a group → create a service user with that group → set directory ownership to the group.