Skip to content
shellhacks.dev
Security

How to Use ACLs and Groups to Share Files Safely Fast

Share files between users on Linux with groups, the setgid directory and ACLs: default ACLs for new files, the mask, getfacl and common pitfalls.

6 min read
Summarize in AI
Illustration for "How to Use ACLs and Groups to Share Files Safely Fast": a terminal session, progress bars, file permission bits.

Two people need to work on the same set of files, and the common failure is permission denied on whatever the other person created. Plain Unix modes can handle it with a group, and ACLs cover the cases groups do not: one extra reader, or different rights for different people. This post shows both with the traps that cause them to fail. It builds on locking down file permissions. The commands assume Debian 13 with ext4 and acl 2.3.

Groups and the setgid directory

Shell
sudo groupadd project
sudo usermod -aG project ada
sudo usermod -aG project grace
sudo mkdir -p /srv/project
sudo chgrp project /srv/project
sudo chmod 2770 /srv/project
ls -ld /srv/project
Text
drwxrws--- 2 root project 4096 Nov  3 10:02 /srv/project

The s in the group position is the setgid bit: files created in the directory belong to the group project instead of the creator's primary group. The other half is the group's write bit on the files themselves, which depends on each user's umask. If ada's umask is 022, files are created 644 and grace cannot edit them. Use umask 002 for people who share, or set default ACLs as below. Group changes apply only to new logins, so ask users to log out and in, or use newgrp project for a shell.

ACLs for individual access

Shell
sudo setfacl -m u:linus:r-x /srv/project
sudo setfacl -m g:auditors:r-x /srv/project/reports
getfacl /srv/project
ls -ld /srv/project
Text
# file: srv/project
# owner: root
# group: project
# flags: -s-
user::rwx
user:linus:r-x
group::rwx
mask::rwx
other::---
drwxrws---+ 2 root project 4096 Nov  3 10:02 /srv/project

A plus sign after the mode in ls -l means ACL entries exist. The named-user entry gives linus read access without making him a member of the group. This is the tool for the "one more person" case, and also for removing the temptation to make a directory world-readable.

Default ACLs for new files

Shell
sudo setfacl -d -m g:project:rwx /srv/project
sudo setfacl -d -m u::rwx,o::--- /srv/project
sudo -u ada touch /srv/project/new.txt
getfacl /srv/project/new.txt | grep -E 'group|mask'

Default entries (-d) are inherited by files and directories created in the directory. With g:project:rwx as a default, new files carry a group ACL granting write to the group, independent of the user's umask, which closes the gap where a colleague cannot edit a new file. Existing files are not changed; apply an entry recursively with setfacl -R -m g:project:rwX /srv/project.

The mask

Text
user:linus:rwx    #effective:r--
mask::r--

The mask is the upper limit for every entry except the owner and others. It is set automatically when you run chmod g=... on a file with ACLs, because the group bits then represent the mask, which silently reduces named entries. When access fails despite a correct ACL, getfacl shows an #effective comment explaining it. Reset with setfacl -m m::rwx file.

Other things that forget ACLs

Copies with cp drop them unless you add -a or --preserve=all. tar needs --acls, and rsync needs -A. Backups that ignore ACLs restore with the wrong access. Remove all entries with setfacl -b. Network filesystems and some container volumes may not support ACLs; check the mount options.

Where this does not apply

Many named users and rules are hard to audit, and ACLs are invisible to ls beyond the plus sign. When access needs are complex or must be reviewed, put the logic in groups and keep ACLs for exceptions. For code with several authors, Git's own workflow is the sharing mechanism. For application data, a service account with its own directory is simpler than shared users.

For the permission basics behind all of this, see debugging permissions with namei, which shows every directory on a path, and umask in scripts for the defaults that scripts create files with. A shared directory works only when each directory on the path to it allows the group to enter.

Why groups alone are not enough

The traditional way to share a directory is a group: create a group, add the people, make the directory owned by that group with write permission. Two details usually go wrong. New files take the primary group of the user who creates them, not the group of the directory, so a file created by Alice belongs to her personal group and Bob cannot edit it. The fix is the setgid bit on the directory, set with chmod g+s or the octal mode 2775, which makes new files and subdirectories inherit the directory's group. The second problem is the umask: with the common 022, a new file is group-readable but not group-writable, so even with the right group a colleague can read the file and not change it. Setting the umask to 002 for people who work in the shared area fixes that, and it has to be done where their shells start. Groups scale well and give everyone in them the same access, which is the limit: you cannot give one person read-only access and another write access without more groups.

Group membership applies at login, so a person added to a group has to log in again before it takes effect, and a long-running session keeps the old list. The command id shows the groups a session actually has.

What ACLs add and how they are read

Access control lists add per-user and per-group entries to a file or directory, beyond the owner, group and other of the classic model. setfacl -m u:alice:rwx dir gives Alice full access, g:auditors:rx gives a group read access, and getfacl prints the full list. A + after the mode in ls -l output tells you a file has an ACL, which is easy to miss and explains why a file behaves differently from what its mode suggests. The file system must support them, which ext4, XFS and Btrfs do by default on modern kernels, and network file systems may or may not. The ACL has a mask entry that caps the effective permission of every named user and group, and chmod on a file with an ACL changes the mask, not the owner's group bits, which is the cause of the surprise where a permission you granted shows as ineffective. Read getfacl for the line marked effective, and reset the mask with setfacl -m m::rwx when needed.

Default ACLs and the tools that lose them

A default ACL, set with -d, is a template that new files and subdirectories inherit, which is what makes sharing work over time and not only for what exists today. Set both the access entries for the current contents, with -R, and the default entries for future ones, since doing only the first leaves new files without the access. When a directory has a default ACL, the umask is ignored for new files inside it and the template governs, so the two mechanisms are not additive. Several common tools do not preserve ACLs unless asked: cp needs -a or --preserve=all, rsync needs -A, tar needs --acls, and backup programs vary. A restore or a copy to another disk can silently drop the access you set up. Keep the scheme simple, document it in a sentence next to the directory, and check with getfacl after a move. If you find you are managing many individual entries, create a group and use it, which is easier to audit.

See setfacl(1) and acl(5).

Also inLinux
Share

Keep reading

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.