SELinux Policy Module tracking

So, today in the smoke pit I was contemplating the method in which organize to a standard the creation, approval, and tracking of SELinux Policy modules. While most GNU Linux provides SELinux policies to allow the software to do it’s thing with no issues, sometimes it doesn’t catch every scenario or consider it a necessity. I’ve worked on various contracts and projects where something doesn’t work because SELinux isn’t allowing it. Naturally, the most common reflex for most system admins is to create the selinux policy modules to allow things to work. However, from the Information Assurance (IA) Information Security (INFOSEC) that might be an issue if it’s even allowed. Across an enterprise there are various machines doing different things in which Policy Modules were created. How does one keep track of all of these deviations from the OEM policy in which most of the IA DISA STIG rules are based on?

Say you log into a system that’s kind of behaving oddly. If during the investigation you notice some odd selinux policy modules are installed. How can you tell what those for exactly? How can you tell who created it? And of course, how can you tell if it wasn’t installed by a malicious entity to prevent certain actions from being blocked and or reported? How can you present that to IA in a manner in which they could comprehend? How can you tell if the system is deviated from a standardized baseline of security policies?

In my mind, a centralized repository of all the known SELinux policy modules should exist containing the SELinux Policy Module (the PP file) and Type Enforcement (the TE file). Other than the obvious “require” function containing the involved types and classes and the “Allow” statements to permit the actions, the TE file should contain in comments the initiating command that encountered the requirement for the policy, the date of when the issue first started occurring, the creator of the policy and why it’s necessary. Necessity should contain the operational impact if it’s not allowed. An example:

module IPAINSTALL 1.0;

require {
class file execute;
class file execute_no_trans;
class process { noatsecure rlimitinh siginh };
type httpd_exec_t;
type httpd_modules_t;
type ldconfig_t;
type setroubleshootd_t;
type sysadm_t;
type system_dbusd_t;
}

#============= sysadm_t ==============
#INITCMD:ipa-server-install
#SDATE:08AUG2019
#AUTHOR:Boyd H. Ako
#COMMENT:Allows the organization standard STAFF user admin to install IPA server when executing SUDO as SYSADM role.
allow sysadm_t httpd_exec_t:file execute;
allow sysadm_t httpd_exec_t:file execute_no_trans;
allow sysadm_t httpd_modules_t:file execute;
allow sysadm_t ldconfig_t:process { noatsecure rlimitinh siginh };
allow system_dbusd_t setroubleshootd_t:process { noatsecure rlimitinh siginh };

Now upon review you’ll notice that the first line is the module designation line containing the module name and version. When you convert the TE file to module (the MOD file) then to the PP file that module name will need to match the file name and will be name of the module that gets installed. which would be visible if you ran an `semodule -l`. But, once it’s a MOD, PP, and or installed it’s technically difficult to see what it’s actually for unless you’re fluent in C. Which brings us to the next part of standardizing the policy modules; the naming convention.

Obviously the naming convention needs to be informative, but short. It also needs to only contain alpha characters. No hyphens, dashes, numbers, or spaces. To differentiate it seperatly from the OEM modules, I think you should use an organization anagram. Like PHNSY, CPF, or HOME for example. Then use the command without hyphens or underscores. In this case “ipaserverinstall”. I’ve contemplated the concept of using the involved types and functions that are involved. But, then you’ll end up with a really long module name.

Now, over time things definitely change which might require you change or alter the policy for “ipa-server-install”. For this command it’s highly unlikely, but let’s continue and pretend it does. The changes will require you to add classes, types, and allow rules to do the whatever without issues. After troubleshooting and identifying all the rules that content that needs to be added; change the version number. The version number is the last field in the module line. The version matters because when you convert the TE to a PP and install the policy it will overwrite the existing policy. Version control is important after all.

Now the tricky; yet interesting, part is how does one handle these various policies on a system to a repository hosted on another system? In this modern day and age, the de facto standard is to create some sort of web based application and interaction will use web apis. However in some environments, SSL certificates are requred for both the server and individual client (via pkcs11 or pkcs15) for authentication and validation. Yes it possible, but pretty complicated especially when you’re ssh’d into a remote system that doesn’t have access to your smartcard certificate and trying to do this. What else do we got? Old fashioned NFS share? I don’t know about that. Sometimes NFS has issues and sometimes certian security constraints make it difficult for all systems to access and interact with. What about the new commonly used GIT? Well… it’s a distributed version control system. Which would mean having to clone/download the entire repository. Which could be excessive. I’d hate to be bias, but I think using RSYNC would be the solution.

Setting up an RSYNC daemon would allow you to safely and securely provide openly accessible files. Aside from being able to run it in chroot mode you can also configure it to be read-only. Using rsync you can download individual files and/or directories. If you want to be able to write to it, you can also make duplicate rsync modules that allow username and password requirement to write to the location. Or if your account on the server has write permissions to the directory you could just simply `scp` the files straight over to the location. Which is similar to how GIT transfers files over to remote systems.

But, if you’re using basic files and directories how do you keep track of approval? Well, in the rsync module create a config directory containing two files. One containing a list of known policy modules with the information commented in the TE file with a status of IA approval. The second file containing hostnames with the approved policy modules to be installed to that system that’s separate from the OEM repo provided selinux policies. Which leaves us to identify foreign policy modules.

To do a check on the OEM repo policies you can do a check on the files in /etc/selinux/targeted/active/modules to what RPM provides it; i.e. `yum whatprovides /etc/selinux/targeted/active/modules/400/phnsyipaserverinstall/cil`. The ones that have no rpms associated are custom. Then cross check the policy names against the files in the rsync to see if it’s approved and if approved if it’s allowed on that host.