DevOps Foundations · Module 1: Linux working model
Files, Permissions and Ownership
Most Linux outages that look mysterious are permission decisions working as designed. This lesson makes the permission model legible so you can predict failures before they page you.
11 min reading
Objectives
- Read any permission string and predict exactly what each class of user can do
- Repair a service that fails to start because of wrong ownership or mode
- Choose the least privilege that still lets the job run, and justify it
- Explain why running as root fixed it is never the fix
Why this matters
A deployment finishes green, the service will not start, and the log says "permission denied" on a file the deploy itself created. This is one of the most common first pages a junior on-call engineer gets, and it is almost always made of two facts: the process runs as one user, and the file belongs to another. Ten minutes of permission literacy replaces an hour of guessing, and guessing in production usually means widening permissions until the error goes quiet. That quiets the error and opens the door.
Concepts
Every file carries three answers: who owns it (user), which group it answers to (group), and what each of three classes may do (user, group, other). The three actions are read (4), write (2) and execute (1), and the familiar 755 is just those three sums side by side. Directories use the same bits with different meaning: read lists names, write creates and deletes names, and execute lets you reach anything inside. A directory with 644 is a locked room with a glass door: you can see the names but never enter.
Ownership decides which column applies to you. A process runs as exactly one user with exactly one primary group, so the kernel checks the user column first, then group, then other, and stops at the first match. Supplemental groups extend the group check, which is why adding a deploy user to the service group is usually the correct repair: it moves the process into the group column instead of forcing the file open to everyone.
Three special bits complete the picture. Setuid (4) and setgid (2) run a program with the file owner's or group's rights; they are rare, powerful, and worth auditing rather than inventing. The sticky bit (1) on a directory like /tmp lets anyone create files but only owners delete their own. Default permissions come from the umask removed from the requested mode (requested & ~umask, with no default ACL): files request 666 and directories request 777, so a umask of 022 yields 644 files and 755 directories (for example 0666 & ~0022 = 0644), which is why freshly created files are readable but never executable.
Worked example
A service unit runs as user svc-app and fails at boot:
$ ls -l /srv/app/config.yaml
-rw------- 1 deploy deploy 312 Oct 2 11:40 /srv/app/config.yaml
$ sudo -u svc-app head -1 /srv/app/config.yaml
head: cannot open '/srv/app/config.yaml' for reading: Permission deniedExpected reading of this output: the file is 600, owned by user deploy, group deploy. The process user svc-app matches neither, so it lands in the other column, which grants nothing. Two repairs are defensible. If the deploy pipeline owns the file, change the group and open the group column: chgrp svc-app config.yaml && chmod 640 config.yaml. If the service owns its config, transfer ownership: chown svc-app:svc-app config.yaml and keep 600. Verify with the same read-as-the-service-user command, not as yourself and not as root. Root bypasses standard file permission checks, so a successful read as root proves nothing about whether the service user can read the file.
The common wrong move
chmod -R 777 /srv/app makes the error disappear and should be treated as an incident of its own. It grants every local user read, write and execute on application code, configs and any secret the directory holds. Note on version control: Git does not version full Unix ownership or every mode bit; for regular files it records only the executable distinction, so a 777 on disk is not faithfully re-applied as 777 by the next clone, but the over-broad bits stay live on every machine where they were set until someone fixes them. The other classic is chown -R root followed by running the service as root: now a compromised service has the whole machine. When a permission error tempts you toward either, stop and name the two users involved (process user, file owner) first. The repair is always a relationship between those two, never a global opening.
Lab and next step
Lab L01 in this module replays this exact failure against a service you fix without ever widening past 640. Next, lesson 2 puts a process behind those files: users, PIDs, signals and the service manager that starts them.
Quick check
An optional 4-question self-check. Answers never leave your device, are not stored, and never count toward any assessment.
Lesson feedback
No published feedback yet.
Log in and complete the lesson to leave feedback.
Exercise
On your own machine, create /tmp/perm-lab with three files: one readable only by you, one readable by your group, one executable by everyone. For each, write the ls -l line, the octal mode, and which column applies to a second local user. Then predict and test one denial.
Pass criteria
All three files exist with distinct modes; each prediction names the applicable column (user/group/other) before the test; the denial is demonstrated as the other user or explained with id/group output.