Compilar "Apache HTTP" con soporte ACME en SmartOS

Apache HTTP añadió soporte nativo para el protocolo ACME (renovación automática de certificados X.509) en la versión 2.4.30 del servidor, como un componente opcional y experimental del mismo. La versión del paquete PkgSrc distribuido en SmartOS no tiene dicho módulo, así que en abril de 2020 pedí que se incluyese.

La respuesta fue algo decepcionante: Se añadía a PkgSrc la opción de compilar ese módulo opcional, mod_md, pero dado que sus propios autores lo tienen marcado como experimental, el paquete precompilado para SmartOS seguiría sin incluirlo de serie.

Pero, al menos, ahora puedo compilarlo de forma trivial yo mismo si lo necesito.

No voy a entrar en detalles sobre cómo compilar paquetes en PkgSrc para SmartOS. Este blog tienen muchos artículos sobre este tema, accesibles desde el menú de Tags de la parte superior de la página.

Los pasos concretos para compilar Apache HTTP con el módulo mod_md en una zona PkgSrc de SmartOS son los siguientes:

Leer más…

Compilar una versión más moderna de "Bind" que la disponible en PkgSrc para SmartOS

En Compilar "Bind" en PkgSrc para SmartOS con la opción de "dnstap" describo cómo compilar Bind en SmartOS con soporte dnstap, utilizando PkgSrc. Por favor, lee dicho artículo para entender qué estoy haciendo y por qué.

El principal problema en ese artículo es que estoy utilizando la versión trunk de PkgSrc para beneficiarme de una versión más moderna de Bind, pero eso implica que la versión compilada utiliza bibliotecas no disponibles en la paquetería estándar de SmartOS y tenemos que compilarlas, distribuirlas e instalarlas a mano.

Si en vez de utilizar la versión trunk de PkgSrc utilizamos la versión que se corresponda a la Zona SmartOS en la que vamos a instalar Bind, no necesitaremos hacer nada especial con las dependencias.

Nota

Para lo que sigue nos conviente conocer la filosofía de PkgSrc: En PkgSrc, de forma automática, se descarga una versión concreta del código fuente que queremos compilar, se verifica su hash para asegurarnos de que es la versión correcta y no nos están colando gato por liebre, se le aplican una serie de parches locales, que es lo que se mantiene en realidad en PkgSrc, se compila y se genera un paquete. Esta gestión separada del código fuente original y los parches locales que necesitamos en nuestro sistema es la piedra angular de PkgSrc. Permite, por ejemplo, que no se requiera colaboración por parte de los autores originales de los programas para que soporten nuestro sistema operativo. Esto va como anillo al dedo con SmartOS, porque no podemos contar con que nadie ajeno le de mimos y cuide de él.

Los cambios respecto a Compilar "Bind" en PkgSrc para SmartOS con la opción de "dnstap", serán:

  1. Usamos una zona nativa SmartOS con la versión del software PkgSrc que se corresponda a las zonas nativas SmartOS donde vamos a instalar el Bind que compilamos, en vez de la versión trunk de PkgSrc:

    [root@xXx ~]# imgadm avail|grep -i pkgbuild-lts
    188ee9ce-540a-11eb-9cc1-2748cd10e5e2  pkgbuild-lts                    20.4.0        smartos  zone-dataset  2021-01-11
    bd5afd7a-7ec1-11ec-80ab-7b01241031f6  pkgbuild-lts                    21.4.0        smartos  zone-dataset  2022-01-26
    758a4572-911d-11ed-b841-00151714048c  pkgbuild-lts                    22.4.0        smartos  zone-dataset  2023-01-10
    

    Queremos compilar Bind para utilizarlo en una zona 22.4.0, así que importamos esa versión de zona PkgSrc y la desplegamos en una zona de nuestra máquina SmartOS.

  2. Entramos en la zona PkgSrc por SSH y le pedimos que cree un entorno virtual de compilación:

    [root@PkgSrc ~]# run-sandbox 2022Q4-x86_64
    
    It looks like this is the first sandbox creation for this pkgbuild.  It
    will take longer than normal, as support packages need to be downloaded
    first.  Subsequent runs will be much faster after they have been cached.
    
    [...]
    
    Unpacking bootstrap-2022Q4-x86_64 into /data/chroot/dev-2022Q4-x86_64...done.
    Setting up environment...done.
    Installing additional tools packages...done.
    Logging in.  WARNING: On logout the sandbox will be destroyed.
    
    ,---.                   |     ,---. ,---.
    `---. ,-.-. ,---. ,---. |---  |   | `---.  pkgbuild-lts
        | | | | ,---| |     |     |   |     |  22.4.0
    `---' ` ' ' `---' `     `---' `---' `---'
    
    --<root@PkgSrc>-(/data/chroot/dev-2022Q4-x86_64)-<~>--
    ->
    

    Obsérvese que le estamos pidiendo un entorno de compilación 2022Q4-x86_64. En teoría las zonas PkgSrc modernas pueden compilar código para versiones más antiguas de las zonas SmartOS, solicitando la creación del entorno de compilación adecuado.

Leer más…

Parche de idempotencia "pkgin" SmartOS para Ansible

A la hora de usar Ansible en SmartOS una molestia constante es que, a veces, al volver a ejecutar un script Ansible, nos dice que realiza de nuevo las acciones pkgin (instalación de paquetes PkgSrc) o bien salta una excepción Python. Esto no ocurre siempre, pero sí ocurre con frecuencia.

Me explico: Las acciones Ansible se diseñan para que sean idempotentes. Es decir, que lanzar una acción que ya se ha realizado en el pasado debe marcar la acción como "ya realizada", en vez de realizarla de nuevo. En el caso concreto de las acciones pkgin, si le pedimos que instale un paquete que ya está instalado, debería decirnos que ya está hecho y no, en cambio, decirnos que ha realizado la acción de nuevo o fallar sin motivo. Es decir, el resultado de la acción debería ser ok y no changed o, peor aún, que salte una excepción.

En pocas palabras, cuando ejecutamos un script Ansible dos veces, la segunda vez debería darnos ok en todas las acciones porque no ha tenido que hacer nada.

Pero Ansible no lo hace así en el caso de acciones pkgin siempre. A veces lo hace y a veces no, por motivos desconocidos. Y cuando no lo hace, puede saltar una excepción Python.

Cuando ocurre así, si lanzamos de nuevo el script Ansible termina correctamente... casi siempre.

Molesto con la situación, estudio el código fuente de Ansible, que está escrito en Python. Me encuentro lo siguiente, entre otras cosas, en ansible_collections/community/general/plugins/modules/pkgin.py:

if rc == 0:
    if re.search('^nothing to do.\n$', out):
        module.exit_json(changed=False, msg="nothing left to upgrade")
    else:
        module.fail_json(msg="could not %s packages" % cmd, stdout=out, stderr=err)

Aquí se está buscando que el comando pkgin de SmartOS devuelva la cadena "nothing to do.", tal cual. El problema es que pkgin, al menos en las versiones modernas de SmartOS, termina con esa cadena cuando no tiene nada que hacer, pero puede ir precedida por bastante más texto y eso el código de Ansible no lo contempla.

Leer más…

Compilar "Bind" en PkgSrc para SmartOS con la opción de "dnstap" (II)

En Compilar "Bind" en PkgSrc para SmartOS con la opción de "dnstap" describo cómo compilar Bind en SmartOS con soporte dnstap, utilizando PkgSrc. Por favor, lee dicho artículo para entender qué estoy haciendo y por qué.

El principal problema en ese artículo es que estoy utilizando la versión trunk de PkgSrc para beneficiarme de una versión más moderna de Bind, pero eso implica que la versión compilada utiliza bibliotecas no disponibles en la paquetería estándar de SmartOS y tenemos que compilarlas, distribuirlas e instalarlas a mano.

Si en vez de utilizar la versión trunk de PkgSrc utilizamos la versión que se corresponda a la Zona SmartOS en la que vamos a instalar Bind, no necesitaremos hacer nada especial.

Los cambios respecto a Compilar "Bind" en PkgSrc para SmartOS con la opción de "dnstap", serán:

  1. Usamos una zona nativa SmartOS con la versión del software PkgSrc que se corresponda a las zonas nativas SmartOS donde vamos a instalar el Bind que compilamos, en vez de la versión trunk de PkgSrc:

    [root@xXx ~]# imgadm avail|grep -i pkgbuild-lts
    188ee9ce-540a-11eb-9cc1-2748cd10e5e2  pkgbuild-lts                    20.4.0        smartos  zone-dataset  2021-01-11
    bd5afd7a-7ec1-11ec-80ab-7b01241031f6  pkgbuild-lts                    21.4.0        smartos  zone-dataset  2022-01-26
    
  2. Entramos en la zona pkgsrc por SSH y le pedimos que cree un entorno virtual de compilación:

    [root@PkgSrc ~]# run-sandbox 2021Q4-x86_64
    
    It looks like this is the first sandbox creation for this pkgbuild.  It
    will take longer than normal, as support packages need to be downloaded
    first.  Subsequent runs will be much faster after they have been cached.
    
    [...]
    
    Unpacking bootstrap-2021Q4-x86_64 into /data/chroot/dev-2021Q4-x86_64...done.
    Setting up environment...done.
    Installing additional tools packages...done.
    Logging in.  WARNING: On logout the sandbox will be destroyed.
    
       __        .                   .
     _|  |_      | .-. .  . .-. :--. |-
    |_    _|     ;|   ||  |(.-' |  | |
      |__|   `--'  `-' `;-| `-' '  ' `-'
                       /  ; Instance (pkgbuild-lts 21.4.0)
                       `-'  https://docs.joyent.com/images/smartos/pkgbuild
    
    --<root@PkgSrc>-(/data/chroot/dev-2021Q4-x86_64)-<~>--
    ->
    

Leer más…

Cómo usar "ccache" para compilar en PkgSrc de SmartOS (II)

En Cómo usar "ccache" para compilar en PkgSrc de SmartOS explico cómo utilizar ccache a la hora de compilar paquetes PkgSrc.

Ahí propongo realizar un cambio en el fichero /data/pkgbuild/scripts/run-sandbox [1] para añadir lo siguiente al fichero .bashrc del entorno chroot:

# Ver el comentario en
# https://wiki.netbsd.org/tutorials/pkgsrc/build_ccache_distcc/
export CCACHE_DIR=/root/.ccache/
export PKGSRC_COMPILER=ccache gcc

La segunda línea no funciona correctamente en SmartOS porque ahí el fichero /opt/local/etc/mk.conf dentro del entorno chroot ignora la variable de entorno PKGSRC_COMPILER y fuerza un valor explícito de PKGSRC_COMPILER=gcc a la hora de compilar.

Por tanto, lo mejor es cambiar el fichero /data/pkgbuild/scripts/run-sandbox [1] para que modifique ese fichero a la hora de crear el entorno chroot. Sería cuestión de añadirle una línea como esta poco antes del final del fichero:

sed -i "s/^PKGSRC_COMPILER=/PKGSRC_COMPILER?=/g" ${chrootdir}${PKGBUILD_SYSCONFDIR}/mk.conf

Ese cambio en el fichero /opt/local/etc/mk.conf dentro del entorno chroot mantiene la definición por defecto de PKGSRC_COMPILER cuando no le hemos puesto un valor concreto por variable de entorno, pero la variable de entorno manda si existe. Así debería venir de serie en SmartOS. Usando expansiones shell, modificamos el fichero correcto sea cual sea el branch PkgSrc que estamos utilizando para generar el entorno chroot.

Además, el export estaba mal. Hay que poner el valor entre comillas. Por ejemplo:

export PKGSRC_COMPILER="ccache gcc"
[1] (1, 2) Para estos cambios utilizo Ansible. No los hago a mano, que sería un coñazo cada vez que reprovisiono la zona SmartOS.

Cómo cambiar el tamaño del espacio de intercambio (SWAP) en SmartOS

Nota

En este documento voy a usar los términos SWAP y espacio de intercambio de forma indistinta.

Cuando se realiza una instalación nueva, SmartOS crea un dataset de SWAP del mismo tamaño que la memoria RAM del ordenador. Esto puede ser apropiado para máquinas grandes, pero cuando vamos escasos de memoria un SWAP tan pequeño es problemático porque bajo Illumos (Solaris) no existe el concepto de overcommit de memoria como en Linux. Es decir, un kernel Illumos limita el espacio de direccionamiento disponible para los programas a la suma de la memoria RAM y el espacio de intercambio (SWAP).

Por tanto, en SmartOS es común ampliar el espacio de intercambio.

Una de mis máquinas tiene solo 8GB de RAM y veo lo siguiente:

[root@X ~]# swap -s
total: 3928724k bytes allocated + 221992k reserved = 4150716k used, 8223728k available

[root@X ~]# zfs get all zones/swap
NAME        PROPERTY              VALUE                    SOURCE
zones/swap  type                  volume                   -
zones/swap  creation              vie. dic.  2  8:38 2022  -
zones/swap  used                  8,22G                    -
zones/swap  available             614G                     -
zones/swap  referenced            3,71G                    -
zones/swap  compressratio         2.18x                    -
zones/swap  reservation           none                     default
zones/swap  volsize               7,97G                    local
zones/swap  volblocksize          8K                       default
zones/swap  checksum              on                       default
zones/swap  compression           lz4                      inherited from zones
zones/swap  readonly              off                      default
zones/swap  createtxg             92                       -
zones/swap  copies                1                        default
zones/swap  refreservation        8,22G                    local
zones/swap  guid                  1242262060458694733      -
zones/swap  primarycache          all                      default
zones/swap  secondarycache        all                      default
zones/swap  usedbysnapshots       0                        -
zones/swap  usedbydataset         3,71G                    -
zones/swap  usedbychildren        0                        -
zones/swap  usedbyrefreservation  4,52G                    -
zones/swap  logbias               latency                  default
zones/swap  dedup                 off                      default
zones/swap  mlslabel              none                     default
zones/swap  sync                  standard                 default
zones/swap  refcompressratio      2.18x                    -
zones/swap  written               3,71G                    -
zones/swap  logicalused           8,01G                    -
zones/swap  logicalreferenced     8,01G                    -
zones/swap  snapshot_limit        none                     default
zones/swap  snapshot_count        none                     default
zones/swap  redundant_metadata    all                      default
zones/swap  encryption            off                      default
zones/swap  keylocation           none                     default
zones/swap  keyformat             none                     default
zones/swap  pbkdf2iters           0                        default

Por necesidades de servicio, requiero ampliar bastante el espacio de intercambio que, como he dicho, limita el espacio de direccionamiento total disponible para todos los programas.

Leer más…

Cómo saber el tamaño de una función en Código Objeto

Por motivos complicados necesitaba conocer el tamaño de una función en C, una vez compilada a código objeto. A priori no hay forma simple de saberlo.

Acabé volcando el listado de funciones y sus direcciones a partir del código objeto, ordenando las funciones por su dirección, buscando la dirección de la función que me interesa y buscando la dirección de la función que la sigue. Restando ambas obtenía el tamaño de la función.

Años más tarde volví a revisar el tema. Lo que me molestaba era lo que sigue:

Tomemos el siguiente código C:

1
2
3
 int a(int x) {
     return 2*x;
 }

Si compilamos el código anterior y generamos código fuente en ensamblador de x86 con gcc -S -O9 a.c, vemos lo siguiente:

         .file   "a.c"
         .text
         .p2align 4
         .globl  a
         .type   a, @function
 a:
 .LFB0:
         .cfi_startproc
         endbr64
         leal    (%rdi,%rdi), %eax
         ret
         .cfi_endproc
 .LFE0:
         .size   a, .-a
         .ident  "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
         .section        .note.GNU-stack,"",@progbits
         .section        .note.gnu.property,"a"
         .align 8
         .long    1f - 0f
         .long    4f - 1f
         .long    5
 0:
         .string  "GNU"
 1:
         .align 8
         .long    0xc0000002
         .long    3f - 2f
 2:
         .long    0x3
 3:
         .align 8
 4:

La clave del asunto es la línea 14: .size a, .-a. Según el manual de gas, eso guarda como tamaño de la función a la resta entre la posición actual del ensamblador y la primera instrucción de a. Es decir, resta a la dirección final de la función la dirección inicial. Es decir, obtenemos el tamaño.

Aparentemente, entonces, se está generando esa información y se guarda en el código objeto. ¿Cómo acceder a ella?

Leer más…

Código Python para genera la clave pública, la clave privada y el CSR para su firma por parte de una autoridad de certificación

Este código en Python se escribió en 2015 para generar con facilidad un CSR que se pudiese enviar a una autoridad de certificación para que nos proporcionase un certificado X.509 firmado que pudiésemos instalar en el servidor web.

El procedimiento normal es utiizar OpenSSL y así lo estuve haciendo durante décadas, pero, invirtiendo unos minutos para pasar el proceso a Python, el resultado es más sencillo, más configurable y más automatizado.

Hoy en día utilizo Let's Encrypt y este proceso ya no es necesario, pero lo documento aquí por si le resulta de interés a alguien.

Leer más…

Novedades SmartOS de 20200520 a 20221201

Artículos previos:

Lo cierto es que los proyectos SmartOS e Illumos son muy activos y tienen muchísima actividad. Proporcionar un repaso exhaustivo es mucho trabajo para mí, así que me limitaré a detallar lo que me parece más interesante desde un punto de vista personal.

Puedes ver los cambios con detalle en inglés.

Probablemente lo más llamativo en este período es que Joyent se ha retirado de SmartOS. Su puesto lo ha ocupado MNX. Espero mantengan el extraordinario nivel al que nos tiene acostumbrados Illumos y SmartOS.

Algunos parches relevantes:

También se está retirando el soporte de SPARC. Algunos parches relevantes:

Leer más…

Compilar "Bind" en PkgSrc para SmartOS con la opción de "dnstap"

Mi servidor DNS estándar es Bind sobre SmartOS, pero el paquete nativo disponible no tiene soporte dnstap de serie. Hay que compilarlo desde cero.

Los pasos son, en realidad, bastante sencillos si conoces cómo funciona SmartOS, su gestión de paquetes y el entorno PkgSrc:

  1. Tengo una zona nativa SmartOS con el software PkgSrc. En mi caso uso la versión trunk:

    [root@xXx ~]# imgadm avail|grep -i pkgbuild-trunk
    99412e46-9a55-11ec-a6b4-8b38513aaa54  pkgbuild-trunk                  20220302      smartos  zone-dataset  2022-03-02
    7f33bfaa-fed7-11ec-82ce-0f7efc84d370  pkgbuild-trunk                  20220708      smartos  zone-dataset  2022-07-08
    
  2. Entro en la zona pkgsrc-trunk por SSH y le pido que cree un entorno virtual de compilación:

    [root@PkgSrc-trunk ~]# run-sandbox trunk-x86_64
    
    It looks like this is the first sandbox creation for this pkgbuild.  It
    will take longer than normal, as support packages need to be downloaded
    first.  Subsequent runs will be much faster after they have been cached.
    
    [...]
    
    Unpacking bootstrap-trunk-x86_64 into /data/chroot/dev-trunk-x86_64...done.
    Setting up environment...done.
    Installing additional tools packages...done.
    Logging in.  WARNING: On logout the sandbox will be destroyed.
    
      ,---.                   |     ,---. ,---.
      `---. ,-.-. ,---. ,---. |---  |   | `---.  pkgbuild-trunk
          | | | | ,---| |     |     |   |     |  20220708
      `---' ` ' ' `---' `     `---' `---' `---'
    
    --<root@PkgSrc-trunk>-(/data/chroot/dev-trunk-x86_64)-<~>--
    ->
    

Leer más…