Tags

arm arpaname bin_sh blocage blosxom bsd bsdfrance cblog certification chroot cluster dg834 dhcp diffusion dns dnsmasq domU dovecot fail-over fail2ban firefox fossil freebsd ftp git guruplug install ipv6 jail kernel kimsufi lex libre linutop liste makefile mikrotik ml150 mohawk nanojail netbook netbsd nginx ntp ntp.org openbsd openntpd openrd opensmtpd openwrt orke pkgng poudriere privee proxy python rescue reverse rmll route rrdcgi sendmail sieve sjail sl2009 ssd sshd symon unbound update usb var_empty vimperator world xen yacc zfs

Powered by

blOg
maRkdown
awK
shEll

03/07/2014

[ fossil sshd sjail ]

201407032300 fossil sshd sjail

Fossil, ssh et nanojail

Aimant avoir le contrôle de mes développements, je n'ai pas succombé aux sirènes des forges et préfère utiliser fossil.

Ce système de contrôle de version fournit, au sein d'un unique binaire, tout ce qu'on peut attendre de ce type d'outil et réussit le tour de force d'intéger un wiki et un gestionnaire de ticket.

Voyons comment mettre en place ce service à partir des ingrédients suivant:

Fixons les objectifs:

Commençons par créer une jail à l'aide de sjail:

$ cd $HOME && mkdir -p tmp/sjail && fetch -o sjail.tar.gz 'http://fossil.bsdsx.fr/sjail/tarball/sjail.tar.gz?uuid=trunk'
$ alias sjail $HOME/tmp/sjail/sjail
$ cd $HOME && mkdir -p tmp/fossil && cd tmp && sjail fossil init
If you need log, don't forget to add '-l /usr/home/dsx/tmp/fossil/var/run/logpriv'
on syslogd_flags and restart (not reload) syslogd

You could edit /usr/home/dsx/tmp/fossil/usr/local/etc/pkg/repos/sjail.conf before adding any package to match your configuration

Avant d'ajouter /usr/sbin/sshd les plus curieux iront regarder $HOME/tmp/sjail/_sjail_usr_sbin_sshd:

$ sjail fossil /usr/sbin/sshd

Un soupçon de configuration (à adapter suivant vos goûts):

$ cat >> fossil/etc/ssh/sshd_config
UseDNS no
UsePAM no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
StrictModes no
AuthorizedKeysFile /etc/ssh/authorized_keys
AllowGroups src
^D

Pour faire court: j'interdis un maximum de chose et je centralise les clefs des utilisateurs. De toute façon, leur $HOME sera en lecture seule, aucune raison qu'ils y déposent quoi que ce soit.

ATTENTION à StrictModes ! L'arborescence générale de mes jails n'est pas créée par root et cela peut poser problème avec sshd. Sans cette directive, fossil/etc/ssh doit appartenir à root ce qui n'est pas le cas chez moi. Ce n'est pas une faille de sécurité mais un contrôle supplémentaire. L'objectif est de pouvoir manipuler le fichier des clefs depuis l'hôte.

Je rajoute à cette jail /usr/sbin/daemon afin que fossil tourne en temps qu'utilisateur non privilégié:

$ sjail fossil /usr/sbin/daemon
$ sjail fossil pkg install fossil

Passons à la configuration desdits utilisateurs:

$ cat >> fossil/etc/pw.conf
defaultpasswd no
home /repos
homemode 500
shells sh
defaultshell sh
defaultgroup src
minuid 30000
maxuid 31000
^D

Il est temps de créer ce fameux groupe src:

$ sudo chroot fossil pw groupadd src -g 30000

Et un utilisateur toto:

$ sudo chroot fossil pw useradd toto -c 'toto commiter' -m
Password for 'toto' is: 3bzM/cNT
$ grep ^toto fossil/etc/passwd
toto:*:30000:30000:toto commiter:/home/toto:/bin/sh
$ ls -la fossil/home/
total 12
drwxr-xr-x  3 root   wheel  512 Jul  1 22:03 .
drwxr-xr-x  6 dsx    wheel  512 Jul  1 22:00 ..
dr-x------  2 30001  30000  512 Jul  1 22:03 toto

Le service fossil sera exécuté (froidement) par l'utilisateur nobody, je crée le répertoire /repos avec les droits kivonbien:

$ mkdir fossil/repos && sudo chown -R nobody:30000 fossil/repos && sudo chmod -R 775 fossil/repos

La configuration de la jail (attention à la configuration réseau à adapter):

$ cat /etc/jail.conf
exec.clean;
mount.devfs;
exec.jail_user = "root";
exec.consolelog = "/var/log/jails/$name";

fossil {
        path = "/home/dsx/tmp/fossil";
        host.hostname = "fossil.bsdsx.fr";
        ip4.addr = lo1|10.30.12.2;
        exec.start = "/usr/sbin/sshd -e";
        exec.start += "/usr/sbin/daemon -c -u nobody /usr/local/bin/fossil server --files *.json,*.html,*.js,*.css,*.txt --notfound /index.html /repos";
}
$ sudo jail -c fossil
fossil: created

Il me faut une clef pour mon utilisateur toto afin de tester l'accès par ssh:

$ ssh-keygen -q -t rsa -N "" -C "toto's rsa key" -f toto
$ cat toto.pub >> fossil/etc/ssh/authorized_keys
$ ssh -F /dev/null toto@10.30.12.2 -i toto
The authenticity of host '10.30.12.2 (10.30.12.2)' can't be established.
RSA key fingerprint is 2f:e7:02:1c:cc:65:00:06:1b:4d:75:6c:f0:11:e8:cf.
No matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.30.12.2' (RSA) to the list of known hosts.
$ echo /*bin/*  /usr/*bin/* /usr/local/*bin/*
/bin/sh /sbin/ldconfig /usr/sbin/daemon /usr/sbin/nologin /usr/sbin/pw /usr/sbin/pwd_mkdb /usr/sbin/sshd /usr/local/bin/fossil
$ ls
ls: not found
$ echo pouet > toto
cannot create toto: Permission denied

Fervent adepte de chroot, je pensais pouvoir utiliser la commande suivante pour créer un premier projet:

$ sudo chroot -u nobody fossil /usr/local/bin/fossil init /repos/systemd.fossil
invalid home directory: /root

Après avoir essayer:

J'en suis arrivé à la conclusion suivante: on ferait mieux de commencer par le commencement.

$ sudo chroot -u nobody fossil/ /bin/sh 
$ echo $HOME
/root

Tout s'explique. Je disais donc, initialisons un projet de domination du monde:

$ sudo chroot -u nobody fossil /bin/sh -c 'HOME=/repos; /usr/local/bin/fossil init /repos/systemd.fossil'
project-id: 7e8592bc69fbccb40162ef6a17235b8945ed6225
server-id:  c59ad0fe02d3f67d11d2406a951d53602d4cd027
admin-user: root (initial password is "1abd87")

C'est pas encore ça. Mêmes maux, mêmes remèdes:

$ sudo chroot -u nobody fossil /bin/sh -c 'HOME=/repos; USER=nobody; /usr/local/bin/fossil init /repos/systemd.fossil'
project-id: a8581c262d2925e760718319cf5e65287afe60d0
server-id:  22dca47163f6911ba39aba051643418e11364db0
admin-user: nobody (initial password is "4ae1c5")

Est-ce que notre utilisateur toto peut commiter ?

$ cat ~/.ssh/config
Host fossil
    User toto
    IdentityFile ~/.ssh/toto
    IdentitiesOnly yes
$ cd && mkdir -p src/toto && cd src/toto && mkdir src fossils
$ fossil clone ssh://fossil//repos/systemd.fossil fossils/systemd.fossil

ATTENTION !!! Le double / devant repos n'est pas une typo !

Round-trips: 2   Artifacts sent: 0  received: 3
Clone finished with 543 bytes sent, 1044 bytes received
Rebuilding repository meta-data...
  100.0% complete...
project-id: a8581c262d2925e760718319cf5e65287afe60d0
admin-user: dsx (password is "077a9a")
$ cd src/
$ fossil open ../fossils/systemd.fossil 
project-name: <unnamed>
repository:   /usr/home/dsx/src/toto/src/../fossils/systemd.fossil
local-root:   /usr/home/dsx/src/toto/src/
config-db:    /home/dsx/.fossil
project-code: a8581c262d2925e760718319cf5e65287afe60d0
checkout:     8c1b91007ea057d7e9d1a7fbddde1f88b7c4ef45 2014-07-03 19:05:16 UTC
leaf:         open
tags:         trunk
comment:      initial empty check-in (user: nobody)
checkins:     1
$ touch neuneu && fossil add neuneu && fossil commit -m 'add neuneu' neuneu
ADDED  neuneu
Autosync:  ssh://fossil//repos/systemd.fossil
Round-trips: 1   Artifacts sent: 0  received: 0
Pull finished with 319 bytes sent, 228 bytes received
New_Version: 4fcf2e727ba9e86eb64d5dc9ea1c967a7fe9ff59
Autosync:  ssh://fossil//repos/systemd.fossil
Round-trips: 1   Artifacts sent: 2  received: 0
Sync finished with 518 bytes sent, 282 bytes received

Cerise(s) sur le gâteau

Qui dit ssh pense aussitôt FORCE_COMMAND

$ cat fossil/etc/ssh/authorized_keys
command="/usr/local/bin/fossil http /repos/systemd.fossil" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCsZv7o9FjGBW8hpLcCuqE2EC8Togg01M7b5B7k2ogYz+ZnntIwiQcRy9MEUMfY7rK0fhnKiJNd7lg1jUwoZMjbkIOuc/AKe8V3HLALDY/1609IzAb243sVgRGEG6Ezfi2l/PT6Ej2mldwx99L7plXgIZwA5JEdjiaz2SczxtZDAJoBJm1R/lmBc7Min0shV4hzXRcUZ0ncPs84OAfd8hiKbbSOSvhLyqebBmHpUHRiMX6AZkQaUv/JHxl/gPoL996DAPdWso1G0vpniYWw/EFqGVb0D+8omnccpJ/q0hXF/SsuZbeaTcNZX1H8DRgL5+7Bs/ZHZb1Kuhj3iucs8kV toto's rsa key
$ fossil clone ssh://fossil//repos/systemd.fossil fossils/systemd.fossil
Round-trips: 2   Artifacts sent: 0  received: 3
Clone finished with 543 bytes sent, 1045 bytes received
Rebuilding repository meta-data...
  100.0% complete...
project-id: 816a46cf938e770be7dde7323969efdb6e13eb70
admin-user: dsx (password is "cbfaa5")
$ ssh fossil
^CConnection to fossil.bsdsx.fr closed.

Avantages:

Est-ce qu'on peut encore faire mieux ? Je pense que oui:

Ombre(s) sur le gâteau

fossil est lancé en tant qu'utilisateur nobody, il ne peut donc pas écouter sur un port inférieur à 1024 (ce qui tombe bien car par défaut il écoute sur 8080). Mais comment accéder à l'interface web ? La raréfaction des adresses ipv4 impose bien souvent l'utilisation d'un reverse proxy tel que nginx. Pour l'ipv6, il faudra jouer de la redirection de port (80 -> 8080).

Retours

Remarque pertinente (comme à son habitude :) de Natacha: définir le HOME des utilisateurs à /repos. Premier effet kisskool:

$ fossil clone ssh://fossil//repos/systemd.fossil fossils/systemd.fossil
# devient
$ fossil clone ssh://fossil/systemd.fossil fossils/systemd.fossil

Deuxième effet kisskool: inutile de créer des répertoires pour les utilisateurs:

$ sudo chroot fossil pw useradd toto -c 'toto commiter' -m
# devient
$ sudo chroot fossil pw useradd toto -c 'toto commiter'

et

$ cat >> fossil/etc/pw.conf
defaultpasswd random
home /home
homemode 500
shells sh
defaultshell sh
defaultgroup src
minuid 30000
maxuid 31000
^D
# devient
$ cat >> fossil/etc/pw.conf
defaultpasswd random
home /repos
shells sh
defaultshell sh
defaultgroup src
minuid 30000
maxuid 31000
^D

Contre effet kisskool: le $HOME des utilisateurs devient accessible en écriture mais contre contre effet kisskool avec la commande forcée par la clef.

Merci Natacha !

Retour bis

Les perfectionnistes pourront:


Lien vers ce billet