OK, so this is mostly a fedora/rhel/rocky thing. Most Debian distro's don't use SeLinux, they usually use appArmor.
I'm nor nearly as familiar with that one. So for now... just SeLinux basics. Now I have to confess something here, I've been using
SeLinux since the early 2000's. Seems like it was in Fedora 3 or 4. Redhat had it by at least RHEL 4 for sure. But in all that time using it..
I never really used "audit2why". It didn't have all the tools it has now in the early days, but now.. well things are a lot better.
The SELinux Troubleshooting Toolkit - Detailed
ausearch - Search the audit log
bashausearch -m avc -ts recent
ausearch -m avc -ts today
ausearch -m avc -ts 10:00
type=AVC msg=audit(1234567890.123:456): avc: denied { read } for pid=1234
comm="httpd" name="index.html" dev="sda1" ino=789012
scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u
bject_r:user_home_t:s0
tclass=file permissive=0
Translation: httpd tried to read a file labeled as user_home_t (wrong context for web content)
audit2why - Explains WHY something was denied
bashausearch -m avc -ts recent | audit2why
# or directly from log
audit2why < /var/log/audit/audit.log
type=AVC msg=audit(1234567890.123:456): avc: denied { read } ...
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
Was caused by:
Incorrect file context on /data/website/index.html
Run: restorecon -v /data/website/index.html
audit2allow - Generate policy modules (USE CAREFULLY!)
bashausearch -m avc -ts recent | audit2allow -M mypolicy
semodule -i mypolicy.pp
Creates a custom SELinux policy to allow what was denied
DANGER: This is the "just make it work" hammer
Only use when you understand WHY it's being denied and there's no better fix
If audit2why suggests a boolean or restorecon, do that instead!
Think of it as chmod 777 - it works, but it's usually the wrong solution.
chcon - Change context (TEMPORARY)
bashchcon -t httpd_sys_content_t /data/website/index.html
chcon -R -t httpd_sys_content_t /data/website/
ls -Z /data/website/
Changes the SELinux security context of a file/directory
-t = type (the most common thing you change)
-R = recursive
Problem: Next time you run restorecon or the system relabels, your change is GONE
Good for testing: "If I change this context, does it work?"
Not good for production
semanage fcontext - Set context policy (PERMANENT)
bash# Add a rule
semanage fcontext -a -t httpd_sys_content_t "/data/website(/.*)?"
# List existing rules
semanage fcontext -l | grep website
# Delete a rule
semanage fcontext -d "/data/website(/.*)?"
Adds rules to the SELinux policy database
Uses regex patterns: "/data/website(/.*)?" = this directory and everything under it
Changes survive reboots and restorecon
After adding a rule, you MUST run restorecon to apply it
Part of policycoreutils-python-utils package
The pattern explained:
/data/website = the directory itself
(/.*)? = optionally match slash + any characters (everything inside)
restorecon - Restore contexts based on policy
bashrestorecon -v /data/website/index.html # single file, verbose
restorecon -Rv /data/website/ # recursive, verbose
restorecon -Rvn /data/website/ # dry-run (show what would change)
Reads the policy database and sets contexts to what they SHOULD be
-R = recursive
-v = verbose (show what changed)
-n = dry run (don't actually change anything)
The missing piece: After you use semanage fcontext to set policy, use restorecon to apply it
Also useful after copying files (they might have wrong contexts)
Think of it as:
semanage fcontext = "This is what /data/website SHOULD be labeled as"
restorecon = "Go apply those rules now"
semanage port - Manage port labels
bash# List all port definitions
semanage port -l | grep http
# Add a custom port
semanage port -a -t http_port_t -p tcp 8080
# Delete a port definition
semanage port -d -t http_port_t -p tcp 8080
SELinux doesn't just care about file contexts, it also cares about network ports
Apache can only bind to ports labeled http_port_t (default: 80, 443, 8008, 8009, 8443)
If you want Apache on port 8080, you need to label that port
getsebool / setsebool - Toggle policy behaviors
bash# List all booleans
getsebool -a
# Check specific boolean
getsebool httpd_can_network_connect
# Set temporarily (until reboot)
setsebool httpd_can_network_connect on
# Set permanently
setsebool -P httpd_can_network_connect on
SELinux has built-in policy "switches" called booleans
Common ones:
httpd_can_network_connect - can Apache make outbound connections?
httpd_can_sendmail - can Apache send email?
httpd_enable_homedirs - can Apache read from home directories?
ALWAYS use -P for permanent changes or they'll reset on reboot
The Typical Workflow
bash# 1. Something broke - check the log
ausearch -m avc -ts recent
# 2. Understand WHY it was denied
ausearch -m avc -ts recent | audit2why
# 3a. If it says "wrong file context":
semanage fcontext -a -t httpd_sys_content_t "/data/website(/.*)?"
restorecon -Rv /data/website/
# 3b. If it says "needs boolean":
setsebool -P httpd_can_sendmail on
# 3c. If it says "wrong port":
semanage port -a -t http_port_t -p tcp 8080
# 4. Test - try the operation again
I'm nor nearly as familiar with that one. So for now... just SeLinux basics. Now I have to confess something here, I've been using
SeLinux since the early 2000's. Seems like it was in Fedora 3 or 4. Redhat had it by at least RHEL 4 for sure. But in all that time using it..
I never really used "audit2why". It didn't have all the tools it has now in the early days, but now.. well things are a lot better.
The SELinux Troubleshooting Toolkit - Detailed
ausearch - Search the audit log
bashausearch -m avc -ts recent
ausearch -m avc -ts today
ausearch -m avc -ts 10:00
Code:
- Searches `/var/log/audit/audit.log` (the SELinux audit log)
- `-m avc` = look for AVC (Access Vector Cache) denial messages
- `-ts recent` = last 10 minutes
- Much easier than grepping through audit.log manually
- Shows you WHAT was denied, by WHOM, and WHEN
**Example output:**
comm="httpd" name="index.html" dev="sda1" ino=789012
scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u
tclass=file permissive=0
Translation: httpd tried to read a file labeled as user_home_t (wrong context for web content)
audit2why - Explains WHY something was denied
bashausearch -m avc -ts recent | audit2why
# or directly from log
audit2why < /var/log/audit/audit.log
Code:
- Takes AVC denial messages and explains them in plain English
- Tells you if it's a boolean, file context, or port issue
- Often suggests the fix
- Part of the `policycoreutils-python-utils` package (RHEL/Fedora)
**Example output:**
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
Code:
or better:
Incorrect file context on /data/website/index.html
Run: restorecon -v /data/website/index.html
audit2allow - Generate policy modules (USE CAREFULLY!)
bashausearch -m avc -ts recent | audit2allow -M mypolicy
semodule -i mypolicy.pp
Creates a custom SELinux policy to allow what was denied
DANGER: This is the "just make it work" hammer
Only use when you understand WHY it's being denied and there's no better fix
If audit2why suggests a boolean or restorecon, do that instead!
Think of it as chmod 777 - it works, but it's usually the wrong solution.
chcon - Change context (TEMPORARY)
bashchcon -t httpd_sys_content_t /data/website/index.html
chcon -R -t httpd_sys_content_t /data/website/
ls -Z /data/website/
Changes the SELinux security context of a file/directory
-t = type (the most common thing you change)
-R = recursive
Problem: Next time you run restorecon or the system relabels, your change is GONE
Good for testing: "If I change this context, does it work?"
Not good for production
semanage fcontext - Set context policy (PERMANENT)
bash# Add a rule
semanage fcontext -a -t httpd_sys_content_t "/data/website(/.*)?"
# List existing rules
semanage fcontext -l | grep website
# Delete a rule
semanage fcontext -d "/data/website(/.*)?"
Adds rules to the SELinux policy database
Uses regex patterns: "/data/website(/.*)?" = this directory and everything under it
Changes survive reboots and restorecon
After adding a rule, you MUST run restorecon to apply it
Part of policycoreutils-python-utils package
The pattern explained:
/data/website = the directory itself
(/.*)? = optionally match slash + any characters (everything inside)
restorecon - Restore contexts based on policy
bashrestorecon -v /data/website/index.html # single file, verbose
restorecon -Rv /data/website/ # recursive, verbose
restorecon -Rvn /data/website/ # dry-run (show what would change)
Reads the policy database and sets contexts to what they SHOULD be
-R = recursive
-v = verbose (show what changed)
-n = dry run (don't actually change anything)
The missing piece: After you use semanage fcontext to set policy, use restorecon to apply it
Also useful after copying files (they might have wrong contexts)
Think of it as:
semanage fcontext = "This is what /data/website SHOULD be labeled as"
restorecon = "Go apply those rules now"
semanage port - Manage port labels
bash# List all port definitions
semanage port -l | grep http
# Add a custom port
semanage port -a -t http_port_t -p tcp 8080
# Delete a port definition
semanage port -d -t http_port_t -p tcp 8080
SELinux doesn't just care about file contexts, it also cares about network ports
Apache can only bind to ports labeled http_port_t (default: 80, 443, 8008, 8009, 8443)
If you want Apache on port 8080, you need to label that port
getsebool / setsebool - Toggle policy behaviors
bash# List all booleans
getsebool -a
# Check specific boolean
getsebool httpd_can_network_connect
# Set temporarily (until reboot)
setsebool httpd_can_network_connect on
# Set permanently
setsebool -P httpd_can_network_connect on
SELinux has built-in policy "switches" called booleans
Common ones:
httpd_can_network_connect - can Apache make outbound connections?
httpd_can_sendmail - can Apache send email?
httpd_enable_homedirs - can Apache read from home directories?
ALWAYS use -P for permanent changes or they'll reset on reboot
The Typical Workflow
bash# 1. Something broke - check the log
ausearch -m avc -ts recent
# 2. Understand WHY it was denied
ausearch -m avc -ts recent | audit2why
# 3a. If it says "wrong file context":
semanage fcontext -a -t httpd_sys_content_t "/data/website(/.*)?"
restorecon -Rv /data/website/
# 3b. If it says "needs boolean":
setsebool -P httpd_can_sendmail on
# 3c. If it says "wrong port":
semanage port -a -t http_port_t -p tcp 8080
# 4. Test - try the operation again

