> 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.

# User

> Local user accounts, passwords, expiry, and home directories.

`user` manages local Linux accounts in `/etc/passwd` and `/etc/shadow` using the shadow-utils tools. Related resources manage [groups](/resources/group) and [group membership](/resources/group-membership).

```hcl
group "app" {
  system = true
}

user "app" {
  system = true
  primary_group = group.app.name
  home = "/var/lib/app"
  shell = "/usr/sbin/nologin"
  manage_home = true
  password_locked = true
}
```

Names default to the resource label. They must start with an ASCII letter or underscore, contain only letters, digits, underscores, and hyphens, and be at most 32 bytes. UIDs and GIDs are integers from 0 to 4294967294.

## Parameters

| Parameter         | Default               | Behavior                                                                                                                                                        |
| ----------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`            | label                 | Local username.                                                                                                                                                 |
| `ensure`          | `"present"`           | `"present"` or `"absent"`.                                                                                                                                      |
| `uid`             | unmanaged             | Explicit UID allocation on creation; collisions fail. Existing UID changes are refused.                                                                         |
| `primary_group`   | required when present | Local group name or integer GID.                                                                                                                                |
| `groups`          | unmanaged             | List of local supplementary group names; duplicates collapse to a set.                                                                                          |
| `groups_mode`     | `"additive"`          | Add requested memberships, or enforce `"exact"` membership. Exact requires `groups`; exact `[]` removes all supplementary memberships.                          |
| `system`          | `false`               | Creation-time ID allocation policy only.                                                                                                                        |
| `home`            | unmanaged             | Normalized absolute recorded home path.                                                                                                                         |
| `shell`           | unmanaged             | Normalized absolute login shell path.                                                                                                                           |
| `comment`         | unmanaged             | GECOS text; control characters and colons are refused.                                                                                                          |
| `manage_home`     | `false`               | Publish a missing home atomically as 0700 with account ownership; preserve existing directory metadata and contents. Parents must already exist and be trusted. |
| `move_home`       | `false`               | Requires `home` and `manage_home`; migrate an existing home by an atomic rename on the same filesystem.                                                         |
| `remove_home`     | `false`               | Requires `ensure="absent"`, an explicit `home` matching the account, and explicit `uid`, so interrupted removal can verify ownership after account deletion.    |
| `password_hash`   | unmanaged             | Precomputed SHA-256 (`$5$`) or SHA-512 (`$6$`) crypt hash, optionally with `rounds=`. Plaintext and other encodings fail.                                       |
| `password_locked` | unmanaged             | Lock/unlock password authentication. Unlock requires a supported stored hash or `password_hash`.                                                                |
| `expires`         | unmanaged             | Valid date from 1970 in `YYYY-MM-DD` form, or `"never"`.                                                                                                        |

Unspecified account fields stay unmanaged on existing users. New users receive distribution defaults from `useradd` and `/etc/login.defs` for IDs, recorded home, shell, and password aging, with an empty comment and no supplementary memberships unless requested. New passwords start locked; supplying a hash preserves that lock unless `password_locked=false` is explicit. Rivet disables implicit private-group creation, creates homes only with `manage_home`, and does not copy `/etc/skel`. Mail-spool creation follows the distribution default (`CREATE_MAIL_SPOOL=no` on baseline Ubuntu).

Hashes are intrinsically sensitive even with `meta.sensitive=false`, and sensitivity propagates through references and outputs. Bundles contain the hash and require confidentiality. Reports and journals expose property names and digests, never hashes. Password updates use encrypted input on stdin, not process arguments. Password locks do not revoke SSH keys or other authentication methods.

The provider refuses existing UID changes because `usermod --uid` recursively changes home ownership. Existing primary-group changes are supported only when the recorded home is absent and its parent is trusted and not writable by other users: `usermod --gid` can otherwise recursively change group ownership. No recursive permission repair is performed. Supplementary memberships can be managed through `user.groups` or isolated `group_membership` resources; overlapping ownership is rejected.

Home migration and deletion are restricted to account-owned directories below `/home` or `/srv`, with trusted parents, no final symlink, no root-owned directory, and no shared or overlapping home belonging to another local account. Migration refuses overlapping old and new paths and an existing target when the source still exists. Cross-filesystem migration is unsupported. Migration renames before changing the recorded path; reinspection can finish the account update after interruption. Home creation can use other trusted locations, such as `/var/lib/app`.

Account deletion uses `userdel` without automatic home and mail removal. Shadow-utils can remove an unused same-name private group according to `USERGROUPS_ENAB`; catalogs cannot retain that group as present while removing the user. Optional home deletion touches only the declared home directory, does not traverse mounted filesystems, and remains convergent after the account disappears. It does not terminate processes or remove files outside the home; account tools may refuse deletion of an active user. Runner state and lock directories are excluded from both old and desired managed home paths.

## Dependencies

Present users depend on managed primary and supplementary groups, including literal names and explicit GIDs. Managed absent groups cannot satisfy a present user. Omitted IDs cannot be read at compile time; use a group's declared name for dependencies.

If [group membership resources](/resources/group-membership) manage a user's supplementary groups, leave `user.groups` unset for that user. See [group](/resources/group) for removal ordering. Capability: `user.shadow.v1`.