skip to content

After running `usermod -aG deploy alice` on a Linux host, Alice's already-open shell still cannot read the deploy group's files until she logs out and back in. Why, and what would happen if the `-a` had been omitted?

level: middleimportance: must knowfreq 64%

answer

  1. credentials, not the file, decide access
  2. set once at session creation
  3. inherited across fork and exec
  4. database view versus process view
  5. append flag or you replace the list

basics

~20 s

A process's group list is part of its kernel credentials, fixed when the login session was created and inherited by every child. Editing /etc/group changes the database, not a running process, so a new login is needed. Omitting -a replaces all supplementary groups instead of adding one.

solid answer

~50 s

Group membership is evaluated from the process's credentials, not from `/etc/group`, at the moment a file is opened. Those credentials — real and effective UID/GID plus the supplementary group list — are set once by the privileged program that created the session (`login`, `sshd`, `su`) via `initgroups()`, and are then inherited across `fork` and `exec` for the life of that session. Editing the group database afterwards cannot reach back into a running shell, so Alice needs a fresh login; `newgrp deploy` or `sg deploy -c '…'` will start a new shell with the group applied without a full logout. The diagnostic that proves it is `id -nG alice`, which queries the database and shows the new group, versus plain `id -nG`, which prints the running process's set and does not. Omitting `-a` is a real footgun: `usermod -G deploy alice` **replaces** the entire supplementary list, silently dropping every other group she had.

code

bash · 11 lines
bash
# database view: the new group is there
id -nG alice

# process view: the running shell still holds the old credential set
id -nG

# what the kernel is enforcing for a given process
grep '^Groups:' /proc/$$/status

# adopt the group without a full logout
newgrp deploy

go deeper

for a junior

Remember that a group change needs a fresh login, and that usermod needs -aG — with -G alone you replace every supplementary group the user had.

for a middle

Explain that the supplementary list lives in the process's kernel credentials, installed once at session creation and inherited by children, and show the id alice versus id comparison that proves it.

for a senior

Demonstrate the operational consequence: automation that grants a group must restart the affected service, and group removal revokes nothing from live sessions until they end.

for a principal

Own the revocation model — decide what timely access removal means across a fleet where credentials are frozen per session, and where directory caching adds a second staleness layer.

## Two kinds of membership A Linux account has exactly one **primary** group — the GID in field 4 of its `/etc/passwd` line — and any number of **supplementary** groups, which are the groups whose `/etc/group` line names it. The primary group is what newly created files are owned by; supplementary groups only ever grant access. That means `getent group deploy` and `id alice` can disagree. If `deploy` is Alice's primary group, her name will not appear in the group line at all, yet she is a member. `id` merges both sources, which is why it is the right tool to answer "is this user in that group?". ## Where the kernel actually keeps membership The kernel does not consult `/etc/group` when you open a file. Every process carries a credential set: real/effective/saved UID and GID, and a **supplementary group list**. A file access check compares those numbers against the file's owner and group. The text files are merely the *source* those numbers were loaded from, once, long ago. The loading happens in the privileged program that builds a session. `login`, `sshd` and `su` call `initgroups(3)`, which looks the user up through NSS and installs the resulting list with `setgroups(2)` — a call only a privileged process may make. Then it drops to the target UID and executes the shell. From that instant the list is frozen: `fork` copies it, `exec` preserves it, and nothing short of a new privileged session can widen it. ## Why the running shell is stale So `usermod -aG deploy alice` rewrites `/etc/group`, and every session started **afterwards** picks up the change. Alice's existing shell — and every editor, `tmux` pane and background job descended from it — still holds the credential set from her original login. It is not a cache that expires; it is state that was never designed to be updated. The clean demonstration: ``` $ id -nG alice # database lookup: shows deploy alice sudo deploy $ id -nG # this process's credentials: does not alice sudo ``` With no username argument `id` reports the calling process; with a username it queries the account database. Two different questions, two different answers, and the gap between them is the whole phenomenon. ## Getting the group without logging out - `newgrp deploy` starts a **new shell** whose credentials include the group (and makes it the primary group for files created in it). Members join without a password; non-members are challenged for the group password from `/etc/gshadow`, which is almost never set. - `sg deploy -c 'command'` runs one command under the new group set. - Reconnecting SSH, or `su - alice` from root, both create a fresh session and are the usual real-world answer. - Restarting the *service* is the equivalent step for daemons: a long-running process added to a group keeps the old set until it is restarted. ## The `-a` footgun `usermod -G` sets the supplementary list to exactly what you passed. Without `-a`: ``` usermod -G deploy alice # alice is now ONLY in deploy ``` She silently loses `sudo`, `adm`, `docker`, and anything else she had. This has locked administrators out of their own machines. `-a` (append) is only meaningful together with `-G`, and the habit worth building is to use the group-side tool instead: ``` gpasswd -a alice deploy # add gpasswd -d alice deploy # remove ``` `gpasswd` is additive by construction, so there is no destructive form to mistype. ## Practical consequences - **Automation**: a configuration-management run that adds a service account to a group must also restart the service, or the grant does nothing until the next reboot. - **Debugging access denials**: check the *process*, not the database. If a daemon gets EACCES, look at `/proc/<pid>/status` — the `Groups:` line is the credential set that process is actually using. - **Removal is worse than addition**: removing a user from a group does not revoke anything from sessions and processes already running under it. For a real revocation you must end those sessions. - **Directory-backed identity**: with LDAP or SSSD the group list is still installed at session creation, so caching in the directory client can add a second layer of staleness on top of this one.

  • A daemon was added to a group by configuration management but still gets permission denied. How do you confirm what group set it is running with?
    Read `/proc/<pid>/status` and look at the `Groups:` line — that is the supplementary list the kernel is enforcing for that process, independent of `/etc/group`. If the new GID is missing, the process predates the change and needs a restart; the unit must be restarted as part of the same automation run, not left until the next reboot.
  • If you remove a user from a group, when does that actually take effect?
    Only for sessions and processes started afterwards. Existing processes keep the supplementary list they were given at session creation, so a removed user's open shell retains the access until it exits. Real revocation means terminating their sessions — or, when the stakes justify it, changing the resource's ownership so the stale credentials no longer match.
  • What does `newgrp` change beyond making the group's files accessible?
    It starts a new shell in which the named group becomes the **primary** group, so files created in that shell are owned by it rather than by the user's usual primary group. That is often the point in a shared-project directory, but it is a side effect people forget when they use `newgrp` purely to refresh access.

saying these in an interview costs you the question

  • Believing /etc/group is consulted on every file access
  • Saying you must reboot for a group change to apply
  • Using usermod -G without -a and wiping existing groups
  • Assuming removing a group instantly revokes running sessions
  • Trusting `id` with no argument to show database membership

context