Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SELinux support #1012

Merged
merged 4 commits into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .nfpm.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# this is the base "template" for the package
name: nginx-agent
description: NGINX Agent
description: NGINX Agent
arch: ${ARCH}
version: ${VERSION}
priority: optional
Expand All @@ -18,8 +18,20 @@ contents:
mode: 0640
- src: ./scripts/packages/nginx-agent.service
dst: /etc/systemd/system/nginx-agent.service
- src: ./scripts/packages/nginx-agent.openrc
dst: /etc/init.d/nginx-agent
packager: apk
- src: ./scripts/nginx-agent.logrotate
dst: /etc/logrotate.d/nginx-agent
- src: ./scripts/selinux/nginx_agent_selinux.8
dst: /usr/share/man/man8/nginx_agent_selinux.8
packager: rpm
- src: ./scripts/selinux/nginx_agent.if
dst: /usr/share/selinux/devel/include/contrib/nginx_agent.if
packager: rpm
- src: ./scripts/selinux/nginx_agent.pp
dst: /usr/share/selinux/packages/nginx_agent.pp
packager: rpm
- dst: /var/log/nginx-agent
type: dir
overrides:
Expand All @@ -36,6 +48,8 @@ rpm:
apk:
signature:
key_file: ".key.rsa"
scripts:
postupgrade: "./scripts/packages/postupgrade.sh"
scripts:
preinstall: "./scripts/packages/preinstall.sh"
postinstall: "./scripts/packages/postinstall.sh"
Expand Down
21 changes: 16 additions & 5 deletions scripts/packages/.local-nfpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,26 @@ contents:
mode: 0640
- src: ./scripts/packages/nginx-agent.service
dst: /etc/systemd/system/nginx-agent.service
- dst: /var/log/nginx-agent
type: dir
- src: ./scripts/packages/nginx-agent.openrc
dst: /etc/init.d/nginx-agent
packager: apk
- src: ./scripts/nginx-agent.logrotate
dst: /etc/logrotate.d/nginx-agent
- src: ./scripts/selinux/nginx_agent_selinux.8
dst: /usr/share/man/man8/nginx_agent_selinux.8
packager: rpm
- src: ./scripts/selinux/nginx_agent.if
dst: /usr/share/selinux/devel/include/contrib/nginx_agent.if
packager: rpm
- src: ./scripts/selinux/nginx_agent.pp
dst: /usr/share/selinux/packages/nginx_agent.pp
packager: rpm
- dst: /var/log/nginx-agent
type: dir
overrides:
deb:
depends:
- apt-transport-https
deb:
depends:
- apt-transport-https
scripts:
preinstall: "./scripts/packages/preinstall.sh"
postinstall: "./scripts/packages/postinstall.sh"
Expand Down
141 changes: 141 additions & 0 deletions scripts/selinux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# SELinux

https://www.redhat.com/en/topics/linux/what-is-selinux

# Table of Contents
- [Prerequisites](#prerequisites)
- [Enable SELinux](#enable-selinux)
- [Install NGINX Agent Policy](#install-nginx-agent-policy)
- [Updating existing policy](#updating-existing-policy)
- [Troubleshooting](#troubleshooting)
- [Policy version does not match](#policy-version-does-not-match)
- [Unknown Type](#unknown-type)
- [Debugging](#debugging)
- [References](#references)

## Prerequisites
```
sudo yum install policycoreutils-devel rpm-build
```

## Enable SELinux
To enable SELinux, update the file `/etc/selinux/config` by setting `SELINUX=enforcing`. Then reboot the machine for the change to take affect.

To validate that SELinux is enabled run the following command:
```
sestatus
```
The output should look something like this:
```
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
Max kernel policy version: 31
```


## Install NGINX Agent Policy
To install the nginx-agent policy run the following commands:
```
sudo semodule -n -i /usr/share/selinux/packages/nginx_agent.pp
sudo /usr/sbin/load_policy
sudo restorecon -R /usr/bin/nginx-agent
sudo restorecon -R /var/log/nginx-agent
sudo restorecon -R /etc/nginx-agent
```

## Updating existing policy
Check for errors by using the `ausearch` command:
```
sudo ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR --raw -se nginx_agent -ts recent
```
Generate new rule based on the errors by using `audit2allow`:
```
sudo ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR --raw -se nginx_agent -ts recent | audit2allow
```

Update the `scripts/selinux/nginx_agent.te` file with the output from the `audit2allow` command.

Copy the `scripts/selinux/nginx_agent.te` file to a RHEL 8 machine and build a new `nginx_agent.pp` file by running the following command:
```
make -f /usr/share/selinux/devel/Makefile nginx_agent.pp
```
**[NOTE: The policy has to be built on a RHEL 8 machine. If it is built on a different OS like RHEL 8/9 then we will encounter this issue [Policy version does not match](#policy-version-does-not-match) when installing it on an older OS like RHEL 8. Even if the `audit2allow` command was run on a RHEL 8/9 machine the updates to the policy need to be made on a RHEL 8 machine.]**

Install the policy by following the steps here [Install NGINX Agent Policy](#install-nginx-agent-policy)

Then create a PR with the changes made to the `nginx_agent.te` and `nginx_agent.pp` files.

## Troubleshooting
### Updated Policy Not Working

If after installing an updated policy the following command
```
ps -efZ | grep nginx-agent
```
shows nginx-agent is unconfined `system_u:system_r:unconfined_service_t`

On a RHEL 8 machine run the following command to generate a new policy
```
sepolicy generate --init /usr/bin/nginx-agent
```

Replace the `nginx_agent.te` file on the RHEL 8 machine with the `scripts/selinux/nginx_agent.te` file

Run the following command on the RHEL 8 machine to build the new policy
```
sudo ./nginx_agent.sh
```

Make a PR with the changes to `nginx_agent.fc` `nginx_agent.if` `nginx_agent.pp` and `nginx_agent.te`

**[NOTE: If you need to make additional changes to the policy, you will need to delete the generated files on the RHEL 8 machine and repeat all the steps above again]**

### Policy version does not match
If running the command
```
sudo semodule -n -i /usr/share/selinux/packages/nginx_agent.pp
```
results in the following error
```
libsemanage.semanage_pipe_data: Child process /usr/libexec/selinux/hll/pp failed with code: 255. (No such file or directory).
nginx_agent: libsepol.policydb_read: policydb module version 21 does not match my version range 4-19
nginx_agent: libsepol.sepol_module_package_read: invalid module in module package (at section 0)
nginx_agent: Failed to read policy package
libsemanage.semanage_direct_commit: Failed to compile hll files into cil files.
(No such file or directory).
semodule: Failed!
```
this usually means that the policy file was built on a newer environment than isn't complicate with the environment the policy is being installed on.

To resolve this issue the policy file needs to be rebuilt on a RHEL 8 environment. See [Updating existing policy](#updating-existing-policy) for instruction on how to rebuild a policy file.

### Unknown Type
If running the command
```
sudo semodule -n -i /usr/share/selinux/packages/nginx_agent.pp
```
results in the following error
```
/usr/bin/checkmodule: loading policy configuration from tmp/nginx_agent.tmp
nginx_agent.te:52:ERROR 'unknown type bin_t' at token ';' on line 4301:
```
that means that the type is unknown and needs to be added to the require block in the `nginx_agent.te` file like this:
```
require {
bin_t
}
```

## Debugging
* To check for policy violation look at the file `/var/log/audit/audit.log`
* To check if NGINX Agent is confined by selinux: `ps -efZ | grep nginx-agent`
* For debugging nginx selinux issues refer to this nginx blog: https://www.nginx.com/blog/using-nginx-plus-with-selinux

## References
* https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_selinux/writing-a-custom-selinux-policy_using-selinux
1 change: 1 addition & 0 deletions scripts/selinux/nginx_agent.fc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/usr/bin/nginx-agent -- gen_context(system_u:object_r:nginx_agent_exec_t,s0)
40 changes: 40 additions & 0 deletions scripts/selinux/nginx_agent.if
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

## <summary>policy for nginx_agent</summary>

########################################
## <summary>
## Execute nginx_agent_exec_t in the nginx_agent domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`nginx_agent_domtrans',`
gen_require(`
type nginx_agent_t, nginx_agent_exec_t;
')

corecmd_search_bin($1)
domtrans_pattern($1, nginx_agent_exec_t, nginx_agent_t)
')

######################################
## <summary>
## Execute nginx_agent in the caller domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`nginx_agent_exec',`
gen_require(`
type nginx_agent_exec_t;
')

corecmd_search_bin($1)
can_exec($1, nginx_agent_exec_t)
')
Binary file added scripts/selinux/nginx_agent.pp
Binary file not shown.
48 changes: 48 additions & 0 deletions scripts/selinux/nginx_agent.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh -e

DIRNAME=`dirname $0`
cd $DIRNAME
USAGE="$0 [ --update ]"
if [ `id -u` != 0 ]; then
echo 'You must be root to run this script'
exit 1
fi

if [ $# -eq 1 ]; then
if [ "$1" = "--update" ] ; then
time=`ls -l --time-style="+%x %X" nginx_agent.te | awk '{ printf "%s %s", $6, $7 }'`
rules=`ausearch --start $time -m avc --raw -se nginx_agent`
if [ x"$rules" != "x" ] ; then
echo "Found avc's to update policy with"
echo -e "$rules" | audit2allow -R
echo "Do you want these changes added to policy [y/n]?"
read ANS
if [ "$ANS" = "y" -o "$ANS" = "Y" ] ; then
echo "Updating policy"
echo -e "$rules" | audit2allow -R >> nginx_agent.te
# Fall though and rebuild policy
else
exit 0
fi
else
echo "No new avcs found"
exit 0
fi
else
echo -e $USAGE
exit 1
fi
elif [ $# -ge 2 ] ; then
echo -e $USAGE
exit 1
fi

echo "Building and Loading Policy"
set -x
make -f /usr/share/selinux/devel/Makefile nginx_agent.pp || exit
/usr/sbin/semodule -i nginx_agent.pp

# Generate a man page off the installed module
sepolicy manpage -p . -d nginx_agent_t
# Fixing the file context on /usr/bin/nginx-agent
/sbin/restorecon -F -R -v /usr/bin/nginx-agent
Loading