El módulo pwd consulta la base de cuentas de usuario en sistemas Unix. Permite localizar una cuenta por UID numérico o nombre de login y obtener datos como UID, GID primario, directorio home, shell configurado y campo descriptivo.
Aunque históricamente se conoce como “password database”, pwd no es una API de autenticación. En sistemas modernos, las credenciales suelen estar en shadow passwords, PAM, LDAP, SSSD u otro proveedor de identidad. El campo pw_passwd normalmente contiene solo x, * o un marcador similar.
Disponibilidad
pwd está disponible en Unix, pero no en WASI ni iOS. Windows utiliza otro modelo de cuentas.
try:
import pwd
except ImportError:
pwd = None
Para software multiplataforma, usa abstracciones de mayor nivel cuando solo necesites el usuario actual o el directorio home.
Campos de una cuenta
Las funciones devuelven un objeto similar a una tupla con estos atributos:
pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell
pw_uid y pw_gid son enteros. Los demás valores son strings.
Consultar por UID
import os
import pwd
cuenta = pwd.getpwuid(os.getuid())
print(cuenta.pw_name)
print(cuenta.pw_dir)
print(cuenta.pw_shell)
getpwuid() genera KeyError cuando no existe una entrada visible para ese UID.
Consultar por nombre
import pwd
try:
cuenta = pwd.getpwnam("deploy")
except KeyError:
print("Usuario inexistente")
else:
print(cuenta.pw_uid, cuenta.pw_gid)
En una API pública, convierte el KeyError en un resultado de dominio claro en lugar de exponer una excepción interna.
UID real y efectivo
os.getuid() devuelve el UID real y os.geteuid() el UID efectivo. Pueden ser diferentes en programas setuid, containers o procesos que cambian privilegios.
real = pwd.getpwuid(os.getuid())
efectiva = pwd.getpwuid(os.geteuid())
Para permisos, entiende qué identidad utiliza el kernel en cada operación.
No confíes en variables de entorno
USER, LOGNAME y HOME pueden faltar o ser manipuladas.
cuenta = pwd.getpwuid(os.geteuid())
home = cuenta.pw_dir
Con sudo, el usuario efectivo puede ser root y el usuario original aparecer en SUDO_UID. Esa diferencia debe formar parte de una política explícita.
Directorio home
pw_dir contiene el home registrado por el proveedor de identidad. No garantiza que el directorio exista, esté montado o sea accesible.
from pathlib import Path
home = Path(cuenta.pw_dir)
if home.is_dir():
print(home)
No crees archivos en el home de otra cuenta sin verificar ownership, permisos y finalidad.
Shell configurado
pw_shell puede contener /bin/bash, /bin/zsh, /usr/sbin/nologin, /bin/false u otro programa.
Ese campo no demuestra que la cuenta pueda autenticarse ni autoriza ejecutar el shell. Las cuentas de servicio pueden usar valores especiales o vacíos.
Campo GECOS
pw_gecos suele almacenar nombre completo o comentarios administrativos, pero su formato no es un contrato estable. Puede contener comas y datos personales.
No lo uses como identificador único y limita su exposición por privacidad.
pw_passwd no sirve para autenticar
En sistemas con shadow passwords, pw_passwd suele contener x o *. Aunque aparezca un hash, compararlo manualmente no es una arquitectura segura.
Usa PAM, el servicio corporativo de identidad, OAuth, SSH o el mecanismo soportado por el sistema. Nunca solicites una contraseña para validarla con pwd.
Listar todas las cuentas
import pwd
for cuenta in pwd.getpwall():
print(cuenta.pw_uid, cuenta.pw_name, cuenta.pw_shell)
El orden es arbitrario. En máquinas conectadas a LDAP, SSSD, NIS u otros proveedores NSS, la operación puede ser lenta y devolver muchas entradas.
NSS y fuentes remotas
Las funciones siguen la configuración Name Service Switch del sistema. La información puede provenir de /etc/passwd, LDAP, SSSD, NIS, archivos de container o plugins.
Una consulta aparentemente local puede utilizar red y bloquear. No la ejecutes repetidamente en un hot path sin una estrategia de cache y control de latencia.
Cache
Para consultas frecuentes, un cache pequeño puede reducir trabajo.
from functools import lru_cache
import pwd
@lru_cache(maxsize=256)
def usuario_por_uid(uid):
return pwd.getpwuid(uid)
lru_cache no expira. En servicios largos, cambios de cuenta pueden quedar ocultos. Usa TTL cuando la actualización sea importante.
Mostrar ownership de archivos
pwd permite convertir el UID de un archivo en un nombre.
import os
import pwd
info = os.stat("archivo.txt")
try:
propietario = pwd.getpwuid(info.st_uid).pw_name
except KeyError:
propietario = str(info.st_uid)
Conserva el UID numérico como fallback. Un archivo puede pertenecer a una cuenta eliminada o a otro namespace.
Containers y namespaces
Dentro de un container, el proceso puede ejecutar con un UID sin entrada en /etc/passwd. Es común en imágenes minimalistas y plataformas que asignan UIDs aleatorios.
No conviertas esa ausencia en error fatal cuando el número sea suficiente para logs u ownership.
UID cero
UID 0 suele representar root, pero no compruebes privilegios comparando el nombre root.
if os.geteuid() == 0:
print("El UID efectivo es cero")
Incluso UID cero puede estar limitado por namespaces, capabilities, SELinux, AppArmor o el runtime del container.
Reducir privilegios
Un servicio iniciado como root puede resolver una cuenta y después reducir privilegios.
import os
import pwd
cuenta = pwd.getpwnam("appuser")
os.initgroups(cuenta.pw_name, cuenta.pw_gid)
os.setgid(cuenta.pw_gid)
os.setuid(cuenta.pw_uid)
La secuencia es sensible: prepara archivos, directorios y descriptors antes; no intentes recuperar privilegio. Siempre que sea posible, deja que systemd, Docker o el supervisor inicie el proceso con el usuario correcto.
Grupos suplementarios
pw_gid informa solo el grupo primario. Para membresías adicionales, usa grp, os.getgroups() u os.getgrouplist().
El siguiente conjunto de este lote cubrirá el módulo grp.
Expansión de virgulilla
os.path.expanduser("~nombre") puede consultar la misma base. Cuando necesites tratamiento explícito de errores, usa pwd.getpwnam(nombre).pw_dir.
Validación de nombres
No construyas rutas concatenando un login no confiable. Resuelve la cuenta, utiliza el home registrado y comprueba que el resultado permanezca dentro de una raíz permitida.
Los caracteres válidos en nombres cambian según la plataforma y el proveedor de identidad.
Privacidad
getpwall() puede revelar nombres de cuentas, homes y shells. No expongas la base completa en una API web o en logs sin necesidad y autorización.
Latencia y concurrencia
La implementación NSS puede leer archivos de configuración o consultar servicios remotos. No asumas latencia constante porque la API sea síncrona y pequeña.
Manejo de errores
KeyError indica que no se encontró la entrada. Fallos de proveedor o del sistema pueden aparecer de otra forma. Cuando importe, diferencia cuenta ausente de servicio de identidad indisponible.
Integración con logs
Al registrar una identidad en syslog en Python, utiliza UID numérico y un nombre sanitizado, sin exponer campos GECOS o homes completos salvo que sean necesarios.
Procesos limitados
Una cuenta sin privilegios complementa los límites descritos en resource en Python. Ninguna de las dos medidas sustituye una sandbox completa.
Pruebas
Prueba cuentas existentes y ausentes, UIDs sin nombre, container con UID aleatorio, LDAP lento, home inexistente, shell nologin, cuenta eliminada, root dentro de namespace, cache desactualizado y plataformas sin el módulo.
Los tests unitarios no deberían depender de cuentas reales del host. Encapsula las consultas y usa objetos fake.
Errores comunes
Los fallos frecuentes son usar pw_passwd para autenticar, confiar en $USER, tratar pw_gid como todos los grupos, asumir que el home existe, listar cuentas en cada request, fallar cuando un UID no tiene nombre y exponer la base sin necesidad.
Conclusión
pwd es la interfaz estándar para resolver identidades Unix por UID o login. Úsalo para nombres, homes, shells y ownership, conservando IDs numéricos y considerando NSS, containers, latencia y privacidad.
No lo uses para validar contraseñas ni confundas existencia de cuenta con autorización. Consulta la documentación oficial de pwd y el manual passwd(5).







