Set up SELinux on Ubuntu and Debian systems, configure security modes and policies, create custom application rules, and implement comprehensive monitoring for enhanced Linux security hardening.
Prerequisites
- Root or sudo access
- Basic understanding of Linux file permissions
- Familiarity with systemd services
What this solves
SELinux (Security-Enhanced Linux) provides mandatory access controls that enforce security policies at the kernel level, preventing unauthorized access even from compromised applications. This tutorial covers installing SELinux on Ubuntu and Debian systems, configuring security modes, creating custom policies for applications, and monitoring policy violations for comprehensive system hardening.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest security updates and package versions.
sudo apt update && sudo apt upgrade -y
Install SELinux packages
Install the core SELinux packages along with policy management tools and utilities for configuration and monitoring.
sudo apt install -y selinux-basics selinux-policy-default auditd policycoreutils-python-utils setools-console
Configure SELinux activation
On Ubuntu and Debian systems, SELinux needs to be explicitly activated. Configure the system to enable SELinux on next boot.
sudo selinux-activate
sudo selinux-config-enforcing
Configure SELinux main configuration
Set the SELinux configuration file to define the default policy and enforcement mode. The targeted policy provides good security without being overly restrictive.
# This file controls the state of SELinux on the system.
SELINUX= can take one of these three values:
enforcing - SELinux security policy is enforced.
permissive - SELinux prints warnings instead of enforcing.
disabled - No SELinux policy is loaded.
SELINUX=enforcing
SELINUXTYPE= can take one of these values:
targeted - Targeted processes are protected,
minimum - Modification of targeted policy. Only selected processes are protected.
mls - Multi Level Security protection.
SELINUXtype=targeted
Enable audit daemon
The audit daemon logs SELinux events and policy violations, which is essential for monitoring and troubleshooting.
sudo systemctl enable auditd
sudo systemctl start auditd
Reboot and verify SELinux status
SELinux requires a system reboot to initialize properly. After rebooting, verify the installation and current status.
sudo reboot
After the system reboots, check SELinux status:
sestatus
getenforce
Configure SELinux modes and policies
Understanding SELinux modes
SELinux operates in three modes: enforcing (blocks violations), permissive (logs violations), and disabled. Start with permissive mode to identify potential issues.
sudo setenforce 0
getenforce
Configure web server policies
Enable SELinux boolean settings for common web server operations. These settings allow HTTP services to function properly under SELinux.
sudo setsebool -P httpd_can_network_connect 1
sudo setsebool -P httpd_can_network_connect_db 1
sudo setsebool -P httpd_execmem 1
sudo setsebool -P httpd_unified 1
Configure SSH service policies
Allow SSH to use non-standard ports and enable key-based authentication features under SELinux.
sudo setsebool -P ssh_sysadm_login 1
sudo semanage port -a -t ssh_port_t -p tcp 2222
Set file contexts for web directories
Configure proper SELinux contexts for web server directories to ensure applications can read and write files as needed.
sudo semanage fcontext -a -t httpd_exec_t "/var/www/html(/.)?"\nusudo semanage fcontext -a -t httpd_log_t "/var/log/nginx(/.)?"\nsudo restorecon -R /var/www/html
sudo restorecon -R /var/log/nginx
Create custom SELinux policies for applications
Generate policy module from audit logs
Use audit2allow to create custom policy modules based on actual application behavior recorded in audit logs.
sudo grep nginx /var/log/audit/audit.log | audit2allow -m nginx_custom
sudo grep nginx /var/log/audit/audit.log | audit2allow -M nginx_custom
Create custom application policy
Create a Type Enforcement (.te) file for a custom application that needs specific permissions.
policy_module(myapp, 1.0)
type myapp_t;
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t)
type myapp_log_t;
logging_log_file(myapp_log_t)
type myapp_config_t;
files_config_file(myapp_config_t)
Allow myapp to read its configuration
allow myapp_t myapp_config_t:file { read getattr open };
Allow myapp to write to its log files
allow myapp_t myapp_log_t:file { create write append getattr setattr };
allow myapp_t myapp_log_t:dir { add_name write };
Allow network access
corenet_tcp_bind_generic_node(myapp_t)
corenet_tcp_bind_http_port(myapp_t)
Compile and install custom policy
Compile the Type Enforcement file into a policy module and install it into the SELinux policy store.
cd /tmp
sudo checkmodule -M -m -o myapp.mod myapp.te
sudo semodule_package -o myapp.pp -m myapp.mod
sudo semodule -i myapp.pp
Set file contexts for custom application
Define and apply SELinux contexts for your custom application files, logs, and configuration directories.
sudo semanage fcontext -a -t myapp_exec_t "/usr/local/bin/myapp"
sudo semanage fcontext -a -t myapp_config_t "/etc/myapp(/.)?"\nsudo semanage fcontext -a -t myapp_log_t "/var/log/myapp(/.)?"\nsudo restorecon -R /usr/local/bin/myapp
sudo restorecon -R /etc/myapp
sudo restorecon -R /var/log/myapp
Monitor and troubleshoot SELinux denials
Configure audit log monitoring
Set up automatic monitoring of SELinux denials using audit daemon and log rotation for ongoing security monitoring.
# Monitor SELinux denials and policy changes
-w /etc/selinux/ -p wa -k selinux_policy
-w /usr/sbin/setenforce -p x -k selinux_enforce
-a always,exit -F arch=b64 -S execve -F key=selinux_exec
Create SELinux monitoring script
Create a script to parse audit logs and identify SELinux denials with actionable recommendations.
#!/bin/bash
SELinux Denial Monitor Script
LOGFILE="/var/log/audit/audit.log"
OUTPUT_FILE="/var/log/selinux-denials.log"
echo "SELinux Denial Report - $(date)" > $OUTPUT_FILE
echo "=========================================" >> $OUTPUT_FILE
Extract recent denials
ausearch -m avc -ts recent 2>/dev/null | audit2allow -a >> $OUTPUT_FILE 2>/dev/null
Count denials by type
echo "\nDenial Summary:" >> $OUTPUT_FILE
grep "type=AVC" $LOGFILE | awk '{for(i=1;i<=NF;i++) if($i~/scontext/) print $i}' | sort | uniq -c | sort -nr >> $OUTPUT_FILE
Email report if denials found
if [ -s $OUTPUT_FILE ]; then
echo "SELinux denials detected. Check $OUTPUT_FILE for details."
# mail -s "SELinux Denial Report" admin@example.com < $OUTPUT_FILE
fi
sudo chmod +x /usr/local/bin/selinux-monitor.sh
Set up automated monitoring with cron
Schedule regular SELinux monitoring and create a systemd service for continuous monitoring.
echo "0 /6 /usr/local/bin/selinux-monitor.sh" | sudo crontab -
Configure SELinux troubleshooting tools
Install and configure additional tools for SELinux analysis and troubleshooting common policy issues.
sudo apt install -y setroubleshoot-server python3-audit
Enable enforcing mode
After testing and resolving policy issues in permissive mode, enable enforcing mode for full security protection.
sudo setenforce 1
echo 'SELINUX=enforcing' | sudo tee /etc/selinux/config
Verify your setup
sestatus -v
getenforce
sudo semodule -l | head -10
ps auxZ | grep -E "(httpd|nginx|ssh)" | head -5
sudo ausearch -m avc -ts recent
The output should show SELinux as enabled and enforcing, with loaded policy modules and running processes showing proper security contexts. If you see any recent AVC denials, investigate them using the monitoring tools configured above.
For ongoing integration with your security infrastructure, consider connecting to OSSEC intrusion detection systems or setting up comprehensive CIS benchmark compliance across your infrastructure.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Web server returns 403 errors | Incorrect file contexts | sudo restorecon -R /var/www and check contexts with ls -Z |
| Application cannot write logs | Missing write permissions in policy | Use audit2allow to generate policy from denials |
| SSH connection refused | SELinux blocking non-standard port | sudo semanage port -a -t ssh_port_t -p tcp PORT |
| Database connection fails | Missing network connect boolean | sudo setsebool -P httpd_can_network_connect_db 1 |
| Custom application crashes | Missing domain transitions | Create proper .te policy with domain_entry_file rules |
| Policy module load fails | Syntax errors in .te file | Check with checkmodule and review audit logs |
Next steps
- Configure SSH key authentication and security hardening
- Implement container security with AppArmor and seccomp profiles
- Configure SELinux policies for containerized applications
- Integrate SELinux with centralized logging systems
- Implement SELinux policy testing and validation workflows
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration variables
SELINUX_MODE="${1:-enforcing}"
TOTAL_STEPS=8
# Usage message
usage() {
echo "Usage: $0 [enforcing|permissive]"
echo " enforcing - SELinux blocks violations (default)"
echo " permissive - SELinux logs violations without blocking"
exit 1
}
# Validate arguments
if [[ "$SELINUX_MODE" != "enforcing" && "$SELINUX_MODE" != "permissive" ]]; then
usage
fi
# Cleanup function
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Check logs above for details.${NC}" >&2
exit 1
}
# Set trap for cleanup on error
trap cleanup ERR
# Helper functions
log_info() {
echo -e "${BLUE}$1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}$1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}" >&2
}
# Check if running as root or with sudo
check_privileges() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
}
# Auto-detect distribution
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_UPGRADE="apt upgrade -y"
PKG_INSTALL="apt install -y"
SELINUX_PACKAGES="selinux-basics selinux-policy-default auditd policycoreutils-python-utils setools-console"
NEEDS_ACTIVATION=true
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf check-update || true"
PKG_UPGRADE="dnf update -y"
PKG_INSTALL="dnf install -y"
SELINUX_PACKAGES="selinux-policy selinux-policy-targeted policycoreutils-python-utils setools-console audit"
NEEDS_ACTIVATION=false
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum check-update || true"
PKG_UPGRADE="yum update -y"
PKG_INSTALL="yum install -y"
SELINUX_PACKAGES="selinux-policy selinux-policy-targeted policycoreutils-python-utils setools-console audit"
NEEDS_ACTIVATION=false
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution. /etc/os-release not found."
exit 1
fi
}
# Update system packages
update_system() {
log_info "[1/$TOTAL_STEPS] Updating system packages..."
$PKG_UPDATE
$PKG_UPGRADE
log_success "System packages updated successfully"
}
# Install SELinux packages
install_selinux() {
log_info "[2/$TOTAL_STEPS] Installing SELinux packages..."
$PKG_INSTALL $SELINUX_PACKAGES
log_success "SELinux packages installed successfully"
}
# Activate SELinux (Ubuntu/Debian only)
activate_selinux() {
if [[ "$NEEDS_ACTIVATION" == "true" ]]; then
log_info "[3/$TOTAL_STEPS] Activating SELinux for Ubuntu/Debian..."
selinux-activate
selinux-config-enforcing
log_success "SELinux activation configured"
else
log_info "[3/$TOTAL_STEPS] SELinux activation not needed for this distribution"
fi
}
# Configure SELinux main configuration
configure_selinux() {
log_info "[4/$TOTAL_STEPS] Configuring SELinux main configuration..."
# Backup existing config if it exists
if [[ -f /etc/selinux/config ]]; then
cp /etc/selinux/config /etc/selinux/config.backup
fi
# Create SELinux configuration
cat > /etc/selinux/config << EOF
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=$SELINUX_MODE
# SELINUXTYPE= can take one of these values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
EOF
chmod 644 /etc/selinux/config
log_success "SELinux configuration file updated"
}
# Enable and start audit daemon
configure_audit() {
log_info "[5/$TOTAL_STEPS] Configuring audit daemon..."
systemctl enable auditd
systemctl start auditd
log_success "Audit daemon enabled and started"
}
# Configure basic SELinux policies
configure_policies() {
log_info "[6/$TOTAL_STEPS] Configuring basic SELinux policies..."
# Only configure policies if SELinux is already active
if command -v setsebool &> /dev/null && sestatus &> /dev/null; then
# Web server policies
setsebool -P httpd_can_network_connect 1 2>/dev/null || log_warning "Could not set httpd_can_network_connect"
setsebool -P httpd_can_network_connect_db 1 2>/dev/null || log_warning "Could not set httpd_can_network_connect_db"
setsebool -P httpd_execmem 1 2>/dev/null || log_warning "Could not set httpd_execmem"
setsebool -P httpd_unified 1 2>/dev/null || log_warning "Could not set httpd_unified"
# SSH service policies
setsebool -P ssh_sysadm_login 1 2>/dev/null || log_warning "Could not set ssh_sysadm_login"
# Configure common file contexts
if command -v semanage &> /dev/null; then
semanage fcontext -a -t httpd_exec_t "/var/www/html(/.)?" 2>/dev/null || log_warning "Could not set web directory context"
semanage fcontext -a -t httpd_log_t "/var/log/nginx(/.)?" 2>/dev/null || log_warning "Could not set nginx log context"
# Restore contexts if directories exist
[[ -d /var/www/html ]] && restorecon -R /var/www/html 2>/dev/null || true
[[ -d /var/log/nginx ]] && restorecon -R /var/log/nginx 2>/dev/null || true
fi
log_success "Basic SELinux policies configured"
else
log_warning "SELinux not yet active, policies will be applied after reboot"
fi
}
# Verify installation
verify_installation() {
log_info "[7/$TOTAL_STEPS] Verifying SELinux installation..."
# Check if SELinux packages are installed
if command -v sestatus &> /dev/null; then
log_success "SELinux tools installed successfully"
else
log_error "SELinux tools not found"
return 1
fi
# Check audit daemon
if systemctl is-enabled auditd &> /dev/null; then
log_success "Audit daemon is enabled"
else
log_warning "Audit daemon is not enabled"
fi
# Check configuration file
if [[ -f /etc/selinux/config ]]; then
log_success "SELinux configuration file exists"
log_info "Current configuration:"
grep -E "^SELINUX=" /etc/selinux/config || true
grep -E "^SELINUXTYPE=" /etc/selinux/config || true
else
log_error "SELinux configuration file not found"
return 1
fi
# Try to check current status
if sestatus &> /dev/null; then
log_info "Current SELinux status:"
sestatus | head -3
else
log_warning "SELinux not yet initialized (reboot required)"
fi
}
# Final instructions
show_final_instructions() {
log_info "[8/$TOTAL_STEPS] Installation completed!"
log_warning "IMPORTANT: A system reboot is required to fully activate SELinux"
echo ""
echo "After reboot, you can:"
echo " • Check SELinux status: sestatus"
echo " • Check enforcement mode: getenforce"
echo " • Switch to permissive mode: setenforce 0"
echo " • Switch to enforcing mode: setenforce 1"
echo " • View audit logs: ausearch -m AVC"
echo ""
if [[ "$SELINUX_MODE" == "permissive" ]]; then
log_info "SELinux will start in PERMISSIVE mode (logging only)"
echo "Monitor /var/log/audit/audit.log for denials before switching to enforcing mode"
else
log_info "SELinux will start in ENFORCING mode (blocking violations)"
echo "If applications fail, check audit logs and adjust policies accordingly"
fi
log_success "SELinux installation and configuration complete!"
}
# Main execution
main() {
log_info "Starting SELinux installation and configuration..."
check_privileges
detect_distro
log_info "Detected distribution: $ID"
log_info "Package manager: $PKG_MGR"
log_info "SELinux mode: $SELINUX_MODE"
echo ""
update_system
install_selinux
activate_selinux
configure_selinux
configure_audit
configure_policies
verify_installation
show_final_instructions
}
# Run main function
main "$@"
Review the script before running. Execute with: bash install.sh