Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

Mostrando entradas con la etiqueta Apache2. Mostrar todas las entradas
Mostrando entradas con la etiqueta Apache2. Mostrar todas las entradas

martes, 29 de octubre de 2019

Cómo realizar pruebas de carga en nuestro servidor Web

Una de las labores más importantes a la hora de montar un servidor web, es la dimensionarlo correctamente para poder realizar sus labores de forma efectiva. Generalmente a la hora de realizar el dimensionamiento se suele tender a optimizar el servidor lo máximo posible, con los recursos disponibles, para poder soportar el máximo de conexiones posibles, pero aun así, siempre es importante intentar forzar dicho servidor por encima de su capacidad máxima con el fin de ver cómo reacciona... Esto puede ser una labor sencilla si el servidor soporta muy pocas conexiones, pero y si soportase 1000 conexiones simultáneas o más? Afortunadamente existen herramientas especializadas de Linux que nos pueden ayudar a realizar testear nuestro servidor web... Entre ellas hay dos especialmente conocidas: Apache Benchmark  y JMeter.

portada_pruebas_carga

Apache Benchmark

Si bien esta utilidad se puede considerar bastante inferior a JMeter, se trata de una utilidad que tiene la ventaja de que te permite realizar pruebas rápidas desde la consola sin tener la necesidad de tener una interfaz gráfica, cosa que evita el obligarnos a depender de un entorno de escritorio para poder utilizarla. La herramienta en sí es muy fácil de instalar, ya que es parte del conjunto de utilidades estándares de Apache2, llamada apache2-utils, con lo que lo podemos instalar de los repositorios tal que así:

apt-get install apache2-utils

Con esto instalado, podemos hacer pruebas de carga de forma muy rápida mediante el comando ab; donde la sintaxis sería:

ab -c concurrencias -n numero_de_peticiones -r URL

El parámetro -r sería importante, ya que evitaría que el comando se interrumpiese aún cuando hubiese algún error... Además es importante resaltar que la URL tiene que apuntar siempre a un fichero web... Por ejemplo si tenemos un servidor web con IP 127.0.0.1, no valdría con poner dicha IP como URL sino que habría que poner http://127.0.0.1/index.html pues en caso contrario Apache Benchmark pensaría que la URL es errónea.

En caso de querer hacer 1000 peticiones con 20 concurrencias a la URL atrás mencionada, haríamos:

ab -c 20 -n 1000 -r http://127.0.0.1/index.html

Esto nos daría como resultado una serie de líneas, entre las cuales se resaltarían las últimas donde se muestran el porcentaje de paquetes que ha tardado X milisegundos en tener respuesta:

prueba_carga_ab
Resultado prueba carga Apache Benchmark

Lo malo que tiene esta herramienta, es que carece de opciones de personalización a la hora de realizar las pruebas de carga; es decir, no puedes decir si las peticiones se van a hacer de forma controlada, o como un ataque DOS... Simplemente las realiza lo más rápido que puede y listo... Lo cual viene por un lado bien para saber cómo se comporta bajo cierta presión, pero que no emula entornos realistas. Es por eso que esta herramienta tienes sus pros y sus contras y es ahí donde JMeter marca la diferencia, ya que dicha herramienta sí que tiene un mayor abanico de opciones.

Apache JMeter

En este caso para poder siquiera instalar la aplicación es 100% necesario tener instalado un entorno de escritorio, pues instalar elementos gráficos. El entorno de escritorio en sí es indiferente, puede ser XFCE, KDE, Gnome... Al gusto de cada uno... Cumpliendo dicho requisito habría que escribir en la consola:

apt-get install jmeter

Esto preparará todo lo necesario para que Jmeter sea utilizable, si bien Jmeter tiene una peculiaridad. La configuración de los diferentes parámetros y planes de pruebas se realizan desde de la GUI, pero la ejecución del plan de pruebas es extremadamente recomendable hacerlo desde la consola; recomendación que es dada por los propios desarrolladores de la utilidad.

Con lo que teniendo esto claro, primero abriríamos la aplicación desde la GUI, aplicación que, desgraciadamente, al ser tan completa, puede ser algo intimidante inicialmente.

El primer paso que habría que ejecutar sería la creación de un Grupo de Hilos; dicho paso es vital pues marca el número de peticiones simultáneas que se harían, el intervalo entre éstos y el número de veces que se lanzarían peticiones (pudiendo ser infinito); las capturas de a continuación serían realizadas desde un Ubuntu 18.04, capturas en las que, en este caso mostraríamos 100 peticiones simultáneas realizadas cada segundo continuamente :

nuevo_grupo_hilos
Nuevo grupo hilos

configuracion_grupo_hilos
Configuración grupo hilos

Con esto tendríamos las peticiones preparadas; lo que habría que especificar sería qué peticiones se desean realizar... Aquí tenemos diferentes opciones, pero la más común y usada sería una petición HTTP; petición en la que únicamente sería necesario especificar que sería del tipo GET y la IP y puerto de destino de dichas peticiones; habría una serie de parámetros adicionales, pero todos ellos serían completamente optativos:

nueva_peticion_http
Petición HTTP


opciones_peticion_http
Opciones petición HTTP

Por último pero no por ello menos importante, tendríamos que crear un reporte de resumen, el cual nos servirá para conocer los resultados de nuestras pruebas. El cual se encontraría dentro de: Añadir --> Receptor --> Reporte Resumen.  El resumen se puede ver en texto plano desde la propia consola, pero desde la herramienta tendríamos el resultado mostrado de forma sintetizada, lo cual nos es ventajoso.

Ahora que tenemos todo preparado, guardaríamos el proyecto, el cual siempre es guardado en formato .jmx, por ejemplo plan_de_pruebas.jmx. Solamente sería necesario ejecutar dicho plan, ejecución que aunque se puede hacer desde la GUI, tal y como he comentado antes es recomendable hacerlo desde la consola. El comando para ejecutarlo sería:

jmeter -n -t plan_de_pruebas.jmx -l Resumen.jtl

El parámetro -l seguido del fichero jtl sería importante, pues estaríamos especificando donde guardar los resultados de las pruebas realizadas; pruebas que siempre se guardan en ficheros en formato .jtl, si bien se puede leer de forma "normal" haciendo un simple cat sobre dicho fichero.

Gracias a dicho comando estaríamos ejecutando el plan de pruebas, que se estaría ejecutando de forma continua a menos que se pulsase la combinación de teclas CTRL + C, debido a que se trata de una prueba infinita. Esto estaría haciendo una prueba de carga "infinita" sobre el servidor de destino, prueba sobre la que tendríamos más control que mediante Apache Benchmark.

El informe de salida lo podríamos leer dirigiéndonos al `Reporte resumen` antes creado y clickando en navegar para seleccionar el informe generado por nuestras pruebas; en nuestro caso Resumen.jtl... A continuación una pequeña muestra de dicho informe:

reporte_resumen
Informe Jmeter


Como se puede observar, la aplicación JMeter ofrece una amplia gama de posibilidades; estas son solo algunas de ellas, pero las mostradas serían las más "comunes" y usadas. Eso no implica que Apache Benchmark no sea útil; cada una ofrece una serie de características, la cuestión está en saber qué aplicación se adapta mejora nuestras necesidades, al igual que también no siempre se puede contar con una interfaz gráfica, y ahí es donde JMeter flaquea, pues dicho entorno es un requisito para la propia instalación.

Espero que os haya resultado útil.

Saludos.

martes, 17 de abril de 2018

Hotlinking; qué es y como evitarlo en Apache 2

Todos aquellos que tienen un servidor web expuesto al público, saben que al hacerlo dejan dicho servidor expuesto al mundo, y aún con un firewall bien configurado para evitar, en su medida, ciertos ataques, saben que siempre se corre riesgo de que por un motivo u otro, la web deje de estar disponible, su tiempo de respuesta sea lento o que ésta sea vulnerada. Teniendo en cuenta que el objetivo de una web es que "todos" la vean, es harto difícil lograr combinar una seguridad "infranqueable" y disponibilidad, y lo peor de todo es que a veces, acciones insignificantes que no son malintencionadas, pueden afectar al rendimiento de nuestra web... Hoy quiero hablaros de dicho último en especial; concretamente de una acción llamada hotlinking.

hotlink_portada

El hotlinking es una acción que si bien en sí no es maligna, puede perjudicar a otros en determinados aspectos, pues se trata de el uso de imágenes de otros servidores en vez de imágenes propias para enriquecer el contenido de una web. A modo de ejemplo, supongamos que queremos añadir una imagen a nuestra web; tenemos dos opciones, o subirla a nuestro servidor, o hacer referencia a la URL de una imagen ya hospedada en otro servidor; la segunda opción se trataría de un hotlink. Esto en sí no es un problema cuando se tratan de pocas imágenes y pocos links... Pero sí que puede ser problemático cuando el número de hotlinks es muy alto; especialmente si las páginas desde las que se reciben los hotlinks son muy visitadas, pues cada vez que dicha imagen es cargada en la otra página, estaría consumiendo ancho de banda de nuestro servidor, ya que la imagen que estarían solicitando estaría alojada en nuestro servidor, con lo que en verdad nos estarían haciendo una solicitud de imagen a nosotros y no a ellos.

Con el fin de que el ancho de banda de nuestra web no sea consumido involuntariamente, lo ideal es protegernos del hotlinking; lo cual afortunadamente es sencillo de implementar en Apache 2. Para ello hay dos tipos de prevención de hotlinking; aquel que directamente te pone muestra una imagen nula o aquel que te muestra una imagen concreta (y diferente) con el fin de dar a entender que están realizando una práctica no deseada contra nuestras imágenes.

Para poder aplicar dicha medida de protección en nuestro servidor, lo primero que necesitamos hacer es tener el módulo mod_rewrite activado en nuestro servidor web Apache2. Dicho módulo es instalado por defecto con Apache2, pero al mismo tiempo se encuentra desactivado por defecto, con lo que primero activaríamos dicho módulo, lo cual es tan sencillo como escribir el comando de a continuación como root:
a2enmod rewrite 
Veremos que nos solicita reiniciar Apache2 con el fin de hacer efectivo el cambio, pero todavía no lo haremos debido a que necesitaremos hacer un pequeño cambio en la configuración de este servicio para que pueda trabajar con el módulo rewrite... Esto es debido a que Apache2 por defecto está diseñado para no trabajar con dicho módulo y para no permitir que se "sobrescriban" las políticas del servidor web. En este caso, al querer modificar el comportamiento del servidor para prevenir el hotlinking, editaremos el fichero /etc/apache2/apache2.conf; teniendo en cuenta que lo más común es que la página web esté alojada en /var/www/ (o en uno de sus subdirectorios), cambiaremos lo siguiente:

Antes:
<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride none
        Require all granted
</Directory>

Despues:
<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride all
        Require all granted
</Directory>

Con dicho cambio realizado, ahora sí que procederíamos a reiniciar Apache2 mediante el comando:
service apache2 restart
Una vez tengamos los preparativo realizados, pasaremos a implantar nuestra protección contra hotlinks, lo cual lograremos gracias a la intervención de un fichero que crearemos llamado .htaccess, cuya función es rescribir la configuración usada para el servicio web dentro del directorio en el que se aloja ésta y, también, dentro de los subdirectorios de la susodicha. En mi caso en concreto la web se encontraría alojada en /var/www/html, web en la cual estaría hospedada la siguiente imagen:

no_hotlink_prevent

Dicha imagen se encontraría desnuda en estos momentos, es decir que podría ser accedida desde cualquier otra web, con lo que dentro del directorio /var/www/html crearíamos el fichero .htaccess con el siguiente contenido:

RewriteEngine on
RewriteOptions InheritDown
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)://(www\.)?192.168.1.8/.*$ [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [NC]

Desgranemos cada línea con el fin de entender el contenido del fichero y no hacer un simple copia-pega.

La primera línea, RewriteEngine on; habilita la posibilidad de realizar las opciones "rewrite" que se ejecutan a continuación, acciones realizadas gracias al módulo rewrite de Apache2; en caso de carecer de dicha línea o tener dicho valor establecido a off.

La segunda línea, RewriteOptions InheritDown, la cual es opcional, sirve para que los subdirectorios hereden la configuración aplicada en dicho .htaccess.

La tercera y cuarta línea, son las condiciones bajo las cuales se ejecutaría el rewrite. En ambas se tiene en cuenta qué IP o dominio va a hacer referencia a la web debido a que en la condición, RewriteCond, se revisa dicho valor gracias a %{HTTP_REFERER}, después del cual se dice desde donde se realiza una petición HTTP al servidor. Dicha petición se realizaría desde dos orígenes, desde el propio servidor (a nivel interno) para lo cual pondríamos el parámetro en cuestión vacío, lo cual se representa como: !^$. En cambio, para especificar nuestro host, tendríamos que escribir el nombre (o la IP) de éste teniendo en cuenta que se puede hacer referencia al host como http, https (si lo tenemos habilitado), con www o sin este. En mi caso el servidor Apache2 sería la IP 192.168.1.8. Además, veremos que al lado hay un parámetro llamado [NC]; dicho parámetro se encargaría de no hacer distinción entre mayúsculas y minúsculas.

Por último se pondría la re-escritura de "reglas" mediante el RewriteRule, el cual en este caso haría que todas las peticiones que HTTP que se hagan a las imágenes jpg,jpeg,png y gif, sean bloqueadas. Por ejemplo, si hacemos una petición a dicha imagen desde otro servidor web, veremos una imagen en blanco:


hotlink_block
Esto nos serviría para bloquear el hotlinking desde otros sitios; si deseásemos que se mostrase una imagen concreta que fuese indicativa de que tenemos la protección contra hotlinks activada, podríamos editar el contenido anterior para que en la línea RewriteRule nos redirija a una imagen local previamente preparada. La re-dirección la haríamos especificando la ruta local de dicha imagen.

RewriteEngine on
RewriteOptions InheritDown
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?192.168.1.8/.*$ [NC]
RewriteRule \.(jpg|png)$ /var/www/html/imagenes/candado.png [NC]

Ahora en caso de intentar acceder a la imagen desde un origen no grato, veríamos la imagen de un candado tal y como podemos ver en la siguiente captura:

hotlink_redirect

Esta medida puede ser incluso más efectiva que la del bloqueo, ya que sería claramente disuasoria de que las personas intenten hacer hotlinks a dichas imágenes propias y que en caso de desear mostrarlas, tengan la necesidad de descargárselas y subírselas a sus propios servidores.

Como podéis ver la técnica de prevención de hotlinks es fácil y sencilla de aplicar, medida que si bien puede uno pensar que no necesita, puede prevenirle a uno del consumo indeseado de ancho de banda; prevención que se puede aplicar de una forma muy rápida como se ha podido ver aquí.

Espero que os haya resultado útil.

Saludos.

lunes, 15 de enero de 2018

Cómo usar los playbooks con Ansible en Linux

Continuando con el anterior artículo, en esta ocasión vamos a profundizar un poco más en el uso de la herramienta Ansible. Hasta ahora hemos podido mandar ordenes individuales desde el controlador al resto de equipos, a los que llamaremos nodos, pero el problema radica en que por el momento lo único que estamos haciendo es mandar una orden individual a todos... Una orden que puede ser muy práctica y que puede ahorrarnos mucho tiempo, pero que no es lo más práctico cuando queremos gestionar varios servicios y tareas... Es por ello que en este aparado vamos a centrarnos en uno de los aspectos más importantes que ofrece Ansible: Los playbooks. Antes de continuar, es recomendable que, si no se tienen noción alguna de Ansible, os leáis el anterior artículo.

playbooks_portada

Un playbook no es más que un fichero que contiene las ordenes correspondientes que queremos enviar a todos los nodos; ordenes que se irían ejecutando secuencialmente según hallamos escrito en el fichero. Dicho playbook, estará escrito en lenguaje YMAL y tendrá una extensión .yml. La lógica es parecida a la seguida con las ordenes y los módulos usados en el anterior apartado, pero con más opciones y con la posibilidad de crear un conjunto de ordenes de forma estructurada y ordenada. La mejor forma de entenderlo es con un pequeño ejemplo inicial. Para ello, para tener todo bien organizado, vamos a crear un directorio llamado PLAYBOOKS dentro de /etc/ansible y dentro de dicho directorio vamos a crear un fichero llamado master.yml.
mkdir /etc/ansible/PLAYBOOKS
touch /etc/ansible/PLAYBOOKS/master.yml
Dicho fichero tendrá el contenido de a continuación:

---
#Este es el playbook maestro
- hosts: all
  remote_user: root
  tasks:
  - name: Asegurarse que NTP esta en marcha
    service: name=ntp state=started enabled=yes
...

Puede parecer complicado, pero si lo desgranamos, veremos que es muy sencillo:

  • Los primeros tres guiones indican el comienzo del fichero. Todo fichero YMAL debe llevarlo para que Ansible pueda leerlo correctamente.
  • Cualquier línea que comience con una # será considerado un comentario, tal y como ocurre en los scripts de bash.
  • Después comenzaremos con la primera sección de todas, que sería de a qué grupo (especificado previamente dentro del fichero /etc/ansible/hosts) queremos hacer referencia. Allí podemos poner el nombre de un grupo que hayamos creado o, en caso de quererlo, decir que se envíen a todas las IPs y hosts que aparezcan dentro del fichero. En nuestro caso hemos optado por dicha opción, lo cual se representa mediante - hosts: all. Es muy importante comenzar con dicho - pues marcaría el inicio de las acciones y reglas dirigidas a dicho grupo.
  • Tras decir eso, habría que decir a qué usuario remoto nos queremos conectar. Aquí podemos escoger el que queramos, pero en mi caso, ya que he preparado el usuario root del otro equipo para poder conectarme directamente a él sin contraseña alguna, optaré por usar dicho usuario.
  • Ahora habría que pasar a la parte de las tareas... Dichas tareas se definen mediante, el nombre tasks: y después debajo de éste empezaríamos a mencionar las tareas una por una; tareas que siempre empezarían con un -.
  • Toda tarea está compuesta por, cómo mínimo, 2 partes. La primera parte sería meramente informativa. Se pondría un nombre descriptivo que nos mostraría Ansible antes de ejecutar la tarea. Dicho nombre se especificaría mediante - name. La segunda parte sería la tarea a ejecutar, que constaría de: Módulo: argumentos. En este caso hemos usado el módulo service, y los argumentos usados serían name, state y enabled. Se pueden poner tantas tareas como se quieran, siempre y cuando se siga la misma estructura que la que acabo de mencionar.
  • Por último, siempre al final de cada playbook habría que escribir tres puntos.

Este ejemplo es muy sencillo y puede evolucionar a mucho más, poniendo diferentes hosts y tareas, pero sirve de buena base introductoria... Para ejecutar dicho playbook, simplemente habría que escribir el comando:
ansible-playbook /etc/ansible/PLAYBOOKS/master.yml
El contenido del playbook, al hacer referencia a una única tarea, sería lo equivalente al siguiente comando de Ansible:
ansible all -m service -a \
"name=ntp state=started enabled=yes"
Vamos a poner un ejemplo más completo en esta ocasión; supongamos que queramos asegurarnos de que el servicio NTP tenga la última versión; además también vamos a verificar que el servicio Asterisk está en marcha. Por otro lado vamos a crear una tarea exclusiva para el grupo llamado PRUEBAS; una tarea que consistirá en revisar que tenemos la última versión del paquete apache2. Al final sería aplicara los mismos conceptos que hemos visto arriba, pero de forma un poco más amplia, dejando el fichero con el siguiente aspecto:

---
#Este es el playbook maestro

#Reglas para todos los hosts
- hosts: all
  remote_user: root
  tasks:
  - name: Asegurarse que NTP esta en marcha
    service: name=ntp state=started enabled=yes
  - name: Verificar ultima version NTP
    apt: name=ntp state=latest
  - name: Asegurarse que Asterisk esta en marcha
    service: name=asterisk state=started enabled=yes

# Reglas para el grupo PRUEBAS
- hosts: PRUEBAS
  remote_user: root
  tasks:
  - name: Verificar ultima version Apache2
    service: name=apache2 state=started enabled=yes
...

Como podéis ver siempre mantendrá la misma lógica... Es decir primero irían los hosts de destino, luego el usuario con el que queremos hacer las acciones y por último las tareas a realizar.

Una característica muy interesante que podemos aprovechar en los playbooks, es el uso de handlers. Un handler es una tarea que se ejecuta únicamente en caso de que una tarea concreta (especificada por nosotros) haya realizado un cambio de estado. Por ejemplo si tuviésemos un handler preparado para cuando hubiese un cambio de estado en Apache2, y una tarea que se asegurase de que apache2 tuviese la última versión, en caso de que Apache2 no la tuviese, el handler se ejecutaría. Veamos un ejemplo usando como referencia el mencionado Apache2:

---
#Este es el playbook maestro
- hosts: all
  remote_user: root
  tasks:
  - name: Verificar ultima version Apache2
    apt: name=apache2 state=latest
    notify: "Reiniciar Apache2"
  handlers:
  - name: Reiniciar apache si es necesario
    service: name=apache2 state=restarted
    listen: "Reiniciar Apache2"
...

Como podéis observar, el handler está a la escucha de que le llegue una notificación; notificación que enviaríamos desde la tarea de verificación de la última versión de Apache2. Con lo que siempre que trabajásemos con handlers, trabajaríamos de la misma forma que con las tareas, pero con la diferencia de que desde la tarea tendríamos que notificar al handler mediante un notify, y desde el handler tendríamos que escuchar a que nos llegase una notificación concreta mediante un listen.

Gracias a las tareas (tasks) y handlers, podemos realizar playbooks muy completos donde podemos agrupar una enorme cantidad de tareas y handlers para luego así llamarlos a todos a la vez; ahorrándonos tener que escribir los comandos uno a uno para cada tarea que queramos realizar, haciendo que nos ahorremos muchísimo tiempo una vez tengamos todas las tareas correctamente definidas. Aún así, a nivel de gestión, el tener todas las tareas y handlers en un solo playbook puede ser una locura a nivel de mantenimiento... Cuando son pocas tareas y servicios no pasa nada, pero y si queremos gestionar 50 servicios, con diferentes grupos, handlers, etc... Técnicamente al agruparlo todo en un solo playbook es perfectamente viable, pero a nivel mantenerlo en el tiempo puede ser realmente costoso, especialmente si se quieren hacer cambios en el futuro... Es por ello que lo ideal es tener un playbook maestro y que este vaya llamando a diferentes playbooks dependiendo de las tareas que se quieran realizar. La llamada a dichos playbooks desde el playbook maestro se realiza mediante la sentencia include, y podemos crear una estructura perfectamente definida para que con el paso del tiempo se pueda mantener sin demasiados problemas.

Vamos a suponer que queremos poner un firewall para todos los equipos; un firewall común que todos van a tener; además también vamos a verificar que tanto Mysql como Apache2 están en marcha, pues tenemos un servidor web; por otro lado también verificaremos qué Asterisk tiene la última versión y que en dicho caso lo reiniciaremos. Estas tareas se podrían considerar como diferentes entre sí y por ello lo suyo sería tener: El playbook maestro, un playbook para el firewall, otro playbook para el apartado web y otro más para Asterisk. Comencemos con el aspecto del playbook maestro, master.yml:

---
#Este es el playbook maestro
- hosts: all
  remote_user: root
  tasks:
  - include: /etc/ansible/PLAYBOOKS/Firewall.yml
  - include: /etc/ansible/PLAYBOOKS/Web.yml
  - include: /etc/ansible/PLAYBOOKS/Asterisk.yml
  handlers:
  - include: /etc/ansible/HANDLERS/Firewall_handler.yml
  - include: /etc/ansible/HANDLERS/Web_handler.yml
  - include: /etc/ansible/HANDLERS/Asterisk_handler.yml
...

Como podéis ver todo queda alojado en ficheros separados, tanto las tareas como los handlers; handlers que como podéis ver se alojarían en otro directorio llamado /etc/ansible/HANDLERS/. Estos ficheros tendrían una ligera variación con respecto a lo que hemos visto hasta ahora, pues a diferencia de un playbook "normal", en estos no haría falta ponerles las etiquetas, solamente las tareas a realizar, pues ya estarían asignadas previamente por el master.yml. Veamos por ejemplo el contenido de uno de los playbooks de tareas; concretamente el contenido del fichero Firewall.yml que posee un módulo que no hemos visto hasta ahora; el módulo copy en el que copiaremos un fichero desde nuestro controlador al resto de nodos.

---
#ESTE ES EL PLAYBOOK DEL FIREWALL
- name: COPIAR IPTABLES DEL CONTROLADOR A LOS NODOS
  copy: src=/usr/src/iptables.sh dest=/etc/init.d/iptables.sh
  notify: "CORTAFUEGOS"
...

Como veis directamente empezaríamos con el - name; sin mencionar los hosts, ni el usuario remoto, ni el hecho de que es una tarea y no un handler, pues todo eso ya ha sido especificado por el anterior playbook. En este caso lo que hacemos simplemente es copiar un fichero desde la máquina controladora al resto de equipos y que en caso de que haya una diferencia entre el iptables.sh del equipo controlador y el del nodo, mande un notify llamado "CORTAFUEGOS". Obviamente si el fichero iptables.sh no existiese en el nodo, también mandaría dicho notify.

El proceso de llamamiento de un handler mediante un include no difiere apenas con el realizado con las tareas. Buen ejemplo de ello sería el handler Firewall_handler.yml que estaría relacionado con la tarea arriba mostrada; en este caso usaremos otro módulo nuevo llamado file, capaz de modificar los permisos de un fichero para que sea ejecutable:

---
#HANDLERS FIREWALL
- name: Dar permisos firewall
  file: dest=/etc/init.d/iptables.sh mode=755 state=touch
  listen: "CORTAFUEGOS"
- name: Arrancar cortafuegos
  shell: /etc/init.d/iptables.sh start
  listen: "CORTAFUEGOS"
...

En este caso el handler lo primero que haría sería darle los permisos de ejecución necesarios al nuevo script para luego ejecutarlo. El contenido del cortafuegos no es algo relevante para este ejemplo, pero a modo de prueba podría ser algo como lo siguiente:


#!/bin/bash
case "$1" in
        start)
                iptables -F
                iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
                iptables -A INPUT -m state --state NEW -j DROP
                iptables -A OUTPUT -j ACCEPT
        ;;
        stop)
                iptables -F
        ;;
esac

Con esto ya tendríamos el firewall controlado y simplemente siguiendo las mismas pautas se podría hacer exactamente lo mismo para la gestión de tanto la parte Web como Asterisk, pues la base sería la misma que la que hemos estado usando hasta ahora.

Gracias a lo que hemos visto en este artículo, tendríamos un dominio básico de los playbooks gracias al cual podríamos realizar la mayoría de las gestiones necesarias para controlar un grupo de servidores... De aquí en adelante solo sería profundizar conceptos y jugar con los diferentes módulos de Ansible, con el fin de tener los playbooks más óptimos posibles.

Espero que os haya resultado útil.

Saludos.

viernes, 2 de junio de 2017

Cómo crear una autenticación básica en Apache2

Los servidores web están a la orden del día y son cada vez más usados en todo el mundo, ya sea para una web corporativa, una herramienta online o un blog... Existen multitud de servidores webs que pueden alojar dichas páginas, pero sin lugar a duda hay uno de ellos que destaca entre el resto por su popularidad; popularidad que si bien hoy en día ha bajado un poco debido a Nginx, sigue siendo muy alta: Apache2. A veces necesitamos que poner pequeñas restricciones a nuestra página web; restricciones que no guarden cosas de demasiada importancia, pero que tampoco queremos que estén accesibles a todo el mundo... Es por eso que vamos a ver cómo crear una autenticación básica para páginas web alojadas en un servidor Apache2.


APACHE2_LOGO


Obviamente, habría que tener que Apache2 instalado primero (en caso de no tenerlo ya instalado) lo cual afortunadamente es extremadamente sencillo gracias a que el paquete se encuentra incluido entre los repositorios oficiales.

apt-get install apache2

Este proceso es puramente automático con lo que para que Apache2 funcione en sí, no habría que hacer nada más y podemos usar la página de prueba que la instalación ofrece por defecto para comprobar el correcto funcionamiento de nuestra autenticación. Ahora tocaría crear un fichero de autenticación que valide el/los usuarios que nosotros queramos; dicho fichero puede ser almacenado en cualquier parte, pero lo recomendable es que se encuentre dentro del directorio /etc/apache2; El comando que crearía el fichero de autenticación sería htpasswd y si deseásemos que se autenticase a un usuario llamado ivan, haríamos:

htpasswd -c /etc/apache2/.htpasswd ivan

Al introducir el comando nos pediría contraseña, contraseña que tendremos que utilizar más adelante para autenticarnos al acceder nuestra página web, con lo que es conveniente recordarla. Si deseásemos añadir más usuarios a dicho fichero, tendríamos que usar el mismo comando pero sin el parámetro -c; es decir que por ejemplo para añadir el usuario invitado, haríamos:

htpasswd /etc/apache2/.htpasswd invitado

Se pueden añadir tantos usuarios como queramos hasta que cubramos nuestras necesidades. Una vez hayamos preparado todos los usuarios, tendremos que editar el host virtual de Apache2 para que requiera de autenticación antes de acceder la web... El host virtual por defecto se configura en el fichero /etc/apache2/sites-enabled/000-default.conf, y ese será el fichero que editaremos para que tenga el aspecto de a continuación:

  1. <VirtualHost *:80>
  2.         ServerAdmin webmaster@localhost
  3.         DocumentRoot /var/www/html
  4.         <Directory "/var/www/html">
  5.             AuthType Basic
  6.             AuthName "Es necesario autenticarse"
  7.             AuthUserFile /etc/apache2/.htpasswd
  8.             Require valid-user
  9.         </Directory>
  10.         ErrorLog ${APACHE_LOG_DIR}/error.log
  11.         CustomLog ${APACHE_LOG_DIR}/access.log combined
  12.         RewriteEngine on
  13.         RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,QSA,R=permanent]
  14. </VirtualHost>

La parte marcada en rojo sería la parte añadida, pero es importante tener controlado todo el contenido del fichero en sí con el fin de que no quede ningún parámetro suelto.

Luego únicamente tendremos que reiniciar el servicio web para aplicar los cambios:

/etc/init.d/apache2 restart

Tras el reinicio solamente quedaría pasar a probar dicha autenticación, cosa tan simple como acceder a la web normalmente... En dicho momento, antes de poder ver nada, veremos una pantalla de login en el navegador en el que se nos pedirá la contraseña:

Contraseña_web

Con tan solo introducir las credenciales correctas, accederíamos a la web con normalidad, habiendo conseguido un proceso de autenticación web práctico y sencillo; obviamente este método es bastante rudimentario, pero al menos nos serviría para tener unas políticas de seguridad básicas.

Espero que os haya resultado útil.

Saludos.

martes, 29 de noviembre de 2016

Cómo crear nuestros propios repositorios en Debian

Los repositorios tienen un valor incalculable en cualquier sistema Linux; especialmente en aquellos servidores en los que queremos tener las últimas actualizaciones de seguridad. Lo más normal es que no haya impedimento alguno para usar éstos, pero que sea lo más normal no implica que tenga que ocurrir siempre, ya sea debido a políticas de seguridad , a que el repositorio está caído o a que simplemente el equipo no tiene acceso a Internet... La ausencia de este recurso puede resultar fatal en muchos casos, con lo que es bueno contar siempre con un recurso que nos ayude a evadir ese escollo; un recurso que si bien a nivel doméstico no es muy práctico, es perfectamente aplicable en entornos empresariales o en entornos en los que hayan servidores.  Se trataría de tener estos repositorios almacenados en un equipo nuestro al cual sí que sería fácil acceder por el resto de equipos que estén dentro de la misma red; es decir, de tener estos repositorios en local. En este caso veríamos un caso aplicado a Debian, pero para sistemas parecidos tales como Ubuntu no deberíais experimentar problema alguno.

Debian_portada

Esta operación la única "pega" que puede llegar a tener es el hecho de que es necesario tener abundante espacio libre en el disco duro, pero quitando ese detalle, puede sernos una solución realmente útil, con lo que vamos a ello.

Para crear este repositorio, necesitaremos tener dos herramientas instaladas; una de ellas, muy conocida por muchos, sería apache2, mientras que la otra que es bastante menos conocida, sería apt-mirror, con lo que lo primero que haremos será instalarlos desde los repositorios oficiales del sistema (que todavía no serían locales) tal y como hacemos habitualmente.

apt-get install apache2 apt-mirror

La instalación es automática, si bien está instalación no hace que tengamos automáticamente los repositorios en local... Lo primero que necesitamos hacer es bajarnos toda la información, paquetes y otros datos de los repositorios que nosotros queramos en local, si bien para ello lo primero que habría que hacer sería configurar el archivo de configuración de apt-mirror, que se encontraría en /etc/apt/mirror.list. El fichero estaría compuesta por tres secciones: Configuración, repositorios a obtener, repositorios a limpiar. La parte más importante sería la de configuración, ya que es la que determina donde guardar los repositorios, la arquitectura en la que queremos que se descarguen los repositorios, etc... Un fichero de configuración real basado en un Debian 8 con arquitectura amd64 sería el siguiente:

  1. ############# config ##################
  2. #
  3.  set base_path    /var/spool/apt-mirror
  4. #
  5.  set mirror_path  $base_path/mirror
  6.  set skel_path    $base_path/skel
  7.  set var_path     $base_path/var
  8. # set cleanscript $var_path/clean.sh
  9. set defaultarch amd64
  10. # set postmirror_script $var_path/postmirror.sh
  11. # set run_postmirror 0
  12. set nthreads     20
  13. set _tilde 0
  14. #
  15. ############# end config ##############
  16. deb http://ftp.es.debian.org/debian/ jessie main contrib non-free
  17. deb-src http://ftp.es.debian.org/debian/ jessie main contrib non-free
  18. deb http://ftp.es.debian.org/debian/ jessie-updates main contrib non-free
  19. deb-src http://ftp.es.debian.org/debian/ jessie-updates main contrib non-free
  20. clean http://ftp.es.debian.org/debian

Gracias a esta configuración podríamos descargarnos los repositorios "estándar" de Debian 8 (Jessie) dentro del directorio /var/spool/apt-mirror, dentro del cual habrían tres carpetas: La carpeta mirror, la carpeta skel y la carpeta var.

Con los cambios guardados, únicamente habría que ejecutar el comando:

apt-mirror

Este comando hará que se creen las carpetas mirror, skel y var dentro del directorio /var/spool/apt-mirror y que se descargue toda la información de los repositorios en éstos; y al decir toda sería TODA. Es decir que nos estaríamos descargando la información necesaria para que nuestro equipo se pueda convertir en un repositorio.

El tamaño de la información descargada variaría dependiendo de la cantidad de repositorios que nos queramos descargar, pero por ejemplo, en mi caso en particular la descarga sería de 47 GB; una descarga que tomará MUCHO tiempo. También podríamos escoger menos repositorios con el fin de que sea de menor tamaño, pero a nivel conceptual este sería el proceso. Imaginemos que tenemos descargado todo el contenido... Éste estaría descargado, pero eso no significaría que fuese accesible por el resto de equipos; de ahí la necesidad de tener apache2 instalado. Ahora mismo el directorio /var/spool/apt-mirror/mirror tendría que tener la siguiente estructura en su interior:

Arbol_directorios

Queremos ser capaces de acceder vía web a los repositorios, tal y como haríamos con un repositorio real, pero en una red local... Con lo que tendríamos que hacer que dicho contenido pueda ser accedido desde la carpeta /var/www; mover el contenido a dicha carpeta sería engorroso y además cualquier futura actualización se bajaría de nuevo dentro del directorio /var/spool/apt-mirror, con lo que lo más limpio y práctico sería realizar un enlace simbólico desde /var/www a los directorios deseados; que en este caso sería únicamente el directorio Debian con lo que el enlace simbólico que haríamos sería el siguiente:

ln -s /var/spool/apt-mirror/mirror/ftp.es.debian.org/debian/ /var/www/debian

Ahora, para acceder a los repositorios de esta máquina, supongamos que ésta tiene la ip 192.168.1.10, para acceder a los repositorios de aquí en la red local, pondríamos estas líneas dentro del fichero /etc/apt/sources.list


  1. deb http://192.168.1.10/debian/ jessie main contrib non-free
  2. deb-src http://192.168.1.10/debian/ jessie main contrib non-free
  3. deb http://192.168.1.10/debian/ jessie-updates main contrib non-free
  4. deb-src http://192.168.1.10/debian/ jessie-updates main contrib non-free

Con esto podríamos acceder a unos repositorios que se hallen en la red local sin necesidad de acceder a Intenet.

Espero que os haya resultado útil.

Saludos.