Bash: Control de errores y debug

Recientemente hablamos acerca de las diferencias de usar /bin/bash o /usr/bin/env bash. No suele ser algo muy habitual, pero puede resultar de gran ayuda.
Hoy vamos a ver otro de esos pequeños trucos de bash, pero que puede resultar de gran ayuda. Estamos hablando del control de errores y de habilitar el modo debug.
Como suele ser habitual es los script en bash, tras inicializar el entorno, se suele poner el comando 'set -e', abreviatura de 'set -o errexit'.
#!/usr/bin/env bash
set -e

# Código bash a ejecutar...
En caso de que durante la ejecución del script aparezca algún error, inmediatamente detendrá la ejecución del script.

El método antes comentando suele ser útil para scripts de producción, donde se presupone que no van a existir errores y por lo tanto no es necesario saber exactamente lo que pasa. Sin embargo, cuando estamos escribiendo código, sí puede resultar muy útil tener habilitado el modo debug. Para eso, 'set -x' es la solución.
#!/usr/bin/env bash
set -x

# Código bash a ejecutar...

Nota: 'set -x' en el script es lo mismo que 'bash -x tu_script'.
Leer más

MySQL, rotado de slow logs

Hace un tiempo publicamos una entrada acerca de cómo activar el log de Slow Query's para MySQL. Esta práctica suele ser bastante habitual y recomendada. Si una query tarda mucho en ejecutarse puede comprometer todo el rendimiento del sistema. Así que mejor saber cual es, para poder solucionarla (si es posible).
El detalle que nos trae a cuenta es que este log, al final es un fichero de texto con muchas entradas, pero que crece de forma indefinida y cada vez ocupa más o más espacio. Para evitar que crezca de forma descontrolada, lo que debemos hacer es rotarlo. Para hacer esta tarea, los sistemas GNU/Linux emplean logrotate.
Logrotate tiene dos técnicas de rotación,
  • copytruncate, copia el fichero a uno nuevo y luego lo trunca.
  • no copytruncate, emplea la función rename del sistema para mover el fichero a uno nuevo. Luego el daemon que escribe necesita recibir la señal de reopen.
El problema que tenemos es que truncar el fichero de logs de MySQL puede hacer que éste se bloquee y cambiar el nombre del fichero y reiniciar el servicio, no siempre es posible, ya que dejaríamos el sistema por un tiempo sin servicio. Puede no ser mucho, pero suficiente. Para solucionar este problema, desde el blog de Percona ofrecen una solución. Lo primero es crear el fichero de configuración en logrotate (mysql-slow).
/var/log/mysql/slow_query.log {
   nocompress
   create 660 mysql mysql
   size 1G
   dateext
   missingok
   notifempty
   sharedscripts
   postrotate
      mysql -u logrotate -ppasswd -e 'select @@global.long_query_time into @lqt_save; set global long_query_time=2000; select sleep(2); FLUSH LOGS; select sleep(2); set global long_query_time=@lqt_save;'
   endscript
   rotate 150
A diferencia del código original, nosotros vamos a configurar un usuario que tenga acceso restringido al servicio MySQL para poder hacer las operaciones que necesita. El usuario será logrotate,
mysql> CREATE USER 'logrotate'@'localhost' IDENTIFIED BY 'passwd';
mysql> GRANT select,file,super,reload ON *.* TO 'logrotate'@'localhost';
La idea de crear este usuario es para evitar problemas de seguridad de acceder con root o tener el sistema sin contraseña para localhost.
Con el usuario ya creado, probamos si el fichero de configuración de logrotate funciona. Para ello,
shell> logrotate -vf /etc/logrotate.d/mysql-slow
Si no hay fallos, el fichero de logs se rotará de forma automatizada.
Leer más

/bin/bash vs. /usr/bin/env bash

Cuando estamos programando un script en bash siempre solemos inicializarlo con la línea que indica que es eso, un script en bash. Esta línea a mayores nos indica el path del intérprete. Por norma general, suele ser siempre /bin/bash/usr/bin/bash. Este "o" es el que puede causarnos algunos problemas. Para evitarlo, podemos emplear el siguiente truco: llamar a la función de enviroment. Es decir, pasamos de comenzar el script típico,
#!/bin/bash

# Código bash a ejecutar...
A usar las variables de entorno, para que sea ésta la que localice el path exacto donde está bash.
#!/usr/bin/env bash

# Código bash a ejecutar...
Con esto lo que conseguimos es hacer el script más flexible y adaptable a otros entornos donde quizás bash no esté en la misma ruta.
Leer más

Backups incrementales con tar

Sí, es cierto, hacía tiempo que no escribía nada en el blog y eso no puede ser. Después de un tiempo de parón, espero volver a ser más constante en las entradas.
En este caso, vamos a ver un método de hacer un backup incremental, pero sin ningún software adicional, sino empleando el comando tar.
La importancia de realizar backups no hace falta que la comente, pues es un tema muy sabido por todos. El método típico de hacer backup con tar, es comprimir todos los ficheros que así desees en un contenedor y darle un nombre, por ejemplo, una fecha. Si todos los finales de día lo hacemos, tenemos un backup bastante consistente y ante posibles fallos. El único problema, que ocupará mucho espacio! Para resolver este problema está el backup incremental y tar, como no podía ser de otra manera, también lo soporta. A continuación, dejo un ejemplo de cómo se debería de emplear tar para la realización de un backup incremental.
  • Crear el entorno de pruebas
    shell> mkdir -p test/aa test/bb test/cc
    shell> touch test/aa/a test/bb/b test/cc/c
    
  • Realizar el primer backup
    Importante aquí, la opción que le pasamos --listed-incremental file.
    shell> tar --listed-incremental test.metadata \
               -czf test.tar.gz test
    
  • Borrar y cambiar ficheros
    shell> rm test/aa/a
    shell> touch test/aa/aa
    shell> echo "hola" > test/bb/b
    
  • Volver a lanzar el backup incremental
    Cada incremental lo vamos añadiendo a un nuevo contenedor.
    shell> tar --listed-incremental test.metadata \
               -czf test.inc1.tar.gz test
    
  • Restaurar ficheros
    Para ello, necesitamos el fichero de backup completo y también los incrementales
    shell> mkdir restore
    shell> tar xzf test.tar.gz -C restore
    shell> tar --incremental \
               -xzf test.inc1.tar.gz -C restore
    
Como podemos apreciar que ha añadido el fichero creado pero también borrado el fichero eliminado en el momento de hacer el incremental. Espero que os haya resultado útil.
Como ya sabréis, realizar backups al mismo disco no es una buena idea, por lo que si no lo conoces, te recomiendo la lectura del tag bacula, que quizás te ayude a tener un backup más seguro.
Leer más

Grabación de sesiones de consola

No fui el primero, ni seré el último en preguntarse cómo grabar todo lo que estás haciendo en la consola de tu equipo Linux, par a continuación poder dejarlo a libre disposición.
hasta que conocí el software del que os voy a hablar hoy, la forma que tenía de hacerlo no era más que la de grabar toda la pantalla (o una región) y dejar luego el vídeo, por ejemplo en Youtube.
Pues bien, ahora ya no podrás decir que no conoces ttyrec, con el que podrás grabar todo el comportamiento de tu consola de una forma más limpia y rápida.

Instalación

ttyrec está disponible en prácticamente todos los repositorios oficiales de las principales distribuciones, así que para instalarlo,
shell> apt-get install ttyrec

Grabar

Comenzar una nueva sesión o grabación es muy sencillo. Únicamente tendremos que saber el nombre que le vamos a querer dar y a continuación,
shell> ttyrec -a git_usage.tty
Para pararla, emplearemos Control + c.

Reproducir

Una vez tengamos la grabación finalizada, tendremos un fichero que podemos reproducir las veces que queramos, únicamente tendremos que tener instalado ttyplay, que viene con el paquete ttyrec.
shell> ttyplay git_usage.tty
Por suerte, este tipo de ficheros, al almacenar texto plano ocupan muy poco, por lo que pasárselos a alguien es sencillo y no debería de darnos problema. De todas formas existen webs, como playterm.org que nos permiten subir el fichero e incrustarlo en una web o dejarlo público.

Referencias

Leer más

Preguntando a servidores NTP

NTP es el protocolo de red empleado para la sincronización horaria. Eso significa que gracias a él, todos los equipos conectados a Internet (Windows, Linux, MacOX, router's, etc.) pueden tener la misma hora en todo momento. Aunque a nivel de usuario tener un desfase de dos minutos pueda no ser un problema, a nivel de servidores sí lo puede ser. Ahí la importancia de NTP.
Para GNU/Linux, existen paquetes y daemons que se encargan de realizar dicha sincronización horaria, como son ntp o ntpdate. Y estos puede trabajar de forma automática o manual. La mejor opción, es sin duda la primer, puesto que así el equipo sincronizará cuando él crea oportuno la hora y la mantendrá sincronizada en todo momento.
En caso de que deseemos ejecutarlo de forma manual, esto se puede realizar tal que así,
shell> ntpdate 0.debian.pool.ntp.org
13 Apr 21:52:52 ntpdate[6240]: adjust time server 217.130.246.182 offset -0.003814 sec
NTP también incluye una serie de comandos más especializados y que permiten consultar diferentes parámetros al servidor de sincronización para comprobar el estado del mismo. A continuación, vamos a detallar los más interesantes.
  • Servidores conocidos de uno dado
    shell> ntpq -p 0.debian.pool.ntp.org
    remote             refid          st   t  when   poll reach    delay   offset  jitter
    =====================================================================================
    *hora.rediris.es   .GPS.           1   u   329   1024   373   18.034   -3.620   0.039
    +hora.roa.es       .GPS.           1   u   358   1024   377   48.219   -0.635   1.447
    -time.euro.apple   17.72.133.54    2   u   261   1024   333   65.669   -7.850   0.611
    -gong.ci.uv.es     147.156.1.135   2   u   273   1024   377   19.429   -4.927   0.489
    +sigrid.fi.upm.e   138.100.8.3     2   u   281   1024   333   19.523   -3.134   0.419
    
    shell> ntpdc -c dmpeers 0.debian.pool.ntp.org
    remote             local           st   poll reach     delay      offset      disp
    ==================================================================================
    alarich.online-    138.100.11.74   13   1024   377   0.05843   -0.002360   0.12178
    .clock.via.net     138.100.11.74    1   1024   377   0.17661   -0.000670   0.12183
    ntp1.inrim.it      138.100.11.74    1   1024    40   0.03572   -0.000021   2.82416
    .hora.rediris.es   138.100.11.74    1   1024   377   0.00192   -0.000933   0.13663
    hora.roa.es        138.100.11.74    1   1024   377   0.01936   -0.002820   0.13661
    *time.nist.gov     138.100.11.74    1   1024   377   0.16463    0.000173   0.12178
    ntp.nic.cz         138.100.11.74    2   1024   377   0.03534   -0.001691   0.12175
    
  • Información del daemon
    shell> ntpdc -c loopinfo hora.rediris.es
    offset:               -0.120317 s
    frequency:            21.885 ppm
    poll adjust:          -30
    watchdog timer:       24 s
    
  • Márgenes de fallo de los servidores
    shell> ntpdc -c kerninfo hora.rediris.es
    pll offset:           -2.46e-07 s
    pll frequency:        21.953 ppm
    maximum error:        0.121131 s
    estimated error:      2.7e-05 s
    status:               2107  pll ppsfreq ppstime ppssignal nano
    pll time constant:    4
    precision:            8.56e-07 s
    frequency tolerance:  496 ppm
    pps frequency:        21.953 ppm
    pps stability:        0.123 ppm
    pps jitter:           1.159e-06 s
    calibration interval: 16 s
    calibration cycles:   4135711
    jitter exceeded:      432403
    stability exceeded:   74355
    calibration errors:   26
    
Leer más

Opciones de privacidad en Firefox

Hoy os quiero enseñar unos pequeños trucos para Firefox que nos permitirán gestionar un poco mejor nuestra privacidad en Internet. Aunque vas a dejar rastro por donde pases, cuanto menos dejes mejor. Si eres usuario de Firefox esta es tu entrada y si conoces a alguien que lo sea, comparte la entrada.
Por supuesto, todo lo que vamos a ver se gestiona desde las variables de configuración, y para acceder a ellas nada mejor que visitar about:config. Aparecerá un aviso como el que sigue, pero no os asustéis, no sois manazas ;-)
Cuando hayáis accedido, tener presente que vamos a hablar mucho acerca de variables, por lo que fijaros que en la parte de arriba hay un buscador que os simplificará la vida. Así que vamos a ello.
  • Desactivar restauración de sesión
    Una de las cosas más peligrosas que tiene el navegador es que está guardando la sesión cada 10 segundos aproximadamente. Aparte de la carga de I/O que supone, también implica que en caso de que el ordenador se reinicie y no seas tú el que vuelva a abrir el navegador, éste restaurará tu sesión, pestañas, cookies, etc.
    Puesto que no nos interesa que nadie sepa dónde anduvimos navegando ni entre en nuestro correo, lo desactivamos estableciendo a false la variable
    browser.sessionstore.resume_from_crash
  • Eliminar useragent
    Todos los navegadores dejan una huella en todos los servidores identificándose y dando información que no tienen por qué dejar. Para evitarlo, editamos (o creamos la variable)
    general.useragent.override
    
    Y establecemos el valor que más nos guste para dejar nuestra "huella" en la web.
  • Desactivar autocompletado de URLs
    No queremos que el navegador nos ayude a "recordar" las páginas que hemos visitado, por razones obvias de privacidad, así que desactivamos (valor false) el autocompletado de URLs.
    browser.urlbar.autofill
    browser.urlbar.autofill.typed
    
  • Desactivar autocompletado de búsquedas
    Cuando buscamos, todo esto se queda almacenado en el navegador y cuando comenzamos a escribir una nueva búsqueda no autocompleta con cosas que ya hemos buscado. Puesto que no nos interesa que nadie sepa lo que buscamos, establecemos el valor -1 a la variable,
    browser.urlbar.maxRichResults
    
Leer más

PHP-FPM en socket y no TCP

Con la cada vez más rápida implantación y adaptación de php-fpm como servidor de compilación para ficheros tipo PHP, se abre un amplio abanico de posibilidades a la hora de trabajar y escalar sistemas web. En típico sistema Nginx + PHP, todo en la misma máquina ya queda obsoleto y ahora podemos pasar a un sistema con cada uno de los componentes separados en distintas máquinas y por lo tanto escalables. Esto quedará para otra entrada...
Hoy vamos a ver cómo crear una configuración de php-fpm por un socket unix tradicional y no desde una conexión TCP, como suele aparecer en casi todos los lugares. Las ventajas de emplear el socket y no TCP es que trabajando a nivel de localhost no es necesario y nos evitamos la carga innecesaria de la creación de las nuevas conexiones cada vez que se compila un código PHP. Mejoramos en rendimiento y también en seguridad, pues no hay ningún servicio ni ningún puerto abierto, aunque sea a localhost.
Para hacer este cambio y por lo tanto aprovechar esta mejora de rendimiento, podemos hacer lo siguiente,
  1. Editar /etc/php5/fpm/php-fpm.conf y aplicar el siguiente cambio,
    - listen = 127.0.0.1:9000
    + listen = /var/run/php5-fpm.sock
    
  2. Editar el fichero del virtualhost /etc/nginx/conf.d/domain.conf y aplicar el siguiente cambio,
    -fastcgi_pass   127.0.0.1:9000;
    +fastcgi_pass   unix:/var/run/php5-fpm.sock;
    
  3. Reiniciar servicios
    shell> service php-fpm restart
    shell> service nginx restart
Leer más

Red Hat, instalar versión de un paquete

Hoy toca enseñar un pequeño truco acerca de cómo instalar una versión concreta de un paquete en sistemas Red Hat. En la mayoría de los repositorios, los mantenedores van sacando nuevas versiones y aunque puede resultar muy útil tener siempre la última versión instalada (seguridad, estabilidad, etc.) puede darse el caso de que necesites una versión concreta de un paquete para una determinada prueba. En este caso, la forma de instalarlo ya no es la de siempre,
shell> yum install openssh-server
Sino que hay que saber qué versión del paquete necesitas instalar y pasársela al instalador.
Para empezar, vamos a ver el listado de paquetes disponibles en el repositorio y con su correspondiente versión.
shell> yum --showduplicates list openssh-server
Paquetes disponibles
openssh-server.x86_64   5.3p1-104.el6       base
openssh-server.x86_64   5.3p1-104.el6_6.1   updates
Y de ahí, podemos optar por instalar el paquete que deseemos, tal que así
shell> yum install package-version
Que traducido a un caso concreto, quedaría,
shell> yum install openssh-server-5.3p1-104.el6
Espero que os haya sido de ayuda.
Leer más

Link vmlinuz.old is damaged

Pues bien, hoy es uno de esos días en los que te pones a actualizar un equipo y te das cuenta de que queda poco espacio en la partición raíz. Investigando un poco más, observas que hay muchas versiones del kernel instaladas, pero que en realidad no se están empleando para nada, por lo que decides hacer limpieza. Concretamente, éste es el caso,

shell> dpkg -l |grep linux-image
ii linux-image-3.2.0-29-generic 3.2.0-29.46  Linux kernel...
ii linux-image-3.2.0-60-generic 3.2.0-60.91  Linux kernel...
ii linux-image-3.2.0-68-generic 3.2.0-68.102 Linux kernel...
ii linux-image-3.2.0-69-generic 3.2.0-69.103 Linux kernel...
ii linux-image-3.2.0-70-generic 3.2.0-70.105 Linux kernel...
ii linux-image-3.2.0-74-generic 3.2.0-74.109 Linux kernel...
ii linux-image-3.2.0-75-generic 3.2.0-75.110 Linux kernel...
ii linux-image-3.2.0-77-generic 3.2.0-77.114 Linux kernel...
ii linux-image-3.2.0-79-generic 3.2.0-79.115 Linux kernel...
ii linux-image-generic          3.2.0.79.93  Generic Linux
Como veis, hay algunas versiones del kernel instaladas, y que en realidad no son necesarias, así que vamos a realizar una purga de aquellas que no nos interesen. Lo primero es saber qué versión del mismo estamos usando, no vayamos a desinstalar el kernel que estamos empleando. Para ello,
shell> uname -r
3.2.0-75-generic
No está cargada la última versión y siendo un equipo de producción, reiniciar "por que sí", tampoco es posible, así que vamos a purgar aquellos que no nos interesan, es decir, todos menos la última versión (3.2.0-79) y la que estamos usando (3.2.0-75).
shell> apt-get remove --purge linux-image-3.2.0-29-generic
shell> apt-get remove --purge linux-image-3.2.0-60-generic
shell> apt-get remove --purge linux-image-3.2.0-68-generic
shell> apt-get remove --purge linux-image-3.2.0-69-generic
shell> apt-get remove --purge linux-image-3.2.0-70-generic
shell> apt-get remove --purge linux-image-3.2.0-74-generic
shell> apt-get remove --purge linux-image-3.2.0-77-generic
Y tras ello,
shell> apt-get autoremove --purge
Durante la desinstalación del kernel 3.2.0-77 ha aparecido un curioso error,
shell> apt-get remove --purge linux-image-3.2.0-77-generic
Desinstalando linux-image-3.2.0-77-generic ...
...
The link /vmlinuz.old is a damaged link
Removing symbolic link vmlinuz.old 
 you may need to re-run your boot loader[grub]
Purgando ficheros de configuración de linux-image-3.2.0-77...
...
Donde se nos está indicando que el link al fichero /vmlinuz.old está dañado y que no va a funcionar. Para corregirlo, simplemente debemos de recargar nuestro gestor de carga (en mi caso grub), tal como sigue.
shell> update-grub
Y problema solventado.
Leer más

Samba con full audit + recycle

Hace tiempo hablamos en este blog acerca de cómo habilitar una papelera de reciclaje en Samba y también cómo conseguir un log de auditoría desde Samba. En ambos casos, siempre era necesario emplear la siguiente variable,
vfs objects = recycle
o
vfs objects = full_audit
según lo que nos interesase habilitar. Sin embargo, si nos interesa habilitar ambas cosas, la variable la tenemos que definir tal como sigue,
vfs object = recycle full_audit
Y a continuación el resto de parámetros que nos interese.
Saber cómo definir esta variable de forma conjunta es importante, ya que si incluimos dos líneas, una con cada definición únicamente funcionará la segunda escrita. Así que si necesitas registro de actividad y papelera de reciclaje, tenlo presente.

Referencia

Leer más

Manejo de colas de correo en Postfix

Postfix es un excelente servidor de correo del que ya hemos hablado en este blog en numerosas ocasiones. Además de poder trabajar por su cuenta, también es el motor en Zimbra, del que también se han comentado cosas en numerosas ocasiones.
Como servidor de correo, tiene determinados comandos que pueden resultar muy útiles a la hora de administrar las colas de correo y los mensajes.
  • postqueue
    Es el comando que nos permite administrar directamente la cola de mensajes.
    • -f
      Intenta enviar todos los mensajes que están en las colas.
    • -p
      Muestra todos los mensajes que están en la cola.
    • -s domain
      Intenta enviar todos los mensajes que salgan del 'domain' especificado.
  • postfix
    • flush
      Intenta enviar todos los mensajes del servidor.
    • start | stop | abort
      Arranca, para o para forzosamente el servicio postfix.
    • reload
      Recarga la configuración del servidor de correo.
    • status
      Muestra el estado actual del servicio.
  • postsuper
    • -d ALL
      Elimina todos los mensajes de la cola de correo.
    • -d ALL deferred
      Elimina todos los mensajes 'rebotados' que tenga el servidor.
  • postcat -q ID
    Visualiza el correo con el ID especificado.
  • qshape
    Muestra los correos con forma de árbol.
Por supuesto, estos comandos, como casi todos los comandos GNU/Linux se pueden concatenar y crear combinaciones que nos ayuden y faciliten la administración del servidor de correo.
  • Número de mensajes en la cola de correo
    shell> postqueue -p | tail -n 1 | cut -d ' ' -f5
    
  • Borra todos los mensajes recibidos de un destino
    shell> mailq | grep '^[A-Z0-9]' | grep @domain | \
           cut -f1 -d ' ' | tr -d \* | \
           postsuper -d
    
Leer más

Instalación de Debian a un directorio

El uso de máquinas virtuales para comprobar ciertos cambios en probar cosas es algo ya cada vez más habitual. Sin embargo hay ocasiones en las que puede ser necesario instalar un sistema Debian dentro de un directorio de nuestro sistema para hacer pruebas o realizar instalaciones de otra arquitectura diferente.
Por ejemplo, una máquina con Debian de 64bits puede tener otro sistema de 32bits para hacer ciertas pruebas. Para este tipo de tareas, en Debian es muy sencillo instalar un sistema base dentro de un directorio utilizando la herramienta debootstrap.

Instalación

Lo primero es instalar debootstrap.
shell> apt-get install debootstrap

Uso

Una vez tenemos instalada la utilidad, únicamente debemos de crear el directorio sobre el que instalar la nueva máquina, por ejemplo,
shell> mkdir /data/debian-i386
Y luego emplear debootstrap para crear la nueva instalación
shell> debootstrap \
       --arch=i386 \
       wheezy \
       /mnt/debian-i386/ \
       http://ftp.debian.org/debian/
Este proceso tardará un poco y cuando termine nos mostrará un mensaje de que el proceso terminó correctamente.
I: Base system installed successfully.
Y para emplear el nuevo sistema tendremos ahora que 'conectarnos' con chroot a él.
shell> chroot /mnt/debian-i386
Esta nueva consola que acabamos de abrir es en la máquina Debian instalada. Para salir de él, como en cualquier sistema. La ventaja es que no hay que apagarla y podemos copiar ficheros directamente a él, ya que es un directorio en nuestro sistema real.
Leer más

Fail sudo en Zimbra

Hoy, después de hacer un par de cambios en el fichero de configuración de un servidor Zimbra, comenzaron a salir fallos en el estado de algunos servicios. El realidad, todo estaba funcionando correctamente, pero la salida del comando zmcontrol no daba tranquilidad.
shell> zmcontrol status
Host zimbra.local.net
 antispam                Running
 antivirus               Running
 ldap                    Running
 logger                  Running
[sudo] password for zimbra:
 mailbox                 Running
[sudo] password for zimbra:
 mta                     Running
 opendkim                Running
 snmp                    Running
 spell                   Running
 stats                   Running
 zmconfigd               Running
Como veis, algunos de los servicios se estaban ejecutando correctamente, mientras que para averiguar el estado de otros, se pedía la contraseña del usuario zimbra para sudo.
Tras el susto inicial, pensé qué era lo que había cambiado y efectivamente, algo tenía que ver con el fichero de configuración de sudo (/etc/sudoers).

Cómo solucionarlo

Por suerte, la solución no era demasiado complicada y únicamente requería volver a establecer los permisos necesarios de sudo en el fichero /etc/sudoers, dejándolo con las siguientes líneas.

%zimbra ALL=NOPASSWD:/opt/zimbra/libexec/zmstat-fd *
%zimbra ALL=NOPASSWD:/opt/zimbra/libexec/zmslapd
%zimbra ALL=NOPASSWD:/opt/zimbra/postfix/sbin/postfix, /opt/zimbra/postfix/sbin/postalias, /opt/zimbra/postfix/sbin/qshape.pl, /opt/zimbra/postfix/sbin/postconf,/opt/zimbra/postfix/sbin/postsuper
%zimbra ALL=NOPASSWD:/opt/zimbra/libexec/zmqstat,/opt/zimbra/libexec/zmmtastatus
%zimbra ALL=NOPASSWD:/opt/zimbra/amavisd/sbin/amavis-mc
%zimbra ALL=NOPASSWD:/opt/zimbra/libexec/zmmailboxdmgr
%zimbra ALL=NOPASSWD:/opt/zimbra/bin/zmcertmgr

Referencias

Leer más

Crear USB con Windows 7

Sí, lo se, no suelo hablar de temas relacionados con Windows en el blog, pero hay veces que toca hacerlo y hoy será una de esas veces. El problema vino cuando me tocó formatear un ordenador para instalar un Windows 7. Este equipo no tenía lectora de CD para poder arrancar, con lo cual, necesitaba partir de la ISO de Windows y pasarla a un pen drive y hacerlo arrancable. Para eso siempre uso unetbootin, pero esta vez no funcionaba. Investigando un poco se ve que unetbootin no termina de llevarse bien con Win7, así que tuve que buscar otra forma. Esta, la verdad, es que hasta me gustó más. El único problema es que necesitas un Windows previo. Así que... empleé el Windows que iba a 'rematar' para que crease a su asesino.
A continuación os detallo los pasos a realizar, por si a alguien le son de ayuda. El primero y obvio es tener identificado el pen drive al que va a ir el contenido de la ISO. A continuación abrimos una consola (cmd) como administrador y ejecutamos diskpart. Esto nos abrirá una shell de comandos y en ella hacemos lo siguiente,
  • list disk
    Saca un listado de los disco conectados al equipo.
  • select disk 2
    Seleccionamos el disco correspondiente al pen drive. En número puede cambiar dependiente de tu sistema.
  • clean
    Borra todos los datos del pen drive.
  • create partition primary
    Se crea una partición primaria.
  • active
    Se marca la partición como activa.
  • format fs=fat32 quick
    Se formatea el pen drive con un sistema de ficheros fat32.
  • assign
    Confirmamos los cambios.
  • exit
    Salimos del programa.
Una vez finalizados estos pasos, ya estamos casi a punto de terminar de crear nuestro pen drive booteable. Únicamente nos falta por indicarle lo que tenemos que arrancar, es decir, el Windows. Pues bien, cogemos la ISO y la descomprimimos dentro de la unidad. Cuando haya finalizado, reinicia el equipo y ya deberías de poder arrancar desde él.

En caso de que esto fallo, todavía hay un método extra. Vuelve a arrancar el equipo y arrancas una consola (cmd) y ejecutas lo siguiente. Partimos de que la unidad del pen drive es F:
cmd> F:\BOOT\bootsect /nt60 F:
Reinicia el equipo y ahora si que ya debería de poder arrancar.
Leer más

Bacula PKI, cifrando los datos

Si el otro día hablamos acerca de cómo configurar Bacula para que todos los datos de los que realiza backup viajen cifrados (puedes leer el post completo aquí), hoy vamos a ver otra parte no menos importante: la seguridad de los datos almacenados.
Casi tan importante como tener un buen respaldo de los datos es que estos estén seguros. Si alguien se hace con una cinta y tiene ahí todos los datos almacenados en texto plano, pues ya os podéis imaginar... Así que, para evitar que esto suceda, vamos a emplear la opción, también incluida en Bacula, de cifrar los datos en origen. Con ello conseguimos que los datos salgan del cliente ya cifrados, según una clave privada que sólo el cliente debe de conocer. Esto garantiza que los datos que se escriban en la cinta estén ya cifrados, no los cifra el bacula-sd o el bacula-director, sino que es en origen, es decir, bacula-fd. Aquí es importante recalcar que los datos estarán cifrados, es decir, el fichero no se sabrá lo que tiene, pero tanto ruta, permisos, nombre del fichero, etc. estarán disponibles para que en caso de que se necesite recuperar algo, se pueda hacer sin problema.

Generar las claves de cifrado

Como siempre, vamos primero a generar las claves que necesitamos para hacer el cifrado de datos. Para ello, generamos la clave maestra tal como sigue,
shell> openssl genrsa -out master.key 2048
shell> openssl req -new \
       -key master.key \
       -x509 \
       -out master.cert \
       -days 3650
En este caso, y para evitar futuros problemas, creamos un certificado con 10 años de validez. Este será nuestro certificado maestro.
Ahora debemos de generar el par de claves para cada cliente. Este es el paso que debemos de repetir en cada uno de los clientes.
shell> openssl genrsa -out a.local.net.key 2048
shell> openssl req -new \
       -key a.local.net.key \
       -x509 \
       -out a.local.net.cert \
       -days 3650
shell> cat a.local.net.key a.local.net.cert > a.local.net.pem

Configuración

Y ahora, ya únicamente nos queda por editar el fichero del agente (bacula-fd.conf) y añadir las claves de cifrado en el apartado FileDaemon.
FileDaemon {
   ...
   # Data Encryption
   PKI Signatures = Yes
   PKI Encryption = Yes
   PKI Keypair = "/etc/bacula/tls/a.loca.net.pem"
   PKI Master Key = "/etc/bacula/tls/master.cert"
}
Tras el cambio, reiniciamos el daemon y podemos lanzar una tarea de backup, en la que al finalizar aparecerá lo siguiente:
FD Files Written:       139
SD Files Written:       139
FD Bytes Written:       8,719,243,782 (8.719 GB)
SD Bytes Written:       8,719,264,244 (8.719 GB)
Rate:                   23954.0 KB/s
Software Compression:   None
VSS:                    no
Encryption:             yes
Accurate:               no
Todo el proceso de copia y restauración de backups en el cliente es completamente transparente para el administrador. Es el propio software de Bacula quien lo realiza.

Precauciones

Es muy importante tener las claves de cifrado muy bien respaldadas, pues si se pierden no será posible restaurar ningún fichero del sistema.
En caso de de que clave o certificado del cliente se pierda, mientras tengamos las claves maestro podremos restaurar los ficheros. Para ello únicamente deberemos seguir las siguientes instrucciones.
  1. Concatener las claves maestro
  2. shell> cat master.crt master.key > master.keypair
    
  3. Modificar el fichero del agente (bacula-fd.conf)
    FileDaemon {
       ...
       PKI Keypair = /etc/bacula/tls/master.keypair
    }
    

Referencias

Leer más

Etiquetar particiones

Si bien el otro día hablamos de cómo manejar y cambiar el UUID de una partición, hoy vamos a ver cómo emplear las etiquetas (labels) para poder administrar nuestros puntos de montaje y que así tengan más significado. La idea es pasar de un /dev/sda1 a un /dev/disk/by-label/raiz. Algo más legible y entendible por cualquier persona.
Para hacerlo, lo primero que debemos es comprobar si nuestro disco tiene alguna etiqueta. Para ello,
shell> lsblk -f
NAME      FSTYPE      LABEL      MOUNTPOINT
sda                                         
├─sda1    ext4                   /boot
├─sda2    ext4                   /
└─sda3    ext4                                  
Como vemos, no hay ninguna etiqueta de nombre para las particiones. La solución está en el empleo del comando e2label, que sirve precisamente para asignarle etiquetas a las particiones. Procederemos por lo tanto como sigue,
shell> e2label /dev/sda1 boot
shell> e2label /dev/sda2 raiz
shell> e2label /dev/sda3 data
Puedes aplicar etiquetas únicamente a aquellas particiones que te interese, a mi me interesa etiquetarlas las 3 que voy a usar. Si ahora ejecutamos nuevamente el primer comando (lsblk),
shell> lsblk -f
NAME      FSTYPE      LABEL      MOUNTPOINT
sda                 
├─sda1    ext4        boot       /boot
├─sda2    ext4        raiz       /
└─sda3    ext4        data
A partir de este momento, bajo la carpeta /dev/disk/by-label existe los links a los disco y que se pueden usar, por ejemplo, para montar una partición.
shell> mount /dev/disk/by-label/data /mnt
Quizás acordarse de la nueva ruta para realizar los montajes de disco sea más complejo, pero desde luego, para saber qué es lo que se está haciendo, mucho más simple.

Referencias

Leer más

Listado de ramas remotas con git

En el uso cotidiano de git, el manejo y cambio de ramas en local no suele ser un problema. branch y checkout son comando habituales con los que trabajar. Sin embargo, el problema viene cuando quieres contribuir o hacer algún tipo de desarrollo colaborativo contra un repositorio que no conoces. En este caso, tras hacer el clone correspondiente, únicamente tienes, por ejemplo la rama master. Si empleas github o algún interfaz de gestión de repositorios, entonces averiguar el nombre de todas las ramas que tiene el proyecto es más sencillo. Sin embargo, hacerlo desde consola ya no tanto.

Listado de ramas

Si lo que nos interesa es averiguar aquellas ramas que están disponibles para un proyecto, con el comando git también lo podemos lograr. La forma más sencilla,
shell> git branch -r
  origin/test
  origin/prueba
  origin/HEAD
  origin/master
Y si nos interesa tener un listado completo de las ramas remotas y locales,
shell> git branch -a
* master
  origin/test
  origin/prueba
  origin/HEAD
  origin/master
Rápido, limpio y sencillo. Sabiendo aquellas ramas disponibles, si queremos cambiar a alguna, únicamente habrá que realizar el checkout correspondiente, tanto sea local como remota.

Referencias

Leer más

Cambiar UUID del disco

Hace ya un tiempo hablamos en este blog acerca del uso de los UUIDs y los discos. El que no sepa de qué estoy hablando, puede leer la entrada Obtener el UUID del disco. En él se indica de forma clara cómo obtener el identificador universal del disco para posteriormente trabajar con él, por ejemplo en fstab.

Cambiando UUID

Hoy vamos a dar un paso más allá y ver cómo cambiar dicho UUID. A priori, el algoritmo que se emplea para la creación de los UUID no permite que este identificador esté repetido en un mismo equipo, aunque como todo, siempre puede haber excepciones. En caso de que esto os haya pasado, sabréis que trabajar con UUIDs en un sistema con dos repetidos es imposible. En cada montaje del sistema, aparece un disco y otro y hay muchos fallos. Pues bien, la solución en esos casos no es otra que la de cambiar dicho UUID.
Con el comando blkid se puede obtener el listado de los IDs de las particiones del disco,
shell> blkid
/dev/sda1: UUID="e12c98df-7c8e-4f50-be39-e208597f71a7"
/dev/sda2: UUID="2bf49a55-f967-4fec-9127-9d049a5e7091"
/dev/sda3: UUID="a6a1fc9a-48e5-4cff-82b9-04f0afa925e3"
y también está el comando uuidgen, que permite precisamente crear "el churro" alfanumérico que se emplea como identificado.
shell> uuidgen
502eb30f-9c0c-4308-80d7-e1061ba39e4f
Para cambiar el ID de una partición debemos de emplear el comando tune2fs y pasarle el nuevo UUID que nos interese, es decir, uno aleatorio. Por lo tanto,
shell> tune2fs -U `uuidgen` /dev/sda3
tune2fs 1.42.9 (4-Feb-2014)
Y vemos ahora que los cambios han surtido el efecto deseado.
shell> blkid
/dev/sda1: UUID="e12c98df-7c8e-4f50-be39-e208597f71a7"
/dev/sda2: UUID="2bf49a55-f967-4fec-9127-9d049a5e7091"
/dev/sda3: UUID="c6dfe0b1-ceec-477b-a764-9db98439c5f9"

Referencias


Nota: La partición afectada que vayamos a cambiar debe de estar desmontada.
Leer más

Bacula TLS, cifrando la comunicación

Esta semana tocó configurar Bacula. La configuración básica del servicio es bastante sencilla y ponerlo a funcionar suele no llevar mucho. Sin embargo, si estás pensando en realizar backup remoto o entre diferentes redes, la opción de que los datos viajen cifrados, no es discutible. Incluso dentro de la propia red local no debería de serlo.
Por suerte, Bacula ya trae soporte para cifrar los datos mediante certificados TLS. Y es importante que tanto la parte cliente como la parte servidor traigan dicho soporte. Para comprobarlo, podemos emplear el comando ldd contra el binario de Bacula.
shell> ldd /usr/sbin/bacula-dir
   libcrypt.so.1 => /lib/libcrypt.so.1
   libssl.so.0.9.8 => /usr/lib/libssl.so.0.9.8
   libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8
   ...
shell> ldd /usr/sbin/bacula-fd
   libssl.so.0.9.8 => /usr/lib/libssl.so.0.9.8
   libcrypto.so.0.9.8 => /usr/lib/libcrypto.so.0.9.8
   ...
Si vuestros servicios tienen soporte SSL, entonces podemos seguir leyendo la entrada. Si por el contrario el paquete del que dispones no viene con soporte SSL, intenta actualizarlo o compilarlo para que sí lo soporte.

Crear los certificados

Lo primero que debemos hacer es crear los certificados para los equipos. La parte más importante aquí es aclarar que cada equipo tendrá unos certificados diferentes y por lo tanto, los siguientes 4 pasos habrá que repetirlos en cada uno de los equipos en los que vaya algún componente de Bacula.
  1. Clave privada del equipo
    Esta va a ser la llave maestra para el equipo.
    shell> openssl genrsa -des3 -out a.local.net.key 4096
  2. Solicitud de certificado
    Con la clave anteriormente creada generamos una solicitud de certificado. Es importante que estos datos se rellenen correctamente y en especial la parte del Common Name, que debe ser el FQDN del equipo.
    shell> openssl req -new \
           -key a.local.net.key \
           -out a.local.net.csr
    Enter pass phrase for a.local.net.key:
    ...
    Organizational Unit Name (eg, section) []:Elmundoenbits
    Common Name (e.g. server FQDN) []:a.local.net
    ...
  3. Firmamos la solicitud con una CA conocida
    En este caso, recomiendo recurrir a cacert.org como CA. La creación de la cuenta es gratuita y puedes firmar todas las solicitudes que desees, siempre que tengas permiso para el dominio.
    En caso de que tu sistema no tenga el certificado raíz del CACert, lo puedes descargar desde aquí y le vamos a llamar cacert.pem.
  4. Generamos la clave sin contraseña
    Finalmente y puesto que Bacula no permite trabajar con certificados con contraseña, necesitamos exportar la clave privada (paso 1) a la versión sin contraseña.
    shell> openssl rsa \
           -in a.local.net.key \
           -out a.local.net-nopass.key
    shell> mv a.local.net-nopass.key a.local.net.key
    
Como dije, estos pasos los repetiremos para cada uno de los equipos. Para el ejemplo que aquí manejamos, tendremos dos equipos. El equipo servidor de Bacula (bacula.local.net), para el que tenemos los siguientes ficheros disponibles:
  • cacert.pem
  • bacula.local.net.cert
  • bacula.local.net.key
Y el equipo cliente, a.local.net, con sus tres ficheros correspondientes,
  • cacert.pem
  • a.local.net.cert
  • a.local.net.key

director - bconsole

Lo primero que debemos hacer ahora es indicarle al software de consola (bconsole) que para conectarse al bacula-director debe de emplear certificados TLS. Para ello editamos el fichero bconsole.conf y añadimos las opciones de TLS.
Director {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/bacula.local.net.cert
   TLS Key = /etc/bacula/tls/bacula.local.net.key
}
Y a continuación, debemos de indicarle a la parte contrarios (director) exactamente lo mismo (fichero bacula-dir.conf).
Director {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/bacula.local.net.cert
   TLS Key = /etc/bacula/tls/bacula.local.net.key
}
Con ello, ya es posible conectarse con bconsole a Bacula para realizar comprobaciones.

director - bacula-sd

A continuación, hay que establecer la comunicación cifrada entre el director y el storage. Para ello nos toca editar el fichero bacula-sd.conf y en el apartado Director, añadirle las opciones TLS. Como siempre,
Director {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/bacula.local.net.cert
   TLS Key = /etc/bacula/tls/bacula.local.net.key
}
Y a continuación, en el fichero bacula-dir.conf, editar el apartado Storage y también añadir las opciones TLS.
Storage {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/bacula.local.net.cert
   TLS Key = /etc/bacula/tls/bacula.local.net.key
}


bacula-fd - bacula-sd

La que citamos a continuación es quizás la parte más importante en la que aplicar el cifrado, ya que es la que se encarga de enviar y recibir los datos. Por lo tanto, nos interesa mucho que estos sí estén cifrados. Para hacerlo editamos nuevamente el fichero bacula-sd.conf y en el apartado Storage añadimos los TLS,
Storage {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/bacula.local.net.cert
   TLS Key = /etc/bacula/tls/bacula.local.net.key
}
y en cada uno de los clientes (fichero bacula-fd.conf) hacemos lo correspondiente,
FileDaemon {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/a.local.net.cert
   TLS Key = /etc/bacula/tls/a.local.net.key
}


bacula-fd - director

Para finalizar toda la configuración lo que nos queda es realizar la comunicación entre el director y el cliente también cifrada. Para ello, fichero bacula-dir.conf, apartado del cliente,
Client {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem   
   TLS Certificate = /etc/bacula/tls/bacula.local.net.cert
   TLS Key = /etc/bacula/tls/bacula.local.net.key
}
Y en el fichero del cliente (bacula-fd.conf),
Director {
   ...
   TLS Enable = yes
   TLS Require = yes
   TLS Verify Peer = yes
   TLS CA Certificate File = /etc/bacula/tls/cacert.pem
   TLS Certificate = /etc/bacula/tls/a.local.net.cert
   TLS Key = /etc/bacula/tls/a.local.net.key
}
Para terminar, reiniciamos los servidor bacula-sd, bacula-dir y los bacula-fd que correspondan. Si no hay ningún problema, la comunicación debería de estar cifrada en el servicio funcionando perfectamente.

Referencias

Leer más

PoC local de CVE-2015-0235

Como pequeña prueba de concepto para explotación local, la Universidad de Chicago ha liberado un pequeño código escrito en c que permite comprobar de forma sencilla si tu equipo es vulnerable al fallo en la librería glibc y que afecta a la función gethostbyname. Puedes leer más acerca de este fallo aquí.
Por el momento, vamos a ver en qué estado se encuentra el equipo y en caso de que sea vulnerable, la recomendación es actualizar lo antes posible. El código en cuestión es el siguiente:
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define CANARY "in_the_coal_mine"

struct {
  char buffer[1024];
  char canary[sizeof(CANARY)];
} temp = { "buffer", CANARY };

int main(void) {
  struct hostent resbuf;
  struct hostent *result;
  int herrno;
  int retval;

  size_t len = sizeof(temp.buffer) -
               16*sizeof(unsigned char) -
               2*sizeof(char *) - 1;
  char name[sizeof(temp.buffer)];
  memset(name, '0', len);
  name[len] = '\0';

  retval = gethostbyname_r(name,
                           &resbuf,
                           temp.buffer,
                           sizeof(temp.buffer),
                           &result,
                           &herrno);

  if (strcmp(temp.canary, CANARY) != 0) {
    puts("vulnerable");
    exit(EXIT_SUCCESS);
  }
  if (retval == ERANGE) {
    puts("not vulnerable");
    exit(EXIT_SUCCESS);
  }
  puts("should not happen");
  exit(EXIT_FAILURE);
}
Tras copiarlo en un fichero de texto plano, por ejemplo /tmp/test_ghost.c, debemos compilarlo. Siendo código c:
shell> gcc /tmp/test_ghost.c -o /tmp/test_ghost
Y ejecutándolo ya podemos comprobar si el sistema está o no afectado por la vulnerabilidad Ghost in Linux (CVE-2015-0235).
shell> /tmp/test_ghost 
vulnerable
En caso de que no esté, la salida será tal que así,
shell> /tmp/test_ghost 
not vulnerable
Leer más

Ghost in Linux (CVE-2015-0235)

Investigadores de la empresa Qualys han reportada una grave vulnerabilidad en la librería glibc
(biblioteca C de GNU Linux), que permite obtener un acceso no lícito al sistema sin la necesidad de usuario y contraseña.
Dicha vulnerabilidad ya está reportada y se ha identificado como CVE-2015-0235 y afecta a la mayoría de los sistemas ya que lleva 14 años ahí. Afecta a todos aquellos sistemas que tenga glibc-2.2 instalado, liberado en el año 2000! En mucho sitios ya comparan esta vulnerabilidad a heartbleed, que también movió cielo y tierra en su momento.
Las principales distribuciones GNU/Linux ya fueron notificadas de este bug antes de que se publicase, y ya hay parches al respecto para ellas.

Bug y explicación

Este fallo de seguridad afecta a la función gethostbyname, presente en glibc. Dicha función es usada en casi todos los sistemas Linux cuando se intenta acceder a otro equipo conectado en red. O dicho de otra forma, cuando se intenta resolver un nombre de dominio vía DNS.
El fallo se puede aprovechar si el atacante provoca un desbordamiento de buffer al usar un argumento hostname no válido. Es ahí cuando se permite ejecutar código arbitrario y con los permisos del usuario que está ejecutando DNS.
Qualys creó una prueba de concepto sobre un servidor Exim al enviarle un comando SMTP inválido. Un simple correo electrónico mal intencionado permite abrir una shell remota en el sistema.

Solución

Aplicar las actualizaciones de seguridad de los sistemas y reiniciar.

Más información




Leer más

add-apt-repository: command not found

Ubuntu incluyó una forma muy simple de añadir nuevos repositorios de software para disponer de paquetes específicos o más recientes. Esto permite a muchas personas y empresas ofrecer repositorios de fácil instalación en el sistema, para dejar así sus paquetes disponibles. La forma de instalar estos nuevos repositorios es gracias al comando add-apt-repository. Aunque, una vez finalizada la instalación básica del sistema, éste nos puede fallar por que no tiene los paquetes necesarios instalado. Si obtenéis el siguiente error agregando un origen.
shell> add-apt-repository ppa:oisf/suricata-stable
  -su: add-apt-repository: command not found
La solución es sencilla, únicamente hay que instalar el paquete python-software-properties.
shell> apt-get install python-software-properties
Y volver a probar,
shell> add-apt-repository ppa:oisf/suricata-stable
You are about to add the following PPA to your system:
 suricata IDS stable packages
 More info: https://launchpad.net/~oisf/+archive/suricata-stable
Press [ENTER] to continue or ctrl-c to cancel adding it
...
En la última versión de Ubuntu Server, la 14.04, encontré un problema a la hora de usar add-apt-repository e instalar las dependencias para que funcionase. En éste caso, tuve que instalar el paquete software-properties-common,
shell> apt-get install software-properties-common
Y ya luego todo funcionó correctamente.
Leer más

Formulario de contacto

Nombre

Correo electrónico *

Mensaje *

Últimos comentarios