Introducción

Esta tercera parte de la serie de artículos sobre el control de versiones en proyectos de software está enfocada a la configuración del acceso y publicación de repositorios de Mercurial usando servidores HTTP o SSH.

El traspaso de información entre distintos desarrolladores dispersos en la red es uno de los casos de uso en los que se aprecia con mayor claridad la potencia de los sistemas de control de versiones distribuidos.

En la primera parte se puede leer una introducción a los conceptos fundamentales utilizados en los sistemas de control de versiones y Mercurial, mientras que la segunda parte entra de lleno en el uso de Mercurial para gestionar un proyecto de software.

Publicación de repositorios

Para el trabajo en grupos distribuidos resulta fundamental la publicación de los diversos repositorios de trabajo de un proyecto. Es posible usar un servidor (o varios) en los que se agregan los repositorios públicos y el uso de servidores web o que usen el protocolo SSH es una de las formas más sencillas de hacerlo.
Una de las cuestiones que surgen al publicar uno o más repositorios es el de los permisos que tienen los distintos usuarios en cuanto a la lectura o modificación de los repositorios. Mercurial delega en el sistema operativo el control de los permisos sobre los repostorios, por lo que la forma más natural de organizarlos es mediante la separación de privilegios por usuario. En esa situación, el problema se convierte entonces en el de la autentificación de los usuarios entrantes.

En este artículo se explican todos estos conceptos y cómo proporcionar acceso universal de lectura a los repositorios mediante el protocolo HTTP, y acceso de lectura o lectura y escritura mediante el protocolo SSH, usando autentificación por clave pública.

Acceso de serie con el protocolo HTTP

HTTP es el protocolo de comunicación que usan los servidores de la web, y es uno de los mejor soportados tanto en los servicios de alojamiento como por la infraestructura de la red (proxies). Mercurial incluye de serie un servidor de repositorios que usa como protocolo de comunicación HTTP.

El servidor incluido por defecto en Mercurial es especialmente útil para compartir un repositorio a través de la red de forma rápida y sencilla, sin necesidad de instalar ningún software adicional. Para poner en marcha ese servicio, simplemente basta con utilizar el siguiente comando mientras nos situamos dentro del directorio de trabajo del repostorio que queremos compartir:

$ hg serve

Una vez arrancado el servidor, es posible acceder al repositorio exportado usando como URL la dirección desde la que se sirve. El servidor integrado usa también por defecto el puerto 8000, para evitar conflictos con un servidor web que se encuentre en la misma máquina, pero es posible modificar el puerto usado utilizando la opción -p puerto.

Si, en una red local, nuestra máquina tuviese la dirección IP 192.168.0.10, podríamos acceder desde cualquier máquina de la red al proyecto para, por ejemplo, clonarlo así:

$ hg clone http://192.168.0.10:8000 copia-local

Integración con un servidor HTTP dedicado (Apache)

Si se pretende dar acceso de forma continuada a un conjunto de repositorios es preferible el uso de un servidor web dedicado tal como Apache.
La forma de integrar Mercurial con el servidor HTTP es a través de una aplicación CGI especializada que se distribuye con la aplicación principal.

A continuación se explica la configuración de esta modalidad para compartir repositorios utilizando un servidor Apache, basándose en la experiencia del autor en la configuración de este servicio en un servidor compartido en una máquina del proveedor Dreamhost.

Cuenta dedicada

Para limitar los riesgos de seguridad del uso de una aplicación CGI que realiza operaciones de lectura y escritura, es preferible configurar una cuenta de usuario dedicada, diferente a nuestra cuenta habitual. Con esta precaución, en el caso de que la aplicación CGI se viese comprometida por un fallo de seguridad, solamente los datos accesibles por el usuario de la cuenta (preferiblemente sólo los de los repositorios), podrían estar en peligro. La cuenta, por tanto, deberá tener los mínimos privilegios posibles.
En el ejemplo que usaremos en este artículo, el usuario se llamará mercurial.
(Puede ser necesario configurar correctamente la codificación de caracteres con LC_ALL)

Aplicación CGI

En este artículo situaremos la aplicación CGI en el subdirectorio ~/repos

El ejecutable CGI que debemos instalar en ese directorio es hgwebdir.cgi, que se encuentra en la distribución estándar de Mercurial. Este ejecutable es el encargado de realizar la compartición de los repositorios y presenta la interfaz web.

En el archivo cgi existen un par de elementos para personalizar algunas opciones, para el caso en que se quieran mostrar páginas con codificaciones distintas a las predefinidas para el usuario (variable HGENC) y cuando la ruta de instalación de python no sea la general del sistema.

Junto con ese archivo debemos crear un archivo de configuración hgweb.config que servirá para indicar los repositorios compartidos y realizar la traducción entre la URL recibida y el directorio en el servidor. El contenido es el siguiente:

[collections]
./repos = ./repos

En nuestro ejemplo simplemente indicamos que la raíz de los directorios con repositorios se encuentra en el directorio de instalación, pero es posible indicar otras rutas, e incluso indicar rutas específicas por proyecto o por repositorio.
En el lado izquierdo se pone la ruta conocida (o la que se puede omitir en la url).

Control de acceso y reescritura de direcciones

Para realizar el control de acceso, permitir la ejecución de archivos CGI en nuestro directorio y hacer las direcciones de acceso (URLs) más sencillas podemos utilizar los sistemas de configuración estándar de Apache. Bien una configuración global, bien utilizando una configuración por directorio mediante el archivo .htaccess. La primera opción es la más adecuada cuando se tiene acceso a poder modificar la configuración global del servidor, pero aquí explicaremos la última es la opción, puesto que suele estar disponible incluso en servidores de alojamiento compartido, y es sencillo extrapolar la configuración al caso anterior si fuese necesario.

El contenido del archivo ~/repos/.htaccess es el siguiente:

Options +ExecCGI
AddDefaultCharset iso-8859-15
RewriteEngine On
#RewriteBase /
RewriteRule ^$ hgwebdir.cgi [L]
RewriteCond %{REQUEST_URI} !^/hgwebdir.cgi
RewriteRule (.*) /hgwebdir.cgi/$1 [PT]

Esta configuración permite la ejecución de CGIs, reescribe la dirección añadiendo al final hgwebdir.cgi o añadiendo hgwebdir.cgi/directorio/nombre-archivo cuando se solicite un nombre de archivo y un directorio.
De esa manera nuestra aplicación recibirá la ruta que se solicita.

Host virtual

Por comodidad, es conveniente crear un subdominio o host virtual en nuestro dominio principal que esté redirigido hacia la aplicación CGI en la cuenta dedicada. En nuestro ejemplo, la dirección hg.midominio.org podría dirigirnos hacia el directorio repos del usuario mercurial.

Configuración de los repositorios compartidos

Hemos configurado ya el directorio de instalación de la aplicación CGI y hemos decidido que será también el directorio base del árbol de repositorios.
Para cada proyecto tendremos un subdirectorio que contenga los repositorios publicados para dicho proyecto, por ejemplo, para el proyecto «proyecto» y el repositorio «main» tendríamos la siguiente estructura en disco: ~/repos/proyecto/main

Para que los detalles que nos presenta la interfaz web (abriendo en un navegador http://hg.midominio.org/) sean más descriptivos, es recomendable añadir algunos datos en el archivo de configuración de cada repositorio. Este es el archivo ~/repos/proyecto/main/.hg/hgrc y los datos relevantes son:

[web]
contact = Pepito Pérez description = Proyecto - Repositorio principal
name = Proyecto
style = gitweb
allow_archive = gz zip bz2
#allow_push = pachi, coya, ramon

El significado de los distintos campos es bastante obvio, precisando aclaración únicamente:
style: inidica el estilo que se usará en la interfaz web
allow_archive: permite indicar los tipos de archivo que se permiten descargar. Se puede limitar para evitar la sobrecarga del servidor, al exigir cierto trabajo de la CPU.
allow_push: aquí está comentada esta opción, por lo que solamente se permite el acceso para lectura al repositorio publicado por HTTP. La opción allow_push permite incluir un conjunto de usuarios a los que se les permitiría la escritura mediante push al repositorio. La autentificación de los usuarios se podría hacer también mediante la configuración del archivo .htaccess.

En nuestra configuración, evitaremos el acceso mediante contraseñas y daremos acceso de escritura usando autentificación con clave pública, un método mucho más seguro.

Acceso a través de HTTP desde los clientes

Ahora que está configurado el servidor para proporcionar acceso a los repositorios usando el protocolo HTTP es posible realizar cualquier operación (autorizada) desde los clientes simplemente indicando la URL para el protocolo HTTP:

$ hg clone http://hg.midominio.org/proyecto/main proyecto-main-local
$ hg pull http://hg.midominio.org/proyecto/main

Estas órdenes accederían al repositorio ~/repos/proyecto/main del servidor. Hay que cuidar la introducción de la URL de forma correcta, puesto que, gracias a nuestras reglas de reescritura de direcciones no es necesario añadir el directorio repos en la URL.

Acceso de lectura/escritura con clave pública por SSH

El protocolo SSH

SSH es un protocolo de comunicación mucho más seguro que HTTP al incluir la encriptación de los datos, evitando que se puedan interceptar datos privados o sensibles, y, si se combina con la autentificación mediante clave pública se evita también el posible compromiso de las claves de acceso a las cuentas utilizadas.

Una de las ventajas del protocolo SSH es que la mayoría de servidores suelen tener soporte para su uso.

Autentificación con clave pública

A menudo se usa como forma de autentificación en servidores un par usuario/contraseña. En este modo de autentificación un usuario registrado en el sistema se identifica como tal y posteriormente envía su contraseña para asegurar que se trata del usuario legítimo. El problema de esta forma de autentificación es que el envío de la contraseña se produce a través de la red, con lo que una línea no segura puede llevar a comprometer la identidad del usuario.

Existen métodos más modernos de autentificación basados en el intercambio asimétrico de información. Son los llamados sistemas de clave pública. En estos sistemas se utiliza un par de claves, una llamada clave pública y que sirve para identificar la autenticidad y descifrar los mensajes cifrados usando la otra clave, la clave privada.

La clave pública se distribuye y almacena en los servidores que se desea que puedan identificar al poseedor de la clave privada, mientras que la clave privada siempre queda en posesión del usuario que se identifica.
El mecanismo utilizado es el siguiente: una vez iniciada la transmisión, sel servidor solicitar al cliente que desea iniciar una transacción que encripte un mensaje único (de usar y tirar) haciendo uso de su clave privada; luego comprueba que es posible desencriptar el mensaje correctamente usando la clave pública almacenada, y, en ese caso, da acceso al usuario.

La ventaja de este sistema es que en ningún momento se produce un intercambio de contraseñas por la red, quedando la clave privada siempre a salvo de cualquier intento de controlar la comunicación. Es sumamente difícil (prácticamente imposible en un tiempo razonable) generar la clave privada a partir de la clave pública o de ésta y un mensaje conocido encriptado, con lo que el sistema es muy seguro.

Instalación

Para poder utilizar SSH como protocolo de comunicación es necesario, además de un servidor de SSH, la presencia de un cliente que realice las operaciones de comunicación. Uno de los clientes más fiables, que además es software libre, es OpenSSH, y suele estar instalado en cualquier sistema GNU/Linux o BSD. En sistemas Windows es preferible, por más práctico, usar el conjunto de aplicaciones ‘Putty’ (putty.exe y plink.exe), que se puede obtener en http://www.chiark.greenend.org.uk/~sgtatham/putty/.

Generación de pares de claves para controlar el acceso

Uno de los primeros pasos que debemos dar es la generación del par de claves pública y privada. Para ello utilizamos la herramienta ssh-keygen de la siguiente manera:

$ ssh-keygen -t rsa -f hg-identity

La aplicación ssh-keygen devuelve un par de claves hg-identity, hg-identity.pub, que son la clave privada y la clave privada, que usaremos en los clientes y el servidor.

SSH: Configuración del servidor

Instalación de las claves públicas de los usuarios autorizados

Cada usuario guarda una lista de las claves públicas a las que permite el acceso en el archivo ~/.ssh/authorized_keys.
Debemos añadir en nuestra cuenta dedicada en el servidor la lista de usuarios a los que permitiremos el acceso por SSH a los repositorios publicados.

En él se añade una línea por cada clave, y tiene un aspecto similar a este:

ssh-rsa FACeilOTrm2UFa2RAAGTCIxAAAIExRCBsdwYyLFNzaCiShtyr9qp9KJGPRvJExtnuP3td6EApGyLwb0DU2UJfr9xJG+1LUwBwai7m0bqbxwe3CVBc7ysudePiBbg88ZXHw/77z0CQTFNReySVzzaXyjKWeRxGTu+cyoBjEQcUTltj+ncG78xQYcKHfwC5cX6MgU=4Sk3 pepito@perez.org
ssh-rsa DAGTCIxhtyr9yLqaC3td2RasdwYxtAAABApiSnuPFE9KJGPGCNzARv6IEJexREilOTrm2UFpGy3CVBUwai7mDeey2UJfr9xJHw/bwBG+1LUjK77z0CQbg88ZXxwc7ySVzzaTF0bqbsudePiBXy0NRLwWGTu+cyoBjYcKHxSk3cEQgU=cUTltj+ncG78xQX6MfwC54eR paco@perez.org

Vemos que cada línea empieza por el tipo de clave usado (en este caso, ssh-rsa), la clave codificada como cadena alfanumérica, y acaba con un identificador arbitrario (como pepito@perez.org).

Restricción de las operaciones al trabajo con Mercurial

Es posible limitar la capacidad de los usuarios para que únicamente puedan realizar algunas operaciones con Mercurial . Esto facilita la publicacion de repositorios dando acceso a grupos de usuarios no totalmente confiables, sin comprometer la seguridad del sistema.

Para ello, podemos aprovechar la posibilidad de ejecutar una orden cada vez que se usa una clave pública para la autentificación. Esto se consigue insertando la opción command al principio de cada linea con una clave pública en el archivo ~/.ssh/authorized_keys. Lo que haremos en nuestro caso es utilizar un script que filtrará y redirigirá las acciones permitidas al ejecutable de Mercurial.

El script hg-ssh es el que realiza este trabajo, está escrito por Thomas Arendsen Hein y se puede obtener en la distribución estándar de Mercurial, en el directorio contrib. Para simplificar el uso optamos por instalar el script en ~/hg-ssh.
El script usa como parámetros las rutas de los repositorios en los que se permite actuar y dejaría las entradas en el archivo ~/.ssh/authorized_keys así:

command="hg-ssh repo-pepito/ /repos/main ~/crew-repo", ssh-rsa FACeilOTrm2UFa2RAAGTCIxAAAIExRCBsdwYyLFNzaCiShtyr9qp9KJGPRvJExtnuP3td6EApGyLwb0DU2UJfr9xJG+1LUwBwai7m0bqbxwe3CVBc7ysudePiBbg88ZXHw/77z0CQTFNReySVzzaXyjKWeRxGTu+cyoBjEQcUTltj+ncG78xQYcKHfwC5cX6MgU=4Sk3 pepito@perez.org
command="hg-ssh repo-paco/ /repos/main ~/crew-repo", ssh-rsa DAGTCIxhtyr9yLqaC3td2RasdwYxtAAABApiSnuPFE9KJGPGCNzARv6IEJexREilOTrm2UFpGy3CVBUwai7mDeey2UJfr9xJHw/bwBG+1LUjK77z0CQbg88ZXxwc7ySVzzaTF0bqbsudePiBXy0NRLwWGTu+cyoBjYcKHxSk3cEQgU=cUTltj+ncG78xQX6MfwC54eR paco@perez.org

Vemos que es posible utilizar rutas absolutas, relativas, o con expansión del directorio de usuario a la hora de indicar la situación de los repositorios accesibles para cada usuario.

Con esto está ya completa la configuración por el lado del servidor. Ya está configurado el acceso para lectura y la interfaz web, están registrados los usuarios que pueden utilizar los repositorios a través de SSH y configurado el acceso para permitir únicamente operaciones en los repositorios autorizados para cada usuario.

SSH: Configuración de los clientes

Ahora veremos la parte de los clientes, que deben acceder a los repositorios remotos que acabamos de configurar.
Como primer paso debemos indicar a nuestro cliente SSH el lugar donde guardamos nuestra clave privada para que nos identifique correctamente ante el servidor que hemos configurado. La configuración puede variar algo según la realicemos en sistemas GNU/Linux o BSD, o en sistemas Windows. Los primeros admiten cualquiera de las dos formas de configuración, aunque parece más limpia la primera que se indica.

Sistemas GNU/Linux y BSD (o windows con MSYS)

En sistemas GNU/Linux o BSD podemos configurar el usuario y la clave privada para el acceso por SSH a cada dominio. Esta configuración se lleva a cabo en el archivo ~/.ssh/config:

Host hg.midominio.org
    user hguser
    IdentityFile ~/.ssh/hguser-identity

El Host hg.midominio.org identifica el dominio para el que son de aplicación las siguientes opciones. El usuario por defecto se indica tras la opción user, y la clave privada del archivo indicado tras la opción IdentityFile.

Win32

En sistemas Windows (en GNU/Linux se podría hacer igual) no es posible usar la configuración global anterior y por ello se debe recurrir a modificar la configuración de Mercurial. El archivo de configuración para cada usuario, Mercurial.ini (~/.hgrc en sistemas *nix), permite indicar la orden que se ejecuta para realizar la conexión por SSH:

[ui]
ssh=/path/a/plink.exe -ssh -i "c:\ruta\a\hg-identity" -l mercurial

En este ejemplo se usa plink.exe, que es el cliente de SSH para Windows (ssh en *nix), y como opciones se indica -ssh para que use el protocolo ssh en la conexión, -i «/ruta/a/hg-identity» para indicar la ruta del la clave privada para identificarnos en la conexión, y -l mercurial para acceder al servidor a través del usuario mercurial (el usuario de nuestra cuenta dedicada).

Primera conexión

En ambos sistemas, para terminar de realizar la configuración, es necesario conectarse manualmente por primera vez a la máquina remota para que su clave pública sea añadida a las claves públicas reconocidas por nuestra máquina (también podemos haberla añadido manualmente con anterioridad). Esto se realiza con la siguiente orden:

$ ssh hg.midominio.org -i ruta/a/hguser-identity -l mercurial

o

> plink.exe -ssh -i "/ruta/a/hg-identity" -l mercurial

Trabajo con los repositorios

Para clonar un repositorio existente o traer cambios simplemente usamos las órdenes habituales de mercurial, indicando en la URL que el protocolo de comunicación es SSH:

$ hg clone ssh://hg.midominio.org/repos/proyecto/main proyecto-main-local
$ hg pull ssg://hg.midominio.org/repos/proyecto/main

Hay que resaltar que, en este caso, y a diferencia del acceso con HTTP, es preciso indicar la ruta completa a los repositorios (incluyendo repos) desde el directorio raíz del usuario dedicado de nuestro servidor, puesto que es ahí donde se inicia el acceso por SSH.

NOTA:
Si hay conflictos de usuario y no se envía correctamente el nombre de éste puede ser necesario añadir el usuario antes de la máquina:

$ hg clone ssh://mercurial@hg.midominio.org/repos/proyecto/main proyecto-main-local
hg pull ssh://mercurial@hg.midominio.org/repos/proyecto/main

Pendiente: Cambiar «repos» por «mercurial» e igualar la sintaxis del acceso por HTTP y SSH (Modificando RewriteRule o hgweb.config)

NOTA:
En pascaline usamos los siguientes repositorios:

$ hg clone ssh://hg.rvburke.com/repos/pascaline/main pascaline-main
hg clone ssh://hg.rvburke.com/repos/pascaline/pachi pascaline-pachi
hg clone ssh://hg.rvburke.com/repos/pascaline/pascaline-crew pascaline-crew
hg clone ssh://hg.rvburke.com/repos/pascaline/ramon pascaline-ramon
hg clone ssh://hg.rvburke.com/repos/pascaline/coya pascaline-coya

Enlaces interesantes

Página con trucos sobre la instalación y uso de Mercurial y MQ.