miércoles, 10 de abril de 2019

Añadir disco a clúster IBM Spectrum Scale



Cómo añadir un disco a un clúster de IBM Spectrum Scale en un sistema Linux, paso a paso.



Me encontré recientemente con una base de datos que no arrancaba. Esta base de datos está ubicada en un servidor Linux, así que descartando posibles causas del problema, hice un df -h para ver el procentaje de ocupación de los filesystems del S.O. Fue entonces cuando vi que el filesystem sobre el que reside la base de datos, al que llamaremos "montaje", estaba totalmente lleno (Use%: 100%):

HOST# df -h Filesystem             Size Used Avail Use% Mounted on /dev/sda2               95G  12G   79G  13% / devtmpfs               420G 8.0K  420G   1% /dev tmpfs                  420G  80K  420G   1% /dev/shm tmpfs                  420G  10M  420G   1% /run tmpfs                  420G    0  420G   0% /sys/fs/cgroup /dev/sda1              148M    0  148M   0% /boot/efi /dev/montaje           1.3T 1.3T     0 100% /montaje

Este "montaje" está montado sobre un clúster de IBM Spectrum Scale. Tras ver que no podía liberar espacio en el directorio, decidí añadir un disco al clúster para darle más espacio a /montaje.

Para añadir un disco a un clúster de IBM Spectrum Scale, primero debemos añadir un disco físico o virtual al sistema operativo. Añadí un disco de 1 TB a la máquina virtual y luego miré qué letra se le había asignado al disco a nivel de sistema operativo:

HOST# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT fd0    2:0    1 4K    0 disk sda    8:0    0 128G  0 disk ├─sda1 8:1    0 148M  0 part /boot/efi ├─sda2 8:2    0 95.9G 0 part / └─sda3 8:3    0 32G   0 part [SWAP] sdb    8:16   0 250G  0 disk └─sdb1 8:17   0 250G  0 part sdc    8:32   0 1T    0 disk └─sdc1 8:33   0 1024G 0 part sdd    8:48   0 1T    0 disk sr0    11:0   1 4.1G  0 rom sr1    11:1   1 4.1G  0 rom sr2    11:2   1 8.5M  0 rom

Vi que era el disco "sdd". Me dirigí entonces al directorio /var/mmfs/config y copié el fichero usado en la creación del primer nodo del cluster (NSD server) hacia un nuevo archivo:

HOST# cp disk.list.data.gpfsnode01 disk.list.data.gpfsnode01.new.adddisk

Edité este archivo cambiando los siguientes valores:

device=/dev/sda por device=/dev/sdd
nsd=data01node01 por nsd=data03node01

De modo que el archivo quedó así:

%nsd: device=/dev/sdd nsd=data03node01 servers=gpfsnode01 usage=dataAndMetadata failureGroup=1001 pool=system

Para saber qué nombre usar en el campo "nsd" (para no introducir un nombre que ya estuviese en uso), ejecuté el comando mmlsnsd para listar los Disk Name ya usados en el clúster:

HOST# mmlsnsd File system   Disk name    NSD servers --------------------------------------------------------------------------- montaje       data01node01 gpfsnode01 montaje       data02node01 gpfsnode01

Preparé el disco para ser añadido al clúster con el comando mmcrnsd -F:

HOST# mmcrnsd -F disk.list.data.gpfsnode01.new.adddisk -v yes mmcrnsd: Processing disk sdd

Hecho esto, el disco data03node01 quedó preparado para ser añadido al clúster:

HOST# mmlsnsd File system   Disk name    NSD servers --------------------------------------------------------------------------- montaje       data01node01 gpfsnode01 montaje       data02node01 gpfsnode01 (free disk)   data03node01 gpfsnode01

Por último, añadí el disco al clúster con el comando mmadddisk:

HOST# mmadddisk montaje -F disk.list.data.gpfsnode01.new.adddisk The following disks of montaje will be formatted on node HOST: data03node01: size 1048576 MB Extending Allocation Map Checking Allocation Map for storage pool system Completed adding disks to file system montaje.

Verifiqué que se hubiera añadido el disco al clúster:

HOST# mmlsnsd File system   Disk name    NSD servers --------------------------------------------------------------------------- montaje       data01node01 gpfsnode01 montaje       data02node01 gpfsnode01 montaje       data03node01 gpfsnode01

Con el disco ya añadido al clúster, vi que el espacio total de "montaje" había incrementado en 1 TB. Gracias a esto, el filesystem ya no estaba al 100% de uso:

HOST# df -h Filesystem             Size Used Avail Use% Mounted on /dev/sda2               95G  12G   79G  13% / devtmpfs               420G 8.0K  420G   1% /dev tmpfs                  420G  80K  420G   1% /dev/shm tmpfs                  420G  10M  420G   1% /run tmpfs                  420G    0  420G   0% /sys/fs/cgroup /dev/sda1              148M    0  148M   0% /boot/efi /dev/montaje           2.3T 1.3T     0  50% /montaje

Llegados a este punto, probé a levantar la base de datos y ya arrancó sin problemas.


Fuentes:

https://www.ibm.com/support/knowledgecenter/STXKQY_4.2.0/com.ibm.spectrum.scale.v4r2.adm.doc
https://www.ibm.com/support/knowledgecenter/STXKQY_4.2.0/com.ibm.spectrum.scale.v4r2.adm.doc
0

miércoles, 3 de abril de 2019

HTTP Load Balancing en nginx



Cómo configurar load balancing de un servicio HTTP/HTTPS en nginx.



nginx, cuando actúa como reverse proxy, permite hacer balanceo de carga (load balancing) de las peticiones HTTP que le entran a un dominio determinado. Es decir, permite enviar tráfico entrante de un dominio hacia un servidor web u otro dependiendo de ciertas condiciones.

Imaginemos que tenemos un servicio antispam de la marca Barracuda, compuesto por dos aparatos cuyas IPs son 192.168.1.1 y 192.168.1.2. Estos aparatos están conectados en clúster para ofrecer un servicio de alta disponibilidad, de modo que si un aparato cae, el otro recibe todas las conexiones y sigue ofreciendo servicio y viceversa. Además, este clúster permite que los cambios aplicados en un apartado se repliquen al instante al otro aparato, de modo que la administración del servicio antispam puede realizarse desde cualquiera de las dos IPs.

Supongamos también que queremos apuntar la dirección antispam.dominio.com a los dos aparatos, pues apuntar el FQDN a una sola IP nos dejaría sin gestión si uno de los aparatos cayera.

nginx nos ofrece una solución a esta necesidad con su servicio de load balancing de tráfico HTTP. Para hacerlo, apuntamos antispam.dominio.com a la IP del servidor que corre nginx y en la configuración de nginx creamos una política "upstream" que haga balanceo de carga hacia dos o más servidores finales.

El código que nos permite hacer balanceo de carga HTTP es algo parecido a esto:

http {     upstream upstream_antispam {         server 192.168.1.1:8000;         server 192.168.1.2:8000;     }     server {         listen 443 ssl;         server_name antispam.dominio.com;         location / {             proxy_pass http://upstream_antispam;         }     } }

En este código, he creado un bloque "upstream" de nombre "upstream_antispam" que contiene las dos direcciones IP de los aparatos Barracuda, así como el puerto de gestión HTTP que usan (puerto 8000).

Debajo del bloque upstream, he creado un bloque "server" que realiza la función de reverse proxy (proxy_pass) y envía el tráfico al bloque upstream "upstream_antispam" anteriormente declarado.

Con esto, lo que conseguimos es que el tráfico que vaya a https://antispam.dominio.com se vaya repartiendo entre http://192.168.1.1:8000 y http://192.168.1.2:8000, según criterios varios como ¿están las dos IPs activas? ¿hay muchas sesiones activas en una de las IPs? etc.

A partir de este momento, si cae el aparato con IP 192.168.1.1, todo el tráfico que entre a https://antispam.dominio.com pasará a 192.168.1.2. Y si cayera el 192.168.1.2, todo el tráfico pasaría por 192.168.1.1. Si los dos están activos, el tráfico pasará por ambos.
1

miércoles, 27 de marzo de 2019

Ver fecha de expiración de contraseña de dominio



Cómo ver qué día se nos pedirá cambiar la contraseña de dominio.



Si trabajamos en una empresa y usamos un ordenador, lo más probable es que nuestro usuario esté creado en un directorio activo que se encargue de manejar la fecha de expiración de las contraseñas de los usuarios, entre otras cosas.

Si queremos saber cuántos días nos quedan para que el sistema nos vuelva a pedir cambiar nuestra contraseña de usuario, podemos usar el comando:

net user user1 /domain

donde user1 es el nombre de usuario. Este comando nos devolverá la siguiente información:

C:\Users\user1>net user user1 /domain Se procesará la solicitud en un controlador de dominio del dominio dominio.local. Nombre de usuario                          user1 Nombre completo                            Nombre Apellido Comentario Comentario del usuario Código de país o región                    000 (Predeterminado por el equipo) Cuenta activa                              Sí La cuenta expira                           Nunca Ultimo cambio de contraseña                21/01/2019 17:04:16 La contraseña expira                       21/04/2019 17:04:16 Cambio de contraseña                       22/01/2019 17:04:16 Contraseña requerida                       Sí El usuario puede cambiar la contraseña     Sí Estaciones de trabajo autorizadas          Todas Script de inicio de sesión Perfil de usuario Directorio principal Ultima sesión iniciada                     08/04/2019 11:14:55 Horas de inicio de sesión autorizadas      Todas Miembros del grupo local                   *IT Miembros del grupo global                  *Systems                                            *Usuarios del dominio Se ha completado el comando correctamente.

En este caso, vemos que la contraseña de user1 expira el día 21/04/2019 a las 17:04:16.

En la línea "La contraseña expira" podemos ver qué día expira la contraseña de nuestro usuario, o de cualquier usuario de la empresa sobre el cual realicemos una consulta.
0

miércoles, 20 de marzo de 2019

SSL: comprobar match clave pública/clave privada



Cómo comprobar si un certificado .crt hace match con una clave privada .key que tenemos.



Hace poco me pidieron generar un certificado SSL para un dominio .com, para que al acceder vía navegador mediante HTTPS a ese dominio, apareciera el certificado.

Para hacer tal cosa, empecé generando un archivo CSR y su clave privada (.key) y envié el CSR a la persona encargada de realizar los pagos en la empresa donde trabajo para que lo subiese a la entidad registradora de turno, realizase el pago y me devolviera el certificado en formato .crt.

Hasta aquí todo bien. El problema vino cuando obtuve el archivo .crt y lo quise usar en un nginx. Al hacer un reload de la configuración, nginx se quejó de que había un certificate mismatch entre la clave pública (.crt) y la clave privada (.key).

Buscando por internet, vi que la utilidad openssl dispone de una forma de verificar si los hashes de ambas claves coinciden o no. Para ello, basta con ejecutar un comando que devuelve el hash de cada uno de los archivos involucrados en un certificado y ver si coinciden entre ellos.

Empecemos por obtener el hash del archivo .crt (clave pública del certificado):

HOST:/ # openssl x509 -in cert.crt -pubkey -noout -outform pem | sha256sum 1157e76f78b0580e2a1f289552a6a45d9e7bc60bc37e57549034faaf2fb03f1z -

Del mismo modo, podemos ver el hash de la clave privada (.key):

HOST:/ # openssl pkey -in clave_privada.key -pubout -outform pem | sha256sum 1157e76f78b0580e2a1f289552a6a45d9e7bc60bc37e57549034faaf2fb03f1z -

E incluso podemos ver el hash del CSR original:

HOST:/ # openssl req -in CSR.csr -pubkey -noout -outform pem | sha256sum 1157e76f78b0580e2a1f289552a6a45d9e7bc60bc37e57549034faaf2fb03f1z -

En mi caso, el CSR y la clave privada (.key) hacían match, pero el crt tenía un hash distinto.

Para solucionar el problema, bastó con contactar con la entidad registradora y subir el CSR de nuevo. Esto generó un nuevo .crt que sí hacía match con los archivos anteriores. Subí este crt al servidor de nginx y este ya me permitió usar el certificado sin problema.


Fuentes:

https://www.sslshopper.com/certificate-key-matcher.html
0

miércoles, 13 de marzo de 2019

Acceso por SFTP con jaula chroot, sin acceso SSH



Cómo permitir a un usuario subir/borrar archivos por SFTP a un directorio de un servidor Linux en el cual no tiene permisos, con la peculiaridad de que el servidor está sirviendo una página web.



Escenario:

- Un servidor Linux sirviendo una página web.
- Un directorio llamado "uploads", el cual contiene imágenes mostradas en la página web.
- La necesidad de que un usuario pueda subir imágenes a ese directorio.
- Que el usuario pueda conectarse por SFTP al servidor web, pero no por SSH.
- Que el usuario no pueda acceder a ningún otro directorio a parte de "uploads".

Para resolver esta necesidad, accedí al servidor y averigué los permisos del directorio "uploads":

WEBSERVER:/ # ls -la /srv/www/htdocs/web.com/sites/default/uploads total 76 dr-xr-x--x 5 wwwrun root 4096 Mar 12 16:29 . drwxr-xr-x 4 wwwrun root 4096 Apr 26 2018 .. drw-r--r-- 4 wwwrun root 4096 Oct 29 2016 files drwxr-xr-x 33 wwwrun root 4096 Mar 12 16:30 uploads

Vi que la carpeta uploads tenía como propietario el usuario "wwwrun", como grupo propietario "root" y como permisos de lectura/escritura/ejecución: drwxr-xr-x / 755.


Crear usuario



A partir de aquí, he creado el usuario "nombre_usuario", el cual será el encargado de subir contenido:

WEBSERVER:/ # useradd nombre_usuario

Luego le he dado un password:

WEBSERVER:/ # passwd nombre_usuario

A continuación, he creado una carpeta que servirá como ubicación inicial (home) para las conexiones SFTP del usuario "nombre_usuario":

WEBSERVER:/ # mkdir -p /sftp/nombre_usuario


Jaula chroot



Como he comentado anteriormente, no queremos que el usuario pueda ver otras carpetas del servidor, por lo tanto, vamos a enjaularlo (chroot) en el directorio que acabamos de crear.

Para que esto funcione, es importante que todas las carpetas de la ruta hacia la home del usuario tengan de propietarios root:root (en este caso, tanto /sftp como /sftp/nombre_usuario) así como permisos 75X (con 775 no funciona, por ejemplo). Si los permisos no están configurados de esta forma y usamos una jaula chroot, nos encontraremos con el siguiente error al conectarnos por SFTP:

WEBSERVER:/ # sftp nombre_usuario@192.168.1.1 password: Connection to 192.168.1.1 closed by remote host. Couldn't read packet: Connection reset by peer


Acceso SFTP sí, acceso SSH no



A parte de enjaular al usuario, necesitamos que éste pueda conectarse a la máquina por SFTP pero no por SSH. Para satisfacer ambas necesidades, podemos usar una directiva Match de OpenSSH con los siguientes parámetros:

- ForceCommand internal-sftp limita al usuario a realizar solamente conexiones SFTP.
- ChrootDirectory /sftp/nombre_usuario no permite salir del directorio /sftp/nombre_usuario:

WEBSERVER:/ # vi /etc/ssh/sshd_config [...] Match User nombre_usuario ChrootDirectory /sftp/nombre_usuario ForceCommand internal-sftp AllowTcpForwarding no

Recordar que cada vez que modifiquemos el archivo sshd_config debemos reiniciar el servicio ssh:

WEBSERVER:/ # service ssh restart

Ahora modificamos el directorio home del usuario, ya que al conectarse por SFTP, el usuario ve como directorio raíz su directorio ChrootDirectory (/sftp/nombre_usuario) y en ese directorio no existe la ruta "/home/nombre_usuario". Por lo tanto, usamos usermod -d para indicar que este usuario se conectará a su propia raíz (usamos un 'vacío' - dos comillas dobles - para indicar raíz):

WEBSERVER:/ # usermod -d "" nombre_usuario

Llegados a este punto, comprobamos que el usuario puede conectarse por SFTP, pero que al tratar de conectarse por SSH, el sistema no se lo permite:

WEBSERVER:/ # ssh nombre_usuario@192.168.1.1 Password: This service allows sftp connections only. Connection to 192.168.1.1 closed.


Bind mount



El siguiente paso es permitir a "nombre_usuario" ver el contenido del directorio "/srv/www/htdocs/web.com/sites/default/uploads". Para ello, realizaremos un "bind mount" de la siguiente manera.

1. Creamos un directorio dentro de la carpeta home del usuario, que servirá como punto de montaje:

WEBSERVER:/ # mkdir /sftp/nombre_usuario/uploads

2. Montamos la ruta a la que queremos acceder sobre el directorio "uploads" que acabamos de crear:

WEBSERVER:/ # mount -o bind /srv/www/htdocs/web.com/sites/default/uploads /sftp/nombre_usuario/uploads

Una vez hecho esto, probamos a conectarnos por SFTP con el usuario "nombre_usuario" y comprobamos que el usuario ve una carpeta "uploads". Si entramos, veremos el contenido de la carpeta montada (es decir, el contenido de /srv/www/htdocs/web.com/sites/default/uploads).

Si quisieramos que el usuario accediera directamente a /uploads al conectarse por SFTP, podríamos forzarlo modificando el home del usuario mediante:

WEBSERVER:/ # usermod -d /uploads nombre_usuario


Permisos de escritura



Por último, otorgamos permisos de escritura a "nombre_usuario" en la carpeta de destino:

1. Cambiamos el grupo propietario de la carpeta final (/srv/www/htdocs/web.com/sites/default/uploads) a "users" ("nombre_usuario" pertenece al grupo "users"):

WEBSERVER:/ # chown wwwrun:users /srv/www/htdocs/web.com/sites/default/uploads

2. Permitimos al grupo propietario escribir en la carpeta:

WEBSERVER:/ # chmod 775 /srv/www/htdocs/web.com/sites/default/uploads

A partir de este momento, ya cumplimos con lo que se nos ha pedido:

- Que un usuario pueda subir contenido a la carpeta uploads por SFTP.
- Que el usuario no pueda iniciar conexiones SSH.
- Que el usuario no pueda salir de su directorio (ni de uploads).
- Que la web siga mostrando el contenido de "uploads".
1

miércoles, 6 de marzo de 2019

nginx: [emerg] unknown directive "stream"



Cómo solucionar el error nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:72



Recientemente me han pedido realizar un cambio de configuración en un nginx que usamos como reverse proxy. Antes de incluir los nuevos parámetros en el archivo nginx.conf, he decidido actualizar todos los paquetes del sistema operativo que sirve de base, ya que hacía días que no se actualizaba. Al hacerlo, me he encontrado con el siguiente cambio, al cual no he dado importancia:

The following package is going to change vendor: nginx Nginx, Inc. -> openSUSE

Una vez actualizado el sistema operativo, he añadido los parámetros que me han pedido a la configuración de nginx y al ejecutar nginx -s reload me he encontrado con el siguiente error:

HOST# nginx -s reload nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:72

He probado entonces a reiniciar el servicio nginx, y el servicio ha fallado:

HOST# service nginx restart Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details.

Llegados a este punto, he buscado por internet y he visto que la forma en que la nueva versión de nginx ha sido compilada carga el módulo stream de forma dinámica en vez de hacerlo de forma estática.
Lo podemos ver mirando los parámetros de la versión de nginx que tenemos instalada:

HOST# nginx -V nginx version: nginx/1.14.2 built by gcc 4.8.3 20140627 [gcc-4_8-branch revision 212064] (SUSE Linux) built with OpenSSL 1.0.1i-fips 6 Aug 2014 (running with OpenSSL 1.0.2j-fips 26 Sep 2016) TLS SNI support enabled [...] --with-stream=dynamic

Lo que nos interesa es:

--with-stream=dynamic

Para hacer que nginx cargue el módulo stream de forma estática en vez de hacerlo de forma dinámica, debemos llamar al módulo desde nginx.conf con la siguiente línea:

load_module /usr/lib64/nginx/modules/ngx_stream_module.so;

Luego de añadir esta línea en nginx.conf, ya podremos realizar un reinicio del servicio normalmente:

HOST# nginx -s reload HOST# service nginx restart

A partir de este momento, ya podremos hacer reloads de nginx o reiniciar el servicio sin problemas.


Fuentes:

https://serverfault.com/questions/858067/unknown-directive-stream-in-etc-nginx-nginx-conf86
0