📜 ⬆️ ⬇️

Setting up the SELinux environment by the example of a LAMP server

This is the third article in the series.


And today, she fell into the stream "Administration". Today, we will not write modules or configure RBAC , but take the path of least resistance and simply use the usual LAMP server with the help of a ready-made policy, including the necessary settings.

If anyone forgot, behind the LAMP abbreviation is L inux, A pache, M ysql, P HP, i.e. This is a big part of all VDS people buy for keeping their personal blogs. Hope this one helps all of them become a little safer :)

Assumptions


So, we assume that:

  1. Distribution - CentOS 7 x64, user - root
  2. SELinux is on, policy is loaded
  3. SELinux mode - enforcing

Training


If LAMP is already installed and configured, you can skip it.
Install the standard software package for LAMP:
')
[root @ lamp ~] # yum install -y httpd mariadb-server php-fpm php-mysql

Minimally set up the software:

/etc/php-fpm.d/www.conf
[www]
listen = 127.0.0.1:9009
user = apache
group = apache
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
pm.status_path = / status
request_terminate_timeout = 10s
request_slowlog_timeout = 1s
slowlog = /var/log/php-fpm/www-slow.log
security.limit_extensions = .php
php_admin_value [error_log] = /var/log/php-fpm/www-error.log
php_admin_flag [log_errors] = on
php_admin_value [memory_limit] = 128M
php_value [session.save_handler] = files
php_value [session.save_path] = / var / lib / php / session

/etc/httpd/conf.d/userdir.conf
<IfModule mod_userdir.c>
UserDir enabled
UserDir www
</ IfModule>
<Directory "/ home / * / www">
AllowOverride FileInfo AuthConfig Limit Indexes
Options MultiViews Indexes
Require method GET POST OPTIONS
DirectoryIndex index.html index.htm index.php
<FilesMatch "\ .php $">
<If "-f% {REQUEST_FILENAME}">
SetHandler "proxy: fcgi: //127.0.0.1: 9009"
</ If>
</ FilesMatch>
</ Directory>

Run all the necessary services:

[root @ lamp ~] # systemctl enable httpd mariadb php-fpm
[root @ lamp ~] # systemctl start httpd mariadb php-fpm

Add some user, for example phpbb:

[root @ lamp ~] # useradd -Z user_u -m -g apache phpbb
[root @ lamp ~] # chmod 750 / home / phpbb

And create a simple test file with phpinfo ():

[phpbb @ lamp ~] $ mkdir www
[phpbb @ lamp ~] $ echo "<? php phpinfo ();?>"> www / info.php

Follow the link ...


... and get exactly what everyone gets :)

We understand with errors


Unlike other manuals, where the next step is to "turn off SELinux", we now find out why this happened and what can be done.

First, install the console utilities for managing SELinux policies:

[root @ lamp ~] # yum install -y policycoreutils-python policycoreutils-newrole policycoreutils-restorecond setools-console

And then we turn on the modules we need ( using the semodule command):

[root @ lamp ~] # semodule -e apache
[root @ lamp ~] # semodule -e mysql

Let's see what kind of problems apache encountered when opening this page?

audit2allow -lb -t httpd_t
# ============= httpd_t ==============
# !!! This can be used:
# httpd_enable_homedirs, httpd_read_user_content, httpd_unified
allow httpd_t httpd_user_content_t: file getattr;

That's right: the www folder (as well as the web and public_html folders) inside the user's home directory automatically gets the httpd_user_content_t type, as specified in the rules:

sesearch -T -s user_t -c dir -d
...
type_transition user_t user_home_dir_t: dir httpd_user_content_t "public_html";
type_transition user_t user_home_dir_t: dir httpd_user_content_t "www";
type_transition user_t user_home_dir_t: dir httpd_user_content_t "web";
...

The cure is indicated in the output of audit2allow, setting variables is done with the setsebool (or semanage boolean ) command .

[root @ lamp httpd] # setsebool -P httpd_read_user_content = 1

We update the page and get:


Look logs:

/ var / log / httpd / error_log
[Tue Feb 28 21: 15: 04.555595 2017] [proxy: error] [pid 21586] (13) Permission denied: AH00957: FCGI: try to connect to 127.0.0.1:9009 (*) failed
[Tue Feb 28 21: 15: 04.555892 2017] [proxy_fcgi: error] [pid 21586] [client 192.168.56.101Cl7974] AH01079: failed to make back connection: 127.0.0.1

Everything is clear: httpd cannot connect anywhere, httpd can only go where it should. This is logical: if the web server suddenly connects via ssh, then something strange is clearly happening.
Let's see where the web server can go?

sesearch -A -s httpd_t -c tcp_socket -p name_connect -d -C
DT allow httpd_t port_type: tcp_socket name_connect; [httpd_can_network_connect]
DT allow httpd_t mythtv_port_t: tcp_socket name_connect; [httpd_can_connect_mythtv]
DT allow httpd_t zabbix_port_t: tcp_socket name_connect; [httpd_can_connect_zabbix]
DT allow httpd_t smtp_port_t: tcp_socket name_connect; [httpd_can_sendmail]
DT allow httpd_t mssql_port_t: tcp_socket name_connect; [httpd_can_network_connect_db]
DT allow httpd_t postgresql_port_t: tcp_socket name_connect; [httpd_can_network_connect_db]
ET allow httpd_t ocsp_port_t: tcp_socket name_connect; [kerberos_enabled]
DT allow httpd_t oracle_port_t: tcp_socket name_connect; [httpd_can_network_connect_db]
DT allow httpd_t gopher_port_t: tcp_socket name_connect; [httpd_can_network_relay]
DT allow httpd_t osapi_compute_port_t: tcp_socket name_connect; [httpd_use_openstack]
DT allow httpd_t mongod_port_t: tcp_socket name_connect; [httpd_can_network_connect_db]
DT allow httpd_t memcache_port_t: tcp_socket name_connect; [httpd_can_network_relay]
DT allow httpd_t memcache_port_t: tcp_socket name_connect; [httpd_can_network_memcache]
DT allow httpd_t http_cache_port_t: tcp_socket name_connect; [httpd_can_network_relay]
DT allow httpd_t cobbler_port_t: tcp_socket name_connect; [httpd_can_network_connect_cobbler]
DT allow httpd_t ftp_port_t: tcp_socket name_connect; [httpd_can_connect_ftp]
DT allow httpd_t ftp_port_t: tcp_socket name_connect; [httpd_can_network_relay]
DT allow httpd_t gds_db_port_t: tcp_socket name_connect; [httpd_can_network_connect_db]
DT allow httpd_t pop_port_t: tcp_socket name_connect; [httpd_can_sendmail]
DT allow httpd_t http_port_t: tcp_socket name_connect; [httpd_can_network_relay]
ET allow httpd_t http_port_t: tcp_socket name_connect; [httpd_graceful_shutdown]
ET allow httpd_t kerberos_port_t: tcp_socket name_connect; [kerberos_enabled]
DT allow httpd_t ldap_port_t: tcp_socket name_connect; [httpd_can_connect_ldap]
DT allow httpd_t ephemeral_port_type: tcp_socket name_connect; [httpd_use_openstack]
DT allow httpd_t ephemeral_port_type: tcp_socket name_connect; [httpd_can_connect_ftp]
DT allow httpd_t ephemeral_port_type: tcp_socket name_connect; [httpd_can_network_relay]
DT allow httpd_t squid_port_t: tcp_socket name_connect; [httpd_can_network_relay]
DT allow httpd_t mysqld_port_t: tcp_socket name_connect; [httpd_can_network_connect_db]

In square brackets are variables that are responsible for the operation of this rule.
Total: add port 9009 to one of the types to which the connection is allowed, and then set the variable httpd_can_network_relay to 1.

The new port is added using the semanage port command :

[root @ lamp httpd] # semanage port -a -t http_cache_port_t -p tcp 9009
[root @ lamp httpd] # setsebool -P httpd_can_network_relay = 1

We update the page and see:



Something more complicated


Let's complicate the task now and put phpbb on this host.

phpBB 3.2.0 installation
[phpbb @ lamp ~] $ curl www.phpbb.com/files/release/phpBB-3.2.0.zip -O
[phpbb @ lamp ~] $ unzip phpBB-3.2.0.zip
[phpbb @ lamp ~] $ mv phpBB3 / * www /
[phpbb @ lamp ~] $ restorecon -R www /

Let's try to create a base for ourselves:

[phpbb @ lamp www] $ mysql -uroot
ERROR 2002 (HY000): Can't connect to MySQL server through socket '/var/lib/mysql/mysql.sock' (13)

We look for how to allow the user to connect to the database?

sesearch -R -A -s user_t -t mysql -C -d
DT allow user_t mysqld_var_run_t: dir {getattr search open}; [selinuxuser_mysql_connect_enabled]
DT allow user_t mysqld_db_t: dir {getattr search open}; [selinuxuser_mysql_connect_enabled]
DT allow user_t mysqld_t: unix_stream_socket connectto; [selinuxuser_mysql_connect_enabled]
DT allow user_t mysqld_t: unix_stream_socket connectto; [selinuxuser_mysql_connect_enabled]
DT allow user_t mysqld_var_run_t: sock_file {write getattr append open}; [selinuxuser_mysql_connect_enabled]
DT allow user_t mysqld_var_run_t: sock_file {write getattr append open}; [selinuxuser_mysql_connect_enabled]

Ok, we include selinuxuser_mysql_connect_enabled and continue:

[root @ lamp httpd] # setsebool -P selinuxuser_mysql_connect_enabled = 1

Create a database and try to install phpbb:



Why is that? Because httpd cannot change user data. Let's find out what he can change?

sesearch -A -s httpd_t -p write -t ​​user -C -R -d
ET allow httpd_t httpd_user_rw_content_t: file {ioctl read write create getattr setattr lock append unlink link rename open}; [httpd_builtin_scripting]
ET allow httpd_t httpd_user_ra_content_t: dir {ioctl write getattr lock add_name search open}; [httpd_builtin_scripting]
ET allow httpd_t httpd_user_ra_content_t: dir {ioctl write getattr lock add_name search open}; [httpd_builtin_scripting]
ET allow httpd_t httpd_user_rw_content_t: dir {ioctl read write getattr lock add_name remove_name search open}; [httpd_builtin_scripting]
ET allow httpd_t httpd_user_rw_content_t: dir {ioctl read write getattr lock add_name remove_name search open}; [httpd_builtin_scripting]
ET allow httpd_t httpd_user_rw_content_t: dir {ioctl read write create getattr setattr lock unlink link rename add_name remove_name reparent search rmdir open}; [httpd_builtin_scripting]
ET allow httpd_t httpd_user_rw_content_t: dir {ioctl read write getattr lock add_name remove_name search open}; [httpd_builtin_scripting]
DT allow httpd_t user_tty_device_t: chr_file {ioctl read write getattr lock append}; [httpd_tty_comm]
ET allow httpd_t httpd_user_rw_content_t: sock_file {read write getattr append open}; [httpd_builtin_scripting]
DT allow httpd_t user_devpts_t: chr_file {ioctl read write getattr lock append}; [httpd_tty_comm]
ET allow httpd_t httpd_user_rw_content_t: lnk_file {ioctl read write create getattr setattr lock append unlink link rename}; [httpd_builtin_scripting]

Install php-xml , enable httpd_builtin_scripting and set the httpd_user_rw_content_t context to the specified files and folders ( using the chcon command):

[root @ lamp httpd] # setsebool -P httpd_builtin_scripting = 1
[phpbb @ lamp www] $ chmod 660 config.php
[phpbb @ lamp www] $ chcon -t httpd_user_rw_content_t cache / store / files / config.php images / avatars / upload /

We get:



Install phpBB further, delete install and get a working forum:



Change the context of the config back:

[phpbb @ lamp www] $ chcon -t httpd_user_content_t config.php
Enjoying a safe forum :)

Instead of an afterword


Without writing a single line of code, using only knowledge from the man-files and the standard SELinux default policy, you can set up a safe environment for standard services in 30 minutes. And this is not only about LAMP: the standard policy contains 403 ready-made modules. This is enough for most tasks that will ever face the administrator. Do not turn off SELinux, do not make Dan cry .

Bonus # 1
For those who have read all this - a ready-made image from the article.

Link: ufile.io/5eced (846 Mb) (link will expire on 03/29/2017)

Passwords
root: root
phpbb: phpbb
mysql root: root
mysql phpbb: i6p0AYF1B4Hg
phpbb: phpbb: phpbb1

Bonus # 2
A small cheatsheet.

Teams

  • semodule - manages the list of modules
  • sestatus - current SELinux status
  • setenforce 1/0 - enable / disable enforcing
  • audit2allow - utility for generating rules (and for hints)
  • sesearch - utility for finding rules in a policy
  • seinfo - shows information about types, roles, attributes, etc.
  • semanage - allows you to make changes to policies
  • chcon - allows you to change the context on FS
  • restorecon - restores the default context
  • setsebool - sets the variable to on / off. C -P - writes to disk
  • getsebool - gets the variable. -a - see all

Policy changes

  • semanage port -a / -d -t httpd_port_t -p tcp 8044 - add / remove port number to context
  • semanage fcontext -a / -d -t httpd_cache_t "/srv/http/cache(/.*)?" - add / remove context for this mask
  • semanage permissive -a / -d httpd_t - enable / disable permissive mode for httpd_t

Arguments to teams

  • id -Z - shows the context of the current user
  • ls -Z - shows file context
  • ps -Z - shows the context of processes
  • netstat -Z - shows connection context
  • usermod / useradd -Z bind user to SELinux user
  • ausearch -m AVC - shows policy violations

Source: https://habr.com/ru/post/322904/


All Articles