Table of Contents
- Introduction to ACLs: Why Use Them Over POSIX Permissions?
- A Stepwise Tutorial
- Additional Notes and Special Cases
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.
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.