User Tools

Site Tools


enjaular_nginx_chroot_en_centos_6.x

Enjaular (Chroot) Nginx con soporte para PHP, FastCGI, MySQL y SMTP en CentOS 6.x (64 bits)

Esta guía explica los pasos a seguir para poder tener Nginx enjaulado en un directorio de nuestra elección con soporte para PHP, FastCGI (Bash, C, Perl, Python, etc.) y consultas a base de datos Mysql. Antes explicaremos algunos conceptos básicos sobre las herramientas utilizadas en esta guía.

Herramientas.

  • php-fpm
  • php-cgi
  • spawn-fcgi
  • fcgiwrap
  • mini_sendmail

Combinación de herramientas.

  • Soporte para PHP (Opción 1): php-fpm
  • Soporte para PHP (Opción 2): spawn-fcgi + php-cgi
  • Soporte para FastCGI: spawn-fcgi + fcgiwrap
  • Soporte para SMTP: mini_sendmail + postfix (Podría usarse cualquier servicio SMTP)

Chroot

Enjaular aplicaciones es una operación que invoca un proceso, cambiando para este y sus hijos el directorio raíz del sistema. Comúnmente, el entorno virtual creado por chroot a partir de la nueva raíz del sistema se conoce como “jaula chroot”. Al usar “chroot” para invocar un proceso, se impedirá al mismo y a sus procesos hijos acceder por su nombre a ningún fichero que esté por encima del nuevo directorio raíz. Esto se consigue cambiando el número de i-nodo raíz que tenía el kernel para ese proceso. Esto es entendido a menudo como un dispositivo de seguridad, ya que en teoría crea una zona segura para ejecutar un programa que provoca desconfianza, no está probado, o de alguna forma puede presentar un comportamiento peligroso para la integridad del sistema. Cabe señalar que las jaulas chroot no son tan seguras como otro tipo de jaulas o la virtualización.

Como añadido ya que no se utilizará en la guía, recordar que un fichero (enlace duro) aplica unos permisos de acceso a los datos referenciados. La creación de enlaces duros adicionales permite crear enlaces con distintos permisos o propietarios para acceder a los mismos datos. De esta forma, por ejemplo, un enlace puede permitir acceso de escritura, mientras que otro ofrezca sólo de lectura, pudiéndose crear distintas combinaciones para distintos grupos o usuarios. Asimismo, al ser indistinguibles de los archivos, se pueden utilizar enlaces duros para ofrecer acceso a datos desde entornos chroot sin necesidad de duplicar los datos en disco.

Debido a que los programas esperan encontrar en lugares determinados su espacio de almacenamiento, los archivos de configuración o sus bibliotecas de enlace dinámico, entre otros, preparar una jaula chroot implica también incluir dichos recursos dentro de ella.

Los programas enjaulados tienen permitido llevarse descriptores de archivos abiertos (sean archivos físicos, tuberías, o conexiones de red / Sockets) dentro de la jaula, lo cual usaremos en nuestro caso para comunicar Nginx con PHP, simplificando el acceso de Nginx a recursos que se encuentran fuera de su jaula chroot.

Medidas de seguridad y recomendaciones básicas para jaulas chroot

  • No correr procesos como root.
  • Mantener los permisos lo más restrictivos posibles.
  • Mantener la jaula chroot lo más simple que se pueda.
  • No tener descriptores de ficheros abiertos antes de crear el entornos chroot.
  • Evitar los enlaces físicos en la medida de lo posible.
  • De usar directorios montados (bind) que sean con permiso de solo lectura a poder ser.
  • Que la jaula contenga siempre el mínimo de programas / librerías posibles.

FastCGI

Son interfaces que ponen en contacto programas ejecutables (Perl, Python, PHP, C, etc) con el servidor web. Cuando se realiza una petición desde un navegador, el servidor web la envía al servicio FastCGI, este, se encarga de ejecutar el programa requerido, por ejemplo en Python. Una vez ejecutado y obtenido los resultados (calculo matemático, consulta a base de datos, etc.), el servicio Fastcgi envía los datos resultantes al servidor web, siendo finalmente entregados al usuario que realizo la petición.

Las peticiones de páginas son enviadas desde el servidor web hacia los procesos a través de una conexión TCP (para procesos remotos) o a través de zócalos de Unix (para procesos locales). Las respuestas son devueltas desde el proceso hacia el servidor web sobre la misma conexión, de ahí que se hable de programas FastCGI remotos y locales.

La diferencia básica entre FastCGI y los modulos de Apache, es que los módulos están integrados de forma más óptima en las bases del propio servidor web y por tanto tienen mejor rendimiento. La elección de usar un módulo o FastCGI depende también de otro tipo de cosas, como son la seguridad, portabilidad, escalabilidad, independencia entre el servicio web y los ejecutables,etc.

PHP-FPM

Web oficial: http://php-fpm.org
Manual de configuración:http://www.php.net/manual/es/install.fpm.configuration.php

Con PHP-FPM, a diferencia de las tradicionales implementaciones de php como cgi, las instrucciones invocadas en una petición son cacheadas en memoria para reutilizarlas en futuras peticiones sin necesidad de volver a leer el código php en cada solicitud. Debido a estas mejoras de rendimientos y sus posibilidades de configuración, es el recomendable a utilizar con Nginx. A PHP-FPM se le puede indicar el directorio donde realizamos el enjaulado del servidor web para que actúe en consecuencia.

Si se quieren enjaular varios proyectos con PHP-FPM, APC y Nginx, es recomendable la siguiente lectura: leer

PHP-CGI

Es un servidor FastCGI para PHP. Por defecto, PHP se construye como un programa CLI y CGI, que puede ser utilizado para el procesamiento de CGI. Usar PHP como un binario CGI es una opción para configuraciones que por alguna razón no desean integrar PHP como un módulo dentro del software de servidor (como Apache), en el caso de Nginx, es necesario usar php-cgi ya que no tiene soporte para módulos como Apache. Este servidor CGI de PHP suele ser utilizado junto a “spawn-fcgi”, el cual facilita su gestión, aunque puede usarse sin necesidad de spawn-fcgi.

spawn-fcgi

Web oficial (lighttpd): http://redmine.lighttpd.net/projects/spawn-fcgi

Genera y administra procesos FastCGI remotos o locales, no es siempre necesario si el cgi nativo otorga todas las necesidades requeridas, pero facilita lanzar procesos fastcgi, por ejemplo es muy útil cuando el CGI nativo no soporta determinadas funciones. Al igual que PHP-FPM, spawn-fcgi tiene opción para indicar el directorio donde realizamos el enjaulado del servidor web, de esa forma, los CGI no saldrán del la jaula chroot. Si por ejemplo en un cgi de Bash usamos el comando pwd, este devolverá “/www/cgi-bin” y no “/opt/nginx_jail/www/cgi-bin”. Nosotros vamos a utilizarlo junto con cgiwrap para fastCGI y/o con php-cgi si no se utiliza la opción php-fpm (Opción recomendada) o bien se quieren tener las dos funcionando a la vez (poco sentido).

fcgiwrap

Web oficial: https://nginx.localdomain.pl/wiki/FcgiWrap

Es un simple servidor de aplicaciones FastCGI para servidores web, nos permite ejecutar aplicaciones CGI (C, Ruby, Python, Perl, Bash,..) en el servidor web. Es el más utilizado a fecha de esta guía en instalaciones junto a Nginx. Si no se quiere utilizar junto a spawn-cgi en la misma web oficial se puede encontrar un script en perl para ejecutarlo.

mini_sendmail

Web oficial: http://www.acme.com/software/mini_sendmail/

Programa compilado de forma estática encargado de recibir correos electrónicos y enviarlos al servidor SMTP especificado. Se usará para poder enviar correos con la función mail de php a traves de postfix, debido a que Nginx y PHP se encuentran dentro de la jaula chroot pero no así postfix, hace falta algo que haga de vinculo para comunicar la jaula con el servidor de correo.

Alternativa: http://quigon.bsws.de/femail/

Instalar aplicaciones: Nginx + PHP +FastCGI + MySQL en CentOS 6.x

Instalar Nginx Crear el fichero /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/6/$basearch/
gpgcheck=0
enabled=1
yum install nginx

Instalamos el repositorio para FastCGI y el paquete fcgiwrap en Centos 6.X (Si se desea tener soporte para FastCGI).

yum groupinstall 'Development Tools'
# Se instala el repositorio EPEL: http://fedoraproject.org/wiki/EPEL/es
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
yum install fcgi-devel

Compilamos e instalamos mini_sendmail (Si se desea tener soporte para SMTP).

Descargar y descomprimir mini_sendmail: http://www.acme.com/software/mini_sendmail/mini_sendmail-1.3.6.tar.gz

Dentro del directorio descomprimido, aplicamos el siguiente parche.

mini_sendmail.patch
--- mini_sendmail-1.3.6/mini_sendmail.c 2005-06-29 19:37:15.000000000 +0200
+++ mini_sendmail.c     2008-04-25 17:04:21.026619403 +0200
@@ -31,9 +31,9 @@
 ** a significant savings in executable size.
 */
 #define DO_RECEIVED    /* whether to add a "Received:" header */
-#define DO_GETPWUID    /* whether to try a getpwuid() if getlogin() fails */
+//#define DO_GETPWUID  /* whether to try a getpwuid() if getlogin() fails */
 #define DO_MINUS_SP    /* whether to implement the -s and -p flags */
-#define DO_DNS         /* whether to do a name lookup on -s, or just IP# */
+//#define DO_DNS               /* whether to do a name lookup on -s, or just IP# */
 
 
 #include <unistd.h>
@@ -145,7 +145,8 @@
        ++argn;
        }
 
-    username = getlogin();
+   /* username = getlogin();*/
+      username = "nginx";
     if ( username == (char*) 0 )
        {
 #ifdef DO_GETPWUID

Instalamos la dependencia glibc-static (Soluciona: /usr/bin/ld: cannot find -lc) y postfix.

yum install glibc-static
yum install postfix
tar -zxvf
cd mini_sendmail-1.3.6.tar.gz
patch -p1 < mini_sendmail.patch
make
mkdir -p /usr/local/man/
make install

NOTA: Posteriormente copiaremos el binario “/usr/local/sbin/mini_sendmail” dentro de la jaula con el nombre “sendmail”, que es lo que buscará php dentro de la jaula para poder enviar correos. Como se verá posteriormente, para que mini_sendmail funcione dentro de la jaula debemos tener el binario bash dentro de la misma.

Compilamos e instalamos fcgiwrap (Si se desea tener soporte para FastCGI).

wget  https://codeload.github.com/gnosek/fcgiwrap/legacy.tar.gz/master -O fcgiwrap.tar.gz
tar zxvf fcgiwrap.tar.gz
cd gnosek-fcgiwrap-66e7b7d
autoreconf -i
./configure
make
make install

Instalar paquetes.

yum install nginx
yum install php-mysql
yum install mysql-server
# Opción 1: Si se quiere usar el soporte PHP mediante php-cgi (Alternativa a FastCGI + PHP).
yum install php-fpm
# Opción 2: Si se quiere usar el soporte PHP mediante FastCGI (Alternativa a php-fpm).
yum install php-cli
yum install spawn-fcgi

Usuarios utilizados para cada aplicación

  • Usuario Nginx: nginx (De forma predeterminada).
  • Usuario mysql: mysql (De forma predeterminada).
  • Usuario php-fpm: nginx (Se debe especificar en la configuración).
  • Usuario fastCGI: nginx (Se debe especificar en la configuración).

Chroot de Nginx en CentOS 6.X (Primera parte)

  • El directorio seleccionado para la jaula es: /opt/nginx_jail.
  • Esta primera parte crea el esqueleto base de la jaula chroot.
  • Una vez creado el esqueleto, se configurará la jaula según necesidades PHP y/o fastcgi.
  • La Segunda parte configura usuarios propietarios y permisos de los directorios de la jaula chroot.
# Se crea el directorio que hará de jaula.
 
export JAIL=/opt/nginx_jail
mkdir -p $JAIL/dev
 
# Creamos los dispositivos.
 
mknod -m 0666 $JAIL/dev/null c 1 3
mknod -m 0666 $JAIL/dev/random c 1 8
mknod -m 0444 $JAIL/dev/urandom c 1 9
 
# Creamos los directorios.
 
mkdir -p $JAIL/etc/nginx/logs
mkdir -p $JAIL/{lib,lib64,bin,sbin}
mkdir -p $JAIL/usr/{local,lib,lib64,bin,sbin}
mkdir -p $JAIL/usr/share/nginx
mkdir -p $JAIL/var/{log,lib,cache}/nginx
mkdir -p $JAIL/var/lib/mysql
mkdir -p $JAIL/www/cgi-bin
mkdir -p $JAIL/{run,tmp}
mkdir -p $JAIL/var/run
mkdir -p $JAIL/usr/local/sbin/
 
cd $JAIL
 
 
# Sistema de ficheros tmpfs
 
mount -t tmpfs none $JAIL/run -o 'noexec,size=1M'
mount -t tmpfs none $JAIL/tmp -o 'noexec,size=100M'
 
touch $JAIL/etc/fstab
echo 'tmpfs /opt/nginx_jail/run tmpfs rw,noexec,relatime,size=1024k 0 0' >> $JAIL/etc/fstab
echo 'tmpfs /opt/nginx_jail/tmp tmpfs rw,noexec,relatime,size=102400k 0 0' >> $JAIL/etc/fstab
 
# Copiamos nginx a la jaula.
 
cp -r /usr/share/nginx/html/* $JAIL/www
cp /usr/sbin/nginx $JAIL/usr/sbin/
cp /bin/false $JAIL/bin/
 
cp /lib64/ld-linux-x86-64.so.2 $JAIL/lib64
cp $(ldd /usr/sbin/nginx |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /usr/sbin/nginx |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64
 
cp /lib64/libns* $JAIL/lib64
cp -rfvL /etc/{services,localtime,nsswitch.conf,nscd.conf,protocols,hosts,ld.so.cache,ld.so.conf,resolv.conf,host.conf,nginx} $JAIL/etc
 
# Usuario / grupo (Se recomienda poner el mismo ID que el de /etc/passwd, en caso contrario instalaciones con php-cgi y spawn-fcgi no funcionarán, si vamos a utilizar unicamente php-fpm podemos elegir el id que queramos.)
 
touch $JAIL/etc/{group,passwd,shadow,gshadow}
echo `grep -i nginx /etc/group` >> $JAIL/etc/group
echo `grep -i nginx /etc/passwd` >> $JAIL/etc/passwd
echo `grep -i nginx /etc/shadow` >> $JAIL/etc/shadow
echo `grep -i nginx /etc/gshadow` >> $JAIL/etc/gshadow
 
# Shells / PID / sockets
 
touch $JAIL/etc/shells
touch $JAIL/var/run/nginx.pid
touch $JAIL/var/lib/mysql/mysql.sock
touch $JAIL/var/run/php5-fpm.sock
touch $JAIL/var/run/spawn-fcgi.sock

PHP / FastCGI en Nginx (chroot)

Soporte PHP para la jaula de Nginx (Opción 1: php-fpm)

Si no se necesita soporte para el lenguaje PHP podemos obviar esta sección.

Editar el fichero /etc/php-fpm.d/www.conf

Variables y sus respectivos valores para php-fpm.

;listen = 127.0.0.1:9000
chroot = /opt/nginx_jail
listen = /opt/nginx_jail/var/run/php5-fpm.sock

listen.owner = nginx
listen.group = nginx

user = nginx
group = nginx

Soporte PHP para la jaula de Nginx (Opción 2: spawn-fcgi + PHP)

Si no se necesita soporte para PHP o bien hemos optado por PHP-FPM, podemos obviar esta sección.

Nota: Si hay que elegir entre usar php-fpm (Opción 1) y spawn-fcgi + PHP, se recomienda encarecidamente php-fpm. Esto se debe a mejoras en rendimiento por parte de php-fpm y menor necesidad de librerías a la hora de tener acceso a Mysql dentro de la jaula chroot.

Para esta segunda opción se necesita tener instalado: php, fcgiwrap y spawn-fcgi.

# Librerías (php-cgi / fcgiwrap)
 
# FastCGI de PHP que será lanzado por spawn-fcgi
cp $(ldd /usr/bin/php-cgi |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /usr/bin/php-cgi |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64
 
# Ejecutable (php-cgi / fcgiwrap)
cp /usr/bin/php-cgi $JAIL/usr/bin/
 
# Soporte mysql. (Si no se necesita no es necesario seguir las instrucciones).
cp -r /etc/php.d/ $JAIL/etc/
cp -r /usr/lib64/php $JAIL/usr/lib64/
cp $(ldd /usr/lib64/php/modules/mysql.so |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /usr/lib64/php/modules/mysql.so |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64
cp $(ldd /usr/lib64/php/modules/mysqli.so |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /usr/lib64/php/modules/mysqli.so |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64
cp $(ldd /usr/lib64/php/modules/pdo_sqlite.so |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /usr/lib64/php/modules/pdo_sqlite.so |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64

Crear el socket fastcgi para php.

Opción A: Mediante la configuración del servicio: /etc/sysconfig/spawn-fcgi

SOCKET=/var/run/spawn-fcgi_php.sock
OPTIONS="-c /opt/nginx_jail/ -u nginx -g nginx -U nginx -G nginx -s $SOCKET  -P /opt/nginx_jail/var/run/fastcgi_php.pid -- /usr/bin/php-cgi"
service spawn-fcgi start

NOTA: El resultado del comando anterior es el proceso “php-cgi” corriendo en el sistema, pero este no parará ejecutando “service spawn-fcgi stop”, hay que eliminarlo a mano o bien modificar el init script de spawn-fcgi para que lo haga. Si se agregan librerías relacionadas con PHP mientras “php-cgi” está arrancado, se debe reiniciar el proceso.

Opción B: Por linea de comandos.

spawn-fcgi -c /opt/nginx_jail/ -u nginx -g nginx -U nginx -G nginx -s "/var/run/spawn-fcgi_php.sock"  -P /opt/nginx_jail/var/run/fastcgi_php.pid -- /usr/bin/php-cgi

Soporte FastCGI para la jaula de Nginx (spawn-fcgi + fcgiwrap)

Si no queremos soporte para Fastcgi podemos obviar esta sección.

# FastCGI generico (Bash, python, perl,..) lanzado también por spawn-fcgi
cp $(ldd /usr/local/sbin/fcgiwrap |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /usr/local/sbin/fcgiwrap |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64
cp /usr/local/sbin/fcgiwrap $JAIL/usr/local/sbin

Ahora faltaría agregar a la jaula los binarios + librerías utilizados por los ficheros cgi de la jaula chroot. Si por ejemplo utilizamos scripts en bash como archivos cgi, se debe copiar “/bin/bash” a “/opt/nginx_jail/bin/”. Después se debe copiar las librerías compartidas que utiliza bash, para obtener sus rutas se utiliza el comando “ldd /bin/bash”. Es importante seguir las rutas de forma precisas, si el comando ldd nos muestra “/usr/lib64/perl5/CORE/libperl.so”, en la jaula se debe crear ese mismo directorio y copiar dentro dicha librería compartida. En algunos casos puede funcionar un determinado cgi con solo algunas de las librerías mostradas por ldd, pero lo recomendable, al no ser que se sepa lo que se está haciendo, es copiarlas todas.

Es un trabajo minucioso y requiere de un poco de paciencia, de esta forma se concede a los archivos cgi únicamente los ejecutables que pueden utilizar en un entorno medianamente controlado.

Crear el socket fastcgi.

Opción A: Mediante la configuración del servicio: /etc/sysconfig/spawn-fcgi

SOCKET=/var/run/spawn-fcgi.sock
OPTIONS="-c /opt/nginx_jail/ -u nginx -g nginx -U nginx -G nginx -s $SOCKET  -P /opt/nginx_jail/var/run/fastcgi.pid -- /usr/local/sbin/fcgiwrap"
service spawn-fcgi start

NOTA: Al igual que con “php-cgi”, el comando anterior lanza el proceso “fcgiwrap” corriendo en el sistema, pero este no parará ejecutando “service spawn-fcgi stop”, hay que eliminarlo a mano o bien modificar el init script de spawn-fcgi para que lo haga.

Opción B: Por linea de comandos.

spawn-fcgi -c /opt/nginx_jail/ -u nginx -g nginx -U nginx -G nginx -s "/var/run/spawn-fcgi.sock"  -P /opt/nginx_jail/var/run/fastcgi.pid -- /usr/local/sbin/fcgiwrap

Soporte SMTP para la jaula de Nginx (mini_sendmail + Postfix)

Si no queremos soporte para smtp (postfix) podemos obviar esta sección.

Copiar el binario estático mini_sendmail dentro de la jaula.

cp /usr/local/sbin/mini_sendmail $JAIL/usr/sbin/sendmail

Copiar bash y librerías compartidas en la jaula chroot (necesario para mini_sendmail).

cp /bin/bash $JAIL/bin/
ln -s bash $JAIL/sh
# Por norma no habrá librerías compartidas utilizadas por bash en /usr/lib64, pero no está demás comprobarlo (futuras versiones.)
cp $(ldd /bin/bash |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /usr/lib64") $JAIL/usr/lib64
cp $(ldd /bin/bash |grep -Po '(?<=>).*(?=\(0x.*)'  | grep -i "^ /lib64") $JAIL/lib64

Configurar php-fpm (/etc/php-fpm.d/www.conf).

php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -fremitente@dominio -s127.0.0.1

NOTA: El enlace simbólico bash - sh es importante que no utilice rutas no albergadas en la jaula chroot, si “/opt/nginx_jail/bin/sh” apunta a “/opt/nginx_jail/bin/bash” mini_sendmail simplemente no funcionará.

Probar funcionamiento básico de mini_sendmail.

chroot /opt/nginx_jail/ /usr/sbin/sendmail -t -i -fremitente@dominio -s127.0.0.1
To:usuario@dominio
Subject: Asunto del correo
Texto del cuerpo del correo.

Error al no parchear mini_sendmail.

chroot /opt/nginx_jail/ /usr/sbin/sendmail -t -i -fremitente@dominio -s127.0.0.1
/usr/sbin/sendmail: can't determine username

Soporte MySQL para la jaula de Nginx

Editar el archivo /etc/my.cnf.

[mysqld]
socket=/opt/nginx_jail/var/lib/mysql/mysql.sock
...

[mysqld_safe]
socket=/opt/nginx_jail/var/lib/mysql/mysql.sock
...

[client]
socket=/opt/nginx_jail/var/lib/mysql/mysql.sock

[mysqldump]
socket=/opt/nginx_jail/var/lib/mysql/mysql.sock

[mysqladmin]
socket=/opt/nginx_jail/var/lib/mysql/mysql.sock

Si por el contrario queremos ejecutar MySQL desde la linea de comando, este comando permite establecer los parametros pertinentes dada nuestra configuración.

/usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --verbose --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/opt/nginx_jail/var/lib/mysql/mysql.sock

NOTA: Es recomendable deshabilitar o configurar MySQL para que pueda escribir dentro de /opt/nginx_jail.

Chroot de Nginx en CentOS 6.X (Segunda parte)

Estos comandos asignan propietario y permisos al directorio que hace de jaula chroot. Cuando se agreguen ficheros php, cgi, ejecutables y demás archivos que necesitemos debemos prestar especial atención a los permisos otorgados. Por supuesto que estos permisos pueden ser más restrictivos, pudiendo quitar privilegios de escritura, crear ACLs, directorios montados con solo lectura, etc.

# Permisos

chown -R root:root $JAIL/
chown -R nginx:nginx $JAIL/{www,run}
chown -R nginx:nginx $JAIL/etc/nginx
chown -R nginx:nginx $JAIL/var/{log,lib,cache}/nginx
chown nginx:nginx $JAIL/var/run/*
chown -R mysql:mysql $JAIL/var/lib/mysql/

find $JAIL/ -gid 0 -uid 0 -type d -print | xargs chmod -rw
find $JAIL/ -gid 0 -uid 0 -type d -print | xargs chmod +x
find $JAIL/etc -gid 0 -uid 0 -type f -print | xargs chmod -x
find $JAIL/usr/sbin -type f -print | xargs chmod ug+rx
find $JAIL/ -group nginx -user nginx -print | xargs chmod o-rwx
chmod +rw $JAIL/tmp
chmod +rw $JAIL/run
setcap 'cap_net_bind_service=+ep' $JAIL/usr/sbin/nginx

Configuración básica del servidor Nginx

Editamos el fichero de la configuración de nginx en la jaula: /opt/nginx_jail/etc/nginx/conf.d/default.conf

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /www;
        index  index.html index.htm;
    }

    
    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /www;
    }

    location ~ \.php$ {
        root           /www;
        fastcgi_pass   unix:/var/run/php5-fpm.sock;      # Opción 1: php-fpm
       #fastcgi_pass   unix:/var/run/spawn-fcgi_php.sock;# Opción 2: spawn-fcgi + php-cgi
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
    
    # URL: http://dominio/cgi-bin/index.cgi
    location ~ ^/cgi-bin/.*\.cgi$ {  
        root           /www;
        try_files $uri =404;
        gzip off;
        fastcgi_pass   unix:/var/run/spawn-fcgi.sock;    # spawn-fcgi + fcgiwrap
        fastcgi_index index.cgi;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
      }

}

Comandos útiles para utilizar Nginx desde la jaula

# Comprobar sintaxis de la configuración de nginx.
/usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -t
 
# Arranca Nginx
/usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx
 
# Recarga la coinfiguración de forma paulatina.
/usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s reload 
 
# Lo para deprisa.
/usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s stop
 
# Lo para de forma menos agresiva, paulatinamente.
/usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s quit
 
# Reabre los logs.
/usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s reopen

A continuación se muestra un script de inicio con alguno de estos comandos para facilitar el uso del servidor Nginx con chroot.

Init script para Nginx enjaulado (chroot)

Ruta del init script: /etc/init.d/nginx_jail

nginx_jail
#!/bin/bash
# Nginx chroot startup script
 
# chkconfig: 345 90 90
# Description: Nginx Chroot init script
 
PID=`pidof -o %PPID -x /opt/nginx_jail/sbin/nginx`
 
start() {
         if [[ -z $PID ]]; then
                /usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx;
                echo "Starting Nginx jail.";
         else
                echo "PID Error ($PID): Nginx jail is currently running.";
         fi
}
 
stop() {
        if [[ -n $PID ]]; then
                /usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s quit;
                echo "Stopping Nginx jail.";
                PID=`pidof -o %PPID -x /opt/nginx_jail/sbin/nginx`
        else
               echo "Error: Nginx jail is currently not running.";
        fi
}
 
reload(){
        if [[ -n $PID ]]; then
                /usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s reload;
                echo "Reload done.";
        else
               echo "Error: Nginx jail is currently not running.";
        fi
}
 
status(){
        if [[ -n $PID ]]; then
               echo "Nginx jail is currently running, PIDs: $PID";
        else
               echo "Nginx jail is currently not running.";
        fi
}
 
restart(){
 if [[ -n $PID ]]; then
                /usr/sbin/chroot /opt/nginx_jail /usr/sbin/nginx -s stop;
                echo "Stopping Nginx jail.";
                PID=`pidof -o %PPID -x /opt/nginx_jail/sbin/nginx`;
        else
               echo "Error: Nginx jail is currently not running.";
        fi
        sleep 2;
        start
}
 
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  reload)
        reload
        ;;
  status)
        status
        ;;
  restart)
       restart
        ;;
  *)
        echo "Usage: $0 {start|stop|restart|reload|status}"
esac
 
exit 0
chmod 755 /etc/init.d/nginx_jail

Arranque automático al inicio del sistema.

chkconfig mysqld on
chkconfig php-fpm on
chkconfig nginx_jail on
chkconfig postfix on

Probar el funcionamiento de PHP y Mysql

Este simple script muestra un PHP info, prueba la conexión MySQL y SMTP (Se debe descomentar y editar la linea)

index.php
<html>
<head>
</head>
<body>
 
<?php
$directorio="/www";
chdir($directorio);
echo "<b>Ficheros del directorio actual ".getcwd() . "</b><br><br> ";
 
    if ($handle = opendir($directorio)) {
        while (false !== ($entry = readdir($handle))) {
            if ($entry != "." && $entry != "..") {
                echo "$entry\n <br>";
            }
        }
        closedir($handle);
   }
 
echo "<hr><br><b>Listado de usuarios de la base de datos Mysql, tabla user</b><br>";
$connect=mysql_connect("localhost","root","root") or die("No se puede conectar a Mysql");
mysql_select_db("mysql") or die("No se puede abrir la base de datos");
$showtablequery="select User from user";
$query_result=mysql_query($showtablequery);
while($showtablerow = mysql_fetch_array($query_result))
   {
    echo $showtablerow[0]."<br>";
}
 
echo "<hr><br><b>Phpinfo</b><br>";
phpinfo();
 
// Probar el correo (postfix debe estar arrancado)
//mail('usuario@dominio', 'Asunto', 'Cuerpo');
 
?>
</body>
</html>

Elminar la jaula (borrar el directorio)

Antes de poder eliminar el directorio es necesario desmontar el directorio run y tmp.

umount nginx_jail/run/
umount nginx_jail/tmp/

Errores y Debugging de la jaula chroot Nginx

El problema de usar entornos chroot es que los mensajes de error que se muestran pueden deberse a faltas de librerías pero los logs no nos avisarán de ello. en algunos casos el comando strace puede darnos alguna pista y en otros la información que muestra puede no servir de mucho.

strace comando
strace -p PID -o salida.txt

Vamos a ver algunos ejemplos de errores y su causa para hacernos una idea.

Problema al intentar arrancar el servicio spawn-fcgi.

spawn-fcgi: child exited with: 127

Problema al intentar arrancar el servicio spawn-fcgi con strace.

connect(4, {sa_family=AF_FILE, path="/var/run/spawn-fcgi.sock"}, 26) = -1 ECONNREFUSED (Connection refused)

Problemas al intentar acceder a un index.php utilizando spawn-fcgi y php-cgi teniendo IDs de nginx diferentes entre el fichero “/etc/passwd” del sistema y el enjaulado.

error: [crit] 1915#0: *27 connect() to unix:/var/run/spawn-fcgi.sock failed (13: Permission denied) while connecting to upstream

Problema al intentar acceder a un cgi en perl sin tener el binario ni sus librerías en la jaula o bien tema de permisos.

502 Bad Gateway

Como se puede deducir, hay que poner mucha atención al tema de los permisos y librerías a la hora de crear la jaula chroot ya que los errores pueden no darnos las pistas adecuadas.

chroot como usuario: ejecutar procesos enjaulados (chroot) especificando un ID / GID.

chroot --userspec=500:500 /directorio/ /ejecutable

NOTA: Root debe ser el usuario que ejecute el proceso, no un usuario.

enjaular_nginx_chroot_en_centos_6.x.txt · Last modified: 2020/12/25 22:57 by 127.0.0.1