Linux

Mi particular compendio de comandos y utilidades que voy usando en Linux y que tiendo a olvidar cuando quiero volver a utilizarlas. Harto de buscar en internet cada vez, he decidido ir incorporándolas a esta sección.

Visualización de métricas con Prometheus y Grafana

Visualización de métricas con Prometheus y Grafana

¿Prometheus, Grafana o los dos?

Grafana es una de las herramientas más extendidas y populares para visualizar datos de manera gráfica. Además, estos datos pueden ser adquiridos en tiempo real de sistemas en funcionamiento, lo que permite controlarlos y monitorizarlos con detalle.

La verdad es que a poco que nos hayamos movido por el entorno de Cardano seguro que ya nos hemos encontrado con Grafana, ya que se trata de la opción más extendida y recomendada cuando se trata de supervisar un nodo de la red. No obstante, sus aplicaciones son prácticamente ilimitadas, y en mi caso concreto también me resulta muy útil como panel de control del sistema domótico Openhab.

Grafana puede conectarse a varias fuentes de datos. Una de las más populares, por ser la utilizada por Cardano, es Prometheus. También puede conectarse a InfluxDB, lo cual es muy conveniente, al ser una de las opciones más comunes de entre las disponibles en Openhab.

Prometheus es un software que tiene algunos puntos en común con Grafana. Por sí sólo también es capaz de recolectar datos y mostrarlos en forma de gráficas, aunque sus posibilidades en este sentido son mucho más limitadas. En realidad, sólo con Prometheus ya podríamos realizar la monitorización de un sistema, incluyendo el nodo de Cardano, pero Grafana añade una capa de funcionalidad y prestaciones que resultan muy convenientes. De ahí que, a menudo, en todos los artículos referidos a la monitorización en Cardano aparezcan juntos.

A efectos prácticos utilizaremos Prometheus como un sistema para recolectar y recopilar las métricas que nos interese monitorizar y Grafana como una capa adicional para transformar y visualizar estos datos de la manera que nos resulte más conveniente.

Empecemos por Prometheus

Prometheus recolecta métricas a partir de lo que llama end-points, los cuales no son sino puntos de conexión mediante el protocolo http en los que se encuentran expuestas dichas métricas en un formato XML entendible por Prometheus.

Configuración

La configuración es sencilla, pero si no queremos desorganizar demasiado los scripts de inicio del servicio systemd conviene hechar un vistazo al contenido de éste:

sudo nano /lib/systemd/system/prometheus.service
...
EnvironmentFile=/etc/default/prometheus
ExecStart=/usr/bin/prometheus $ARGS
...

Por cierto, si quieres recordar cómo encontrar la ubicación de los scripts de servicio, echa un vistazo a esta entrada.

En este archivo vemos que el ejecutable es invocado con una variable de entorno $ARGS que contiene los argumentos que se pasan al programa. Vemos también la ubicación del archivo de entorno donde encontraremos la asignación de dicha variable. Si editamos dicho archivo:

sudo nano /etc/default/prometheus

# Set the command-line arguments to pass to the server.
ARGS=""

# Prometheus supports the following options:
#  --config.file="/etc/prometheus/prometheus.yml"
#                             Prometheus configuration file path.
#  --web.listen-address="0.0.0.0:9090"
...

Observamos que la variable de entorno está vacía, lo que nos indica que se toman los argumentos por defecto. Vemos también, comentados, todos los argumentos que pueden ser pasados al ejecutable. Una opción sería especificar dichos parámetros directamente en el archivo de servicio donde se llama al ejecutable, eliminando la variable de entorno $ARGS. Sin embargo, una opción más elegante es colocar dicho parámetro dentro de la cadena $ARGS y permitir que para el resto de parámetros no especificados se apliquen los valores por defecto. Por ejemplo, para modificar el puerto al 9095 podríamos dejar el archivo así (observar las secuencias de escape para las dobles comillas):

sudo nano /etc/default/prometheus

# Set the command-line arguments to pass to the server.
ARGS="--web.listen-address=\"0.0.0.0:9095\""

# Prometheus supports the following options:
#  --config.file="/etc/prometheus/prometheus.yml"
#                             Prometheus configuration file path.
#  --web.listen-address="0.0.0.0:9090"
...

Para configurar los endpoints a los que conectarse, editar el archivo:

sudo nano /etc/prometheus/prometheus.yml

Métricas de Cardano

El software cardano-node ofrece, de manera nativa, un end-point con las métricas de funcionamiento del nodo. En el archivo de configuración de cardano-node encontraremos un apartado donde configurar el número de puerto (por si necesitáramos cambiarlo) y las direcciones desde las cuales es posible conectarse al end-point (punto importante cuando el servidor Prometheus está en una máquina diferente). Concretamente, esta sección tiene el siguiente aspecto:

"hasPrometheus": [
    "127.0.0.1",
    12798
  ]

Ésta es la configuración por defecto. Indica que la conexión sólo es posible desde la máquina local y en el puerto 12798. Si necesitamos conectarnos desde otra máquina, deberemos especificar, o bien la dirección IP de la misma, o bien «0.0.0.0» para la conexión desde cualquier dirección IP. No olvidemos que, en este caso, además deberemos habilitar este puerto en el firewall.

Si queremos echar un vistazo a los datos en crudo ofrecidos por el end-point de nuestro nodo bastará con dirigir nuestro navegador a la dirección:

http://<ip_nodo>:12798/metrics

Obviamente, el end-point deberá ser accesible desde la máquina en la que tengamos el navegador. Como es posible que eso no coincida con la configuración que estamos planeando, y para no andar toqueteando aquí o alla, una buena alternativa al navegador es el comando curl en la misma máquina en la que se encuentre el end-point:

curl -s http://localhost:12798/metrics

Métricas del nodo

Otro conjunto de datos que suele resultar interesante para comprobar el buen desempeño de una máquina es el relacionado con el correcto funcionamiento y rendimiento del hardware y del sistema operativo: temperaturas, carga de la CPU, uso de memoria, etc. Estas métricas pueden obtenerse instalando el software prometheus-node-exporter, el cual recopila todos estos parámetros y los expone en un nuevo end-point en el puerto 9100. Como antes, para comprobar el buen funcionamiento del end-point:

curl -s http://<ip_nodo>:9100/metrics

Aunque parezca una trivialidad, no está de más no confundir el software prometheus-node-exporter, el cual sólo crea un end-point donde exponer métricas de funcionamiento de la máquina, con el servidor Prometheus, que es el que se encarga de recopilar y almacenar todos los datos obtenidos de los diferentes end-points. Aunque a menudo se instalen a la vez, son piezas de software diferentes y ni siquiera es necesario que vayan juntos.

Métricas de dispositivos de red

El protocolo SNMP (Simple Network Management Protocol) permite el intercambio de información entre dispositivos conectados a una misma red. Entre sus usos más frecuentes se encuentra la configuración automática de routers o firewalls por parte de aquellos programas que lo necesiten. Sin embargo, también es posible utilizarlo para obtener métricas de dispositivos de red y mostrarlas en Grafana. Por ejemplo, podemos monitorizar el router y comprobar el buen funcionamiento de nuestra conexión a internet.

Necesitaremos dos cosas:

  • Que nuestro router sea compatible con SNMP y que éste se encuentre habilitado
  • Tener instalado prometheus-snmp-exporter en nuestro servidor. Este software es capaz de comunicar con dispositivos que hablen SNMP y de ofrecer las métricas así obtenidas exponiendo un end-point para Prometheus. Este software se puede instalar directamente desde los repositorios de Ubuntu o bien descargándolo desde github, concretamente, aquí.

Su configuración se encuentra en el archivo:

sudo nano /etc/prometheus/snmp.yml
# Due to licensing reasons, it is not possible to ship a ready-to-use snmp.yml
# config file.
#
# See /usr/share/doc/prometheus-snmp-exporter/README.Debian for instructions
# on using prometheus-snmp-generator to create a suitable snmp.yml config.

En el que nos encontramos este curioso mensaje. La lectura del archivo README.Debian tampoco proporciona mucha más información.

La manera de proceder es sencilla. En github, que es donde se aloja el proyecto, viene un archivo snmp.yml por defecto que en la mayoría de las ocasiones nos funcionará correctamente, así que podemos, simplemente, descargarlo en el directorio arriba mencionado.

Importante: dependiendo del método escogido para instalar prometheus-snmp-exporter nos encontraremos con una versión u otra. Normalmente, las versiones disponibles en los repositorios oficiales de Ubuntu suelen estar algo desfasadas con respecto a la última versión disponible en GitHub. Esto es importante, porque si el software instalado y el archivo de configuración descargado corresponden a versiones diferentes, podría no funcionar.

Por ejemplo, en el momento de escribir esta entrada, la versión instalada a partir de los repositorios de Ubuntu es la v0.16.1, bastante anterior a la versión actual de GitHub, que es la v0.20.0. Por lo tanto necesitamos buscar el archivo de configuración de la versión adecuada, lo que conseguimos tecleando:

sudo wget https://raw.githubusercontent.com/prometheus/snmp_exporter/v0.16.1/snmp.yml

Si todo va bien, podemos observar las métricas en el endpoint correspondiente:

curl http://<server_ip>:9116/snmp?target=<router_ip>

Visualizando con Prometheus

Como decíamos, Prometheus por sí mismo puede ser utilizado como herramienta de monitorización y visualización. Para ello, sólo hay que conectarse desde un navegador a la dirección de la máquina donde se esté ejectuando el servidor:

http://<nodo_prometheus>:9010

Y veremos algo como esto:

Prometheus

En esta página disponemos de algunas opciones que nos permiten ir añadiendo gráficas y seleccionando las métricas deseadas.

Y sigamos con Grafana

Grafana suele ser instalada en la misma máquina en la que tenemos el servidor Prometheus pero, en realidad, podría estar en cualquier otro. Dispone de la posibilidad para conectar con diferentes fuentes de datos, entre ellas, como ya hemos comentado, con Prometheus y con InfluxDB.

Contrariamente a lo que pensé en un principio, Grafana no es capaz de conectar directamente con los end-points que proporcionan los datos para Prometheus, sino sólo con éste último. Es decir, que para monitorizar un nodo de Cardano, Grafana nos la podríamos ahorrar, pero Prometheus no.

Base de datos

Grafana utiliza una base de datos de tipo SQLite ubicada en /var/lib/grafana/grafana.db

  • Si en algún momento metemos la pata y deseamos deshacer el desaguisado manualmente, siempre podemos descargar el archivo y editarlo manualmente con esta excelente herramienta de código abierto: DB Browser for SQLite
  • No está de más incluir este archivo entre aquellos de los que solemos hacer copia de seguridad.
Publicado por David en Cardano, Domótica, Linux, 0 comentarios
Acceso remoto mediante SSH. Generalidades

Acceso remoto mediante SSH. Generalidades

En ocasiones, si hemos cambiado el nombre o la dirección IP de la máquina a la que deseamos acceder, puede que al conectarnos nos aparezca el siguiente mensaje de aviso:

Warning: the ECDSA host key for 'pioneer' differs from the key for the IP address '192.168.1.x'
Offending key for IP in /home/david/.ssh/known_hosts:<n>
Are you sure you want to continue connecting (yes/no)?

Donde <n> es un número entero.

Se trata de un aviso estándar de seguridad que nos advierte de una posible brecha de seguridad. Obviamente, si estoy funcionando en mi red privada y soy consciente de que he estado haciendo cambios, este mensaje puede ignorarse con total tranquilidad. No obstante, si queremos deshacernos del mismo, hay dos maneras muy simples.

  1. Las máquinas a las cuales nos hemos conectado se guardan en el archivo mostrado en la ruta del mensaje (known_hosts). Si abrimos este archivo veremos que el formato no es muy amigable, pero tiene la ventaja de que cada host se guarda en una línea de archivo. Así que bastará con borrar la línea número <n> y ya estará.
  2. Lo anterior es sencillo si en dicho archivo tenemos una lista de tres o cuatro máquinas. Pero ¿qué pasa si, como me acaba de ocurrir, resulta que n = 61? Bien, siempre podemos editar el archivo de manera que nos muestre los números de línea, lo cual facilita mucho las cosas:
    nano ~/.ssh/known_host -l
  3. Y si no, siempre podemos usar el siguiente comando, que es de lo más molón:
    sed -i '61d' ~/.ssh/known_hosts
Publicado por David en Linux, SSH, 0 comentarios

Manejo de paquetes de instalación en Ubuntu

Linux packages

El misterio de los paquetes marcados como instalados manualmente

En ocasiones, cuando intentamos instalar un paquete que ya está instalado, el sistema nos devuelve el siguiente mensaje:

<package> is already the newest version (<ubuntu_version>).
<package> set to manually installed.

En realidad, este mensaje no tiene la menor importancia. Muchos paquetes se instalan de manera automática, bien durante la instalación inicial del sistema, bien como dependencias de otros paquetes. Y luego están los paquetes que los instalamos nosotros manualmente de manera explícita cuando los necesitamos. El gestor de paquetes simplemente guarda esta información en forma de un marcador que indica si la instalación del paquete se hizo de forma automática o manual. Esta información es la que el gestor utiliza, cuando desinstalamos un paquete, para decidir cuáles de sus dependencias ya no son necesarias y pueden ser desinstaladas, y cuáles es mejor mantener.

El tema viene cuando intentamos instalar un paquete que ya está instalado. Si este paquete se instaló en su momento de manera automática, el gestor lo marcará ahora como instalado manualmente. La única implicación práctica, que yo sepa, es que si ese paquete se había instalado automáticamente como dependencia de otro instalado anteriormente, cuando desinstalemos éste el gestor no nos sugerirá desinstalar la dependencia (lo cual es bastante conveniente en la mayoría de los casos, por cierto). No obstante, a los obsesivos un tema así nos puede traer de cabeza, así que si queremos devolverlo a su estado original, sólo tenemos que hacer lo siguiente:

sudo apt-mark auto <package>

Y listo.

Publicado por David en Herramientas, Linux, 0 comentarios
Acceso remoto SSH con clave pública

Acceso remoto SSH con clave pública

El acceso a un servidor mediante el uso de clave pública es una alternativa cómoda y segura al tradicional acceso con contraseña. Para ello, lo primero que tenemos que hacer es generar un par de claves pública y privada en el mismo cliente desde el que queramos acceder al servidor por primera vez:

~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/<USER>/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/<USER>/.ssh/id_rsa
Your public key has been saved in /home/<USER>/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:mU/wwq4it1/2pIYfl9o5hM4WughDxubXZuGDvR9vo78 engineer@home
The key's randomart image is:
+---[RSA 3072]----+
|                 |
|                 |
|        .        |
| .     . =       |
|  =   . S.o      |
| =   = oo+..     |
|  + o B=*o=      |
|  .+o+o*=@+.     |
|   oo+=**+E+     |
+----[SHA256]-----+

Al generar las claves podemos dejar todos las opciones por defecto, en cuyo caso se nos generarán los archivos correspondientes a una identidad genérica de nombre id_rsa en el directorio /home/<USER>/.ssh/ Sin embargo, es posible y, en ocasiones, aconsejable, utilizar un nombre personalizado para dichos archivos. De esta manera podemos crear varias identidades diferentes, lo que nos permitirá acceder a los servidores remotos bajo diferentes nombres de usuario. En nuestro ejemplo, los archivos creados son los siguientes:

ls ./.ssh/
id_rsa id_rsa.pub

Como podemos ver, la clave pública se guarda en un archivo con la extensión .pub, mientras que la clave privada está en un archivo sin extensión. Cada vez que generemos un nuevo par de claves, éste es el lugar en el que se almacenarán. Por supuesto, las claves pueden ser copiadas de una máquina a otra para poder conectarnos desde diferentes lugares.

En este sentido, es evidente que sólo será necesario generar un nuevo par de claves si no las hemos generado previamente en ésta o en cualquier otra máquina. En este caso, podemos saltarnos este paso y, simplemente, asegurarnos de tener las claves que queremos utilizar en este directorio.

Ahora ya podemos enviar nuestra clave pública al servidor al cual deseamos tener acceso para que nos reconozca a través de la clave privada, la cual permanecerá a buen recaudo en nuestro ordenador cliente.

ssh-copy-id <USERNAME>@<HOSTNAME>

O bien, si hemos especificado un nombre personalizado para el fichero (sin extensión):

ssh-copy-id -i <identidad> <USERNAME>@<HOSTNAME>

Obviamente, necesitamos tener acceso al servidor remoto mediante nombre de usuario y contraseña, los cuales se nos pedirán a continuación. El programa cliente ssh de nuestra máquina local conectará entonces con el servidor y transferirá la clave pública de la identidad especificada, la cual quedará almacenada en el servidor.

A veces, sobre todo si hemos elegido un nombre personalizado para la identidad, puede ser necesario especificar el directorio en el cual se encuentran las claves, es decir: ./.ssh/<identidad>

Insistimos en este punto: A pesar de que cuando especificamos la identidad en el comando anterior no ponemos la extensión, con lo que en realidad la ruta que hemos de escribir coincide con la de la clave privada, la única clave que se transfiere al servidor es la clave pública. Como regla general, una clave privada debe siempre permanecer en nuestro poder y jamás debería ser subida a ningún servidor público ni copiada a ninguna máquina que no está directamente bajo nuestro control y que sea lo bastante segura. Por algo se llama privada.

Y ya está. Sólo nos queda comprobar que podemos conectarnos sin problemas. Como al subir la identidad ésta queda asociada al nombre de usuario podemos, simplemente, escribir:

ssh <USERNAME>@<HOSTNAME>

¿Y si no puedo entrar?

En primer lugar, deberíamos comprobar que el servidor remoto ssh está correctamente configurado para aceptar conexiones mediante autenticación por clave pública. Ésta es la configuración por defecto, por lo que, en principio, no debería ser necesario. Sin embargo, cuando la cosa no funciona, éste uno de los puntos a comprobar, sobre todo si hemos estado toqueteando la configuración del servidor, la cual se encuentra en el siguiente archivo:

sudo nano /etc/ssh/sshd_config

Y comprobar que el parámetro PubkeyAuthentication no esté inadvertidamente configurado en no

Por cierto, ya que estamos, para incrementar la seguridad no está de más desactivar el acceso mediante contraseña:

PasswordAuthentication no

Otra causa frecuente por la que puede estar fallando es que el cliente no esté seleccionando de manera automática la identidad correcta. Esto puede pasar cuando ya llevo un tiempo creando y borrando identidades para entrar en distintos servidores bajo diferentes cuentas. En cualquier caso, la manera de asegurar el tiro es tan sencillo como explicitar la identidad de la que se trata:

ssh -i .ssh/identidad <USERNAME>@<HOSTNAME>
Publicado por David en Linux, Seguridad, SSH, 0 comentarios
A vueltas con openHAB

A vueltas con openHAB

Actualizando Openhab

Si hemos instalado Openhab siguiendo las recomendaciones, lo más probable es que hayamos elegido Zulu como la plataforma de Java. Sin embargo, Openhab no es compatible con versiones de Java mayores que 11 y si instalamos Zulu a partir de los repositorios, cada vez que haya una actualización inevitablemente se configurará la más reciente como versión por defecto. Por eso es necesario, antes de reiniciar Openhab, seleccionar la versión correcta de Java:

~$ sudo update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                          Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/zulu15/bin/java   2153801   auto mode
* 1            /usr/lib/jvm/zulu11/bin/java   2115401   manual mode
  2            /usr/lib/jvm/zulu15/bin/java   2153801   manual mode

Press <enter> to keep the current choice[*], or type selection number:
1 

Consola Karaf

OpenHab proporciona una consola desde la que poder monitorizar y gestionar algunos aspectos del sistema. Podemos conectarnos de dos maneras:
Si estamos estamos conectados con una sesión remota de shell:

openhab-cli console

Mediante ssh, solamente si estamos conectados localmente

ssh -p 8101 openhab@localhost

Por cierto, que las credenciales por defecto son:
usuario: openhab, contraseña: habopen

Archivos de log

El archivo principal de log se encuentra en la siguiente ubicación

 tail -f /var/log/openhab/openhab.log

Ahora bien, para definir qué es lo que queremos que quede registrado, la manera más sencilla es abrir una consola y ajustar el nivel de registro de depuración deseado:

log:set <nivel> <paquete>

Los niveles de depuración están definidos por constantes de este pelo: OFF, ERROR, WARN, INFO, DEBUG, TRACE, DEFAULT

Respecto a los nombres de los paquetes, podemos obtener un listado de la siguiente manera:

list -s

 

Publicado por David en Domótica, Linux, 0 comentarios
Utilidades de audio y vídeo

Utilidades de audio y vídeo

Descargar un vídeo…

…de youtube y otras páginas de streaming. No funciona siempre, pero cuando lo hace me suelo llevar una alegría.

youtube-dl https://youtube.com/xxxx

Extraer audio de un vídeo

Si lo que queremos es quedarnos únicamente con la música, obviamente.

ffmpeg -i sample.avi -q:a 0 -map a sample.mp3

Por cierto, que ffmpeg es un comando tan versátil que quizás un día añada una entrada solamente para él.

Convertir entre formatos

Y a propósito de la versatilidad de ffmpeg, la conversión entre formatos con las opciones por defecto resulta muy sencilla, ya que los formatos de entrada y de salida pueden, simplemente, especificarse a través de la extensión del archivo. Obviamente, existen parámetros para ajustar con precisión el modo en que se realiza la conversión.

ffmpeg -i input.wav output.mp3

El codec para H.264

Este codec viene por defecto con la aplicación VLC. Sin embargo, instalar esta aplicación nos permitirá reproducir este contenido solamente desde la propia VLC. Si queremos que el codec esté disponible para todo el sistema, es mejor instalarlo específicamente.

Instalamos unos paquetes por aquí…

sudo apt install libdvdnav4 gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly libdvd-pkg -y

Tras lo cual nos aparecerá un mensaje que nos advierte de la descarga de código fuente desde videolan.org (la web de VLC…), su compilación y nos preguntará si queremos que la actualización se realice automáticamente. Le decimos a todo que sí. Y para terminar…

sudo dpkg-reconfigure libdvd-pkg

Comando que, por cierto, es sugerido desde la misma salida de la compilación anterior. Pero por si no nos hemos fijado, ahí lo dejo también

Sobreimpresionar subtítulos

ffmpeg -i <video.mp4> -vf subtitles=<subs.srt>:force_style='FontSize=24' output.mp4

Extraer subtítulos de un archivo de vídeo

ffmpeg -i video.mkv -map 0:s:0 subs.srt

(para la primera pista de subtítulos. Para extraer las siguientes usar 0:s:1, etc)

Añadir pista de subtítulos a un archivo de vídeo

ffmpeg -i video.mp4 -i subs.srt -c copy -c:s mov_text output.mp4

 

Publicado por David en Linux, 0 comentarios

Usuarios y grupos

  • Listar usuarios o grupos

Una manera sencilla es consultar el contenido de los archivos /etc/passwd y /etc/group

  • Añadir un usuario o un grupo

Nota: Cada usuario debe pertenecer por lo menos a un grupo principal, que es el que viene especificado en el mismo archivo /etc/passwd. Adicionalmente podrá pertenecer a cuantos grupos más se desee, lo que vendrá indicado en el archivo /etc/group. Si durante la creación del usuario no especificamos ningún grupo se le asignará uno por defecto, el cual variará según el procedimiento utilizado. En unos casos se creará un grupo con el mismo nombre e ID que el usuario. En otros casos se asignará a un grupo especial de sistema llamado nogroup.

Lo primero es no confundir el comando adduser con useradd. Como regla general, y en la mayoría de las situaciones, utilizaremos adduser con las opciones deseadas. Por ejemplo, para añadir un usuario con un uid específico, utilizaremos el siguiente comando.

sudo adduser <USUARIO> --uid <UID>

En este caso, se crea por defecto un grupo con un gid = uid como grupo principal de dicho usuario. Además, se creará el directorio de usuario, se nos pedirá la contraseña y alguna otra información complementaria. Digamos que adduser es la herramienta administrativa por excelencia.

Y si lo que queremos es añadir un grupo con un GID específico:

sudo addgroup <GRUPO> --gid <GID>

 

Los comandos useradd y groupadd se utilizan para trabajar con usuarios y grupos en un más bajo nivel y de manera más granular.

  • Para comprobar uid o gid de un usuario

sudo id -u <usuario>
sudo id -g <usuario>
  • Elevar un usuario a sudoer

Basta con añadirlo al grupo sudo

sudo usermod -aG sudo <usuario>
  • Cambiar contraseña de un usuario

passwd <usuario>
    • Cuando se pasa sin argumentos, se entiende que se desea cambiar la contraseña del usuario actual.
    • Si no se suministra contraseña, no se cambia.
    • Sólo un usuario con privilegios de administrador puede modificar las contraseñas de otros usuarios
    • Las contraseñas se almacenan en formato cifrado en el archivo /etc/shadow
  • Comprobar a qué grupos pertenece un usuario

groups <usuario>
  • Borrar un usuario o un grupo

deluser <usuario>

o…

delgroup <usuario>
  • Borrar a un usuario de un grupo

deluser <usuario> <grupo>
  • Crear un usuario sin directorio de inicio ni capacidad de iniciar sesión

Esto es lo que viene a ser un usuario de sistema, es decir, un usuario que sirve para determinar la propiedad de determinados archivos o procesos pero que no va a trabajar en la máquina en cuestión.

En esta ocasión no se crea ningún grupo por defecto, lo cual es lógico tratándose de un usuario de sistema. Si queremos que se cree un grupo con el mismo nombre y ID deberemos utilizar la opción –group. De lo contrario, el usuario no pertenecerá a ningún grupo, lo que en la práctica significa que quedará asignado al grupo nogroup.

sudo adduser --system --no-create-home --uid <UID> --group <usuario>
Publicado por David en Herramientas, Linux, 0 comentarios
Securizar un stake pool

Securizar un stake pool

Lo primero, el servicio SSH

Lo primero que tenemos que hacer para estar razonablemente seguros de que nuestro stake pool se encuentra seguro ante posibles intrusiones es ajustar el servicio SSH a nuestras necesidades reales. en nuestro caso, utilizamos una autenticación de dos factores mediante un par de claves pública y privada y el servicio de autenticación de Goggle. Tampoco estaría de más restringir las direcciones desde las cuales vamos a autorizar las conexiones al servicio SSH, siempre que esto sea posible. Lógicamente, si estamos en una red privada o una VPN en la que disponemos de direcciones privadas bien definidas, o nos conectamos desde accesos con IP’s públicas fijas, esta opción es inmejorable. Sin embargo, si necesitamos conectarnos desde lugares más o menos arbitrarios con IP’s públicas o privadas asignadas dinámicamente, esta estrategia no es posible.

Como siempre, no existe un plan de seguridad estándar perfecto. El mejor plan de seguridad es el que se adapta de manera adecuada a la estructura de nuestro sistema y a las circunstancias personales de cada cual.

Después, el firewall

Lo siguiente es restringir el tráfico a nuestros ordenadores mediante el firewall. Como la mayoría de operadores de Stake Pools, he elegido la opción de ufw (Uncomplicated FireWall) frente a la configuración de IPtables. Sé que los más avezados expertos en Linux no tardarán en advertir que si IPtables existe es por algo, y que su mayor complejidad ofrece la contrapartida de un control mucho más preciso y robusto de las conexiones del PC. Y tendrán toda la razón. En mi descargo diré que también es bastante más lioso de configurar y, por lo tanto, mucho más probable que en manos de un zarpas como yo se deslicen gazapos que puedan convertirse en brechas de seguridad.

Es importante entender que la seguridad real implica un compromiso entre la robustez de la herramienta y la habilidad para manejarla de manera correcta. No hay nada más peligroso que un AK-47 en manos de un chimpancé.

Y, la verdad, es que ufw cumple con este cometido, al menos para mí. Si un día me decido a estudiar IPtables a fondo, os prometo que seréis los primeros en saberlo.

Dicho esto, lo primero será asegurarnos de que tenemos ufw instalado en nuestro equipo, lo cual no es difícil porque en la mayoría de distribuciones suele venir por defecto. En cualquier caso, basta con teclear:

sudo apt install ufw

Reading package lists... Done
Building dependency tree       
Reading state information... Done
ufw is already the newest version (0.36-6).
ufw set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

Lo cual nos demuestra que, efectivamente, ya está instalado. Cuando hacemos esto, nos encontramos con el mensaje de que el paquete en cuestión ha sido marcado como instalado manualmente, lo cual a mí, que soy un maniático, me ralla un poco. Si quieres saber más, mira esta otra entrada.

Volviendo al firewall, lo primero que comprobamos es su estado

sudo ufw status
Status: inactive

Es decir, que viene deshabilitado por defecto. Lo cual es conveniente para evitar cortar servicios que pudieran estar en ejecución antes de poder configurarlo. Sin ir más lejos, si estamos conectados a la máquina por SSH y habilitamos el firewall ya podéis imaginar lo que iba a pasar (spoiler: la conexión se corta sin posibilidad de volver a conectar hasta poder acceder físicamente)

Así que lo primero de todo, habilitaremos la conexión al servicio ssh

sudo ufw allow ssh
Rules updated
Rules updated (v6)

Como vemos, esta es una manera rápida de habilitar conexiones al ordenador, basándonos en servicios, en lugar de puertos.

Nota: En muchos manuales veremos que es interesante como medida adicional de protección modificar el puerto por defecto utilizado por el servicio ssh (que pertenece a ese grupo de puertos denominados como «bien conocidos» y que corresponde siempre al 22). En mi opinión, se trata de una medida más incómoda que eficaz. Cualquier atacante puede imaginar que el servicio ssh se puede estar ejecutando en cualquier otro puerto y el primer paso antes de probar nada suele ser un escaneo de puertos para averiguar qué tenemos por ahí. Y lo mismo vale para cualquier servicio ejecutado en uno de los susodichos «well known ports»

Ahora sí, habilitamos el firewall

sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Y como era de esperar en un programa bien implementado y dirigido a dummies como yo, nos advierte de los peligros antes de hacernos caso.

Comprobemos las reglas que tenemos hasta ahora:

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere 
22/tcp (v6)                ALLOW       Anywhere (v6)       

Efectivamente, el bien conocido puerto 22 accesible para el protocolo tcp desde cualquier lugar. Eso es lo que ha mantenido nuestra conexión activa. Nuevamente, si sabemos desde qué direcciones nos vamos a conectar, éste sería otro buen lugar para restringir el acceso desde esas direcciones, además de la configuración del propio servicio ssh. Cuantas más puertas, mejor.

Bien, si ya teníamos nuestro stake pool en funcionamiento con un núcleo y un relé hablando entre sí, será interesante lanzar la aplicación gLiveView para ver lo que ha pasado. Y es que, si todo va bien, las dos máquinas ya no podrán hablar entre sí. Al menos, el relé ya no podrá acceder al núcleo, ya que éste está restringiendo todas las conexiones entrantes. Lógicamente, nos interesa añadir una regla que permita esta comunicación. Será la siguiente:

sudo ufw allow proto tcp from <IP_RELAY> to any port <PORT_KERNEL>

En cristiano, permitir toda conexión entrante en protocolo tcp desde la IP del relé al puerto en el cual se ejecuta el nodo del núcleo. Sencillo, ¿no?

Comprobemos…

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
<PORT_KERNEL>/tcp          ALLOW       <IP_RELAY>             
22/tcp (v6)                ALLOW       Anywhere (v6) 

Y para evitar paranoias, nada como un túnel SSH

Cualquier manual básico de Cardano nos explica que la necesidad de disponer un cierto número de relés además del nodo productor de bloques (o núcleo) tiene que ver con una cuestión básica de seguridad: el núcleo jamás debería estar directamente expuesto a la red. De este modo, los únicos nodos que pueden ser comprometidos son los relés, y si disponemos de más de uno, bastaría con apagarlo y usar los otros mientras arreglamos el desaguisado. Pero claro, la primera pregunta que surge es… y si el núcleo no está abierto a la Internet… ¿cómo diablos me conecto a él para configurarlo? Si te has hecho esta pregunta, felicidades: vas por el buen camino (y estás jodido).

Y ahora, veamos las distintas respuestas:

1.- ¡Qué le vamos a hacer!

Dejaremos el puerto ssh abierto con un porrón de medidas de seguridad, especiamente, autenticación multifactorial (MFA) y cruzaremos los dedos.

Bien, no está mal. Conozco a unos cuantos que han seguido esta política y aún no les ha pasado nada. Afortunadamente, un servicio ssh bien configurado es muy seguro.

2.- Restringimos también el acceso ssh a través del relé.

Es decir, nos conectaremos mediante ssh al relé, y de allí al núcleo. Es una medida muy sensata. Y lo único que requiere es modificar un poquito el firewall para que el acceso al núcleo quede restringido únicamente al relé.

Añadimos una regla por aquí… (la que nos permitirá el acceso al núcleo desde el relé)

sudo ufw allow proto tcp from <IP_RELAY> to any port 22

Con lo cual:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
6000/tcp                   ALLOW       <IP_RELAY>             
22/tcp                     ALLOW       <IP_RELAY>             
22/tcp (v6)                ALLOW       Anywhere (v6)   

Y eliminamos otra por allá… (la que permitía el acceso ssh indiscriminado)

sudo ufw delete 1
Deleting:
 allow 22/tcp
Proceed with operation (y|n)? y
Rule deleted

Y ya estaría. Sin embargo, esta estrategia plantea un nuevo problemilla nada trivial. Como comentábamos en el apartado relativo a la conexión segura con SSH, si ya era importante no dejar la llave privada en cualquier máquina local, aún más lo será no dejarla permanentemente en el relé para cuando necesitemos realizar la conexión al núcleo desde allí. La solución de copiarla mediante scp y borrarla cada vez puede ser una opción, pero desde luego resulta lo bastante incómoda como para caer en la muy humana tentación de dejarla almacenada en el relé y confiar en el sistema 2FA. Aunque, si todo este guirigay de relés tienen que ver con considerar la posibilidad de que se estos puedan verse comprometidos, ya no parece tan buena opción, ¿verdad?. Afortunadamente, aún existe una tercera opción (y más que habrá, pero hasta aquí llega mi cacumen por hoy).

3. Crear un túnel ssh desde la máquina local al núcleo a través del relé

Y una vez establecido dicho túnel, conectarnos directamente desde la máquina local al núcleo. Tenemos como prerequisito que la máquina núcleo sea accesible únicamente desde la máquina relé, lo cual ya ha quedado descrito en la opción número 2. La magia vienen a continuación:

En primer lugar, creamos un túnel a través del relé que redirija un puerto de nuestra máquina local a otro puerto de la máquina núcleo.

ssh -L 8022:<IP_CORE>:22 <user_relay>@<IP_RELAY> -i /route-to-key/private-key

Este comando crea un túnel desde el puerto 8022 de mi máquina local al puerto 22 de la máquina core. Utilizamos el puerto local 8022 ya que el puerto 22 suele estar ocupado por el servidor ssh local y es preferible utilizar uno libre para evitar conflictos. Los datos de conexión son los mismos que usamos para conectar al relé: el nombre de usuario y su IP. Y, por supuesto, la clave pública que guardamos en nuestro pendrive, y que se especifica con el parámetro -i (identidad). Si todo va bien, el único dato que nos pedirá será el código del Google Authenticator y el túnel quedará establecido.

Desde ahora, cualquier petición al puerto 8022 a la máquina local será como si la realizáramos directamente al puerto 22 del nucleo, por lo que podremos conectar simplemente así:

ssh  -p 8022 <user>@127.0.0.1 -i /route-to-key/private-key 

Es decir, que en realidad nos estamos conectando a nuestra propia máquina en el puerto 8022. Y, por supuesto, el archivo de clave privada permanece a buen recaudo en nuestro preciado pendrive. ¿A que mola?

Publicado por David en Cardano, Linux, Seguridad, SSH, 0 comentarios

Iniciar un servicio mediante systemd

En este caso se trata de una Raspberry Pi que controla unos paneles de leds que muestran, además de la fecha y la hora, algunos mensajes de información provenientes del controlador domótico mediante el protocolo MQTT, tales como la temperatura de distintas estancias, o la música que se está reproduciendo en ese momento (Y sí, os habéis fijado bien. La fecha viene en Esperanto. Qué le vamos a hacer…). El dispositivo cuenta además con un sensor de luz, el cual le permite, además de regular la luminosidad de los leds en función de la luz ambiente, proporcionar al sistema información sobre el nivel de luminosidad real de la estancia, permitiendo un control preciso de persianas y luces regulables.

Aspecto del reloj con matriz de leds en la parte superior de la librería de mi dormitorio, junto a algunos libros y colecciones de pelis en viejos archivadores de CD’s. Todo un compendio de mis pequeñas pasiones 😉

Para que el dispositivo funcione de manera autónoma, el programa deberá arrancar automáticamente cuando se encienda la placa, lo cual se puede lograr de varias maneras. Una de ellos, seguramente la más conocida, consiste en añadir la ruta al ejecutable en el archivo /etc/rc.local, aunque también es posible iniciar tareas utilizando el servicio crontab. En ambos casos tenemos un pequeño problema, y es que si el programa se cuelga o experimenta una salida inesperada debida a cualquier excepción no convenientemente capturada, todo el dispositivo se detiene dejando de funcionar.

Para salir al paso, una solución consiste en ejecutar el programa como un servicio. En el  caso que nos ocupa vamos a utilizar el sistema systemd, el cual presenta, entre otras, la gran ventaja de que si se produce un error y el progama se detiene, él mismo se reinicia automáticamente. Algo que a los manazas que vamos dejando rastros de programas mal depurados nos viene que ni de perlas. También es un sistema bastante robusto y que nos permite ajustar las condiciones adecuadas para la ejecución del probrama.

Lo primero que necesitamos es un archivo de script que contenga las instrucciones de inicio de nuestro programa. Si fuera necesario pasar parámetros para el inicio este archivo sería un lugar adecuado para especificarlos. En nuestro caso, es una simple llamada a la ejecución de un script Python:

nano /home/pi/mqtt-matrix/start.sh

#!/bin/bash
#
python3 /home/pi/mqtt-matrix/mqtt-matrix.py

Lo siguiente será la creación del archivo de unidad de servicio. Éste contendrá el nombre con el que queremos que systemd reconozca a nuestro servicio. Aunque sería improbable, no está de más comprobar que no vamos a darle un nombre que ya se encuentra en uso. Para ello, basta con echar un vistazo al contenido de la carpeta que suele contener los archivos de unidad de servicio:

cd /etc/systemd/system/
ls

También podemos probar este comando más específico y que resulta de lo más molón:

sudo systemctl list-unit-files --type=service

En mi caso, como el programa que pretendo ejecutar está en el archivo mqtt-matrix.py, he decicido que el servicio se llame mqtt-matrix.service y listos. Así que creamos el archivo en cuestión:

sudo nano /etc/systemd/system/mqtt-matrix.service

[Unit]
Description=mqtt-matrix
Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
ExecStart=/home/pi/mqtt-matrix/start.sh
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

El archivo que hemos creado contiene las opciones más comunes, la mayoría de las cuales resultan bastante autoexplicativas. Además, podríamos especificar el usuario y el grupo bajo el cual se va a ejecutar nuestro servicio. Si no se especifica nada, por defecto se ejecutará con permisos de administrador, que es exactamente lo que deseamos, por ser uno de los requisitos del modo en el que accedemos a los pines de nuestra raspberry, así que lo dejamos tal cual.

Y ya está. A continuación enumeramos varios de los comandos más utilizados para manejar los servicios systemd

Recargar los archivos de servicio después de alguna modificación

sudo systemctl daemon-reload

Iniciar el servicio

sudo systemctl start mqtt-matrix.service

Detener el servicio

sudo systemctl stop mqtt-matrix.service

Reiniciar el servicio

sudo systemctl restart mqtt-matrix.service

Comprobar el estado del servicio

Además, nos proporciona información adicional, tal como:

  • Avisarnos si tenemos errores en la sintaxis del archivo, aunque el servicio no esté en ejecución
  • Indicarnos la ruta del ejecutable
  • Indicarnos la ubicación del archivo de servicio si no está donde esperábamos
sudo systemctl status mqtt-matrix.service

Y, lo más importante, teniendo en cuenta de qué va todo esto, indicarle al sistema que queremos que el servicio arranque automáticamente al inicio

sudo systemctl enable mqtt-matrix.service

O bien, deshabilitar el arranque al inicio

sudo systemctl disable mqtt-matrix.service
Publicado por David en Domótica, Linux, 0 comentarios
Funciones útiles con el Subsistema Linux en Windows 10 (WSL)

Funciones útiles con el Subsistema Linux en Windows 10 (WSL)

  • Acceder a una memoria USB desde WSL

En la estructura de archivos del subsistema de Linux vienen por defecto varios directorios con las típicas letras de unidad de disco de windows. En efecto, si miramos el contenido de la carpeta de montaje:

ls /mnt

c d e f

Sin embargo, cuando entramos en el directorio correspondiente a la letra de unidad donde tenemos insertada la memoria, resulta que está vacío. Al parecer, las unidades externas no se montan automáticamente, sino que hay que hacerlo explícitamente mediante el comando mount . En el siguiente ejemplo, vemos los parámetros con los que ejecutar este comando cuando montamos la unidad presente en E:

sudo mount -t drvfs E: /mnt/e

Y para desmontar, exactamente igual que en Linux…

sudo sudo umount /mnt/e
  • Acceder a los archivos del espacio WSL desde Windows

El espacio de archivos utilizado por WSL está disponible directamente desde el explorador de Windows 10 introduciendo esta ruta en la barra de direcciones del explorador de archivos: \\wsl$\Ubuntu

Nota: Si nos fijamos en la notación, veremos que Windows 10 maneja esta ruta como un sitio de red. Para que la ubicación de red esté montada, será necesario que en ese momento se esté ejecutando la sesión correspondiente en el WSL

Publicado por David en Blog, Linux, 0 comentarios