Linux ACLs
February 26, 2016
When basic unix permissions can't express the access requirements you need to impose on a filesystem, you need to turn to the more powerful Access Control List (ACL). Enabled by default on most filesystems in most Linux distributions these days, ACLs provide a rich toolset for handling complex permissions. While they may be intimidating at first, they are actually quite easy to understand.
Checking for ACL Support
For ext3 and ext4 filesystems, we can check if ACLs are enabled by running:
tune2fs -l /dev/sda1 | grep 'Default mount options'
Replace /dev/sda1
with the path to the block device or file that backs the
filesystem. In particular, if you see acl
listed then you know ACL support
is enabled within the filesystem. It's possible to disable ACL support for the
mount itself by specifying noacl
. In order to use ACLs, both the filesystem
and the mount must allow it. Likely, this is already the case, but if you run
into issues setting ACLs then you may need to double-check things.
You may also need to install packages to provide ACL support. On Debian-based
distros you need to install acl
.
apt-get install acl
First Steps
To start things off, let's pretend we work for a company. We're asked to create
a directory called stooges
that contains three subdirectories called larry
,
curly
, and moe
. Regardless of the companies rather unprofessional choice of
names, we can do that.
mkdir -p stooges/larry stooges/curly stooges/moe
If we list the contents of stooges
, we can see the current unix permissions
on the subdirectories.
# cd stooges
# ls -l stooges
total 12
drwxr-xr-x 2 root root 4096 Feb 25 22:35 curly
drwxr-xr-x 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x 2 root root 4096 Feb 25 22:35 moe
The unix permissions are pretty straightforward. Only the root user can create
files within these folders, while anyone else can view the files within the
directories. If we wanted members of the staff group to be able to create files
in the curly
directory, we could simply change the group ownership and modify
the permissions.
# chgrp staff curly
# chmod g+w curly
# ls -l
total 12
drwxrwxr-x 2 root staff 4096 Feb 25 22:35 curly
drwxr-xr-x 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x 2 root root 4096 Feb 25 22:35 moe
Great! Some time later, the company hires some contractors. We create a special
group for them called contractors
. They also need access to the curly
directory. How can we resolve this? With unix permissions, we would need to
either create a new group including members from both staff
and contractors
or add staff
members to contractors
or vice-versa. This is a great fit for
ACLs.
ACLs provide the flexbility required to handle multiple permission sets for
multiple objects. This makes working with multiple groups really easy. To set an
ACL on a file or directory we use setfacl
. Each group can be given their own
set of permissions.
# setfacl -m group:contractors:rwx curly
# ls -l
total 12
drwxrwxr-x+ 2 root staff 4096 Feb 25 22:35 curly
drwxr-xr-x 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x 2 root root 4096 Feb 25 22:35 moe
You can see we've set an ACL on curly
because it now has a +
beside its
permissions. To see the ACL we use getfacl
.
# getfacl curly
# file: curly
# owner: root
# group: staff
user::rwx
group::rwx
group:contractors:rwx
mask::rwx
other::r-x
The lines starting eith a #
are just comments. These comments can be suppressed
by using the -c
option. You can see that while we only set one ACL, we can
actually see four sets of permissions (plus a mask). This is because ACLs treat
unix permissions as generic ACL entries. The owner of the file or directory uses
the user
entry, the group owner uses the group
entry and everyone else uses
the other
entry.
Members of the contractors
group can now access the curly
directory because
members of the group will match the group:contractors:rwx
entry.
For reference, setfacl
allows us to add, modify, and delete ACL entries. The
-m
option adds or modifies an entry, while -x
deletes an entry. We could
delete the entry we just added simply enough.
setfacl -x group:contractors curly
When deleting ACLs, we don't specify the permissions, just the identifying part
of the ACL (in this case group:contractors
). We'll leave the ACL for the
contractors
group there for now, but it's good to know how to delete ACLs.
Managing ACLs on Files and Directories
Copying ACLs
The company decides they want to the same access on larry
that curly
has. While we could follow the same steps as last time, there's a faster way.
setfacl
has the handy ability to understand the output of getfacl
, which
allows us to easily copy ACLs from one directory to the other.
# getfacl curly | setfacl -M - larry
# ls -l
total 12
drwxrwxr-x+ 2 root staff 4096 Feb 25 22:35 curly
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x 2 root root 4096 Feb 25 22:35 moe
# getfacl -c larry
user::rwx
group::rwx
group:contractors:rwx
mask::rwx
other::r-x
The -M
option reads ACL information from a file, or STDIN when a hyphen is
used (as in the case). So we were able to copy the ACL information over but we
still have a problem. Members of staff
won't be able to access the directory
because the group ownership didn't copy over. This is because ownership isn't
recorded in ACLs. To simplify management of ACLs, it's a good idea to store as
much information in the ACLs as possible.
# chgrp root curly
# setfacl -m group:staff:rwx curly larry
Now we have ACL entries for staff
on both directories.
Backing ACLs Up
While our ACLs aren't difficult to restore it's good to get in the habit of backing them up. As our ACLs get more complex, it will become more and more costly if we lose them.
How can we lose them? Anytime files or directories with ACLs are copied without special attention to the use of the tools or media it's possible to lose the ACL information in transit. If the tool doesn't understand or doesn't know to look for ACL information it will ignore it. If the media the data is being copied too doesn't support ACLs, then ACL information will be discarded. By backing up the ACL information on a regular basis we can prevent the disaterous situation where we can recover the data, but can't determine who has access to it.
Fortunately, as we've seen, setfacl
understands the output from getfacl
. We
can use this to create a backup of an entire directory tree of ACLs.
getfacl -R . > backup.acl
The -R
option for getfacl
specifies a recursive lookup. backup.acl
can now
be used to restore all ACLs for files and directories beneath the current
directory. To test this, we can delete the ACLs on curly
and larry
and try
to restore them.
# setfacl -Rb .
# ls -la
total 16
-rw-r--r-- 1 root root 470 Feb 25 23:59 backup.acl
drwxrwxr-x 2 root root 4096 Feb 25 22:35 curly
drwxrwxr-x 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x 2 root root 4096 Feb 25 22:35 moe
The -R
option for setfacl
specifies a recursive operation and the -b
option clears all ACLs. As we can see from the absence of the +
beside the
unix permissions, we no longer have ACLs on curly
and larry
. But don't fret
because we were good sys admins and backed our ACL information up. Now we just
need to restore it.
setfacl --restore backup.acl
This needs to be run from the directory the backup was taken from. Our ACLs are now back and our customers are happy!
# ls -l
total 16
-rw-r--r-- 1 root root 470 Feb 25 23:59 backup.acl
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 curly
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x 2 root root 4096 Feb 25 22:35 moe
Understanding How Access is Calculated
Due to curtain circumstances, HR has requested that access for a staff member
(matt
) to the larry
directory must be revoked temporarily. To faciliate this
we could create a special group for matt
in which he is the only member and
grant that group access to curly
not larry
. It would work, but if we
understand how access is calculated when using ACLs we can come up with an even
better solution.
Essentially, ACLs are evaluated from most-specific to least-specific. User entires are evaluated before group entries are evaluated before the other entry is evaluated. The first matching ACL entry's permissions are used to determine the access to the file or directory.
We can apply this understanding to the current problem. We have a single user who we need to revoke access for. While we grant access based on the group we can revoke access based on the user. But how do we set non-permissions? Simple.
# setfacl -m user:matt:- larry
# getfacl -c larry
user::rwx
user:matt:---
group::rwx
group:staff:rwx
group:contractors:rwx
mask::rwx
other::r-x
Non-permisions (or no permissions) can be specified by simply using a hyphen
in the ACL defintion. As we can see, matt
has no permissions. When matt
attempts to access files in larry
the ACL will first look for user entries, and
upon finding the entry for matt
access to the file will be denied. All other
members of staff
will match the group entry as per usual and will continue to
have access.
Unix Permissions when Using ACLs
Because employees work all hours of the night, it can be hard to find time to
complete automated backups. If staff are writing to files while we're trying to
copy them, we could end up with corrupted files in our backups. The moe
directory in particular maintains a unique backup schedule limiting our options
(we can't remount the volume read-only). How can we easily prevent staff from
making changes while we run our backups?
Let's gather some info first.
# ls -l
total 16
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 curly
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 larry
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 moe
# getfacl -c moe
user::rwx
group::r-x
group:marketing:rwx
group:finance:rwx
group:sales:rwx
group:hr:rwx
group:it:rwx
group:qa:rwx
group:legal:rwx
group:operations:rwx
group:purchasing:rwx
mask::rwx
other::r-x
Though we could change all these ACLs to rx
there's enough of them to make it
a pain in the butt. There might be a simpler way. Let's dive a bit deeper into
the relationship between unix permissions and ACLs to find out how this can be
done.
Once a file or directoy has ACLs applied to it, the semantics of the unix permissions change. They no longer reflect the permissions of the user, group or other users, rather they define the upper bound of permissions that can be granted via ACLs. This is reflected by the mask entry in the ACL, which is bound the group unix permissions.
If the mask defines the most permissive set of permissions, we can use a mask to quickly limit all ACLs to read-only.
# setfacl -m mask::rx moe
# getfacl -c moe
user::rwx
group::r-x
group:marketing:rwx #effective:r-x
group:finance:rwx #effective:r-x
group:sales:rwx #effective:r-x
group:hr:rwx #effective:r-x
group:it:rwx #effective:r-x
group:qa:rwx #effective:r-x
group:legal:rwx #effective:r-x
group:operations:rwx #effective:r-x
group:purchasing:rwx #effective:r-x
mask::r-x
other::r-x
# ls -l
total 16
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 curly
drwxrwxr-x+ 2 root root 4096 Feb 25 22:35 larry
drwxr-xr-x+ 2 root root 4096 Feb 25 22:35 moe
getfacl
now shows us the effective permissions based on the ACL entry and
the ACL mask. Also notice that the unix group permissions reflect the ACL mask
as well. In reality, chmod g-w moe
and setfacl -m mask::rx moe
do the same
thing. This is because the unix group permissions and the ACL mask are bound
together.
Now that staff can no longer modify files, we can take our backup. When we're done we just need to restore the permission by changing the mask back.
setfacl -m mask::rx moe
OR
chmod g+w moe
Inheritance
Up until this point, we've not really had a functional set of ACLs given our use
case. Staff would likely need to create directory structures within our
directories. Currently, our ACL lists would grant them access to create files
and directories within larry
, curly
, and moe
, but the ACLs wouldn't be
inherited by the new child directories. The missing piece of the puzzle in
default ACLs.
Default ACLs can be added to directories. When files or directories are created within a directory with default ACLs, the default ACLs are inherited. For files, the default ACLs become regular access ACLs. For directories, they remain default ACLs.
Before we continue, let's just see what happens when we create a subdirectory without current ACL setup.
# mkdir curly/foo
# ls -l curly
total 4
drwxr-xr-x 2 root root 4096 Feb 26 01:54 foo
As we can see, the new directory hasn't inheirted any ACLs, which means nobody has permission to access it. Let's fix our current ACL situation so that our access can be inherited properly.
# getfacl -c curly
user::rwx
group::rwx
group:staff:rwx
group:contractors:rwx
mask::rwx
other::r-x
# setfacl -b curly
# setfacl -d -m g:staff:rwx,g:contractors:rwx
# getfacl -c curly
user::rwx
group::rwx
other::r-x
default:user::rwx
default:group::rwx
default:group:staff:rwx
default:group:contractors:rwx
default:mask::rwx
default:other::r-x
The -d
option to setfacl
means modify a default ACL entry. We also used the shorthand for group
which is just g
, and added two entries at the same time (every keystroke counts you know!). What happens if we re-create our subdirectory now?
# rm -r curly/foo
# mkdir curly/foo
# ls -l curly
total 8
drwxrwxr-x+ 2 root root 4096 Feb 26 01:56 foo
# getfacl -c curly/foo
user::rwx
group::rwx
group:staff:rwx
group:contractors:rwx
mask::rwx
other::r-x
default:user::rwx
default:group::rwx
default:group:staff:rwx
default:group:contractors:rwx
default:mask::rwx
default:other::r-x
Awesome! The new directory inherited the ACLs which means users will continue to have access! The remaining directories just need to receive the same treatment.
Conclusion
Unix permissions have been around a long time and provide enough flexibility to acheive the access your looking for in most cases. In the cases where unix permissions just won't cut it you can lean on ACLs for more expressive access control. Understanding the added complexity that ACLs brings is critical. ACLs are a tool in your sys admin belt, to be used where appropriate and in conjunction with safegauards to protect the information they contain.
Comments