SELinux, Apache and remote database connectivity

A strange error was noticed when migrating a client site to a CentOS server: the client's PHP scripts could no longer connect to their (remotely hosted) database server:

[Tue Feb 23 23:05:36 2010] [error] [client ...] PHP Warning:  mysql_pconnect() [<a href='function.mysql-pconnect'>function.mysql-pconnect</a>]: Can't connect to MySQL server on 'remotehost' (13) in ....

The problem, it seems, was due to the selinux mode being enforciny, and having a policy preventing Apache scripts from making remote connections - a very laudable policy. However, remote DB connections is sufficiently often requested to make this something we wanted to allow, so we needed a new policy to explicitly enable that.

A new policy can easily be created by simply taking the "denied" entry from the audit log and converting it into a new module:

grep httpd /var/log/audit/audit.log | grep 3306

Shows entries such as this:

type=AVC msg=audit(1266966336.533:13939026): avc:  denied  { name_connect } for  pid=9404 comm="httpd" dest=3306 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:mysqld_port_t:s0 tclass=tcp_socket

Luckily, selinux provides a handy little command to convert such entries into allowed actions:

grep httpd /var/log/audit/audit.log | grep 3306 | audit2allow -M httpdmysql

This will create a module in the current directory, which can then be installed using semodule:

semodule -i httpdmysql.pp

After which we are able to connect to remote MySQL databases - listening on the default MySQL port - with the rest of our selinux rules intact.