Configurando repositorios de terceros en Debian 9 «Stretch»

Logotipo oficial de uso libre de Debian.

En el trabajo se avecina una época de cambios radicales. Para anticiparnos llevamos algunas semanas diseñando, investigando y realizando todo tipo de preparativos.

Entre las tareas, tocaba preparar algunas máquinas nuevas para reemplazar el último servidor monolítico que aún presta servicio tras más de 10 años, cientos de actualizaciones, varias migraciones tanto de software como de hardware, alguna mudanza (literalmente, transportado entre edificios del campus en el maletero de un coche) y una conversión de físico a virtual a sus espaldas. Así que me puse manos a la obra y preparé una instalación desatendida de Debian 9 «Stretch», la última versión liberada, para ir desgajando el servidor en varios “micro—servicios”.

Uno los servicios se pretende montar sobre Symfony 4 que tiene como requisito mínimo PHP 7.1.3 mientras que Debian distribuye PHP 7.0.30. También son necesarios Node.js junto a Yarn que no se encuentran en los repositorios oficiales de Debian. Tocaba añadir algunos repositorios de terceros que proporcionaran esos paquetes.

Sin embargo, tras configurar como siempre los repositorios, falla la comprobación de una firma. Buscando qué podía pasar, descubro que hay una nueva forma de gestionar los repositorios pero que, como aplicamos cual robot descerebrado las recetas de siempre repetidas hasta la saciedad en blogs/FAQ/tutoriales desfasados, había pasado completamente desapercibida en la documentación oficial.

Así que me planteé describir la nueva forma para arrojar un poco más de luz. Aunque está orientado a Debian probablemente pueda aplicarse a todas las distribuciones derivadas de ella (Ubuntu, Mint…) pero es imprescindible leer la documentación o manuales al respecto.

Este artículo está plagado de simplificaciones ya que el objetivo es ser una referencia sencilla de fácil comprensión y no una detallada e intrincada explicación técnica.

Para quienes estén interesados en profundizar en los distintos aspectos, se proporcionan enlaces a la documentación.

Repositorios en Debian

Simplificando muchísimo, los repositorios en Debian suelen ser webs (aunque pueden usarse otros protocolos) que proporcionan los distintos paquetes junto a índices/metadatos que entiende APT.

Desde siempre, los repositorios que se querían utilizar se listaban en el fichero /etc/apt/sources.list que, tras la instalación, suele tener cuatro o cinco fuentes en función de las elecciones tomadas en el instalador.

deb     http://deb.debian.org/debian stretch main non-free contrib
deb-src http://deb.debian.org/debian stretch main non-free contrib

deb     http://deb.debian.org/debian-security stretch/updates main contrib non-free
deb-src http://deb.debian.org/debian-security stretch/updates main contrib non-free

# stretch-updates, previously known as 'volatile'
deb     http://deb.debian.org/debian stretch-updates main contrib non-free
deb-src http://deb.debian.org/debian stretch-updates main contrib non-free

# stretch-backports, previously on backports.debian.org
deb     http://deb.debian.org/debian stretch-backports main contrib non-free
deb-src http://deb.debian.org/debian stretch-backports main contrib non-free

Si se necesitaban paquetes de otro repositorio, simplemente se añadían líneas al fichero, se actualizaba y los paquetes quedaban accesibles. Los repositorios proliferaron, habitualmente proporcionando paquetes que no cumplían las políticas para entrar en los oficiales o proporcionando versiones más actualizadas, llegando el punto en el que surgieron webs capaces de generar el fichero según los repositorios que el usuario elegía de una inmensa lista1.

Según se añaden más y más repositorios, el fichero crece en tamaño y complejidad, llegando a resultar poco manejable y muy propenso a errores. Para abordar este problema surge el directorio /etc/apt/sources.list.d/ en el que se podían añadir ficheros, con el mismo formato y extensión, que se cargaban como si se tratara del /etc/apt/sources.list. Esto permitía organizar así los repositorios en varios grupos simplificando la gestión: podría desactivarse uno de ellos eliminando o cambiando la extensión sin necesidad de buscar y editar un fichero de cientos de líneas.

La práctica habitual es reservar el fichero /etc/apt/sources.list para las entradas de los repositorios oficiales (básicamente, las que genera el instalador) y crear un fichero para cada repositorio de terceros en el directorio /etc/apt/sources.list.d/.

Verificando paquetes

Otro de los aspectos importantes es verificar el origen y la integridad de los paquetes. Debian utiliza la firma digital basada en GPG desde el año 20052: existe un fichero denominado Releases que se distribuye junto a su firma (Releases.gpg) mediante una clave que únicamente tiene el administrador del repositorio.

El fichero Releases contiene un hash de comprobación de varios ficheros de metadatos que, a su vez, contienen otros hashes cubriendo todos los ficheros de los paquetes distribuidos. Cualquier modificación en cualquier fichero hará que cambie su hash de comprobación, alterará alguno de los ficheros de metadatos y por lo tanto cambiará el fichero Releases y su firma Relases.gpg.

Cada vez que se descarga algo del repositorio, se verifica la firma de este fichero y los distintos hashes de comprobación. En el caso de que alguno no coincida, se asume que está comprometido y no se utiliza en el proceso de instalación o actualización de paquetes.

Este mecanismo, ampliamente utilizado en informática, permite verificar que los paquetes son los que deberían ser, pero deja un asunto pendiente: la gestión de la confianza en las claves de firma de los distintos repositorios.

Esta gestión se realizaba mediante la herramienta apt-key (un recubrimiento de GPG). En las instrucciones para añadir el repositorio se solía indicar la forma de obtener la clave pública GPG que, normalmente, se dejaba en la raíz del repositorio consultable por HTTP o se subía a algún servidor de claves, y cómo confiar en ella.

wget -qO - http://thirdparty.example.com/archive.key | sudo apt-key add -

Inicialmente apt-key almacena esta información en un llavero GPG situado en /etc/apt/trusted.gpg, que contiene todas las claves de confianza. Cuando APT realiza la verificación de cualquier firma, comprueba si está generada por alguna de las claves de confianza registradas en el fichero para decidir si se considera válido o no.

De manera similar a la aparición del directorio /etc/apt/sources.list.d/, aparece el directorio /etc/apt/trusted.gpg.d/ para poder tener cada clave por separado en lugar de tener que gestionar el llavero añadiendo/borrando claves, un paralelismo evidente.

Nuevo sistema

Entre los ficheros /etc/apt/sources.list y /etc/apt/trusted.gpg (y sus variantes en directorio) existe una pequeña y sutil diferencia que genera serias implicaciones: las listas de repositorios son claramente globales para toda la instalación mientras que las claves son de aplicación para un repositorio concreto. Sin embargo, tanto el fichero /etc/apt/trusted.gpg como el directorio /etc/apt/trusted.gpg.d/, tienen carácter global: una clave almacenada en ellos validará cualquier repositorio.

Lo ideal sería indicar de manera unívoca qué clave debe utilizarse para validar las firmas de cada repositorio. Y ahora es posible, aunque hay que cambiar ligeramente la forma de trabajar3.

El primer cambio: no se utilizará apt-key (/etc/apt/trusted.gpg) o el directorio /etc/apt/trusted.gpg.d/. En su lugar las claves públicas se almacenarán en /usr/share/keyrings/ como una clave GPG binaria4. Estas claves se podrán obtener desde la raíz del repositorio (en un fichero denominado [repo]-archive-keyring.gpg) o desde algún servidor de claves.

El segundo cambio es que es necesario indicar expresamente la clave de firma utilizada en cada repositorio, añadiendo el parámetro signed-by a las entradas en el /etc/apt/sources.list.d/

deb     [signed-by=/usr/share/keyrings/thirdparty-archive-keyring.gpg] https://thirdparty.example.com/debian/ stable main
deb-src [signed-by=/usr/share/keyrings/thirdparty-archive-keyring.gpg] https://thirdparty.example.com/debian/ stable main

Aunque es posible añadir la opción en los ficheros .list existentes, existe un nuevo formato para definir los repositorios que está recomendado.

El formato deb822

En lugar de entradas deb / deb-src en un fichero .list, está recomendado utilizar el formato deb822 para definir los repositorios a incluir.

Basta con crear un fichero con extensión .sources en el directorio /etc/apt/sources.list.d/

Types       : deb deb-src
URIs        : https://thirdparty.example.com/debian/
Suites      : stable
Components  : main
Signed-By   : /usr/share/keyrings/thirdparty-archive-keyring.gpg

El formato es más conciso y mucho más potente al generar el producto cartesiano de todas las opciones. Esto redunda en una menor probabilidad de error.

Usando uno de los ejemplos de página man sources.list (5), el fichero .sources:

Types       : deb deb-src
URIs        : http://deb.debian.org/debian
Suites      : stable testing unstable
Components  : main contrib non-free

equivale al fichero .list:

deb     http://deb.debian.org/debian stable   main contrib non-free
deb-src http://deb.debian.org/debian stable   main contrib non-free
deb     http://deb.debian.org/debian testing  main contrib non-free
deb-src http://deb.debian.org/debian testing  main contrib non-free
deb     http://deb.debian.org/debian unstable main contrib non-free
deb-src http://deb.debian.org/debian unstable main contrib non-free

Evidentemente, existe una mayor probabilidad de introducir un error en el fichero .list al tener que duplicar múltiples veces la misma información (la URI aparece seis veces). Si se añaden otros parámetros (el signed-by para indicar la clave de firma o la arquitectura…), la probabilidad aumenta exponencialmente.

Conversión

Como este mecanismo es bastante nuevo, es habitual encontrarse con repositorios que siguen distribuyendo claves para descargar en /etc/apt/trusted.gpg.d/ o, incluso, que explican como añadirlas al fichero /etc/apt/trusted.gpg utilizando apt-key. En los peores casos se proporciona un script que automatiza el registro del repositorio y de la clave asociada usando alguno de estos métodos, ocultando las direcciones en el proceso, y que es necesario analizar para poder realizar la conversión.

Cuando se tiene la URL de la clave pública en cualquier formato es relativamente trivial almacenarla como un fichero GPG binario (el ejemplo usa wget aunque se puede usar curl o cualquier otro mecanismo para descargar el fichero):

wget -qO - http://thirdparty.example.com/debian/thirdparty.gpg | gpg --no-default-keyring --keyring /tmp/thirdparty.gpg --import
gpg --no-default-keyring --keyring /tmp/thirdparty.gpg --export --output /usr/share/keyrings/thirdparty-archive-keyring.gpg

Si se distribuye a través de un servidor de claves el proceso es ligeramente diferente:

gpg --no-default-keyring --keyring /tmp/thirdparty.gpg --keyserver keyserver.example.com --recv-keys [FINGERPRINT]
gpg --no-default-keyring --keyring /tmp/thirdparty.gpg --export --output /usr/share/keyrings/thirdparty-archive-keyring.gpg

En ambos casos, el fichero almacenado en /tmp/thirdparty.gpg puede eliminarse sin problemas tras exportar la clave.

Conclusión

En resumen, para registrar un repositorio de terceros basta con crear un fichero en /etc/apt/sources.list.d/[reponame].sources con el formato deb822 indicando la clave de firma del mismo (opción Signed-By) que se almacenará en /usr/share/keyrings/[reponame]-archive-keyring.gpg en formato GPG binario. También es posible hacerlo creando el fichero /etc/apt/sources.list.d/[reponame].list con entradas tipo deb o deb-src con dicha opción, aunque está recomendado utilizar el nuevo formato.

En cualquier caso, hay que tener precaución antes de instalar paquetes de fuentes desconocidas. Esos paquetes pueden modificar el sistema de manera no deseada y acarrear serios problemas de seguridad o, incluso, legales. Es necesario aplicar el sentido común y entender las implicaciones antes de realizar este tipo de modificación en un sistema.

Por último, una pequeña reflexión. Cuando se busca información sobre este tema es muy habitual encontrar documentación o tutoriales escritos hace más de 10 años centrados en apt-key (la herramienta usada por aquel entonces) y repetidos constantemente en todo tipo de medios. Es importante fijarse en la fecha de publicación para saber si es posible que la información esté desfasada y contrastarla con publicaciones más recientes (cuidado con el copy & paste) y la documentación oficial. Esto se aplica a todo: probablemente este artículo dentro de 10 años quede desfasado y carezca de validez.

Ejemplos

Estos son algunos pequeños scripts que utilizo para configurar repositorios en mis máquinas. Normalmente los uso más como recordatorio o base y suelen requerir algún tipo de modificación.

Estos scripts precisan ejecutar como root. Antes de ejecutar cualquier tipo de código con esos permisos es necesario comprender las implicaciones.

Los scripts se proporcionan como ejemplos y sin garantía de ningún tipo. No me hago responsable de que funcionen como es debido o de los daños de cualquier tipo ocasionados por su uso.


  1. Aunque algunos de los generadores iniciales han dejado de existir, surgen nuevas alternativas como Debian Sources List Generator o Ubuntu Sources List Generator en las que se pueden ver la ingente cantidad de repositorios que pueden añadirse a estas distribuciones que conocen estas herramientas. ↩︎

  2. La información detallada sobre este mecanismo se puede leer en Secure Apt↩︎

  3. La nueva forma de añadir un repositorio de terceros en Debian está descrita en la documentación oficial del proyecto. ↩︎

  4. Justamente este es el punto que me llevó a descubrir esta solución. Al añadir un repositorio bajé esta clave binaria y la añadí a /etc/apt/trusted.gpg.d/. Al ser un formato inválido, la ignoraba generando errores en la verificación de las firmas. ↩︎

Oscar Cubo Medina
Oscar Cubo Medina
Ingeniero en informática

Responsable técnico @ DC Rectorado—UPM. Ciencia, informática, música, libros y nuevas tecnologías.

Relacionado