7.1.3. SSH como servidor FTP¶
Nota
Para la instalación y configuración de un servidor SSH consulte el apartado referente la administración remota.
Bajo el epígrafe trataremos de afinar la configuración de un servidor SSH para que cumpla las veces de un servidor FTP. Esto supone la posibilidad de implementar los siguientes aspectos, aparte de la obvia transmisión de ficheros:
Cortar la conexión tras un tiempo de inactividad.
Limitar el número de conexiones simultáneas.
Habilitar la transferencia anónima.
Enjaular usuarios.
Usuarios virtuales.
De todas ellos, sólo el último no es posible, al menos no si pretendemos realizar el acceso con usuarios realmente virtuales. Restringir el acceso a otros servicios, en cambio, sí es posible.
Antes de entrar en harina, definiremos un grupo ftpusers al que pertenecerán todos aquellos usuarios de los que queremos que su relación con el servidor se limite a la transferencia de ficheros:
# addgroup --system ftpusers
Además, nos proponemos implementar dos versiones distintas:
Un servidor FTP puro, que sólo permita la conexión mediante un cliente, a la manera de como lo hacen los servidores FTP tradicionales.
Un servidor FTP con esteroides, que habilite también el uso de scp e incluso de un script que permita el cambio de contraseña al usuario.
Advertencia
Es preciso notar, antes de empezar que, aunque hablemos de servidor FTP, lo que implementamos es un servidor sFTP, que no es lo mismo, aunque sirva para lo mismo: no habrá dos canales independientes ni podrán usarse clientes FTP (aunque muchos como Filezilla también implementan el protocolo sFTP)
7.1.3.1. FTP puro¶
Lograr esto es relativamente sencillo gracias a que el servidor de openssh dispone de un servidor sFTP interno, que propicia que se puedan hacer enjaulamientos sin necesidad de preparar jaulas.
7.1.3.1.1. Configuración básica¶
Basta añadir a /etc/ssh/sshd_config
las siguientes líneas:
Match Group ftpusers
ChrootDirectory %h
ForceCommand internal-sftp
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 120
ClientAliveCountMax 0
Es decir, creamos una configuración particular para los usuarios pertenecientes a grupo ftpusers para que sólo puedan usar el servidor como servidor FTP, no puedan hacer túneles TCP, ni arrancar aplicaciones gráficas, se desconecten automáticamente tras 2 minutos de inactividad y estén enjaulados dentro su propio directorio personal (%h).
Advertencia
Para que el enjaulamiento funcione es necesario que todos los directorios que constituyen la ruta de la jaula pertenezcan al administrador[1].
Nota
El resto de aspectos no básicos que incluiremos en este FTP puro, son tambien aplicables al FTP con esteroides.
7.1.3.1.2. Acceso anónimo¶
Definitivamente, no es buena idea permitir un acceso anónimo ya que este suele incluirse para permitir la descarga de ficheros y, para esto, es mejor usar un servidor web, por ejemplo. Si, a pesar de todo, deseamos permitirlo, debemos primero crear un usuario adecuado:
# adduser ftp --ingroup ftpusers --no-create-home --home /srv/ftp/anonymous --shell /bin/false --disabled-password --gecos "Anonimo"
# useradd anonymous -g $(getent group ftpusers | cut -d: -f3) -M -d /srv/ftp/anonymous/ -s /bin/false -c "Anonimo" -o -u $(id -u ftp)
# mkdir -p /srv/ftp/anonymous
Lo que hacemos es crear un usuario, ftp, y otro usuario llamado anonymous, que en realidad es el mismo porque comparte uid con él.
Además debemos usar el módulo pam_ftp en la autenticación, por lo que
deberemos añadir en /etc/pam.d/sshd
justamente antes de que se incluya
la configuración de autenticación la línea que carga ese módulo:
auth sufficient pam_ftp.so ignore
# Standard Un*x authentication.
@include common-auth
Advertencia
Hacer esto es una pésima idea. Incluso la página de manual del módulo advierte de que «this module is not safe and easily spoofable».
7.1.3.1.3. Limitación de conexiones¶
El servidor SSH no permite directamente la limitación en el número de conexiones, ni totales ni por usuario; pero puede lograrse su implementación actuando sobre el proceso de autenticación.
Como las sessiones de FTP, no abren para el servidor consolas interactivas, es absolutamente inútil usar pam_limit, ya que maxlogins y maxsyslogins sólo son aplicables cuando se abren shells en el servidor. Por tanto, añadir al fichero de configuración una línea de este tipo:
@ftpusers - maxlogins 2
%ftpusers - maxlogins 4
que, teóricamente, limitaría el número máximo de sesiones parsa cada usuario de ftpusers a 2 y el total de sesiones para todos los integrantes del grupo a 4 es absolutamente inútil[2].
Como esta solución es inútil, hemos de aplicar otra basada en la creación de un
script que ejecute pam_exec. Es éste
.
Para aplicar el script basta con añadir al final de /etc/pam.d/sshd
la
siguiente línea (suponemos alojado el script en /usr/local/bin
):
session required pam_exec.so quiet /usr/local/bin/sftp_limit.sh max_per_user=2
Advertencia
El script es muy simple y, aunque sólo se aplica a los grupos de usuarios que le indiquemos (ftpusers en nuestro caso), en el caso del maxclients y max_per_ip cuenta cualquier conexión SSH, la haga quien la haga. Como consecuencia, todos los usuarios que acceden por SSH contribuyen a alcanzar el máximo, aunque no les afecte.
7.1.3.2. Cuota¶
Ver también
Consulte cómo crear cuotas de disco.
7.1.3.3. FTP con esteroides¶
En este caso, la dificultad estriba en que para que podamos enjaular usuarios, necesitamos construir una jaula con todo lo necesario. Recordemos, además, que nuestro propósito es permitir al usuario:
El acceso sFTP.
El uso de scp.
El cambio de contraseña.
Nota
Si sólo nos interesaran las dos primeras acciones, podríamos usar rssh.
Para resolver la papeleta tiraremos —cómo no— de script. La idea es crear uno que dependiendo de qué cliente usemos (si ssh, si scp o si sftp) indique al servidor cómo debe comportarse (pedir contraseña, permitir la copia remota o ejecutar el servidor sFTP, respectivamente)[3]. Además el propio script se encargará de realizar el enjaulado.
Necesitamos cinco ingredientes:
el propio script
que colocaremos en/usr/local/bin
.La utilidad fakechroot que permite enjaular con un usuario distinto del administrador:
# apt-get install fakechroot
El directorio donde haremos el enjaulamiento (
/srv/ftp
):# mkdir -p /srv/ftp
Asegurarnos de que
/etc/ssh/sshd_config
contiene descomentada la línea[4][5]:Subsystem sftp /usr/lib/openssh/sftp-server -d %d
Un grupo al que pertenezcan los usuarios del FTP y un usuario de pruebas[6]:
# addgroup --system ftpusers # adduser paco --ingroup ftpusers --no-create-home --home /home/paco --gecos "PacoFTP" --shell /bin/sh # mkdir -p /home/paco/.ssh # chown -R paco:ftpusers /home/paco
Hecho esto, tantearemos dos soluciones: una en que todos los usuarios enjaulados comparten una jaula común; y otra en la que cada usuario se enjaula en una distinta.
Creación de jaulas
Antes, sin embargo, es preciso aclarar cómo crear jaulas apropiadas. En principio, una jaula es un subárbol del sistema de ficheros en que se encierra la acción de un usuario o programa. Esto implica, que dicho subárbol debe contener todos los componentes (programas y librerias) necesarios para que se puedan desarrollar dentro de él las acciones para la que ha sido concebida. Por ejemplo, si queremos que un usuario enjaulado pueda copiar ficheros es obvio que dentro de la jaula debe encontrarse el ejecutable cp.
Por tanto, para crear una jaula primero debemos determinar cuáles son los ficheros que necesitaremos dentro de ella. En nuestro caso, son exclusivamente estos[7][8]:
/etc/nsswitch.conf
/etc/ld.so.conf
/etc/ld.so.cache
/etc/ld.so.conf.d/*
/lib/x86_64-linux-gnu/libnss_compat.so.2
/lib/x86_64-linux-gnu/libnss_files.so.2
/lib/x86_64-linux-gnu/libnsl.so.1
/usr/bin/scp
/usr/lib/openssh/sftp-server
O sea, los ficheros de configuración y las librerías necesarios para resolver usuarios, y los dos programas que se usarán dentro de la jaula[9]. Por supuesto, a esta lista es necesario añadir:
Las librerías que usan los dos programas[10].
Algunos dispositivos (
/dev/null
y/dev/zero
).
Para evitarnos la tediosa tarea hacer a mano la jaula, hemos escrito…
otro script
, que admite por la entrada estándar
la lista de ficheros y exige como argumento la dirección que ocupará la jaula.
Así, si almacenamos la lista anterior en req.txt
y queremos crear la
jaula en /srv/ftp
, podemos hacer lo siguiente:
# ./enjaular.sh /srv/ftp < req.txt
Advertencia
Recuerde que los nuevos usuarios que cree no se añadirán
automáticamente al /etc/passwd
de la jaula.
7.1.3.3.1. Jaula única¶
Advertencia
Es necesario que lea (y haga) los preliminares de FTP con esteroides.
Nuestra primera intención es enjaular a todos los usuarios del FTP, dentro de
/srv/ftp
. Para ello debemos añadir a /etc/ssh/sshd_config
, lo
siguiente:
Match Group ftpusers
X11Forwarding no
AllowTcpForwarding no
ForceCommand /usr/local/bin/rssh.sh /srv/ftp
A continuación debemos copiar la lista de ficheros requeridos en un fichero
(p.e. /srv/ftp
) y crear la jaula:
# ./enjaular.sh /srv/ftp`< req.txt
y, finalmente, copiar el script en la ruta apropiada:
# cp /path/donde/este/rssh.sh /usr/local/bin
Además, /home
debe aparecer dentro de la jaula, así que:
# ln -s /home /srv/ftp/home
Nota
Recuérdese que se fijó el directorio personal del usuario como
el habitual /home/usuario
, pero, como estos usuarios siempre actúan
enjaulados, su directorio real es /srv/ftp/home/usuario
,
Nota
Con esta solución, al usar scp, el directorio remoto de trabajo es la raíz de la jaula no el directorio personal, por lo que algo como:
$ scp fichero.txt paco@servidor:
intentaría copiar fichero.txt
en /srv/ftp
y no en
/srv/ftp/home/paco
[11].
Advertencia
Obsérvese que la shell del usuario es sh, porque así
lo requiere el servidor SSH para ejecutar nuestro script. Esta
circunstancia provoca que el usuario puede autenticarse sin restricciones en
cualquier otro servicio. Por ejemplo, a través de login, si alcanza
físicamente el servidor. Para evitar este inconveniente podemos añadir al
final de /etc/pam.d/common-session
, las líneas:
session [success=2 default=ignore] pam_succeed_if.so service = sshd
session [success=1 default=ignore] pam_succeed_if.so user notingroup ftpusers
session required pam_deny.so
session required pam_permit.so
las cuales harán que el acceso falle cuando el servicio no sea sshd y el usuario pertenezca al grupo ftpusers.
Nota
El usuario puede, incluso, usar autenticación con claves si quiere, aunque no podrá usar ssh-copy-id para subirla, ni utilizar más de una pareja de claves:
$ scp .ssh/id_ecdsa.pub paco@servidor:~/.ssh/authorized_keys
7.1.3.3.2. Jaula personal¶
Advertencia
Es necesario que lea (y haga) los preliminares de FTP con esteroides.
Si queremos una jaula personal distinta para cada usuario es obvio que debemos construirla, pero crear físicamente una distinta para cada uno es un desperdicio de espacio en disco. Podríamos usar enlaces duros, pero sigue siendo una solución bastante guarra. Una estrategia más elegante es la siguiente:
Se construye la base de la jaula que contiene todos los ficheros de configuracion, ejecutables y librerías necesarios en una ubicación, p.e.
/var/lib/sftp_jail
.Cuando un usuario de FTP accede, sin tener abierta otra sesión previa, se crea la vuelo la jaula fusionando con overlay el directorio anterior con el directorio personal del usuario. Cuando el usuario abandona el FTP sin dejar otras sesiones abiertas, se destruye la jaula.
Al construir al vuelo la jaula, se crea también un fichero
/etc/passwd
con solamente una línea: la referente al usuario. Eso impedirá que dentro de la jaula haya información sobre el resto de usuarios.
Empecemos por indicar cuál es la configuración a añadir dentro de
/etc/ssh/sshd_config
:
Match Group ftpusers
X11Forwarding no
AllowTcpForwarding no
ForceCommand /usr/local/bin/rssh.sh %x/ftp
o sea, la misma que anteriormente, excepto por el hecho de que ahora el
directorio de enjaulamiento es %x/ftp
. %x
representa el directorio
XDG_RUNTIME_DIR
que crea systemd para cada usuario[12].
Como en el caso anterior hemos de crear la base de jaula:
# ./enjaular.sh /var/lib/sftp_jail
Finalmente, crear al vuelo la jaula durante la autenticación, requiere manipular
pam. El script sftp_jail.sh
para pam_exec
hace esto suponiendo, de modo predeterminado, que la jaula se montará en
%x/ftp
, que la base de la jaula está en /var/lib/sftp_jail
y que
la parte de la jaula que contiene los datos de usuario está en
/srv/ftp/nombre_usuario
[#]_.
Para que pam ejecute el script se ha preparado un fichero de
automatización
para pam-auth-update que, además,
soluciona el problema de que el usuario pueda acceder al sistema con otros
servicios:
# mv /path/a/sftp_jail /usr/share/pam-configs
# pam-auth-update
Por último, necesitamos que el directorio personal de usuario aparezca debajo en uno de los componentes que constituirá el sistema de ficheros fusionado, de modo que para cada usuario habrá que hacer lo siguiente:
# mkdir -p /srv/ftp/paco/home
# ln -s /home/paco /srv/ftp/paco/home
Notas al pie