Table of Contents

Introduction to ACLs: Why Use Them Over POSIX Permissions?

Access Control Lists (ACLs) provide a more flexible and granular way to manage file and directory permissions compared to traditional POSIX permissions. While POSIX permissions are limited to defining access for the file owning user (owner), the owning group (group), and all others (other), ACLs allow you to specify permissions for multiple users and groups individually. This makes ACLs particularly useful in collaboration between multiple users and groups that may not share a single overarching POSIX group, and where finer-grained control over file access is needed.

However, ACLs add appreciable complexity to permission management. They should be used thoughtfully, as misconfigurations, which are easy to inadvertently enable, can lead to unintended access.

High Level Takeaways Up Front

NOTELC does not guarantee functional ACL capability across all its islands of shared storage in the HPC center. If using elaborate ACL schemas in directory and file dataset layouts, you must document and backup your own schemas. LC does not backup or restore ACL definitions in case of accidental deletion nor does it broadly support ACL preservation across various data management tooling (e.g., htar, tar, cp, rsync, scp, etc.). 

NOTEWhen using ACLs to share data outside normal POSIX group directory ownership, the intended user or group still requires the ability to traverse into the directory structure where the data exists. If not done via traditional POSIX group ownership (which may be the reason you're considering ACLs in the first place), you will need to set ACLs on the parent directories to ensure users or groups can traverse the directory structure. Be mindful of files and directories that may have "other" read/write permissions which are now exposed to the user(s) being shared with via ACLs who previously had no such access. 

Best practice After issuing setfacl commands, get in the habit of running both ls -l and getfacl.

Best practice Look for the plus sign ("+") in ls -l output to indicate additional ACL definitions exist requiring further access understanding. 

Best practice If you get an overly complex ACL table created for a directory or file or otherwise need to fix a mistake, it is often best to simply run setfacl -b <filename> to remove special ACLs and return the file to normal POSIX file permission bits and start over.

Best practice Avoid directory default ACLs (a.k.a. inheritance) in group ownership shared directories with many members or disparate membership to avoid unintended access. 

Basic Commands and Terms

ACLs can be viewed and managed with the getfacl  and setfacl commands, respectively.

The setfacl command is typically used to either modify or remove an entry in the ACL and take the forms:

setfacl --modify [user|group]:ID:permissions filename
setfacl --modify [mask|other]:permissions filename
setfacl --remove [user|group]:ID filename
setfacl --remove [mask|other] filename
setfacl [-b|--remove-all] filename

The user/group/mask/other argument can either be short or long form, as detailed in this table:

Short Long
u user
g group
m mask
o other

Permissions must either be combinations of the representative characters or a summed value:

Character Numberic Value Meaning
r 4 read
w 2 write
X 1 execute

The tutorial below demonstrates the usage of these commands. 

ACLs and POSIX File Permissions 

Wikipedia has a very helpful page describing POSIX file system permissions. Details about how ACLs are processed can be found in the ACL man page (run `man 5 acl` on LC systems). In particular, the ACL man page includes a section titled 'ACCESS CHECK ALGORITHM,' which explains how ACLs and file permissions are evaluated when granting access to a file.

A file's POSIX permissions for owner and other will always match the permissions of the corresponding ACL entry. The POSIX group permissions will be the value of the ACL-defined mask (if set) or the ACL-defined group permissions. Modification of the file permission bits results in the modification of the associated ACL entries, and modification of these ACL entries results in the modification of the file permission bits.

A Stepwise Tutorial

This step-by-step guide demonstrates how to set up and manage ACLs.

NOTEThis tutorial must be done on a filesystem that supports ACLs, e.g., Lustre. Most NFS filesystems in LC do not support ACLs, specifically NFS v3. The examples assume users granted access can also access the parent directories leading to the file (e.g., /p/lustre1/<username>).

Step 1: Create a Sample File in an ACL-supporting file system

Start by creating a file to work with. You can see that the initial ACL is the same as what is specified by POSIX permissions.

$ cd /p/lustre1/$USER/
$ touch sample.txt
$ ls -al sample.txt 
-rw------- 1 yourusername yourusername 0 Apr  3 13:15 sample.txt
$ getfacl sample.txt 
# file: sample.txt
# owner: yourusername
# group: yourusername
user::rw-
group::---
other::---

Step 2: Set ACLs for Individual Users

Use ACLs to grant specific permissions to individual users.

Grant john read and write permissions:

$ setfacl --modify u:john:rw sample.txt

This gives the user john read (r) and write (w) permissions on sample.txt.

Grant david read-only permissions:

$ setfacl -m u:david:r sample.txt

This gives the user david read-only (r) permissions on sample.txt.

Step 3: Set ACLs for a Group

Use ACLs to grant specific permissions to a members of a group.

Grant the group developers execute-only permissions:

$ setfacl -m g:developers:rx sample.txt

This gives the group developers read and execute (r-x) permissions on sample.txt.

Step 4: Modify the Mask

LC strongly recommends that users do NOT rely on the mask feature of ACLs. Unless otherwise specified, the mask permissions are recalculated on subsequent setfacl calls. When being recalculated, the mask entry is set to the union of all permissions of the owning group, and all named user and group entries. Thus, a mask can become more permissive on subsequent setfacl calls.

ACLs allow for a "mask" to be set. This mask sets the maximum permissions from ACLs that a file or directory can have (this will not affect the POSIX user or other permissions). We explicitly set the mask using the setfacl command:

$ setfacl -m m:rw sample.txt

If the ACL-defined user or group permissions exceed the mask then the effective permissions are reduced. For example, a file with user r-x permissions and a mask of rw- will result in the user only having r-- permissions to the file. 

The mask restricts the maximum permissions for ACL-defined users and groups but does not affect the file owner's (user::) or others' (other::) permissions. Additional explanation of how this works in practice can be seen in Step 5.

If higher permissions are set for a user or group after the mask has been set the default behavior is to recalculate the masks to match the highest permissions across ALL user and groups permissions currently set. This behavior can be disabled by adding the -n option (--no-mask) with setfacl.

Step 5: Check the ACLs

View the ACLs for the file to verify the permissions:

$ getfacl sample.txt

# file: sample.txt
# owner: yourusername
# group: yourgroup
user::rw-
user:john:rw-
user:david:r--
group::---
group:developers:r-x   #effective:r--
mask::rw-
other::r--

Explanation of the output:

# owner:
# group:    POSIX owner and group
user::rw-    File owner's permissions (POSIX owner).
user:john:rw-    Named user john has read and write permissions.
user:david:r--    Named user david has read-only permissions.
group::---    While this line seems to indicate that owning group (yourgroup) has no permissions, that is not in fact the case. When a mask entry is set, the owning group will experience those permissions, rather than the permissions indicated on the "group::" line.
group:developers:r-x 
#effective:r--

Group developers has read and execute permissions set, but the effective permissions are read-only because of the mask.

mask::rw-    Limits maximum permissions* for users and groups specified by ACLs.

other::r--   All other users have read-only permissions.

* john, david and developers in this example. In this case, the developers group only has read permissions because the execute permission (--x) exceeds the mask (rw-). The mask does not affect the "owner" permissions nor the "other" permissions. The mask permission value is used for the group permissions.

Step 6: Remove an ACL Entry

To remove a specific ACL entry, in this case david's:

$ setfacl --remove u:david sample.txt
$ getfacl sample.txt
# file: sample.txt
# owner: yourusername
# group: yourgroup
user::rw-
user:john:rw-
group::---
group:developers:r-x  
mask::rwx
other::r--

Notice that user:david is no longer listed.

Note also that the effective rights mask been recalculated and has become more permissive than previously set.

Step 7. Resetting ACLs

As you become more familiar with ACLs, you may find old settings or incorrect attempts having been made. To wipe away ACLs on a file or directory use the -b (--remove-all) option:

$ setfacl -b sample.txt

or, if you would like to ensure that your lustre1 directory and everything under it has their ACLs removed, use the recursively flag:

$ setfacl -R -b /p/lustre1/$USER

Additional Notes and Special Cases

Indication a special ACL exists

You can see with traditional linux list (ls) commands when an ACL exists on a file or directory:

$ ls -l 
-rw-r-----  1 sam samproj  0 Apr  1 13:49 file_without_ACL
-r--r-----+ 1 sam samproj 60 Apr  1 13:50 file_with_ACL



A plus sign (+) to the right of the mode field indicates the file has an ACL.

Error Handling

You may encounter errors such as:

$ setfacl: Option -m: Invalid argument near character 3

This typically happens if the user or group specified in the setfacl command does not exist. Ensure that the user or group is valid before setting ACLs.

Recursive ACLs

To apply ACLs recursively to all files and subdirectories, use the -R option:

$ setfacl -R -m u:john:rw /path/to/directory

Parent Directory Access

Users or groups granted access via ACLs must also have access to the parent directories leading to the file. For example, if john cannot access /p/lustre1/<username>, they will not be able to access /p/lustre1/<username>/sample.txt even if ACLs are set correctly on sample.txt.

Users or groups granted access via ACLs must also have permissions to traverse the parent directories. This can be achieved through POSIX permissions or ACLs applied to the directories. If the user lacks access to the parent directories, they will not be able to access the target file, even if ACLs are set correctly on the file.

Data Sharing Example coupled with Directory Access all via ACLs

Let's imagine we are user sam as data owners wishing to grant the user alice specific access to sample.txt in /p/lustre1/sam/samproj. alice is not a member of the group samproj. 

# Illustrating the environment
ls -l /p/lustre1/sam
drwxr-x--- 11 sam samproj 33792 Apr  1 13:49 /p/lustre1/sam
ls -l /u/lustre1/sam/samproj
drwxr-x--- 2 sam samproj 33280 Apr  1 17:10 /p/lustre1/sam/samproj

# Give alice access to data in question
setfacl -m u:alice:rw /p/lustre1/sam/samproj/sample.txt

# Give alice directory structure access (avoiding recursion to limit scope of access)
setfacl -m u:alice:r-x /p/lustre1/sam/samproj/
setfacl -m u:alice:r-x /p/lustre1/sam/

While user alice may now access sample.txt, they can also cd into /p/lustre1/sam and /p/lustre1/sam/samproj and do 'ls' commands. Anything previously opened up with world permissions is now exposed to alice. There is a way to disallow 'ls' ability and that is by only allowing "x" on the directory ACL. The nuance is alice will require previous knowledge about the file(s) absolute pathnames as alice will not be able to list directories.  

Note that the above setfacl also changed the POSIX group permissions for the file as shown by 'ls -l':

$ ls -l sample.txt 
-rw-rw----+ 1 sam samproj 56 Apr  9 15:04 sample.txt

$ getfacl sample.txt 
# file: sample.txt
# owner: sam
# group: samproj
user::rw-
user:alice:rw-
group::r--
mask::rw-
other::---

However, even though the POSIX group permissions suggest that members of the samproj group can now write to the file, this is not the case. We must pay attention to the ACL output from getfacl for the owning group to realize that it's still read-only as shown by "group::r---". This is why it's important to follow any plus ("+") sign you see in the ls output with getfacl to truly understand the granted access. 

Owning Group and ACL mask 

We've seen in our Data Sharing example just above how ACLs can display a change in POSIX permissions. So, too, in the other direction can changing the POSIX permissions change the ACL masking:

$ ls -l sample.txt 
-rw-rw----+ 1 sam samproj 56 Apr  9 15:04 sample.txt

$ chmod 640 sample.txt

$ ls -l sample.txt
-rw-r-----+ 1 sam samproj 0 Apr  9 14:16 sample.txt

$ getfacl sample.txt
# file: sample.txt
# owner: sam
# group: samproj
user::rw-
user:alice:rw-                 #effective:r--
group::r--
mask::r--
other::---

Above we see that the chmod command removed the write access for owning group samproj. It also removed the write bit on the ACL mask. Further, although our temporary collaborator alice still shows the original ACL of read+write access, however the effective permissions of read-only have now been applied due to the mask effect and the chronology of execution with the chmod having been the most recently executed command between it and setfacl, thereby obviating our original plan to give alice write capability to our file sample.txt. To fix this and restore write capability for user alice, we would need to re-run the 'setfacl -nm u:alice:rw sample.txt' command once again. 

Inheritance via Directory Default ACL

Setting default ACLs on a directory can create an unintended access issue for other users within the directory-owning group were they to create files in the directory and be unaware of the inheritance ACL. Best practice is to avoid default directory ACLs. Avoid inheritance in broadly shared directories unless deeply understood by all group members. 

Thus far we've treated directory and file objects distinctly in terms of setting ACLs intentionally for each object. It is possible to set an inheritance ACL known as a "default ACL" for directories which then governs creation of an initial access ACL for all objects created within that directory. 

Using a previous example and assuming it was run before any default ACL existed on the directory, here's what would be seen:

$ setfacl -m u:alice:r-x /p/lustre1/sam/samproj
$ getfacl /p/lustre1/sam/samproj
# file: p/lustre1/sam/samproj
# owner: sam
# group: samproj
user::rwx
user:alice:r-x
group::r-x
mask::r-x
other::---

$ whoami
sam
$ touch newfile1
$ ls -l newfile1
-rw-r----- 1 sam sam 0 Apr  9 17:23 newfile1 

Note above that no ACL for alice exists (due to the lack of a "+" in the ls output). 

Now let's set a directory default ACL and create another file:

$ setfacl -dm u:alice:rwx  /p/lustre1/sam/samproj

$ getfacl  /p/lustre1/sam/samproj
getfacl: Removing leading '/' from absolute path names
# file: p/lustre1/sam/samproj
# owner: sam
# group: samproj
user::rwx
user:alice:r-x
group::r-x
mask::r-x
other::---
default:user::rwx
default:user:alice:rwx
default:group::r-x
default:mask::rwx
default:other::---

$ whoami
sam

$ touch newfile2

$ ls -l newfile2
-rw-rw----+ 1 sam sam 0 Apr  9 17:28 newfile2

$ getfacl newfile2
# file: newfile2
# owner: sam
# group: sam
user::rw-
user:alice:rwx                 #effective:rw-
group::r-x                      #effective:r--
mask::rw-
other::---    

Above we see that newfile2 inherited the ACL for alice to be able to effectively read and write newfile2 when user sam created the file.