Python grp: Query Unix Groups

Published on: August 26, 2026
Reading time: 5 minutes
Close-up view of a computer screen displaying code in a software development environment.

The grp module queries the Unix group database. It can find a group by numeric GID or name, list explicitly registered members, and translate file ownership into readable group names.

Unix groups participate in access control for files, devices, services, and system resources. However, the group database is not a complete authorization model. Effective permissions also depend on the user’s primary group, supplementary groups, mode bits, ACLs, capabilities, namespaces, SELinux, AppArmor, mount options, and other policies.

Availability

grp is available on Unix but not WASI, Android, or iOS. Windows uses a different group model.

try:
    import grp
except ImportError:
    grp = None

Cross-platform applications should isolate this code and retain a numeric fallback when a group name is not essential.

Group entry fields

Functions return a tuple-like object with these attributes:

gr_name, gr_passwd, gr_gid, gr_mem

gr_name is the name, gr_gid the numeric ID, and gr_mem a list of explicitly listed login names. gr_passwd is historical and normally empty or unusable.

Query by GID

import grp

try:
    group = grp.getgrgid(1000)
except KeyError:
    print("No group entry for this GID")
else:
    print(group.gr_name, group.gr_mem)

Since Python 3.10, a non-integer argument such as a string or float raises TypeError. Validate CLI and API input before calling the function.

Query by name

import grp

try:
    group = grp.getgrnam("developers")
except KeyError:
    print("Unknown group")
else:
    print(group.gr_gid)

Do not use an untrusted group name to make a privileged decision without resolving it and checking the process’s actual credentials.

Primary and supplementary groups

A user’s primary group is stored as pw_gid in Python pwd. The gr_mem list contains users explicitly associated with the group entry.

The official documentation warns that users are often not listed in gr_mem for their primary group. Looking only at that list therefore gives an incomplete result.

Find every group for a user

import grp
import pwd


def groups_for_user(name):
    account = pwd.getpwnam(name)
    gids = {account.pw_gid}

    for group in grp.getgrall():
        if name in group.gr_mem:
            gids.add(group.gr_gid)

    return [grp.getgrgid(gid) for gid in sorted(gids)]

On LDAP-connected systems or machines with many groups, getgrall() can be expensive. When available, prefer os.getgrouplist(name, primary_gid).

Groups of the current process

os.getgid() returns the real GID, os.getegid() the effective GID, and os.getgroups() supplementary GIDs.

import os

print("Real:", os.getgid())
print("Effective:", os.getegid())
print("Supplementary:", os.getgroups())

The kernel normally checks the effective GID and supplementary group list rather than reconstructing membership from static files.

Translate file ownership

import grp
import os

info = os.stat("file.txt")
try:
    group_name = grp.getgrgid(info.st_gid).gr_name
except KeyError:
    group_name = str(info.st_gid)

print(group_name)

Keep the numeric GID as a fallback. Files can outlive a group or come from another namespace or host.

gr_passwd is not authentication

Group passwords are a historical feature and are rarely used. gr_passwd is normally empty or contains a marker.

Do not validate credentials with it. Authentication and authorization should use PAM, service policy, ACLs, or another supported mechanism.

List all groups

import grp

for group in grp.getgrall():
    print(group.gr_gid, group.gr_name, group.gr_mem)

The order is arbitrary. NSS may consult LDAP, SSSD, NIS, or another remote source, making this operation slow and potentially large.

NSS and remote identity providers

Like pwd, grp follows the Name Service Switch configuration. Entries may come from /etc/group, LDAP, SSSD, NIS, container files, or plugins.

A seemingly local call can block on network I/O. Avoid getgrall() inside every web request or file operation.

NIS references

Group names beginning with + or - may be YP/NIS references and may not be individually accessible through getgrnam() or getgrgid().

Do not treat them as ordinary local groups without understanding host configuration.

Cache with expiration

Frequent lookups may use a short-lived cache.

import time

_cache = {}

def group_by_gid(gid, ttl=60):
    now = time.monotonic()
    item = _cache.get(gid)
    if item and now - item[0] < ttl:
        return item[1]

    value = grp.getgrgid(gid)
    _cache[gid] = (now, value)
    return value

Use a monotonic clock for TTL and do not cache failures forever.

Containers and namespaces

Inside a container, a GID may have no entry in /etc/group. Kubernetes and other platforms may also inject supplementary groups without creating names.

Do not fail when displaying ownership. Show the numeric GID. For authorization, use the credentials actually applied by the kernel.

Shared volumes

The same GID can map to different names on different hosts. For NFS and shared volumes, consistent numeric IDs matter more than display names.

Plan UID and GID allocation across hosts, containers, and services before relying on POSIX permissions.

Check current-process membership

import os


def process_in_group(gid):
    return gid == os.getegid() or gid in os.getgroups()

This answers a question about the current process and is more relevant to an immediate operation than rebuilding membership from database entries.

Let the kernel make the final decision

Even a process in a group can be denied by mode bits, ACLs, mount options, SELinux, AppArmor, read-only filesystems, or capabilities.

Attempt the operation and handle PermissionError. Group queries help diagnosis but do not replace the system call.

Change a file’s group

import grp
import os

target = grp.getgrnam("developers")
os.chown("file.txt", -1, target.gr_gid)

This requires permission. Validate paths and avoid following untrusted symbolic links. Security-sensitive code should use directory-relative APIs and appropriate flags.

Change the effective group

Privileged processes can use os.setgid() or os.setegid(). These operations are security-sensitive and may be irreversible.

Prefer having the service manager start the application with the correct user and group.

initgroups()

os.initgroups(user, primary_gid) initializes supplementary groups according to system policy.

import os
import pwd

account = pwd.getpwnam("appuser")
os.initgroups(account.pw_name, account.pw_gid)
os.setgid(account.pw_gid)
os.setuid(account.pw_uid)

Call initgroups() before dropping privileges. The wrong order can prevent configuration or retain privileged groups.

Clear inherited supplementary groups

Changing only UID and primary GID may leave inherited supplementary groups that retain access.

Use initgroups() for the target account or os.setgroups([]) when the policy requires no additional groups.

Race conditions

Membership can change between a lookup and an operation. For security, rely on the system call’s authorization result and handle failure.

Do not use a check-then-use sequence as the only protection.

Privacy

Membership lists expose account names and organizational structure. Do not publish getgrall() through an API or dump it into logs without authorization and a clear need.

Logging

When reporting access failures through Python syslog, prefer numeric GID and a sanitized name. Avoid logging the full member list.

Resource isolation

Unprivileged users and groups complement the quotas described in Python resource, but neither measure forms a complete sandbox.

Testing

Test existing and missing groups, non-integer arguments, a user whose primary group omits them from gr_mem, supplementary groups, containers without names, slow LDAP, NIS, shared volumes, actual permission checks, and privilege dropping.

Unit tests should not depend on the host’s real group database. Wrap lookups and provide fake records.

Common mistakes

Common failures include treating gr_mem as complete, using gr_passwd for authentication, assuming every GID has a name, calling getgrall() in a hot path, forgetting supplementary groups while dropping privileges, and assuming membership guarantees access.

Conclusion

grp resolves Unix groups by name or GID and helps interpret ownership and membership. Combine it with pwd and the process’s effective group list for an accurate view.

Preserve numeric IDs, account for NSS and containers, never use the database for authentication, and let the kernel decide final access. Consult the official grp documentation and group(5).

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Close-up of HTML and CSS code displayed on a computer screen, ideal for tech and programming themes.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python pwd: Query Unix User Accounts

    Learn Python pwd to query Unix users by UID or login, retrieve home, shell, and ownership without using the database

    Ler mais

    Tempo de leitura: 5 minutos
    26/08/2026
    Stack of cut logs covered in snow, showcasing a cold winter texture and woody elements.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python syslog: Send Logs to Unix

    Learn Python syslog to send Unix logs with priorities, facilities, masks, structured content, and protection against log injection.

    Ler mais

    Tempo de leitura: 5 minutos
    26/08/2026
    High-resolution close-up of a CPU processor, RAM sticks, and a hard drive, showcasing modern computer hardware.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python resource: CPU and Memory Limits

    Learn Python resource to measure CPU, peak memory, page faults, and set limits for files, processes, descriptors, and address space

    Ler mais

    Tempo de leitura: 5 minutos
    26/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python pty: Automate Unix Terminals

    Learn Python pty to run and test interactive programs, control pseudo-terminals, handle EOF, resize, signals, timeouts, and cleanup.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python tty: Raw and Cbreak Modes

    Learn Python tty to use raw and cbreak modes, read keys, parse sequences, handle Unicode, and safely restore Unix terminals.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026
    Detailed view of programming code in a dark theme on a computer screen.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python termios: Safe Terminal Control

    Learn Python termios for canonical mode, echo, key reads, baud rate, queues, window size, and safe restoration of POSIX terminals.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026