ACLs: Extended Permissions Beyond chmod
AI generated
$
/etc
Linux · File System · System Administration · Magento
ACLs: Extended Permissions Beyond chmod
when one owner and one group are not enough

chmod only understands a single owner and a single group per file, yet real server environments often need several access levels at once. This guide explains setfacl and getfacl, walks through a deploy user example showing granular access control beyond rwx, and covers default ACLs that automatically apply the right rights to newly created files.

13 min. read setfacl · getfacl · Default ACL · ACL Mask Linux · Debian/Ubuntu · Magento 2

1. The limit of chmod: one owner, one group

The classic Unix permission model assigns exactly three target classes to every file: the owner, a single associated group, and everyone else. chmod and chown cover most day-to-day cases with that, but they hit a hard wall as soon as more than one group needs different rights on the same path at the same time. A typical example: a directory is owned by a service's system user, say redis or www-data, and a deploy team also needs to write there, without changing the file's primary group or forcing the service account into a foreign group.

With plain chmod, the only options left are unattractive compromises: either switch the group and break the service's original ownership logic, or grant other-class rights and thereby open access to every local process. Both paths violate the principle of least privilege. Access Control Lists (ACLs) solve exactly this problem: they extend every file and directory with an arbitrary number of additional user and group entries, completely independent of the primary ownership. The classic rwx bits remain fully intact and are only supplemented, never replaced.

ACLs are not a replacement for chmod, but a targeted extension for edge cases. On most servers, owner, group, and umask are entirely sufficient for 95 percent of all paths. The remaining 5 percent, shared directories between multiple teams, monitoring access to log directories owned by other services, or deploy pipelines with restricted rights, are exactly where ACLs earn their keep.

2. getfacl: reading and understanding ACL entries

Before setting any rights, you should know the current state. The command getfacl file shows every entry of a file or directory in a readable format: owner, group, the classic rwx bits as user::, group::, and other::, plus additional entries as user:name:rwx or group:name:rwx. An additional entry called mask:: caps the effective rights of all named user and group entries, covered in more detail in the ACL mask section below.

A hint that ACL entries exist appears even before you run getfacl: ls -l appends an extra + after the regular nine permission characters for files carrying an ACL, for example drwxr-x---+. That plus sign is the only clue in standard output; the actual details always come from getfacl. For analyzing entire directory trees, getfacl -R directory/ recursively dumps all ACL entries and works well as a text baseline for diffing two server states. A typical output summarizes owner, group, and every entry compactly: user::rwx, user:deploy:rwx, group::r-x, group:monitoring:r-x, mask::rwx, and other::---, each line its own permission set.

3. setfacl: setting, modifying, removing entries

The setfacl command sets, modifies, and removes ACL entries. The -m option (modify) adds an entry or overwrites it if it already exists: setfacl -m u:deploy:rwx file grants the user deploy full rights without touching the classic owner or group permissions at all. For groups the same works with g: instead of u:, for example setfacl -m g:monitoring:r-x directory. Multiple entries can be set in a single call, comma-separated, which keeps scripts compact and reduces the number of process invocations.

To remove a single entry, use -x (remove): setfacl -x u:deploy file removes exactly that entry without touching any other ACL entries or the classic bits. To strip all extended ACL entries at once and fall back to plain chmod logic, use setfacl -b file. The -R option applies any of these operations recursively across an entire directory tree, which becomes especially relevant combined with -d for default ACLs. Important: calling setfacl without -m or -x, but with plain --set, replaces the entire ACL rather than individual entries, which quickly causes unintended loss of rights if confused with -m.


#!/usr/bin/env bash
# setfacl: modify, remove, and reset ACL entries
set -euo pipefail

# Grant a user read/write/execute without touching owner or group
setfacl -m u:deploy:rwx /var/www/shared-uploads

# Grant a group read/traverse access
setfacl -m g:monitoring:r-x /var/www/shared-uploads

# Multiple entries in one call, comma-separated
setfacl -m u:deploy:rwx,g:monitoring:r-x,u:backup:r-x /var/www/shared-uploads

# Remove a single named entry, leave everything else untouched
setfacl -x u:deploy /var/www/shared-uploads

# Remove ALL extended ACL entries, fall back to plain chmod bits
setfacl -b /var/www/shared-uploads

# Apply recursively to an entire tree
setfacl -R -m u:deploy:rwx /var/www/shared-uploads

4. Practical example: deploy user writes to a foreign directory

A concrete scenario from day-to-day operations: a cache directory is owned by a service's system user, say redis:redis, with a strict baseline of 750. A separate deploy user, deploy, writing configuration files into this directory via CI/CD pipelines, needs write access without the service account being added to a foreign group or the ownership being changed. Without ACLs, the only option would be adding deploy to the redis group, which immediately grants that user access to every path owned by that group, far beyond the one target directory.

With a targeted ACL, access stays scoped exactly to the required path: setfacl -m u:deploy:rwx /var/lib/redis/config grants deploy full rights on exactly this directory, while owner and group remain unchanged at redis:redis. For directories with many subfolders, combine it with -R to cover the existing tree completely. What matters is that this solution stays stable even through a later change of the service account or a reinstall of the service, as long as the ACL is reapplied after a reinstall, since ACLs are not automatically managed by package managers.

For Magento setups, this pattern is especially relevant when a separate reporting or backup service needs read access to var/log, which is owned by the PHP-FPM user. Instead of adding the backup user to the www-data group and thereby potentially opening write access to the entire application, a targeted r-x entry for exactly this path is enough.


#!/usr/bin/env bash
# Grant a deploy user write access to a directory owned
# by an unrelated service account, without group changes
set -euo pipefail

readonly TARGET_DIR="/var/lib/redis/config"
readonly DEPLOY_USER="deploy"
readonly READONLY_USER="backup"

# Confirm current ownership stays with the service account
stat -c "%U:%G %n" "$TARGET_DIR"   # redis:redis /var/lib/redis/config

# Grant the deploy user full access, scoped to this path only
setfacl -R -m u:${DEPLOY_USER}:rwx "$TARGET_DIR"

# Grant a backup service read-only traversal, no write at all
setfacl -R -m u:${READONLY_USER}:r-x "$TARGET_DIR"

# Verify: ownership is unchanged, ACL grants the extra access
getfacl "$TARGET_DIR" | grep -E "^(user|owner|group):"

5. Default ACLs: inheritance for newly created files

A regular ACL only applies to the file or directory it was set on. New files created later inside a directory inherit nothing from it. That is exactly what default ACLs are for, set with the d: prefix or the -d option: setfacl -d -m u:deploy:rwx directory/ ensures that every new file and every new subdirectory created inside that directory from that point on automatically receives the same ACL entry. This is comparable to the setgid bit, but with full control over arbitrary users instead of just the group.

Default ACLs are stored separately from regular access ACLs, so a directory can simultaneously carry a current access ACL for itself and a default ACL for future contents. In getfacl output, default entries appear prefixed with default:. There is an important distinction between files and directories: a default ACL granting execute rights does not automatically make new files executable, since a file's executable bit remains bounded by the internal mask and the original creation mode. New subdirectories, on the other hand, inherit both the access ACL and the default ACL of the parent directory, so inheritance continues to arbitrary depth.


#!/usr/bin/env bash
# Default ACLs: automatic inheritance for future files
set -euo pipefail

readonly SHARED_DIR="/var/www/shared-uploads"

# Set both an access ACL (applies now) and a default ACL
# (applies to every file/subdir created from now on)
setfacl -m u:deploy:rwx,g:monitoring:r-x "$SHARED_DIR"
setfacl -d -m u:deploy:rwx,g:monitoring:r-x "$SHARED_DIR"

# Create a new file as another user, then verify inheritance
sudo -u www-data touch "${SHARED_DIR}/report-2026-07-12.json"
getfacl "${SHARED_DIR}/report-2026-07-12.json"

# Expected: user:deploy:rwx and group:monitoring:r-x
# appear automatically, without any manual setfacl call

# Remove only the default ACL, keep the current access ACL intact
setfacl -k "$SHARED_DIR"

6. The ACL mask: the underestimated factor

Every extended ACL carries a mask:: entry that caps the maximum effective rights for all named user and group entries as well as the owning group. The classic owner's user:: entry is exempt from the mask, everything else is not. If you run setfacl -m u:deploy:rwx file on a file whose mask only allows r-x, deploy effectively still only gets r-x, even though the entry shows rwx. getfacl flags this discrepancy with an #effective: comment right next to the affected entry, a detail that is easy to miss in standard output.

setfacl recalculates the mask automatically by default as the union of all set rights, so this problem does not normally occur. It becomes relevant once chmod is applied to the same file after ACL entries were set: chmod on a file carrying an ACL does not modify the group rights in the classic sense at all, but directly rewrites the mask instead. A later chmod g-w file can therefore inadvertently restrict every named ACL entry, even ones explicitly set to rwx. Setting the mask explicitly with setfacl -m m::rwx file is the most reliable way to control this behavior rather than relying on implicit recalculation.

7. Backing up, copying, and restoring ACLs

Standard backup tools like tar silently discard ACL entries unless run with the --acls option, and cp does not carry them over either unless run with -p or --preserve=all. Anyone using ACLs on production directories must build these options explicitly into backup and deploy scripts, or the extended rights silently disappear at the next restore without any error being reported. This is one of the most common causes of permissions that seem to spontaneously vanish after a server migration.

For targeted backup and restore, the pair getfacl -R and setfacl --restore works well: a recursive getfacl dump can be version-controlled as a plain text file and fully restored on another server or after a rebuild with setfacl --restore=file. This approach is particularly valuable for disaster recovery plans, since it documents ACL state independently of the actual file content and makes it fully reproducible without depending on a specific backup format.


#!/usr/bin/env bash
# Backing up and restoring ACLs independently of file content
set -euo pipefail

readonly TARGET="/var/www/shared-uploads"
readonly ACL_DUMP="/var/backups/acl/shared-uploads.acl"

# tar preserves ACLs only with --acls, cp only with --preserve=all
tar --acls -czf /var/backups/shared-uploads.tar.gz "$TARGET"
cp -a --preserve=all "$TARGET" /mnt/backup/shared-uploads

# Dedicated ACL snapshot, independent of file content
mkdir -p "$(dirname "$ACL_DUMP")"
getfacl -R "$TARGET" > "$ACL_DUMP"

# Restore ACLs on a rebuilt directory tree after migration
setfacl --restore="$ACL_DUMP"

echo "[OK] ACL snapshot restored from ${ACL_DUMP}"

8. File system requirements and mount options

ACLs are not a pure userland feature; they must be supported and enabled by the file system itself. On current ext4 and XFS installations, ACL support is enabled by default nowadays, with no explicit mount option required. On older systems or manually written /etc/fstab entries, however, the option can be missing, causing setfacl to fail with the error Operation not supported. In that case, acl must be explicitly added as a mount option and the partition remounted.

Before any production use, it is worth a quick check with tune2fs -l /dev/sdX | grep "Default mount options" on ext file systems to see whether acl is already anchored as a default option in the superblock. If it is missing, it can be set permanently with tune2fs -o acl /dev/sdX, without any changes to /etc/fstab at all. Network file systems like NFS additionally require matching NFSv4 ACL support on both server and client side, which differs from the POSIX ACLs described here in the details but follows the same underlying concept.


# /etc/fstab: ensure ACL support is enabled on the mount
# Modern ext4/XFS defaults already include acl, but older
# or manually written entries may need it explicit.

# UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /var/www ext4 defaults,acl 0 2
/dev/sdb1   /var/www   ext4   defaults,acl   0   2

# Remount without a reboot after editing fstab:
# mount -o remount /var/www

# Persist acl as a default mount option in the ext4 superblock
# tune2fs -o acl /dev/sdb1

9. ACLs compared to chmod and chown

Choosing between classic permissions and ACLs is not an either-or decision, but a question of the right tool for the specific use case. The table below lines up typical situations against the more sensible solution for each.

Situation Wrong / risky Recommended solution Why
Two teams need different rights Add user to a foreign group setfacl -m u:name:rwx path Access stays scoped to the path
Monitoring reads foreign logs chmod o+r /var/log/service setfacl -m u:monitoring:r-x Not world-readable for every process
New files should inherit rights Manual chmod after every upload setfacl -d -m u:name:rwx directory Automatic inheritance, no manual step
Simple owner/group setup ACLs over-engineered for a trivial case chmod 750 plus chown Simpler, more transparent, less error-prone
Backup after migration tar czf without --acls tar --acls or a getfacl -R dump ACL entries otherwise silently vanish

As a rule of thumb: chmod and chown remain the first choice for simple, clearly delineated ownership relationships. As soon as more than one group needs different rights on the same path at the same time, or as soon as future files should automatically inherit certain rights, ACLs are the more precise and safer tool, because they uphold the principle of least privilege without disturbing existing ownership structures.

Mironsoft

Server hardening, deployment automation, and Magento hosting operations

Access control that goes beyond chmod?

We analyze shared directories and deploy workflows, set up precise ACLs with default inheritance, and document them so they survive every restore and every migration.

Access audit

Full review of ownership, groups, and existing ACL entries

ACL design

Setting up targeted setfacl entries and default ACLs for shared directories

Backup integration

Anchoring tar --acls and getfacl snapshots firmly in backup and deploy pipelines

10. Summary

ACLs extend the classic chmod model exactly where a single owner and a single group are not enough. getfacl reads existing entries, already recognizable from the appended + in ls -l. setfacl -m sets new entries for users and groups, setfacl -x removes individual entries in a targeted way, setfacl -b clears everything. A deploy user thereby gains write access to a foreign directory managed by a service account, without ownership or the primary group ever needing to be touched.

Default ACLs set with setfacl -d ensure these rights are automatically inherited by newly created files and subdirectories, comparable to the setgid bit but with full control over arbitrary users. The ACL mask caps effective rights and deserves special attention after a later chmod. Backup tools must save ACLs explicitly with --acls or via a getfacl dump, or they silently vanish at restore time. For simple cases chmod remains the right choice, while for shared directories with multiple access levels ACLs are the more precise tool.

ACLs: Extended Permissions Beyond chmod, the Essentials at a Glance

The core problem

chmod only knows one owner and one group. ACLs add an arbitrary number of extra user and group entries per file.

setfacl & getfacl

setfacl -m u:name:rwx sets, -x removes individually, -b clears everything. getfacl shows the current state.

Default ACLs

setfacl -d -m automatically inherits rights to newly created files and subdirectories.

Backup & mask

tar --acls and getfacl -R dumps back up ACLs. The mask caps effective rights after chmod.

11. FAQ: ACLs and Extended Permissions

1Why is chmod not always enough?
chmod only knows one owner and one group. As soon as multiple groups need different rights, the classic model falls short.
2How do I recognize ACL entries?
An appended plus in ls -l indicates ACL entries. Details always come from getfacl file.
3Access for one user, without changing the group?
setfacl -m u:username:rwx path grants targeted access, owner and group stay unchanged.
4How do I remove an entry?
setfacl -x u:name path removes it individually. setfacl -b path removes all extended entries.
5What are default ACLs?
Set with setfacl -d, they automatically inherit rights to newly created files and subdirectories.
6What is the ACL mask?
It caps the effective rights of all named entries. A later chmod rewrites the mask and can restrict rights.
7Do ACLs get lost in a backup?
Yes, without tar --acls or cp --preserve=all they are silently discarded.
8How do I restore ACLs?
A getfacl -R dump can be fully restored with setfacl --restore=file.
9Does the file system need to support ACLs?
Current ext4/XFS support ACLs by default. Older systems need the acl mount option explicitly.
10Should I use ACLs everywhere?
No, for simple cases chmod remains the more transparent solution. ACLs pay off for shared directories with multiple groups.