CentOS 7 – Security

Install PHP on CentOS 8

In this chapter, we will find different tools and utilities that we can use to secure the CentOS system we are using. Security is the most important part for a system or server and thus, a System Administrator’s job is always to keep the system up to date and secure from different kind of attacks that happen on a regular basis on servers.

We will discuss several tools here starting from SELinux to other security tools and measures that we can take on a CentOS 7 system. Let’s dive into them one by one.

In this chapter, we will look into:

  • SELinux and its tools
  • Installing SELinux
  • Domain transition
  • SELinux users
  • SELinux audit logs and troubleshooting

Introducing SELinux

Security Enhanced Linux ( SELinux) is a set of kernel modifications and user-space tools that have been present in CentOS for quite a long time. It is a kind of mechanism that supports Mandatory Access Control security policies, which were initially developed by the US National Security Agency and later released in the public domain to protect computer systems from malicious intrusion and tampering.

Not many System Administrators use SELinux. Commonly, people are reluctant to learn about SELinux and just disable it directly. However, a properly configured SELinux system can reduce the security risks to a great extent.

SELinux implements Mandatory Access Control ( MAC), which works on top of already available Discretionary Access Control ( DAC) on CentOS 7. DAC is the traditional security model that we have on Linux systems where we have three entities: User, Group, and Others who can have a combination of read, write, and execute permission for files and directories. By default, if a user creates any file in his home directory, the user and his group will have the read access and the user will have write access to the file but the other entity might also have read access to it.

The user who owns the file can change this access policy and grant or revoke access as well as ownership of the file. This might leave critical files exposed to accounts that don’t need access to these files and thus pose as a security threat to the running system. It confines every process to its own domain and makes sure that it can interact only with a defined type of files and processes and thus protect the system from a hacker hijacking a script or process and gaining system-wide control through it.

To check what SELinux packages are installed on your system, run the following command:

rpm -qa | grep selinux

The command will display the following output:

Installing SELinux

Install all the packages with the following command; this will install the rest of the packages and update the already installed packages on the system:

yum install policycoreutils policycoreutils-python selinux-policy selinux-policy-targeted libselinux-utils setroubleshoot-server setools setools-console mcstrans

Now, we will have all the packages required by SELinux installed on the system. Let’s install two more services apache ( httpd) for the web server and FTP ( vsftpd) server on the system, so that we can test the SELinux with them:

yum install httpd vsftpd

Run the apache service now using either of the following commands:

systemctl start httpd
service httpd start

Check the status of httpd using either of the following commands:

service status httpd
systemctl status httpd

These commands will show that it’s running, as seen in the following screenshot:

Also, start vsftpd using either of the following commands and then check the status of vsftp in the same way:

systemctl start vsftpd
service vsftpd start

Check the status of ftpd using either of the following commands:

service status ftpd
systemctl status ftpd

SELinux mode

There are three types of SELinux modes; they are as follows:

  • Enforcing: In this mode, SELinux enforces its policies onto the system and makes sure that all access by unauthorized users or processes are denied. These access denial events are also logged in to the system as well, which we will look into later on in this chapter.
  • Permissive: This is like a semi-enabled mode state where SELinux doesn’t deny any access as the policies are in permissive mode. This is the best mode to test the SELinux policies.
  • Disabled: In this mode, the SELinux is in a completely disabled state and no logs are created or permissions are denied.

We can run the following commands to get the present SELinux status:


The outputs from the preceding commands are shown in the following image when SELinux is enabled on the system:

The main SELinux configuration file is /etc/selinux/config. We will now enable SELinux by setting up SELINUX=permissive in this file, and then saving and rebooting the system.

The SELINUXTYPE parameter in the config file also has three options, as follows:

  • Targeted: This is the default value that allows you to customize and fine-tune your policies
  • Minimum: In this mode, only the selected processes are protected
  • MLS: Multi Level Security is an advanced mode of protection and you need an additional package to install it as well

We will keep the SELINUXTYPE at the default value (that is, targeted).

This is necessary to set the SELinux into the permissive mode the first time it runs, as it’s required to label all files on the system. Otherwise, processes running under confined domains might fail as they can’t access the files with correct contexts.

Once we are set and we reboot the system, it will label all the files, which will take some time depending on the system with SELinux contexts. Since it’s in the permissive mode, only failures and access denials will be reported.

We must check the system once it is up for any errors using the following command:

grep 'SELinux' /var/log/messages

This will show you outputs such as the following if the SELinux is running in permissive mode:

May 25 01:54:46 localhost kernel: SELinux:  Disabled at runtime.
May 25 03:06:40 localhost kernel: SELinux:  Initializing.
May 25 03:06:58 localhost systemd[1]: Successfully loaded SELinux policy in 2.863609s.
May 27 06:31:39 localhost kernel: SELinux:  Initializing.
May 27 06:31:55 localhost systemd[1]: Successfully loaded SELinux policy in 1.944267s.

Now, since all the rules are loaded and the files are labeled, we have to enable the SELinux enforcing mode instead of the permissive mode. So, edit the SELinux config file once again and set the following to enforcing:


Now, reboot the server once again.

Once it is back, check the SELinux status with the sestatus command and it will show you an output similar to the following:

Now, if you grep SELinux in /var/log/messages you will find the following:

May 27 11:18:21 localhost kernel: SELinux: Initializing.
May 27 11:18:34 localhost systemd[1]: Successfully loaded SELinux policy in 715.664ms.

To check the SELinux enforcing status, run the getenforce command, and it will display the status as

The sestatus command will display more details about the operating SELinux configuration as follows:

If we want to change the SELinux mode temporarily while running SELinux, we can do that using the setenforce command as follows:

setenforce permissive

Now, sestatus will show you the following screen:

Switch back to the enforcing mode using the following command:

setenforce enforcing

SELinux policy

You must have noticed from the previous SELinux outputs in /var/log/messages that it is based on Policy. Policy means a set of rules that defines the relation, security and access rights to the following:

  • User: All regular Linux users are defined by one or more SELinux users. However, please note that SELinux users are different from Linux users. Also, note that a running process or a program is defined as subject in the SELinux.
  • Role: They are like filters that define which user can access a process and so on. It’s like a gateway between a user and a process. A user can only run a specific process if the role grants it and the user has access to the role. SELinux is based on Role Based Access Control ( RBAC).
  • Subject and Object: Subject is like a process or a program and object is anything than can be acted on; like a file, port, directory, and so on. The actions that are performed by a subject on an object depend on the subject’s permissions.
  • Domain: This is like a wrapper around the Subject (process), which tells the process what it can or can’t do. For example, the domain will define the directories, folders, files, ports, and so on a process can access. Domains are related to subject in SELinux.
  • Type: A file’s context is called its type. For example, the context of a file describes whether it’s only accessible to the local web server process or it’s available to any process within any other directory such as / and so on or which specific SELinux user is the owner of the file. Type is related to the object in SELinux.

In SELinux, policy defines rules for users access to roles, role access to domains, and domain access to types.

There are three forms of access control in SELinux defined by the SELINUXTYPE in the /etc/selinux/config file:

  • Type Enforcement ( TE): This is the primary mechanism of access control used in the targeted policy
  • Role-Based Access Control ( RBAC): This is based around SELinux users (not necessarily the same as the Linux user), but not used in the default targeted policy
  • Multi-Level Security ( MLS): This is not commonly used and often hidden in the default targeted policy.

The targeted policy is used by default in SELinux and we will continue our discussion based on it here.

Also, remember that SELinux doesn’t replace the traditional DAC policy in the Linux system. Instead, if a file access is prohibited by the DAC policy, the SELinux policy will not be evaluated and will not grant access to the file even if is allowed by SELinux.

SELinux policies are loaded in a modular format much like a kernel module into the memory and can be viewed using the following command:

semodule -l | more

The semodule command can be used for installing, removing, reloading, upgrading, enabling, and disabling SELinux policy modules as well.

The module files are located in /etc/selinux/targeted/modules/active/modules/ with the .pp extension and are not human readable. But, if you look into them closely, you will surely find that they are actually related to different applications in Linux.

These policy modules are combined into an active policy and are then loaded into the memory. This combined binary policy can be found in the /etc/selinux/targeted/policy/ directory:

We cannot modify these rules directly but can manage them using the semanage boolean command. The output of the semanage boolean -l | less command will show us this:

It is clearly evident in the second line of the preceding output that the FTP service access to user home directories is turned off at this moment. We can also see just the status of the ftpd service policies using the following command pipeline:

semanage boolean -l | grep ftpd

Now, to allow FTP users to access their home directories and allow read-write access we have to issue the following commands. First check the status of the ftp_home_dir policy using the following command:

getsebool ftp_home_dir

This will display the following output:

ftp_home_dir --> off

Now, enable access to the user home directory using setsebool -P for permanent:

setsebool -P ftp_home_dir on

Now, check the status again:

getsebool ftp_home_dir

This will show the following output:

ftp_home_dir --> on

Now, users will be allowed to access their home directories via the FTP provided; the FTP protocol is allowed in the firewall.

SELinux files and processes

So far, we have looked into the basics of SELinux and how to allow a service like vsftpd to allow users to access their files from ftp. Let’s look into the details of the context of files and how they are defined in SELinux. Context in SELinux is a collection of information related to security, which helps SELinux determine access control policies. In Linux, everything can have a security context such as files, directories, services, or ports but security context means different type of things for different objects.

We can display the SELinux file context for any file by using the ls –Z parameter like this:

ls -laZ /home/test/*

In the preceding output, this part is the SELinux context for that specific file:


There are four parts, each separated by a colon ( :). The first part is the SELinux user context, which is shown as system_u here. As you already know, each Linux system user is mapped to a SELinux user and here it is system_u.

The second part is the SELinux role, which is object_r here.

The most important part here is the third part, which is mentioned as user_home_t. This is the one that defines the type of file, and from this, we can understand that it belongs to the user’s home directory.

The fourth part (s0) actually explains the sensitivity of the file and it actually works with the Multi-Level Security. The first three parts are more important, so we will only work with them.

Now, let’s look at the SELinux process context using the httpd file that we installed before. Let’s start the httpd process first using:

systemctl httpd start

Now let’s run the ps
command with the additional -Z flag to see the process context:

ps -efZ | grep httpd

The security context in the preceding output is as follows:


In SELinux, users are suffixed by _u, roles are suffixed by _r, and types are suffixed by _t.

For a process to run like httpd, it needs to access its files and action them. We already have seen that each process can only have access to certain types (files, directories, ports, and so on).

SELinux defines these access rules in a policy. These access rules follow the standard allow statement as follows:

allow <domain> <type>:<class> { <permissions> };

A generic allow
statement indicates:

  • Whether a process is of a certain domain
  • That the resource object the process is trying to access is of a certain class and type
  • Whether it can allow access or deny access

Let’s see how this works in consideration with the security context of the https process that we have already looked into.

The document root or the default directory for httpd is /var/www/html. Now, let’s create a file in there and check its security context:

touch /var/www/html/index.html
ls -Z /var/www/html/*

The file context for the index.html file we created is shown to be httpd_sys_content_t.

We will use the sesearch command in the following way to check the type of access allowed for the httpd daemon:

sesearch --allow --source httpd_t --target httpd_sys_content_t --class file

The flags used in the preceding command are easily understandable; source domain is httpd_t, which the domain apache is running within. We wanted to list the target resources that are files and have the type context httpd_sys_content_t.

Notice the first line of context output in the preceding screenshot is:

allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ;

Now, if you relate it with the generic allow statement previously, we will clearly understand that the httpd service has I/O control, read, get attribute, lock, and open access to the files of the httpd_sys_content_t type. And, in our case, the index.html file that we created is also of the same type, which means the httpd service will have access to this index.html file.

Let’s create a test web page modifying the index.html file so that we can check its output from the browser. Add the following lines into the index.html file using your favorite editor and save it:

  Test page
  <h1>This is a test page</h1>

We will change the permission of the /var/www folder followed by httpd restart using the following commands:

chmod -R 755 /var/wwwsystemctl restart httpd

You might have to allow the http port in the firewall if you are doing it for the first time using the following commands:

firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-service=http
firewall-cmd –reload

Now try to access it from the browser. It will show you the output as in the following screenshot:

Now, let’s see if we change the type context of the index.html file and whether we will still be able to access it or not. We will use the chcon command to change the type context and will use the –type flag for this purpose as shown here:

chcon --type var_t /var/www/html/index.html

If we check the context of the file using ls -Z , it will show us:

-rwxr-xr-x. root root unconfined_u:object_r:var_t:s0   /var/www/html/index.html

It is visible that the type has been changed to var_t here.

Now, if you try to access the web page again, it will show you an error or you might see a default page but not the same page that we saw before. This is because we have changed the type context for the index.html file.

To revert it, we will use the following command:

restorecon -v /var/www/html/index.html

Now, if we access the site again, we will see that it works again as before.

The SELinux enforcing mode guarantees that unless otherwise specified by the policy, processes and files are created with the same context as their parents. What this means is that if process A is spawning process B, the spawned process B will run in the same domain as process A unless specified differently by the SELinux policy, and similarly, if we have a directory with some context_t type, unless defined otherwise, the files or directories under it will inherit the same context_t type.

In CentOS 7, the contexts of all files that exist in the system are listed in the /etc/selinux/targeted/contexts/files/file_contexts file and contexts of new directories and files are recorded in the /etc/selinux/targeted/contexts/files/file_contexts.local file. Since chcon is used to change context temporarily and restorecon is used to restore the context, restorecon actually looks into this file to restore the original context of a file.

Let’s create /www/html:

mkdir -p /www/html

Now, we copy the contents from /var/www/html to /www/html using the following command:

cp /var/www/html/index.html /www/html/

If we check the context of the file, we will find that it’s different from what we have for /var/www/html/index.html and its default_t because that is the context of its parent directory.

Further, even if we change the httpd configuration file to an open index.html file from this new location, we will still face errors because the contexts are not right yet. While copying the index.html file from /var/www/html to /www/html, it inherited the context from its parent directory, which is default_t.

To resolve this issue we will have to change its context.

To permanently change the context of the index.html file under /www/html that we created before, we will follow two steps:

semanage fcontext --add --type httpd_sys_content_t "/www(/.*)?"
semanage fcontext --add --type httpd_sys_content_t "/www/html(/.*)?"

Now, we check the context database from the /etc/selinux/targeted/contexts/files/file_contexts.local file:

Now, we will run the restorecon command to relabel the file or directory to what has been recorded in the previous step:

restorecon -Rv /www

This will work in three levels; first it will relabel the /www directory, then the /www/html directory, and finally, the /www/html/index.html file.

Now, if we try to access the web page it should work.

There is also a command called matchpathcon, and it is very handy to troubleshoot context related issues. It can compare the context of a current resource with what’s under the SELinux context database and report back. If the match is different, it suggests the changes required. We can run the command using the -V flag for /www/html/index.html in the following way:

matchpathcon -V /www/html/index.html

Comments are closed.