Identity & Access
Follow usernames from human configuration through NSS resolution into the numeric kernel credential vectors (RUID, EUID, FSUID) and hierarchical directory traversal gates.
What this chapter builds
Start here if usernames, groups, sudo, SSH, and file permissions feel like one security feature. This chapter separates account lookup, process credentials, authentication, and authorization.
By the end, you can
- Resolve a name to numeric identity without confusing NSS with authentication
- Predict which owner, group, or other mode class the kernel selects
- Locate the first directory that blocks a pathname
- Explain what sudo and SSH change—and what they do not
Objects to keep straight
struct credUID / GID vectorsinode ownershipsupplementary groupsApplied task: Diagnose why nginx UID 33 cannot read /srv/site/config.json without reaching for chmod 777.
Before looking at the mechanics, what actually is a User or a Group?
What are the foundational primitives of Linux Identity?
UID (User ID)
Linux does not care about your username ("nginx"). It only cares about an integer number (e.g. 33). This integer is stamped onto every process and every file to determine who owns what.
GID (Group ID)
Another integer. A single UID can belong to multiple GIDs (like belonging to both HR and Engineering). This allows multiple different users to share access to the same files.
NSS (Name Service Switch)
The system that translates human names (like "nginx") into the integer IDs (like 33). It can look up names in local files (/etc/passwd) or over the network (Active Directory).
Mode Bits (Permissions)
Every file has 3 locks: one for the Owner UID, one for the Group GID, and one for Everyone Else. Each lock grants or denies Read, Write, or Execute access.
Identity in Linux fundamentally reduces to two 32-bit integers: a UID and a GID. Everything you do on a Linux system—starting a web server, reading a file, SSHing in—is evaluated mathematically by the kernel comparing your process's UID against a file's UID. Human names like "root" are just illusions provided by user-space tools for our convenience.
Model scope. The kernel evaluates numeric credentials, not the spelling of a username. UID 0 conventionally receives a full capability set, but namespaces, dropped capabilities, LSM policy, seccomp, and mount state can still constrain a process.
uid=1000(darshan) gid=1000(darshan) groups=1000(darshan),27(sudo)
0:0
Usernames are human syntax; the kernel only evaluates numeric IDs.
How does Linux translate a username into kernel-enforced credentials?
Configure the order glibc searches for users.
root:x:0:0::/root:/bin/bash nginx:x:33:33::/var/cache/nginx:/sbin/nologin
ldap_user:x:5001:5001::/home/ldap_user:/bin/bash nginx:x:9999:9999::/network/nginx:/bin/bash
getpwnam()When a service starts or a user authenticates, glibc calls getpwnam() to resolve the username. The Name Service Switch (/etc/nsswitch.conf) configures the resolution order—typically local files first, then directory services like LDAP, SSSD, or Winbind. The kernel itself has no concept of usernames; all discretionary access checks operate exclusively on 32-bit integer UIDs and GIDs.
Model scope. In rootless containers and user namespaces, container UID 0 is mapped to an unprivileged high UID on the host (e.g. 100000) via /etc/subuid.
nginx:x:33:33:nginx user:/var/cache/nginx:/sbin/nologin
33
Every process carries a vector of distinct numeric identities.
Which UIDs does a running process hold, and which one gates file access?
Linux processes do not hold a single UID; the kernel maintains a credential structure (struct cred) with Real, Effective, Saved, and Filesystem IDs. The Real UID tracks who started the process. The Effective UID determines process privileges and signals. The Filesystem UID (FSUID) is tested for all filesystem open() and stat() operations, allowing NFS daemons and setuid binaries to drop filesystem privileges without losing signal control.
Model scope. Saved UID (SUID) allows a process that temporarily lowered its EUID to regain root privileges when needed, a pattern common in setuid utility binaries.
418 root root nginx 421 nginx nginx nginx
Uid: 33 33 33 33 Gid: 33 33 33 33
Access is a hierarchical walk: ancestor directories gate the leaf file.
Why can a process with read permission on a file still get Permission Denied?
✓ GRANTED
✓ GRANTED
✗ DENIED (EACCES)
NOT REACHED!
Default fixture: To open any file, the kernel must resolve every component of its path from the root directory downward (path_resolution(7)). For every directory along the way, the process requires the execute (+x) permission bit, which functions as the "search" right. If even one ancestor directory denies execute permission to the process credentials, traversal immediately aborts with EACCES (Permission Denied)—the leaf file permissions are never even evaluated.
To open any file, the kernel must resolve every component of its path from the root directory downward (path_resolution(7)). For every directory along the way, the process requires the execute (+x) permission bit, which functions as the "search" right. If even one ancestor directory denies execute permission to the process credentials, traversal immediately aborts with EACCES (Permission Denied)—the leaf file permissions are never even evaluated.
Model scope. The namei utility is essential in production to inspect permissions at every step of a path chain simultaneously.
f: /srv/site/index.html drwxr-xr-x root root / drwxr-xr-x root root srv drwxr-x--- root root site # BLOCKED: other lacks +x -rwxrwxrwx root root index.html
cat: /srv/site/index.html: Permission denied
chmod 777 destroys security boundaries and masks architectural bugs.
Why is chmod 777 dangerous, and how do you implement least-privilege access?
# "Works" immediately, but directory is now world-writable and vulnerable to tampering
World-writable directories allow any unprivileged process or compromised container to overwrite application binaries, tamper with logs, or plant backdoors. It treats an access-control failure by eliminating access control entirely.
# Least-privilege: only root and www-data group can read/traverse; others receive EACCES
Identify the exact failing boundary using namei, set appropriate group ownership (chown root:appgroup), and grant group-read/search (chmod 0750 or 0640).
Every permission error has an exact reason: a specific UID or GID failed a specific bit check on a specific inode. Least-privilege system administration requires assigning files to a shared group (like www-data or appgroup) and using mode 0640 for files and 0750 for directories. This ensures application workers can read their data while preventing rogue processes from reading secrets or altering code.
Model scope. SetGID on directories (chmod g+s /dir) causes new files created inside to automatically inherit the directory group rather than the creating user primary group.
640 root:www-data
Read OK
Controlled privilege delegation with attributable records.
How does sudo safely elevate process credentials from unprivileged to root?
Stage 01: sudo -l lists all allowed privileges for the current user, including NOPASSWD exemptions for automated operational commands.
User dev1 may run the following commands on devbox-01:
(ALL : ALL) ALL
(root) NOPASSWD: /bin/systemctl restart nginxsudo -l lists all allowed privileges for the current user, including NOPASSWD exemptions for automated operational commands.
uid=0(root) gid=0(root) groups=0(root)
When sudo runs, its setuid bit transitions EUID to 0. It verifies /etc/sudoers policy, prompts for the invoking user password, and executes the target binary.
devbox-01 sudo: dev1 : TTY=pts/0 ; PWD=/home/dev1 ; USER=root ; COMMAND=/bin/systemctl restart nginx
With normal logging enabled, sudo records the invoking user, target identity, working directory, and command. Protect and centralize logs if tamper resistance matters.
/etc/sudoers: parsed OK
Never edit /etc/sudoers with a standard text editor. visudo locks the file and validates syntax before committing, preventing lockouts.
The sudo binary relies on the setuid permission bit (mode 04755). When an ordinary user executes /usr/bin/sudo, the kernel transitions the process Effective UID (EUID) to 0 (root) while preserving the Real UID (RUID). sudo reads /etc/sudoers, checks if the invoking user is authorized to run the command, prompts for authentication, and logs the execution to journald or /var/log/auth.log before execve()ing the command.
Model scope. By default, sudo sanitizes the environment (env_reset), stripping LD_PRELOAD, PATH, and custom variables to prevent privilege escalation exploits.
nginx
-rwsr-xr-x 1 root root 232416 /usr/bin/sudo # Notice "s" setuid bit!
Cryptographic challenge-response eliminates brute-force vectors.
How does SSH public key authentication work at the protocol level?
Action 01: Generate modern elliptic-curve keypair
Your identification has been saved in ~/.ssh/id_ed25519 Your public key has been saved in ~/.ssh/id_ed25519.pub
Field Note: Ed25519 keys are faster, shorter, and cryptographically superior to legacy RSA-2048 keys.
Number of key(s) added: 1 Now try logging into the machine.
Field Note: Appends the public key to ~/.ssh/authorized_keys and enforces strict 0600 file permissions.
19:50:00 up 42 days, 2 users, load average: 0.12, 0.08, 0.05
Field Note: Always confirm key-based access in an independent shell before modifying sshd_config!
# Password authentication disabled
Field Note: Eliminates 100% of brute-force dictionary attacks against the SSH daemon.
# Daemon reloaded without dropping active sessions
Field Note: Reloading preserves existing connected SSH sessions while applying key-only policy to new handshakes.
SSH public-key authentication uses proof of private-key possession. After the server accepts a permitted public key, the client signs session-bound authentication data with its private key; the private key never crosses the network. The server verifies that signature, then applies account, PAM, and session policy before starting the requested session.
Model scope. sshd will silently reject public key authentication if ~/.ssh (0700) or ~/.ssh/authorized_keys (0600) are writable by group or other (StrictModes).
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyPayload admin@devbox-01
pubkeyauthentication yes passwordauthentication no