SELinux

Introduction

BeeGFS supports full SELinux labeling and enforcement. This allows administrators to apply SELinux access controls to files stored on BeeGFS just like with local filesystems such as ext4 or XFS.

Key concepts:

  • SELinux support is built into BeeGFS: if the system policy includes a fs_use_xattr rule for BeeGFS, SELinux can store and enforce file labels directly on BeeGFS inodes.

  • Default labels: When you first mount a BeeGFS filesystem, files and directories may appear with the unlabeled_t type until you configure SELinux contexts.

  • Persistent labeling: Once you configure fcontext rules, labels are persistent across reboots and new files inherit the correct context.

Important

BeeGFS is only responsible for storing and retrieving SELinux labels. As with all file systems, checking and enforcing SELinux policies based on those labels is done entirely by the kernel Linux Security Module (LSM). All machines that mount BeeGFS must have SELinux configured consistently to ensure uniform enforcement.

Getting Started

Note

Setting up SELinux on BeeGFS servers is outside the scope of this guide and not typically recommended for performance reasons. For a file system like BeeGFS, the ability to configure/use SELinux is typically only important for client machines that need to mount the file system.

BeeGFS Server Configuration

SELinux labels are stored in a special security.selinux extended attribute for each entry. This means all BeeGFS Metadata nodes must be configured to store client extended attributes. In the configuration file (by default at /etc/beegfs/beegfs-meta.conf) for all metadata nodes set:

storeClientXAttrs = true

BeeGFS Client Configuration

Verify SELinux Configuration

On each BeeGFS client, SELinux must be enabled and in enforcing or permissive mode:

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33

To use SELinux with BeeGFS your base SELinux policy must include an fs_use_xattr rule telling SELinux that BeeGFS uses extended attributes (xattrs) to store per-file contexts. First check if your SELinux policy already enables support for BeeGFS:

seinfo --fs_use | grep beegfs
    fs_use_xattr beegfs system_u:object_r:fs_t:s0;

While BeeGFS is being added to the upstream selinux-policy package, it may take time for your Linux distribution to pickup a version that includes BeeGFS. If your base SELinux policy does not yet include the rule fs_use_xattr beegfs gen_context(system_u:object_r:fs_t,s0); it must be manually added to filesystem.te.

Important

If BeeGFS is already mounted, please unmount it before rebuild your selinux-policy with support for BeeGFS. Failure to do so may result in the system hanging as the policy status of an already mounted file system changes.

Here is one example of a script that handles rebuilding the selinux-policy RPM from your distribution’s SRPM until an updated package is available for your distribution. Modify the script as needed for the base SELinux policy in use in your environment:

#!/usr/bin/bash
set -euo pipefail

RELEASE_TAG="${RELEASE_TAG:-thinkparq1}"

echo "[+] Installing minimal build tooling..."
sudo dnf -y install rpm-build rpmdevtools dnf-plugins-core

echo "[+] Ensuring selinux-policy build dependencies are present..."
sudo dnf -y builddep selinux-policy

echo "[+] Preparing rpmbuild tree..."
rpmdev-setuptree

echo "[+] Downloading the matching selinux-policy SRPM..."
dnf download --source selinux-policy

echo "[+] Installing SRPM into ~/rpmbuild..."
rpm -ivh selinux-policy-*.src.rpm

SPECDIR=~/rpmbuild/SPECS
SRCDIR=~/rpmbuild/SOURCES

# find the single source tarball
pushd "$SRCDIR" >/dev/null
TARBALL=$(ls -1 selinux-policy-*.tar.* | head -n1)

echo "[+] Unpacking source: $TARBALL"
tar xf "$TARBALL"

SRCTOP=$(ls -d selinux-policy-* | head -n1)

FILES_TE="$SRCTOP/policy/modules/kernel/filesystem.te"

echo "[+] Patching filesystem.te to add BeeGFS fs_use_xattr (idempotent)..."
# Insert our line if it's not already present.
if ! grep -qE '^\s*fs_use_xattr\s+beegfs\b' "$FILES_TE"; then
# Just insert BeeGFS at the end of filesystem.te to avoid using sed.
echo 'fs_use_xattr beegfs gen_context(system_u:object_r:fs_t,s0);' >> "$FILES_TE"
else
echo "    - BeeGFS fs_use_xattr already present; skipping insertion."
fi

echo "[+] Repacking sources (keeping original tarball name so spec does not change)..."
rm -f "$TARBALL"
tar czf "$TARBALL" "$SRCTOP"

popd >/dev/null

SPEC="$SPECDIR/selinux-policy.spec"

echo "[+] Bumping RPM Release with .$RELEASE_TAG (idempotent)..."
# Append tag only if not already present
if ! grep -q "$RELEASE_TAG" "$SPEC"; then
sed -i "s/^Release:\s*\([0-9][^ ]*\)/Release: \1.$RELEASE_TAG/" "$SPEC"
else
echo "    - Release already contains $RELEASE_TAG; leaving as-is."
fi

echo "[+] Building selinux-policy RPMs..."
rpmbuild -ba "$SPEC"

echo "[+] Installing rebuilt policy RPMs..."
# Install only base and targeted policy RPMs we just built.
# This should also rebuild the policy store so fs_use_xattr will be available for BeeGFS.
sudo dnf -y install --allowerasing \
~/rpmbuild/RPMS/noarch/selinux-policy-[0-9]*.$RELEASE_TAG.noarch.rpm \
~/rpmbuild/RPMS/noarch/selinux-policy-targeted-[0-9]*.$RELEASE_TAG.noarch.rpm

# Optional: verify with seinfo if available
if command -v seinfo >/dev/null 2>&1; then
echo "[+] Verifying fs_use rule..."
seinfo --fs_use | grep -i beegfs || echo "WARN: fs_use_xattr for beegfs not visible via seinfo (you could try running 'sudo semodule -B')"
else
echo "[i] setools-console (seinfo) not installed; skipping pretty verification."
fi

echo "[✓] Done. If BeeGFS is already mounted it must be unmounted then remounted."
echo "    After remounting BeeGFS verify the mount options include 'seclabel' in /proc/mounts."
echo "    If seclabel is not included after a remount you may also need to reboot.."

At this point you probably want to “pin” or otherwise protect the custom selinux-policy so DNF won’t silently replace it in the future with a newer stock version. One approach is to “lock” the version with dnf version lock which will ignore the packages for all future upgrades:

$ dnf -y install python3-dnf-plugins-extras-versionlock
$ dnf versionlock add selinux-policy selinux-policy-targeted
$ dnf versionlock list
Last metadata expiration check: 0:45:03 ago on Thu 21 Aug 2025 12:03:11 PM CDT.
selinux-policy-0:40.13.26-1.el10.thinkparq1.*
selinux-policy-targeted-0:40.13.26-1.el10.thinkparq1.*

The lock can later be removed with dnf versionlock delete selinux-policy selinux-policy-targeted, for example if you want to build/install an updated version, or once you move to a distribution release where BeeGFS is supported upstream.

If for any reason you need to rollback to the stock policy use dnf downgrade -y selinux-policy selinux-policy-targeted --allowerasing.

Configure and Mount BeeGFS

If your SELinux policy includes BeeGFS (see above) you will be unable to mount BeeGFS by default:

Aug 19 15:47:34 client01 kernel: SELinux: (dev beegfs, type beegfs) has no security xattr handler

You must explicitly enable SELinux support in your BeeGFS client configuration file (by default at /etc/beegfs/beegfs-client.conf) by specifying:

sysSELinuxEnabled = true

Note

You do not also need to set sysXAttrsEnabled=true as this will be automatically enabled when SELinux support is enabled in the client configuration. This means in addition to the protected SELinux security.selinux attribute, other user defined attributes can be set on entries.

Since BeeGFS is a shared file system that can be mounted by multiple clients, it is important to ensure label changes made by one client are quickly propagated to all clients. However because the kernel often requests extended attributes like security.selinux multiple times in quick succession, briefly caching these labels improves performance of common file system operations.

How often the BeeGFS client revalidates SELinux labels with BeeGFS metadata nodes is configurable using the client sysSELinuxRevalidate configuration option:

  • The default cache mode means labels are valid for at most tuneDirSubentryCacheValidityMS (default: 1s), or tuneFileSubentryCacheValidityMS (default 0s).

  • The optional always mode means clients never cache labels and always retrieve the latest labels from the metadata node.

In environments where SELinux labels change infrequently and it is acceptable that label updates can take up to 1 second to be updated on all clients, the default settings provide a good balance between performance and security/correctness. Adjust these settings as needed for your environment. If you wish to adjust the tune*SubentryCacheValidityMS parameters refer to their full descriptions in /etc/beegfs/beegfs-client.conf as these affect more than SELinux label caching.

Once you have updated the client configuration, proceed to mount BeeGFS as you would normally.

Labeling BeeGFS

By default when you first mount BeeGFS all existing entries will typically show as unlabeled_t in ls -lZ /mnt/beegfs. At this point you can configure labeling according to your requirements. Here are some examples of how you might label files and directories inside BeeGFS.

Context fields in SELinux are defined as user:role:type:level. The first field (system_u vs unconfined_u) depends on SELinux user mappings (see semanage login -l). For file systems, the type field (*_t) is typically the most relevant for policy enforcement.

If you just run restorecon -Rv /mnt/beegfs then you should see:

$ restorecon -Rv /mnt/beegfs
Relabeled /mnt/beegfs from system_u:object_r:unlabeled_t:s0 to system_u:object_r:mnt_t:s0

This will not relabel existing files, but any new files/directories will inherit the mnt_t label.

$ mkdir /mnt/beegfs/scratch
$ touch /mnt/beegfs/scratch/a
$ ls -lZ /mnt/beegfs/scratch/
total 0
-rw-r--r--. 1 joe joe unconfined_u:object_r:mnt_t:s0 0 Aug 21 12:22 a

File context rules for the entire file system or specific directories can be created with semanage fcontext:

$ semanage fcontext -a -t var_t "/mnt/beegfs/scratch(/.*)?"
$ semanage fcontext -l | grep -i beegfs
/mnt/beegfs/scratch(/.*)?          all files          system_u:object_r:var_t:s0

This will not immediately relabel existing directories/files until you use restorecon. Here the recurse (-R) and force reset (-F) flags are used to apply the rule to all existing files under the scratch/ directory even if they have a different label:

$ restorecon -RFv /mnt/beegfs/scratch
Relabeled /mnt/beegfs/scratch from unconfined_u:object_r:mnt_t:s0 to system_u:object_r:var_t:s0
Relabeled /mnt/beegfs/scratch/a from unconfined_u:object_r:mnt_t:s0 to system_u:object_r:var_t:s0

$ ls -lZ /mnt/beegfs/scratch/
total 0
-rw-r--r--. 1 root root system_u:object_r:var_t:s0 0 Aug 21 12:22 a

Now scratch/ and all existing files in that directory are labeled var_t. New files and directories in this directory will also inherit the label automatically:

$ touch /mnt/beegfs/scratch/b
$ ls -lZ /mnt/beegfs/scratch/
total 0
-rw-r--r--. 1 root root system_u:object_r:var_t:s0     0 Aug 21 12:22 a
-rw-r--r--. 1 root root unconfined_u:object_r:var_t:s0 0 Aug 21 12:23 b

Note

This is a vanilla Rocky 10 installation with minimal SELinux configuration so it is expected the SELinux portion of the label shows unconfined_u. This would switch to system_u the next time restorecon is executed. Refer to semanage login -l to map logins to SELinux users.

BeeGFS also supports labeling using chcon or setfattr and fetching labels with getfattr:

$ chcon -t public_content_t /mnt/beegfs/scratch/a
$ setfattr -n security.selinux -v 'system_u:object_r:public_content_t:s0' /mnt/beegfs/scratch/b
$ getfattr -n security.selinux /mnt/beegfs/scratch/*
getfattr: Removing leading '/' from absolute path names
# file: mnt/beegfs/scratch/a
security.selinux="system_u:object_r:public_content_t:s0"

# file: mnt/beegfs/scratch/b
security.selinux="system_u:object_r:public_content_t:s0"

The next time restorecon is executed it will correct the labels based on the defined context mappings:

$ sudo restorecon -RF /mnt/beegfs/scratch
$ ls -lZ /mnt/beegfs/scratch/
total 0
-rw-r--r--. 1 root root system_u:object_r:var_t:s0 0 Aug 21 12:22 a
-rw-r--r--. 1 root root system_u:object_r:var_t:s0 0 Aug 21 12:23 b

SELinux enforcement can be tested by “accidentally” configuring an HTTP server to serve scratch:

dnf -y install httpd
systemctl enable --now httpd
ln -sf /mnt/beegfs/scratch /var/www/html/root

Trying to access the HTTP server should result in an 403 HTTP error due to an SELinux denial:

$ curl -s -o /dev/null -w "%{http_code}\n" http://localhost/
403
$ sudo ausearch -m avc -ts recent | tac | awk '/^----/{exit} {print}' | tac
[...]
time->Thu Aug 21 13:02:22 2025
type=PROCTITLE msg=audit(1755799342.895:912): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
type=SYSCALL msg=audit(1755799342.895:912): arch=c00000b7 syscall=79 success=no exit=-13 a0=ffffffffffffff9c a1=ffff7400f990 a2=ffff7fffe158 a3=0 items=0 ppid=8558 pid=8560 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1755799342.895:912): avc:  denied  { getattr } for  pid=8560 comm="httpd" path="/mnt/beegfs/scratch/index.html" dev="beegfs" ino=12685084967277094189 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file permissive=0

If we did want to allow this directory to be served over HTTP we can change the context:

$ semanage fcontext -a -t httpd_sys_content_t "/mnt/beegfs(/.*)?"
$ restorecon -RFv /mnt/beegfs/scratch
$ curl -s -o /dev/null -w "%{http_code}\n" http://localhost/
200

This shows that SELinux policies apply transparently to BeeGFS content, preventing accidental data exposure unless explicitly relabeled.