Unix File Permissions — Keeping Your Data Safe from Supervillains
For the past few weeks, I’ve been onboarding to our dev ops squad at Flatiron. I’m learning everything from the ground up and documenting my learnings along the way. From my experiences so far, a big part of ops is permissions: making sure the correct users and programs are able to read, write and execute specific files. In order to control this, we need to be able to interact with files in Linux, a family of operating systems that servers frequently utilize.
We permission files not only to control what team members have access, but more importantly to control what programs can access them. For example, if we are running a service on our server, we might want to permission the service as a user that can write to a log file. However, we might want other users or even another service (like a logging and monitoring service) to be able to read those logs but not to write to them. We can achieve this security by setting up file permissions.
Below is a picture of my new squad, always ready to save the day.
Just kidding. Our ops squad is more like Peter Quill and Baby Groot.
Here I am dancing around while everything is on fire and an interdimensional being is smashing all of our applications into the ground.
Unix Permission Types
There are basically three levels of file permissions on Unix-like systems: read, write and execute. These same permissions can exist on both a file and a directory level. For a file, read permissions permit viewing its contents (and seeing if the file exists), write permissions let a user modify content, and execute permissions allow a user to run a file as a program. For directories the permissions are similar. Read permissions let a user see filenames (but no file contents or metadata), write permissions permit a user to create/delete/rename files, and execute permissions allow a user to search within the directory (using Unix commands like
cd) and view metadata for known filenames. In general, directories will need execute permissions along with whatever read or write permissions we provide in order to execute commands.
To view permissions for a file or directory, we can use
ls -lah followed by the path.
ls is a Unix command to display directory contents. The letters
lah are each flags applied to the
ls command, which specify further options about how the command should be executed.
l is for a longer listing format, which shows metadata about the files and directories (including permissions).
a tells the command to also display files with filenames beginning in
.. This flag not only displays hidden files with names prefixed by
., but it also displays information for
.., which refer to the current directory and its parent directory respectively. Lastly,
h specifies that the file size output should be human readable and include units of measurement.
Let’s make some practical use of these commands. The Flatiron team has a lot of die-hard Avenger fans (and also some avenging Die Hard fans). In preparation for the release of Avengers: Endgame, we started having regular Avenger standup meetings. Naturally we needed to store notes from these meetings on a shared server. So after sshing into our server, we made a directory and created some files in it.
$ mkdir avengers-endgame
$ touch avengers-endgame/thanos-theories.md
$ touch avengers-endgame/spoilers.md
Great, now we have places to store our favorite fan theories about Thanos and notes about spoilers after we see the movie. These files would have been given default permissions based on the user we are currently logged in as. If we try to view these permissions by running
ls -lah avengers-endgame, we will get the below output:
drwxr-xr-x 4 niky staff 128B Apr 20 22:33 .
drwxr-xr-x+ 46 niky staff 1.4K Apr 20 22:31 ..
-rw-r — r — 1 niky staff 0B Apr 20 22:32 spoilers.md
-rw-r — r — 1 niky staff 0B Apr 20 22:33 thanos-theories.md
We will ignore the first row because it’s data about the block size of the directory, something we don’t need right now. The two lines directly below that refer to the
avengers-endgame directory and its parent directory. The last two lines are about the
thanos-theories.md files. If our
avengers-endgame directory contained other files, they would likewise be listed below. The first column for all these rows is a set of flags that reveal information about our file mode and permissions. The first flag (character) indicates the type of the file, commonly either a directory (d) or file (-). After that the set contains three subsets of three flags apiece that indicate file permissions for various user-groups. Flags 2–4 show permissions for the owner, 5–7 for file’s group and 8–10 for everyone else. All of these permissions can be interpreted in a binary way: a letter (
r for read,
w for write and
x for executable) indicates that permission is present for that user and a dash indicates that permission is not present. These permissions are always presented in the
The second column indicates the number of links associated with that file. The third column lists the id of the owner and the fourth lists the group id (which defaults to the group the owner is a member of). Column 5 displays the file size in bytes. Column 6 is the last modified date and column 7 is the filename.
When it comes to permissions, columns 1, 3 and 4 contain the most useful information for us. For example, using those columns we can see that
avengers-endgame is a directory and has the following permissions:
rwx for the owner => niky can read, write and execute within that directory
r-x for the group => staff can read and execute
r-x for everyone => anyone can read and execute
Symbolic and Numeric Notations
This way of displaying file permissions (drwxr-xr-x) is called symbolic notation. In numeric notation, read, write, and execute permissions are represented by different numbers (read is 4, write is 2, execute is 1 and no privileges is 0). These numbers come from our binary representation of each permission as on or off, but using 1 and 0 (for on and off respectively) instead of our
rwx letters. Again these permissions are always presented in the same order of
rwx. Read and execute permissions only for a file would be represented as 101 (on-off-on) which is 5 in binary. Representing these permissions in binary for all our user-groups would take 9 digits (the same as symbolic notation). However, in numeric notation we convert these binary numbers into octal (or base-8).
avengers-endgame directory permissions can also be expressed as:
rwx for the owner => 111 in binary => 7 in octal
r-x for the group => 101 in binary => 5 in octal
r-x for everyone => 101 in binary => 5 in octal
Now instead of 9 digits, we can represent these permission triads each as a single digit per user-group. Our directory is mode 755. Since our only number options for individual permissions are 4, 2, 1 and 0 as we saw above, there is only one possible combination that can mathematically combine to each number between 0 and 8. Said another way, these numbers are never ambiguous: each indicates exactly what digits (permissions) added to it.
Back to our files:
thanos-theories.md both have read and write permissions for the owner, but only read for anyone else (including the group). This is great if we want everyone to have access to view the information in these files, but that won’t always be the case. If these files exist on a shared server, we might want to protect some of them. Perhaps once the owner sees the movie and writes to the spoilers file, we want to make it unreadable by everyone . No one wants the movie ending Ruffaloed for them.
To accomplish these changes, we can use the
chmod command. Chmod allows us to change the mode (permissions) of a file or directory. We can execute it by running
chmod <permissions-info> <file-path>; however,
chmod allows us to input the permissions in a variety of ways. If we want to limit who can read
spoilers.md, we can use
chmod to add or subtract permissions using an initial for the user-group and the plus, minus and equal operators with symbolic notation.
Both our files are starting with permissions of -rw-r — r — or 644. We can run
chmod o-r spoilers.md from inside our
avengers-endgame directory. With this command we have subtracted read permissions from the ‘others’ group resulting in file permissions of -rw-r — — or 640. I can add execute permissions for the user
chmod u+x spoilers.md or set permissions equal to read-write for the group with
chmod g=rw spoilers.md After these two commands our permissions look like -rwxrw — or 760.
Another way to set permissions is using numeric notation, which requires a bit of math but is syntactically lighter. If we want to crowdsource our Thanos theories from all users, we must decide what permissions we want and what number represents that. For everyone to be able to read-write, we can
chmod 666 spoilers.md. This is an absolute command that sets our permissions equal to whatever number we provide. For each user-group we are setting the permission to read (2) + write (4). With our symbolic notation we could accomplish the same by cherrypicking permissions to add and subtract, then running
chmod g+w,o+w spoilers.md.
If someone else wants to moderate our thanos-theories, we can change ownership of the file by running
chown johann thanos-theories.md where johann is the username of another user who becomes the keeper of all our hypotheses. We also could change the default group for the file using
chgrp shield spoilers.md. Now all users included in the Shield group have the group access to the file (which is read-write).
There are a lot more advanced things that can be done with file permissions, but these are some of the basics that can get you started. Now our spoiler secrets are so safe that even Hydra can’t crack them! (Untrue. Cut off one head and two more will take its place.)
Thanks for reading! Want to work on a mission-driven team that loves Ops and the Avengers? We’re hiring!