How to Enable and Configure SELinux Policy Modules for Custom Applications

SELinux policy modules for custom applications

Learn how to enable, write, and configure SELinux policy modules for custom applications. Includes step-by-step instructions, file context management, CLI examples, and best practices for secure deployments.

Table of Contents

🔈Introduction

Security-Enhanced Linux (SELinux) is one of the most robust mandatory access control (MAC) frameworks available in modern Linux distributions. It enforces strict boundaries between processes, files, and system resources—significantly reducing the risk of privilege escalation and unauthorized access.

However, organizations often deploy custom applications that require unique permissions not covered by default SELinux policies. The good news: SELinux provides a flexible system for writing, enabling, and configuring policy modules tailored to your custom workloads.

This guide walks you through everything you need to know about creating, enabling, and managing SELinux policy modules for custom applications—whether you’re securing an enterprise stack or a homegrown microservice. You’ll find step-by-step instructions, tables for quick reference, and practical CLI examples you can apply immediately.


✅ Why SELinux Matters for Custom Applications

SELinux enforces “least privilege” for every process on the system. But custom applications—especially in-house tools or containerized workloads—often behave differently from standard packages. Without proper SELinux rules, these workloads may:

  • ✅ Fail to read configuration files
  • ✅ Be blocked from binding to network ports
  • ✅ Lose access to logs, sockets, or shared memory
  • ✅ Trigger frequent denial messages in /var/log/audit/audit.log

Configuring policy modules is the cleanest way to address these issues while maintaining a secure posture. Unlike simply switching SELinux to permissive mode or setting file contexts manually, custom modules:

  • ✅ Maintain policy consistency across reboots
  • ✅ Can be version-controlled and audited
  • ✅ Allow fine-grained permission assignments
  • ✅ Avoid broad or dangerous exceptions

🧠 Understanding SELinux Policy Modules

Policy modules are packaged sets of SELinux rules that extend or modify the base system policy. They include:

ComponentDescription
.te fileType Enforcement rules (core logic of what’s allowed)
.fc fileFile context specifications for directories and files
.if fileOptional interfaces for reusable rules
.mod fileCompiled module used before final packaging
.pp fileBinary policy package that SELinux installs

Most administrators interact only with .te and .pp files. A typical workflow looks like this:

Capture audit denials -> Create or modify a .te policy file -> Compile the module -> Package it into a .pp file -> Install and enable the module -> Test and refine

SELinux policy modules for custom applications

Photo by admingeek from Infotechys


📋Prerequisites

Before beginning, ensure the following tools are installed:

				
					sudo dnf install policycoreutils policycoreutils-python-utils selinux-policy-devel -y
				
			
				
					# or on Debian-based:
sudo apt install policycoreutils selinux-basics selinux-policy-dev -y
				
			

Confirm SELinux is in enforcing or permissive mode:

				
					getenforce
				
			

If it reports Disabled, enable SELinux first by editing /etc/selinux/config.


🔁 Step 1: Identify SELinux Denials

Your first step in designing a policy module is identifying what SELinux is blocking.

▶️ Check audit logs

				
					sudo ausearch -m avc -ts recent
				
			

Or read directly:

				
					sudo less /var/log/audit/audit.log
				
			

You’ll find entries resembling:

				
					avc:  denied  { read } for pid=2412 comm="myapp" name="config.yaml" dev="sda1" ino=12345 scontext=system_u:system_r:myapp_t:s0 tcontext=unconfined_u:object_r:etc_t:s0 tclass=file
				
			

▶️ Use sealert for human-friendly diagnostics

				
					sudo sealert -a /var/log/audit/audit.log
				
			

This tool often provides suggestions for file contexts or policy rules.


🔁 Step 2: Use audit2allow to Generate a Base Policy

audit2allow can take audit denials and convert them into policy rule suggestions.

▶️ Generate a policy template

				
					sudo audit2allow -M myapp < /var/log/audit/audit.log
				
			

This generates:

  • myapp.te
  • myapp.mod
  • myapp.pp

Review the .te file carefully. For example:

				
					cat myapp.te
				
			

Example output:

				
					module myapp 1.0;

require {
    type etc_t;
    type myapp_t;
    class file read;
}

#============= myapp_t ==============
allow myapp_t etc_t:file read;
				
			
💡Important note: Never blindly install policy modules. Ensure rules are specific and minimal.

🔁 Step 3: Install the Policy Module

Once you’ve validated the .te file:

				
					sudo semodule -i myapp.pp
				
			

Confirm installation:

				
					sudo semodule -l | grep myapp
				
			

Now restart or test your application to confirm expected behavior.


🔁 Step 4: Create a Policy Module Manually (Optional but Recommended)

While audit2allow is useful, writing your own .te file gives you more control and prevents over-permissive rules.

▶️ Example: Creating a minimal custom policy

Create a file named myapp.te:

				
					module myapp 1.1;

require {
    type myapp_t;
    type var_log_t;
    class file { read write append };
}

# Allow custom app to write to its log directory
allow myapp_t var_log_t:file { read write append };
				
			

▶️ Compile and build

				
					checkmodule -M -m -o myapp.mod myapp.te
				
			
				
					semodule_package -o myapp.pp -m myapp.mod
				
			
				
					sudo semodule -i myapp.pp
				
			

🔁 Step 5: Configure File Contexts for Custom Application Files

SELinux must correctly label application files and directories. Without proper labeling, even correctly written policy modules won’t work.

▶️ View current contexts

				
					ls -Z /opt/myapp
				
			

▶️ Assign a new context

Example: Your app stores configs in /opt/myapp/config. Add a persistent rule:

				
					sudo semanage fcontext -a -t myapp_etc_t "/opt/myapp/config(/.*)?"
				
			

Apply the new labels:

				
					sudo restorecon -Rv /opt/myapp/config
				
			

▶️ File context quick reference table

GoalSELinux ToolExample
Add a new labelsemanage fcontext -aAdd custom type to config dir
Modify existing labelsemanage fcontext -mChange label for logs
Remove rulesemanage fcontext -dDelete custom context rule
Apply labelsrestorecon -RRestore contexts recursively

🔁 Step 6: Assign the Application to Its SELinux Domain

For SELinux to apply your rules, the application’s process must run under the correct domain (type).

There are three common ways to do this:

▶️ Using systemd service files

Add this to your service unit:

				
					[Service]
SELinuxContext=system_u:system_r:myapp_t:s0
				
			

Reload systemd:

				
					sudo systemctl daemon-reload
				
			
				
					sudo systemctl restart myapp
				
			

▶️ Using file transitions

A transition rule automatically labels the process when it starts. Example .te addition:

				
					type_transition init_t myapp_exec_t:process myapp_t;
				
			

▶️ Using runcon (for testing)

				
					runcon system_u:system_r:myapp_t:s0 /opt/myapp/bin/myapp
				
			

🔁 Step 7: Test, Audit, and Iterate

After deploying the module:

▶️ Check for new denials

				
					sudo ausearch -m avc -ts recent
				
			

If new issues appear, refine your .te file accordingly.

▶️ Disable a module temporarily

				
					sudo semodule -d myapp
				
			

▶️ Remove it entirely

				
					sudo semodule -r myapp
				
			

▶️ Keep modules in version control

Place .te and .fc files in a Git repository to maintain a secure and auditable development lifecycle.


🧰 Troubleshooting Common Issues

🔧 Issue 1: Policies seem correct but the app still fails

Run:

				
					sudo restorecon -R /opt/myapp
				
			

Mislabelled files cause most SELinux issues.

🔧 Issue 2: System logs flood with denials

Confirm correct domain:

				
					ps -eZ | grep myapp
				
			

🔧 Issue 3: Permissive mode hides misconfigurations

Ensure SELinux is enforcing:

				
					sudo setenforce 1
				
			

🔥Best Practices for SELinux Policy Modules

To keep your SELinux policy environment clean and secure:

✅ Do

  • Limit rules to the smallest required set

  • Use domain separation for each application

  • Keep .te files under version control

  • Regularly audit the policy with seinfo and sesearch

  • Write clear comments in policy files

❌ Don’t

  • Use unconfined_t for production applications

  • Apply wildcard rules that allow broad access

  • Ignore audit logs

  • Mix unrelated permissions into a single module


🖥️ Example: Complete Custom SELinux Policy Setup

Below is a full example for a hypothetical application named myapp that needs to:

  • Read /opt/myapp/config.yaml

  • Write myapp.log in /var/log/myapp/

  • Bind to TCP port 8080

✅ Create file contexts

				
					sudo semanage fcontext -a -t myapp_etc_t "/opt/myapp/config.yaml"
				
			
				
					sudo semanage fcontext -a -t myapp_log_t "/var/log/myapp(/.*)?"
				
			
				
					restorecon -Rv /opt/myapp /var/log/myapp
				
			

✅ Create policy file

myapp.te:

				
					module myapp 1.2;

require {
    type myapp_t;
    type myapp_etc_t;
    type myapp_log_t;
    class file { read write append open };
    class tcp_socket name_bind;
}

allow myapp_t myapp_etc_t:file { read open };
allow myapp_t myapp_log_t:file { write append open };
allow myapp_t self:tcp_socket name_bind;
				
			

✅ Compile and install

				
					checkmodule -M -m -o myapp.mod myapp.te
				
			
				
					semodule_package -o myapp.pp -m myapp.mod
				
			
				
					sudo semodule -i myapp.pp
				
			

✅ Test and validate

				
					sudo ausearch -m avc -ts recent
				
			

If the logs show no denials, your policy module is ready for production.


🏁 Conclusion

Configuring SELinux policy modules for custom applications is one of the most effective ways to balance tight security with operational flexibility. By understanding how to analyze denials, write .te rules, manage file contexts, and deploy modules, you can ensure each application runs safely within its own controlled domain.

With proper structure, testing, and version control, SELinux becomes not a barrier—but a powerful guardian of both system integrity and application stability.

Did you find this article helpful? Your feedback is invaluable to us! Feel free to share this post with those who may benefit, and let us know your thoughts in the comments section below.


📕 Related Posts