> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://rivet.chrisboulton.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://rivet.chrisboulton.com/_mcp/server.

# Group membership

> Manage supplementary group entries with additive or exclusive ownership.

```hcl
group_membership "app" {
  ensure = "present"
  members = ["user1", "user2"]
  exclusive = true
}
```

| Parameter   | Default     | Behavior                                                                                              |
| ----------- | ----------- | ----------------------------------------------------------------------------------------------------- |
| `group`     | label       | Local group whose supplementary membership is managed.                                                |
| `ensure`    | `"present"` | Add listed members when present; remove only listed members when absent.                              |
| `members`   | required    | List of local usernames; duplicates collapse to a set.                                                |
| `exclusive` | `false`     | With present, make the supplementary member list exactly equal to `members`. Unsupported with absent. |

Additive `members=[]` preserves membership; exclusive `members=[]` clears the supplementary list. The resource neither creates nor deletes users or groups and leaves memberships in other groups untouched. Primary-group membership stays under `user.primary_group`; exclusive applies only to explicit supplementary entries, so users with this primary GID retain primary membership. Group administrators and passwords stay unmanaged. Native operations use [gpasswd](https://manpages.debian.org/trixie/passwd/gpasswd.1.en.html), which updates the local group and gshadow files under shadow-utils locking.

Present membership requires an existing local group and existing local members; remote NSS identities are refused. Absent membership also works after the group or listed users have been removed. Managed group and listed user declarations automatically precede membership, including literal names; present membership cannot refer to managed absent accounts. References such as `group.app.name` and `user.worker.name` also retain provenance.

Multiple additive and absent resources may manage disjoint users in the same group. Overlapping member claims are rejected, and an exclusive declaration owns the whole supplementary list. Conflicts with `user.groups` are rejected too: additive user ownership conflicts when it lists the same group and member; exact user ownership conflicts whenever the membership resource manages that user, or manages the group exclusively. Leave `user.groups` omitted for those users when delegating their supplementary membership to these resources.

## Execution and exports

The shared resource budget is 60 seconds. Mutations are journaled before native execution and verified with fresh inspection. Noop does not write memberships or future intent. Names follow the same local account rules as [users](/resources/user) and [groups](/resources/group). Explicit null is rejected for these policy fields.

Static exports are `group`, `ensure`, `members`, and `exclusive`, plus common `meta.sensitive`. Capability: `group_membership.shadow.v1`.