Servidor Web Apache trabalhando em modo chroot + Debian Squeeze

Aqui vou estar abordando a implementação de um servidor Web trabalhando em modo chroot dando suporte a php5, MySQL, Fail2ban, mod_security, mod-evasive para garantirmos a segurança de nosso servidor.

Prepare o seu sistema com o seguinte script http://wiki.douglasqsantos.com.br/doku.php/confinicialsqueeze_en para que não falte nenhum pacote ou configuração.

Vamos primeiro fazer um update de nosso repositórios e a atualização de todo o sistema.

aptitude update && aptitude dist-upgrade -y

Agora vamos instalar o apache e módulo de chroot e o debootstrap para montar a nossa jaula.

aptitude install apache2 libapache2-mod-chroot debootstrap -y

Montando a nossa jaula.

debootstrap squeeze /var/chroot http://ftp.br.debian.org/debian 

Copiando a configuração do nosso sistema para a jaula

cp -a /etc/resolv.conf /var/chroot/etc/
cp -a /etc/hosts /var/chroot/etc/
cp -a /etc/mime.types /var/chroot/etc/
cp -a /usr/share/zoneinfo/America/Sao_Paulo /var/chroot/usr/share/zoneinfo/America
cp -a /etc/adjtime /var/chroot/etc/

Instalando o apache dentro da jaula e o locales pois as vezes temos problemas com idioma dai já podemos corrigir este problema.

chroot /var/chroot apt-get update 
chroot /var/chroot aptitude dist-upgrade -y 
chroot /var/chroot apt-get install apache2.2-common apache2-utils locales -y

Acertando o idioma da jaula.

sed -i 's/# pt_BR.UTF-8 UTF-8/pt_BR.UTF-8 UTF-8/' /var/chroot/etc/locale.gen
chroot /var/chroot locale-gen

Ajustando o pid do apache por causa de nossa jaula.

mv /var/run/apache2.pid /var/chroot/var/run/apache2.pid
ln -s /var/chroot/var/run/apache2.pid /var/run/apache2.pid

Configurando o apache arquivo /etc/apache2/httpd.conf

vim /etc/apache2/httpd.conf
PidFile /var/run/apache2.pid
ChrootDir /var/chroot/

Copiando os sites para a jaula caso já tenha algum.

cp -Ra /var/www/* /var/chroot/var/www/

Vamos testar o acesso a nossa jaula, vamos editar o index.html da nossa jaula e colocar um valor diferente do padrão para termos certeza que o apache esta nos mostrando os dados da jaula.

echo "Teste de chroot no Apache " > /var/chroot/var/www/index.html

Vamos reiniciar o apache

/etc/init.d/apache2 restart

Vamos agora acessar o nosso site.

http://ip_servidor

Vai ter que aparecer a mensagem de teste que colocamos na jaula.

Podemos acompanhar os erros do apache como exemplo abaixo.

tail -f /var/log/apache2/error.log 
[Fri Jun 24 09:24:23 2011] [notice] Apache/2.2.16 (Debian) configured -- resuming normal operations
[Fri Jun 24 09:35:28 2011] [notice] caught SIGTERM, shutting down
[Fri Jun 24 09:35:29 2011] [notice] Apache/2.2.16 (Debian) configured -- resuming normal operations
[Fri Jun 24 09:39:09 2011] [notice] caught SIGTERM, shutting down
[Fri Jun 24 09:39:10 2011] [notice] Apache/2.2.16 (Debian) configured -- resuming normal operations

A primeira parte já esta ok o apache esta trabalhando em modo chroot, agora temos que fazer o php5 e o mysql trabalhar com ele, e vamos também configurar mais alguns módulos para a segurança de nosso apache.

Instalando o php5 ele não precisa ficar na jaula.

aptitude install php5 libapache2-mod-php5 php5-gd php5-ps php5-cli php-pear php5-gd php5-mysql php5-imap php5-mcrypt php5-json -y
aptitude install php5-xmlrpc php5-dev php5-common fail2ban libapache2-mod-security2 vsftpd postfix mysql-client-5.1 mysql-client -y
chroot /var/chroot apt-get install imagemagick php5-common -y

Acertando permissões

rm -rf /var/chroot/dev/*
for SEC in $(echo $(find /var/chroot/ -type f \( -perm -04000 -o -perm -02000 \) -print)); do chmod -s ${SEC}; done
chmod -x /var/chroot/bin/su
chmod -x /var/chroot/bin/stty

Configurando o módulo avasive para nos ajudar a prevenir os ataques do tipo DOS.

apt-get install libapache2-mod-evasive
echo "LoadModule evasive20_module /usr/lib/apache2/modules/mod_evasive20.so" > /etc/apache2/mods-available/evasive.load

Configurando o módulo /etc/apache2/mods-available/evasive.conf

vim /etc/apache2/mods-available/evasive.conf
<IfModule mod_evasive.c>
DOSHashTableSize 3097 
DOSPageCount 2            
DOSSiteCount 50            
DOSPageInterval 1          
DOSSiteInterval 1            
DOSBlockingPeriod 900  
DOSWhitelist 66.249.65.*
DOSWhitelist 66.249.66.*
# As ultimas são as que o google usa para indexar.
</IfModule>

Acertando o idioma do sistema

sed -i 's/# pt_BR.UTF-8 UTF-8/pt_BR.UTF-8 UTF-8/' /etc/locale.gen
locale-gen

Vamos montar um virtualhost para testarmos o nosso chroot /etc/apache2/sites-available/wiki.douglasqsantos.com.br

vim /etc/apache2/sites-available/wiki.douglasqsantos.com.br
<VirtualHost *:80>
 ServerName wiki.douglasqsantos.com.br
 ServerAlias douglasqsantos.com.br

 DocumentRoot "/var/www/website/frontend/"
 <Directory "/var/www/website/frontend/">
   Options -Indexes +FollowSymLinks +MultiViews
   AllowOverride All
   Order allow,deny
   allow from all
 </Directory>

 ScriptAlias /cgi-bin/ "/var/www/website/frontend/cgi-bin/"

 <Directory "/var/www/website/frontend/cgi-bin/">
   AllowOverride All
   Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
   Order allow,deny
   Allow from all
 </Directory>

 ErrorLog ${APACHE_LOG_DIR}/wiki.douglasqsantos.com.br-error.log
 CustomLog ${APACHE_LOG_DIR}/wiki.douglasqsantos.com.br-access.log common
 
 ServerSignature Off
 
 IndexIgnore .??* *~ *# README RCS CVS *,v *,t *

 # Possible values include: debug, info, notice, info, error, crit,
 # alert, emerg.
 LogLevel info
</VirtualHost>

Vamos montar a base do nosso site

mkdir -p /var/chroot/var/www/website/frontend/cgi-bin
mkdir -p /var/chroot/var/www/website/logs
ln -sf /var/chroot/var/www/website /var/www/website

Criando o arquivo index de teste.

echo "<?php phpinfo(); ?>" > /var/www/website/frontend/index.php

Incluindo o shell /bin/true para o usuário ftp

echo "/bin/true" >> /etc/shells

Criando o usuário ftp para o nosso site

useradd -m -d /var/www/website -s /bin/true usuarioftp

Agora vamos definir uma senha para ele

passwd usuarioftp

Carregando o nosso site e descarregando os sites defaults

a2ensite wiki.douglasqsantos.com.br
a2dissite default 
a2dissite default-ssl 
a2enmod rewrite

Agora vamos configurar o mod_security insira no final do arquivo /etc/apache2/apache2.conf o conteúdo abaixo.

vim /etc/apache2/apache2.conf
[...]
#Final do arquivo
<IfModule mod_security.c>
 # Turn the filtering engine On or Off
 SecFilterEngine On

 # Make sure that URL encoding is valid
 SecFilterCheckURLEncoding On

 # Unicode encoding check
 SecFilterCheckUnicodeEncoding Off

 # Only allow bytes from this range
 SecFilterForceByteRange 0 255

 # Only log suspicious requests
 SecAuditEngine RelevantOnly

 # The name of the audit log file
 SecAuditLog /var/log/apache2/audit_log

 # Debug level set to a minimum
 SecFilterDebugLog /var/log/apache2/modsec_debug_log
 SecFilterDebugLevel 0

 # Should mod_security inspect POST payloads
 SecFilterScanPOST On

 # By default log and deny suspicious requests
 # with HTTP status 500
 SecFilterDefaultAction "deny,log,status:500"
</IfModule>

Vamos reiniciar agora o nosso apache.

/etc/init.d/apache2 restart

Agora vamos analisar os logs do apache

tail -f /var/log/apache2/error.log 
PHP Deprecated:  Comments starting with '#' are deprecated in /etc/php5/apache2/conf.d/ps.ini on line 1 in Unknown on line 0
[Fri Jun 24 09:50:34 2011] [notice] ModSecurity for Apache/2.5.12 (http: www.modsecurity.org/) configured.
[Fri Jun 24 09:50:34 2011] [notice] Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze1 with Suhosin-Patch configured -- resuming normal operations
[Fri Jun 24 09:51:55 2011] [notice] Graceful restart requested, doing restart
PHP Deprecated:  Comments starting with '#' are deprecated in /etc/php5/apache2/conf.d/ps.ini on line 1 in Unknown on line 0
[Fri Jun 24 09:51:56 2011] [notice] Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze1 with Suhosin-Patch configured -- resuming normal operations
[Fri Jun 24 10:44:51 2011] [notice] caught SIGTERM, shutting down
[Fri Jun 24 10:44:53 2011] [notice] ModSecurity for Apache/2.5.12 (http: www.modsecurity.org/) configured.
PHP Deprecated:  Comments starting with '#' are deprecated in /etc/php5/apache2/conf.d/ps.ini on line 1 in Unknown on line 0
[Fri Jun 24 10:44:54 2011] [notice] Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze1 with Suhosin-Patch configured -- resuming normal operations

Como pode ser notado temos um aviso sobre o tipo de comentário no arquivo de configuração do php5 /etc/php5/apache2/conf.d/ps.ini vamos corrigir isso só temos que trocar na linha 1 o # por ; que é o tipo de comentário para arquivos de configuração do php5.

vim /etc/php5/apache2/conf.d/ps.ini
; configuration for php ps module
extension=ps.so

Vamos também tirar a assinatura do nosso php

vim /etc/php5/apache2/php.ini
[...]
expose_php = Off
[...]

Agora já podemos reiniciar o nosso apache novamente para ver se vamos ter mais algum aviso ou erro.

/etc/init.d/apache2 restart

Vamos verificar os logs agora

tail -f /var/log/apache2/error.log 
[Fri Jun 24 10:49:12 2011] [notice] caught SIGTERM, shutting down
[Fri Jun 24 10:49:14 2011] [notice] ModSecurity for Apache/2.5.12 (http: www.modsecurity.org/) configured.
[Fri Jun 24 10:49:15 2011] [notice] Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze1 with Suhosin-Patch configured -- resuming normal operations

Vamos configurar o nosso MySQL para o apache ter acesso.

aptitude install mysql-server-5.1 mysql-client-5.1 php5-mysql -y

Agora vamos ajustar o MySQL

/etc/init.d/mysql stop
mv /var/run/mysqld /var/chroot/var/run/mysqld
ln -s /var/chroot/var/run/mysqld /var/run/mysqld

Agora podemos já inicializar o nosso MySQL

/etc/init.d/mysql start

Agora vamos ajustar as permissões do nosso site.

chown -R usuarioftp:www-data /var/chroot/var/www/website

Agora vamos configurar o logrotate para ir fazendo rotação dos logs do nosso site arquivo /etc/logrotate.d/websites

vim /etc/logrotate.d/websites
#/etc/logrotate.d/websites
/var/www/website/logs/*.log {
 weekly
 missingok
 rotate 52
 compress
 delaycompress
 notifempty
 create 640 www-data www-data
 sharedscripts
 postrotate
 /etc/init.d/apache2 reload > /dev/null
 endscript
}

Vamos configurar o vsftdp para podermos subir os arquivos para o site, os usuários somente vão poder ver o seu home eles vão ficar presos dentro da jaula arquivo /etc/vsftpd.conf

vim /etc/vsftpd.conf 
#/etc/vsftpd.conf
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=002
anon_upload_enable=NO
anon_mkdir_write_enable=NO
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=NO
xferlog_file=/var/log/vsftpd.log
xferlog_std_format=YES
idle_session_timeout=600
data_connection_timeout=120
nopriv_user=ftp
ftpd_banner=Bem-Vindo ao FTP douglasqsantos.com.br.
deny_email_enable=NO
chroot_local_user=YES
chroot_list_enable=NO
banned_email_file=/etc/vsftpd.banned_emails
chroot_list_file=/etc/vsftpd.chroot_list
ls_recurse_enable=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/private/vsftpd.pem

Criando mais alguns arquivos necessários

Nesse arquivos podemos colocar os usuários que vão poder sair da jaula.

touch /etc/vsftpd.chroot_list 

Nesse arquivo podemos colocar os emails que vão ser negados pelo vsftpd.

touch /etc/vsftpd.banned_emails

Vamos reiniciar o nosso serviço.

/etc/init.d/vsftpd restart

Agora vamos testar o acesso via ftp.

ftp localhost
Connected to localhost.
220 Bem-Vindo ao FTP douglasqsantos.com.br.
Name (localhost:root): usuarioftp
331 Please specify the password.
Password: senha
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x    3 1001     33           4096 Jun 24 10:41 frontend
drwxr-xr-x    2 1001     33           4096 Jun 24 10:44 logs
226 Directory send OK.
ftp> quit
221 Goodbye.

Como pode ser notado conseguimos acessar o nosso servidor normalmente com o usuário que criamos.

Agora vamos configurar o Fail2ban para cuidar de nosso servidor arquivo /etc/fail2ban/jail.conf

vim /etc/fail2ban/jail.conf
#/etc/fail2ban/jail.conf
[DEFAULT]
ignoreip = 127.0.0.1, 10.0.0.0/23
bantime  = 600
maxretry = 3
backend = polling
destemail = email_do_webmaster
banaction = iptables-multiport
mta = sendmail
protocol = tcp
action_ = %(banaction)s[name=%(__name__)s, port=\"%(port)s\", protocol=\"%(protocol)s]
action_mw = %(banaction)s[name=%(__name__)s, port=\"%(port)s\", protocol=\"%(protocol)s]
 %(mta)s-whois[name=%(__name__)s, dest=\"%(destemail)s\", protocol=\"%(protocol)s]
action_mwl = %(banaction)s[name=%(__name__)s, port=\"%(port)s\", protocol=\"%(protocol)s]
 %(mta)s-whois-lines[name=%(__name__)s, dest=\"%(destemail)s\", logpath=%(logpath)s]
 
action = %(action_mwl)s

[ssh]
enabled = true
port    = ssh
filter  = sshd
logpath  = /var/log/auth.log
maxretry = 3

[pam-generic]
enabled = true
filter  = pam-generic
port = all
banaction = iptables-allports
port     = anyport
logpath  = /var/log/auth.log
maxretry = 3

[ssh-ddos]
enabled = true
port    = ssh
filter  = sshd-ddos
logpath  = /var/log/auth.log
maxretry = 3

[apache]
enabled = true
port    = http,https
filter  = apache-auth
logpath = /var/log/apache*/*error.log
maxretry = 3

[dominio.com.br]
enabled = true
port    = http,https
filter  = apache-auth
logpath = /var/www/website/logs/*error.log
maxretry = 3

[vsftpd]
enabled  = true
port     = ftp,ftp-data,ftps,ftps-data
filter   = vsftpd
logpath  = /var/log/vsftpd.log
maxretry = 3

[postfix]
enabled  = true
port     = smtp,ssmtp
filter   = postfix
logpath  = /var/log/mail.log

[sasl]
enabled  = true
port     = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s
filter   = sasl
logpath  = /var/log/mail.log

Agora vamos reiniciar o serviço para que o nosso servidor estejá com um agente análisando os logs e bloqueando quando necessário.

/etc/init.d/fail2ban restart

Agora vamos fazer mais alguns ajustes em nosso apache deixe como abaixo arquivo /etc/apache2/conf.d/security

vim /etc/apache2/conf.d/security
[...]
ServerTokens Prod
[...]
ServerSignature Off

E na jaula também /var/chroot/etc/apache2/conf.d/security

vim /var/chroot/etc/apache2/conf.d/security
[...]
ServerTokens Prod
[...]
ServerSignature Off

Agora é só reiniciar o apache.

/etc/init.d/apache2 restart

Agora é só acessar o site em http://wiki.douglasqsantos.com.br

Referências