The Linux Security Model
Linux determines who can access files using three categories of users and three permission types. This is the foundation of Linux security.
Understanding permissions is non-negotiable for DevOps. Misconfigured permissions are a leading cause of security breaches and application failures in production.
The Permission Model
User Categories (U-G-O)
Every file has three layers of access:
| Category | Symbol | Meaning |
|---|---|---|
| User | u | The owner of the file |
| Group | g | Users who belong to the file's group |
| Others | o | Everyone else on the system |
Permission Types (R-W-X)
| Permission | Symbol | On a File | On a Directory |
|---|---|---|---|
| Read | r | View file contents | List directory contents |
| Write | r | Modify file contents | Create/delete files in directory |
| Execute | x | Run file as a program | Enter (cd into) directory |
Reading Permissions — ls -l
When you run ls -l, the first column shows permissions in symbolic form:
$ ls -la /var/log/
total 216
drwxr-x--- 2 root adm 4096 Apr 10 08:00 apache2/
-rw-r----- 1 root adm 6340 Apr 10 09:05 auth.log
drwxr-xr-x 3 root root 4096 Apr 10 08:00 apt/
-rw-r--r-- 1 root root 4096 Apr 10 08:00 bootstrap.logBreaking Down the Permission String
For auth.log:
-rw-r----- 1 root adm 6340 Apr 10 09:05 auth.log
│││││││││
│││││││││└─ Other: READ only
││││││││└── Other: no WRITE
│││││││└─── Other: no EXECUTE
││││││└──── Group: READ only
│││││└───── Group: no WRITE
││││└────── Group: EXECUTE (can cd into dir — not meaningful for files)
│││└─────── User (owner): READ + WRITE
││└──────── User (owner): no EXECUTE
│└───────── File type: regular file (-)
└────────── File type: regular file (-)
For apache2/:
drwxr-x--- 2 root adm 4096 Apr 10 08:00 apache2/
│││││││││
│││││││││└─ Other: no permissions
││││││││└── Other: no access
│││││││└──── Group: READ + EXECUTE (can list and cd)
││││││└───── Group: no WRITE
│││││└────── User (owner): READ + WRITE + EXECUTE
││││└──────── User (owner): full access
││└────────── Directory type: d
└──────────── File type: directory
Permission String Reference
File type + User + Group + Other
- rwx r-x r--
d rwx r-x r-x
Changing Permissions — chmod
Symbolic Notation
# Add execute permission to a file
chmod +x script.sh
# Remove write permission from a directory for others
chmod o-w /shared
# Add read permission for group
chmod g+r config.yaml
# Set multiple permissions at once
chmod u+rw,g+r,o+r file.txtNumeric (Octal) Notation
Each permission has a numeric value:
| Permission | Numeric | Calculation |
|---|---|---|
r | 4 | Read |
w | 2 | Write |
x | 1 | Execute |
rwx | 7 | 4 + 2 + 1 |
r-x | 5 | 4 + 0 + 1 |
rw- | 6 | 4 + 2 + 0 |
Three digits = Owner, Group, Others
# rwx for owner, r-x for group, r-- for others (755)
# Most common for executables and directories
chmod 755 script.sh
# Full access for owner, read-only for group and others (744)
chmod 744 private.txt
# rwx for owner, --- for group, --- for others (700)
# Only the owner can read, write, or execute
chmod 700 /home/admin/secrets
# Full access for owner and group, read-only for others (774)
chmod 774 shared_folder/
# rw-rw-rw- (666) — world-writable — BAD practice
chmod 666 shared_file.txt
# For directories, 'x' must be set to allow traversal (cd)
# chmod 644 mydir/ would prevent cd into mydir/Common Permission Patterns
| Mode | Permissions | Use Case |
|---|---|---|
777 | rwxrwxrwx | Full access for all (avoid!) |
755 | rwxr-xr-x | Executables, scripts, public dirs |
750 | rwxr-x--- | Private project directories |
700 | rwx------ | Private files, scripts, secrets |
644 | rw-r--r-- | Config files, documentation |
600 | rw------- | Private keys, credentials |
400 | r-------- | Highly sensitive (SSH private keys) |
Never set permissions to
777 on files or directories in production. This gives anyone on the system full access to read, write, and execute. Use 700 or 600 for sensitive files.Special Permissions
# SetUID (set user ID) — run as file owner, not caller
# When a user runs /usr/bin/passwd, it runs as root
chmod u+s /usr/bin/passwd
# Shows as 's' in owner execute position: -rwsr-xr-x
# SetGID (set group ID) — run as file's group
chmod g+s /usr/bin/myapp
# Shows as 's' in group execute position: -rwxr-sr-x
# Sticky Bit — in a directory, only owners can delete files
# Classic use: /tmp, /var/tmp
chmod +t /shared/upload
# Shows as 't' in other execute position: drwxrwxrwt
# Sticky bit on /tmp
$ ls -la /tmp | head -5
drwxrwxrwt 11 root root 4096 Apr 10 08:00 .Changing Ownership — chown
# Change file owner
sudo chown alice report.txt
# Change file owner and group
sudo chown alice:developers report.txt
# Change group only (shorthand)
sudo chown :admins report.txt
# Recursively change directory contents
sudo chown -R alice:developers /var/www/app
# Change ownership of a symbolic link itself (not target)
sudo chown -h alice link.txt# Before
-rw-r--r-- 1 bob users 4096 Apr 10 09:00 report.txt
# After: sudo chown alice:developers report.txt
-rw-r--r-- 1 alice developers 4096 Apr 10 09:00 report.txtRecursive Ownership Changes
# Give a new user ownership of an entire application directory
sudo chown -R www-data:www-data /var/www/myapp
# Common Docker container directory permissions
sudo chown -R 1000:1000 /home/admin/appViewing Permissions
# Basic listing
ls -l config.yaml
-rw-r--r-- 1 admin admin 894 Apr 10 08:45 config.yaml
# Get only permissions (numeric)
stat -c '%a' config.yaml
644
# Get only permissions (symbolic)
stat -c '%A' config.yaml
-rw-r--r--
# Full stat information
stat config.yaml
File: config.yaml
Size: 894 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 131088 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ admin) Gid: ( 1000/ admin)
Access: 2026-04-10 08:45:00.000000000 +0000
Modify: 2026-04-10 08:45:00.000000000 +0000
Change: 2026-04-10 09:00:00.000000000 +0000Umask — Default Permissions
The umask determines the default permissions for newly created files and directories.
# View current umask
$ umask
0022
# How umask works:
# Files get: 666 - umask = default
# Directories get: 777 - umask = default
# umask 0022:
# Files: 666 - 022 = 644 (rw-r--r--)
# Dirs: 777 - 022 = 755 (rwxr-xr-x)
# Set umask for current session
umask 027 # More restrictive: only owner has full accessUmask values and their effects:
| Umask | File Default | Dir Default |
|---|---|---|
0000 | 666 (rw-rw-rw-) | 777 (rwxrwxrwx) |
0022 | 644 (rw-r--r--) | 755 (rwxr-xr-x) |
0027 | 640 (rw-r-----) | 750 (rwxr-x---) |
0077 | 600 (rw------- | ) |
Real-World DevOps Scenarios
Scenario 1: Web Server Permissions
# NGINX runs as www-data. It needs to read app files.
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html # Read + execute for all
# For uploads directory, www-data needs write
sudo chown www-data:www-data /var/www/html/uploads
sudo chmod 775 /var/www/html/uploads # Group can write tooScenario 2: SSH Key Permissions
# Private key — most restrictive
chmod 600 ~/.ssh/id_ed25519
-rw------- 1 admin admin 1679 Apr 10 08:00 id_ed25519
# Public key — can be readable
chmod 644 ~/.ssh/id_ed25519.pub
-rw-r--r-- 1 admin admin 397 Apr 10 08:00 id_ed25519.pub
# SSH directory
chmod 700 ~/.ssh
drwx------ 2 admin admin 4096 Apr 10 08:00 .ssh
# Authorized keys
chmod 600 ~/.ssh/authorized_keys
-rw------- 1 admin admin 397 Apr 10 08:00 authorized_keysScenario 3: Application Log Directory
# App writes logs, admin needs to read them
sudo chown -R app:adm /var/log/myapp
sudo chmod -R 750 /var/log/myapp # app and adm can access, others cannotQuick Reference
| Task | Command |
|---|---|
| Show permissions | ls -l file |
| Add execute for owner | chmod u+x file |
| Set exact permissions | chmod 755 file |
| Make file private | chmod 600 file |
| Make directory accessible | chmod 755 dir |
| Recursive permissions | chmod -R 755 dir |
| Change owner | chown user file |
| Change owner + group | chown user:group file |
| Recursive ownership | chown -R user:group dir |
| View umask | umask |
| Set umask | umask 027 |
| Check special perms | stat file |
Practice Challenge
- Create a file
secret.txtand set its permissions to600 - Create a directory
sharedand set permissions to775 - Create an executable script
hello.sh— can you run it with./hello.sh? - What happens when you
chmod -x hello.shand try to run it again? - Set the sticky bit on the
shareddirectory and verify it appears asdrwxrwxrwt - Use
statto view all permission details of a file