OpenSMTPd comme serveur mail sous debian
J'avais dit il y a un certain temps que j'allais écrire un tutoriel expliquant comment gérer ses mails soi-même. Il se trouve que j'ai récemment décidé de changer le serveur qui héberge (entre autres) ce blog, et que ce dernier héberge aussi mes emails. J'ai donc totalement changé d'infrastructure quand a la gestion de mon système de mails.
Ainsi, j'ai décidé de passer de Postfix a OpenSMTPd, changement que je voulais effectuer depuis un certain temps. OpenSMTPd est un projet originaire d'OpenBSD qui a pour but de fournir un serveur SMTP fiable, simple, rapide, et surtout sécurisé (les même buts que ceux qu'a le projet OpenBSD, globalement).
Pour rappel, le système d'emails fonctionne d'une façon très simple : votre MUA (Mail User Agent, ou client email) contacte le MTA (Mail Transport Agent, ou serveur SMTP) de votre fournisseur email, qui contacte le MTA du fournisseur du destinataire, qui lui même contacte le MDA (Mail Delivery Agent) qui délivre le mail au destinataire.
Si vous avez bien suivi, vous pouvez voir que je n'ai pas parlé de récupération ni de lecture des mails. C'est pour une raison simple, qui est que ces taches sont remplies par d'autres services encore (IMAP/POP pour la récupération depuis le serveur, des yeux pour la lecture).
Or ce qui nous intéresse ici, ce n'est pas simplement d'envoyer et de recevoir des emails mais bien aussi de pouvoir les récupérer et les lire, et c'est pour ça que ce tutoriel ne parlera pas que d'OpenSMTPd mais aussi de Dovecot qui fait office de serveur IMAP et amavis/spamassassin pour filtrer les mails entrants et sortants. Le schéma suivant explique la façon dont les mails sont gérés sur le système
╭────────────────╮ ╭──────────╮
│╭──────────────>│────> to filter ───>│─╮ │
mail in ││ │ │ │ amavis │
───────────>│╯ OpenSMTPd ╭──│<─── from filter<───│<╯ │
│ │ │ ╰──────────╯
mail out │ │ │ ╭──────────╮
<───────────│<────────────┴─>│─────> to MDA ─────>│─────────>│──> to user's
│ │ │ dovecot │ mailbox
╰────────────────╯ ╰──────────╯
Normalement, ceci devrait être a peu près clair.
Pour expliquer vite fait, les emails entrants (venant des utilisateurs mais
aussi d'autres correspondants) sont transmis a OpenSMTPd, qui envoie tout a
amavis
, qui vérifie a la fois les spams et les malwares pour les mails
venants de l'exterieur, et qui signe avec DKIM pour les mails venants de
nos utilisateurs, puis qui rentransmet les mails filtrés/signés a OpenSMTPd,
qui a ce moment-ci trie en fonction de la destination : les mails gérés
par le domaine vont via dovecot dans les boites mail des destinataires
locaux, les mails exterieurs vont directement vers le MTA du serveur
distant.
Voyons comment mettre cela en place. Tout d'abord, il faut décider de la façon dont les différents services vont communiquer.
Déjà, amavis étant configuré par défaut pour écouter (en SMTP) sur le port 10024 et répondre sur le port 10025 quand il s'agit de filtrer et écouter sur le port 10026 et répondre sur le port 10027 quand il s'agit de signer, nous allons profiter de cette configuration et donc lui parler en SMTP sur ces ports.
Quand a Dovecot, nous allons lui transmettre les emails en LMTP (Local Mail
Transfer Protocol), non pas sur un port mais via un socket (dans ce cas précis,
/var/run/dovecot/lmtp
).
Ainsi, pour reprendre le schéma présenté plus haut :
╭───────────────╮ ╭───────────╮
│╭─────────────>│──> SMTP (10026) ──>│─╮ │
SMTP in ││ │ │ │ amavis │
────────> 25│╯ OpenSMTPd ╭──│<── SMTP (10027) <──│<╯ (sign) │
│ │ │ ╰───────────╯
SMTP out │ │ │
25 <────────│<───────────╯ │
╰───────────────╯
Pour les mails sortants; et
╭───────────────╮ ╭────────────╮
│╭─────────────>│──> SMTP (10024) ──>│─╮ │
SMTP in ││ │ │ │ amavis │
────────> 25│╯ OpenSMTPd ╭──│<── SMTP (10025) <──│<╯(filter) │
│ │ │ ╰────────────╯
│ │ │ ╭────────────╮
│ ╰─>│──> LMTP (socket) ─>│───────────>│──> to user's
│ │ │ dovecot │ mailbox
╰───────────────╯ ╰────────────╯
Pour les mails entrants.
Maintenant que la théorie est claire, mettons en place tout cela. Je me baserai ici sur le fait que vous utilisiez une plateforme Debian ou OpenBSD. Pour d'autres plateformes, la configuration devrait être sensiblement la même
(Vous aurez besoin de certificats SSL pour ce guide, même self-signés. Si vous ne savez pas comment en créer, vous pouvez aller voir ce post)
Tout d'abord, commençons par installer les programmes nécessaires :
sudo apt-get install opensmtpd dovecot dovecot-pigeonhole amavisd-new dovecot-managesieved
sudo pkg_add dovecot dovecot-pigeonhole amavisd-new
Continuons en configurant OpenSMTPd tel que nous avons vu plus haut :
/etc/smtpd.conf
# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.
## Certs
pki exem.pl certificate "/etc/certs/exem.pl.crt"
pki exem.pl key "/etc/certs/exem.pl.key"
## Ports to listen on, and how to listen on them
listen on eth0 port 25 tls pki exem.pl hostname exem.pl auth-optional
listen on eth0 port 465 tls-require pki exem.pl hostname exem.pl auth mask-source
listen on eth0 port 587 tls-require pki exem.pl hostname exem.pl auth mask-source
## Aliases
table aliases file:/etc/aliases
# coming from amavisd, checked for spam/malware
listen on lo port 10025 tag Filtered
# coming from amavisd, signed with DKIM
listen on lo port 10027 tag Signed
## Receiving
# if the (incoming) mail has been through amavisd, then we can deliver it
accept tagged Filtered for any alias <aliases> deliver to lmtp "/var/run/dovecot/lmtp"
# we directly tranfer incoming mail to amavisd to be checked
accept from any for domain "exem.pl" relay via "smtp://localhost:10024"
# we have to put these lines in this order to avoid infinite loops
## Sending
# if the (outgoint) mail has been through amavisd, then we can deliver it
accept tagged Signed for any relay
# we tranfer the outgoing mail to amavisd to be signed
accept for any relay via "smtp://localhost:10026"
# same, we have to put these lines in this order or infinite loops...
Expliquons un peu ce fichier de configuration :
- Tout d'abord, le paragraphe nommé "Certs" contient les déclaration d'emplacement des certificats SSL.
- Ensuite, le paragraphe contenant les ports externes sur lesquels nous écoutons : port 25 avec TLS optionel et ports 465 et 587 avec TLS obligatoire
- Les alias sont définis juste après
- Le paragraphe suivant contient les ports locaux sur lesquels nous écoutons : 10025 (port de sortie du filtre de amavis) dont on taggue les mails sortants comme "Filtered" et 10027 (port de sortie des mails signés par amavis) dont on taggue les mails sortants comme "Signed"
- Nous avons ensuite le paragraphe qui traite les mails rentrants. Si le mail traité est taggué comme Filtered, alors il a été vérifié par amavis, et on peut donc le transmettre au destinataire. Sinon, c'est qu'il n'a pas encore été vérifié par amavis, donc on lui transmet pour analyse (sur le port 10024 donc). Il est important de mettre les déclarations dans ce sens, car la première règle qui matche l'état du paquet est appliquée. Ici, la deuxième ligne matchant tous les mails arrivant et la première seulement ceux filtrés, inverser leur sens voudrait dire que les mails seraient toujours renvoyés a amavis
- Enfin, le dernier paragraphe traite les mails sortants. De la même façon que pour le paragraphe précédent, si le mail sortant est déjà taggué comme Signed on le transmet au MTA du destinataire, sinon il n'a pas encore été signé par DKIM par amavis et on le transmet donc a amavis pour qu'il le signe. Le problème de l'ordre des lignes se pose encore, pour la même raison qu'au dessus.
Nous allons maintenant configurer dovecot. Comme nous l'avons vu, dovecot doit
écouter en LMTP via la socket /var/run/dovecot/lmtp
et transmettre les
emails a la boite email de l'utilisateur. Il serait aussi interessant
qu'il nous permette de récuperer les mails. Pour cette configuration, on ne
mettra en place que du IMAPS. Cependant, si vous voulez mettre en place du
POP3[s], différents guides sont trouvables facilement sur internet.
/etc/dovecot/dovecot.conf
## Dovecot configuration file
# basic config
info_log_path = /var/log/dovecot-info.log
log_path = /var/log/dovecot.log
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:%h/mail
# authentication
passdb {
driver = pam
}
userdb {
driver = passwd
}
# the protocols we use
protocols = imap lmtp sieve
# ssl config
ssl_cert = </etc/certs/exem.pl.cert
ssl_key = </etc/certs/exem.pl.key
ssl_cipher_list = HIGH+kEDH:HIGH+kEECDH:HIGH:!PSK:!SRP:!3DES:!aNULL
ssl = yes
## configuring services
# disables imap login without SSL (yes dovecot is dumb that way)
service imap-login {
inet_listener imap {
port=0
}
}
service lmtp {
unix_listener lmtp {
mode = 0666
}
}
## configuring protocols
# the dovecot lda, we set it to use sieve
protocol lda {
mail_plugins = $mail_plugins sieve
}
protocol lmtp {
postmaster_address = whoever@exem.pl
mail_plugins = $mail_plugins sieve
}
plugin {
sieve = ~/.dovecot.sieve
sieve_dir = ~/sieve
}
ATTENTION: Sous OpenBSD, remplacez
passdb {
driver = pam
}
par
passdb {
driver = bsdauth
}
pour identifier les utilisateurs système
Ici aussi, voyons comment ce fichier est structuré :
- Tout d'abord, les configurations de base : ou iront les logs, comment formater leur datation, et l'endroit ou seront stockés les mails des utilisateurs.
- Nous configurons ensuite la gestion de l'authentification des utilisateurs. Ici nous identifions les utilisateurs avec le fichier /etc/passwd et leurs mots de passe avec PAM (ou BSDAuth)
- Nous configurons ensuite les protocoles que nous servons. Ici, nous voulons de l'IMAPS, du LMTP local et Sieve (qui sert pour trier les messages).
- Nous configurons le SSL
- Le section suivante contient la configuration des services. Nous avons en premier lieu le service IMAP, dont la configuration sert uniquement a désactiver IMAP. En effet, dovecot ne permet d'activer IMAPS qu'en activant IMAP avec. Comme nous ne voulons pas d'IMAP sans SSL, nous le désactivons. La configuration de lmtp sert a attribuer des permissions plus correctes au fifo qu'il utilise
- Nous configurons maintenant les protocoles, pour faire fonctionner Sieve
- enfin, nous configurons le plugin sieve en lui indiquant quel fichier et quel dossier utiliser pour sa configuration.
Enfin, il nous reste a configurer amavis. Comme expliqué, amavis va nous servir
a deux choses : signer les emails sortants, et filtrer les emails entrants. Il
doit donc écouter sur les port 10026 pour les signatures et 10024 pour le
filtrage, et répondre respectivement sur les ports 10027 et 10025 (le tout, en
SMTP. Comme toutes les transactions se font sur le loopback, il n'y a aucun
risque a utiliser des protocoles non chiffrés.
Pour OpenBSD, pensez a copier la configuration par défaut depuis
/usr/local/share/examples/amavisd-new/amavisd.conf
et ajoutez les
modifications nécessaires a la fin du fichier.
/etc/amavis/conf.d/99-local.conf
(debian)
/etc/amavis.conf
(OpenBSD)
use strict;
$enable_dkim_verification = 1;
$enable_dkim_signing = 1;
dkim_key("exem.pl", "main", "/etc/certs/dkim.key" );
@dkim_signature_options_bysender_maps = (
{ '.' =>
{ ttl => 21*24*3600, c => 'relaxed/simple' }
}
);
$inet_socket_port = [10024, 10026];
$policy_bank{'MYNETS'} = {
originating => 1,
os_fingerprint_method => undef,
};
$interface_policy{'10026'} = 'ORIGINATING';
$policy_bank{'ORIGINATING'} = {
originating => 1,
allow_disclaimers => 1,
virus_admin_maps => ["root\@$mydomain"],
spam_admin_maps => ["root\@$mydomain"],
warnbadhsender => 1,
forward_method => 'smtp:localhost:10027',
smtpd_discard_ehlo_keywords => ['8BITMIME'],
bypass_banned_checks_maps => [1],
terminate_dsn_on_notify_success => 0,
};
#------------ Do not modify anything below this line -------------
1; # ensure a defined return
A nouveau, expliquons ce fichier : - le premier paragraphe définit que nous voulons qu'amavis signe les emails sortants, vérifie la signature DKIM des emails rentrants, et l'endroit ou se trouve la clé privée servant a signer les emails. - le second définit les options DKIM que nous souhaitons utiliser comme défaut. Je vous invite a consulter la RFC 4871 - nous définissons ensuite les ports sur lesquels nous allons écouter, puis les paramètres que nous utiliserons pour les emails venant de nos utilisateurs : ils seront traités comme "originating" et nous ne vérifierons pas l'OS duquel ils viennent. - nous savons que les emails venants du port 10026 sont sortants, nous les traitons donc comme tel - le paragraphe suivant décrit le traitement que nous faisons subir aux emails sortants : tout d'abord, nous réaffirmons qu'ils viennent bien de notre serveur. Nous autorisons les disclaimers (voire encore une fois la RFC 4871. Nous déclarons l'adresse a prévenir en cas de spam/virus venants de notre système, et que nous voulons être prévenus. Nous déclarons ou envoyer les mails une fois signés et filtrés, puis qu'il est nécessaire de convertir les emails au format 7 bits avant de les envoyer au MTA, que nous autorisons tous les types et noms de fichiers, et les notifications de succès d'envoi. Et voila!
Vous avez pu remarquer qu'a aucun moment nous ne configurions ni la signature des emails sortants ni le filtrage des emails entrants. Ces paramètres sont en fait inclus par défaut dans amavis.
Il nous reste cependant quelques opérations a faire, encore. Tout d'abord, il nous faut générer notre clé DKIM. Pour cela, il existe différentes méthodes, j'ai personnellement utilisé opendkim (un tutorial) mais de nombreuses autre méthodes existent. Il nous reste encore a configurer spamassassin :
#rewrite_header Subject *****SPAM*****
# report_safe 1
required_score 2.0
# use_bayes 1
# bayes_auto_learn 1
# bayes_ignore_header X-Bogosity
# bayes_ignore_header X-Spam-Flag
# bayes_ignore_header X-Spam-Status
ifplugin Mail::SpamAssassin::Plugin::Shortcircuit
# shortcircuit USER_IN_WHITELIST on
# shortcircuit USER_IN_DEF_WHITELIST on
# shortcircuit USER_IN_ALL_SPAM_TO on
# shortcircuit SUBJECT_IN_WHITELIST on
# shortcircuit USER_IN_BLACKLIST on
# shortcircuit USER_IN_BLACKLIST_TO on
# shortcircuit SUBJECT_IN_BLACKLIST on
shortcircuit ALL_TRUSTED off
# shortcircuit BAYES_99 spam
# shortcircuit BAYES_00 ham
endif # Mail::SpamAssassin::Plugin::Shortcircuit
Comme vous pouvez le voir, les modifications se résument globalement a baisser le required_score pour ma part.
Pour finir, activez les services nécessaires : opensmtpd, dovecot, amavisd, et spamassassin, et tout devrait fonctionner parfaitement
Bon courage pour votre hosting de mail ensuite...
Installer FreeBSD sur un serveur Online avec MfsBSD
J'ai récemment eu l'occasion de louer un serveur chez Online.net (filiale de Illiad) Voulant depuis pas mal de temps gérer un serveur sous FreeBSD (et tester bhyve) et n'ayant pour différentes raisons pas eu l'occasion de le faire sur mon serveur auto-hebergé ni sur ce serveur ci, j'ai commencé a chercher comment le faire sur ce serveur.
Étant donné que Online ne propose pas directement d'image FreeBSD sur ses serveurs, il m'a fallu chercher un peu plus loin. Il se trouve que ce post sur les forums d'online explique une procédure, mais celle-ci ne fonctionnait pas pour mon serveur en particulier.
J'ai donc cherché un peu sur internet, puis demandé sur irc (#freebsd-fr@freenode), ou l'on m'a dirigé vers mfsbsd, un projet d'installeur alternatif, minimaliste et simplifié pour FreeBSD.
Pour installer FreeBSD sur votre serveur, donc, il vous faudra accéder a une console KVM (dans mon cas personnel, iLO). Cela doit être faisable depuis le panel Online. Une fois cela fait, lancez une console, puis téléchargez l'image mfsbsd. Dans la console iLO, choisissez de booter sur une image CD/DVD, puis choisissez l'image mfsbsd. Ensuite, rebootez le serveur. Choisissez de booter sur l'image CD/DVD (F11 puis 1). Une fois ceci fait, un FreeBSD a l'air tout a fait classique va démarrer. Une fois ceci fait, la partie importante arrive: mfsbsd contient un script d'installation root-on-zfs, nommé logiquement zfsinstall, qui va se charger de tout le travail pour nous.
Utilisez donc ce script ainsi :
# tout d'abord, wipons le MBR :
dd < /dev/zero > /dev/da0 count=1
# maintenant, installons le système
zfsinstall -g da0 -u ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.0-RELEASE/ -s 2G -p root -c
Avec -g da0
votre disque dur principal, -s 2G
la quantité de swap désirée,
-p root
le nom du zpool, et -c
pour activer la compression. D'autres options
sont disponibles, je vous invite a faire un zfsinstall -h
si mon setup ne vous
convient pas.
Une fois ceci fait, faites un chroot dans /mnt (ou doit se trouver le nouveau système) et éditez /etc/rc.conf :
zfs_load="YES"
sshd_load="YES
hostname="whatever"
ifconfig_igb0="DHCP"
Remplacez whatever par votre hostname, et igb0 par le nom de votre interface physique connectée a internet. Quittez le chroot, rebootez, et voila, vous avez maintenant un système FreeBSD tout propre installé sur zfs a découvrir et utiliser!
Voila, c'est la fin de ce tutoriel. (Cela dit, bon courage pour tester bhyve, vu que l'IPv6 chez online est... peu crédible, disons)
Bon sinon sur d'autres sujets, j'ai mis en place des bots twitter wxcafe_ebooks, petitefanfare, capet_ebooks, zengisse, et kim_ebooks. Ils sont tous basés sur ce code, qui vient de @m1sp (github.com/twitter_ebooks). Donc voila.
A plus
SSL ou la sécurité sur l'internet
Disclaimer: Ce billet est écrit après le visionnage de la conférence de Moxie Marlinspike suivante: More Tricks for Defeating SSL, présentée a la DefCon 17 (en 2011), et la lecture du billet suivant: A Critique of Lavabit, ce qui peut avoir l'effet de rendre légèrement parano. Si vous considérez que c'est le cas ici, veuillez ne pas tenir compte de ce billet (et vous pouvez dès a présent dire coucou aux différentes personnes qui écoutent votre connection)
Si vous venez ici souvent (vous devriez), et que vous utilisez SSL pour vous connecter a ce site (vous devriez, vraiment, dans ce cas), vous avez peut être remarqué quelque chose récemment : il se trouve que le certificat qui permet de desservir ce site a changé.
Cela fait suite aux évènements évoqués dans le Disclaimer, mais aussi a des doigts sortis d'un endroit particulier du corps de l'admin/auteur de ce "blog", qui a pris enfin les 5 minutes nécessaires a la compréhension superficielle du fonctionnement de SSL, et les 10 nécessaires a la mise en place d'un système fonctionnel utilisant cette compréhension récemment acquise.
Bref, le certificat a changé. Mais de quelle façon, vous demandez vous peut
être (ou pas, mais bon, je vais expliquer de toute façon). Et bien c'est très
simple : il existait auparavant un certificat pour wxcafe.net
, un pour
paste.wxcafe.net
, un pour mail.wxcafe.net
, etc... Bref, un certificat
différent pour chaque sous-domaine.
Il s'avère que c'est a la fois très peu pratique a utiliser (les utilisateurs
doivent ajouter chaque certificat a leur navigateur séparément, chaque
changement de sous-domaine conduit a un message d'erreur, etc) et pas plus
sécurisé que d'avoir un seul certificat wildcard. J'ai donc généré un certificat
pour *.wxcafe.net
hier, et il sera dorénavant utilisé pour tous les
sous-domaine de wxcafe.net
; et un certificat pour wxcafe.net
, qui ne matche
pas *.wxcafe.net
, et qui sera donc utilisé... bah pour wxcafe.net
.
Il serait préférable de faire des redirections automatiques des adresses http vers les adresses https, cependant, étant donné que le certificat est self-signed, il me semble préférable que l'arrivée sur le site ne commence pas par une page firefox disant "Something's Wrong!", et ces redirections ne seront donc pas mises en place.
De plus, après la lecture de l'article de blog sur Lavabit dont le lien est plus haut, il semble intéressant (et assez important) de faire en sorte que le serveur utilise en priorité (et si possible, uniquement) des ciphers supportant PFS, soit EDH et EECDH (Ephemeral Diffie-Helmann et la version Elliptic Curves de ce même algorithme). Cela permet de faire en sorte que toutes les communications avec ce serveur soient future-proof, c'est a dire que, même si quelqu'un récupérait la clé privée, elle ne serait pas utile pour déchiffrer les communications passées.
Bon, maintenant que les explications basiques sont faites, voyons
l'implémentation :
Pour générer la clé, tout d'abord, il convient d'utiliser les commandes
suivantes:
sudo openssl genrsa -out example.key 4096
# nous utilisons ici une clé de 4096 bits, la taille est laissée a votre appréciation
sudo openssl req -new -key example.key -out example.csr
# OpenSSL va ici vous demander de nombreuses informations, "Common Name" devant contenir le FQDN
sudo openssl X509 -req -days 1095 -in example.csr -signkey example.key -out example.crt
# enfin, nous générons la clé, d'une durée de vie de 3 ans
Bien entendu, si vous voulez utiliser une clé wildcard, il vous faut préciser
*.example.com
comme common name.
Une fois la clé générée, il faut dire aux différents services de l'utiliser, et
de n'utiliser que des ciphers PFS. La méthode dépend donc du service.
Je vais lister ici les methodes pour quelques services que j'utilise :
apache :
# /etc/apache2/mods_enabled/ssl.conf
# [...]
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 \
EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 \
EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
# [...]
# /etc/apache2/sites-enabled/default-ssl
# [...]
SSLEngine on
SSLCertificateFile /etc/certs/example.com.crt
SSLCertificateKeyFile /etc/certs/example.com.key
# [...]
nginx :
# /etc/nginx/nginx.conf
# [...]
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 \
EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 \
EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
# [...]
# /etc/nginx/sites-enabled/default-ssl
# [...]
ssl on;
ssl_certificate /etc/certs/example.com.crt
ssl_certificate_key /etc/certs/example.com.key
# [...]
prosody (jabber) :
# tout d'abord, lancez la commande suivante :
sudo openssl dhparam -out /etc/prosody/certs/dh-2048.pem 2048
# ensuite, pour chaque VirtualHost dans /etc/prosody/prosody.conf :
ssl = {
dhparam = "/etc/prosody/certs/dh-2048.pem";
key = "/etc/certs/example.com.key";
certificate = "/etc/certs/example.com.crt";
}
# la cipher suite de prosody utilise par défaut EDH et EECDH
postfix (email) :
# /etc/postfix/main.cf
# [...]
smtpd_tls_cert_file = /etc/certs/example.com.crt
smtpd_tls_key_file = /etc/certs/example.com.key
tls_preempt_cipherlist = yes
smtpd_tls_eecdh_grade = strong
smtdp_tls_mandatory_ciphers = high
smtpd_tls_mandatory_exclude_ciphers = aNULL, eNULL, MD5, LOW, 3DES, EXP, PSK, SRP, DSS
smtpd_tls_security_level = encrypt
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_use_tls = yes
# [...]
dovecot (imap) :
# /etc/dovecot/dovecot.conf
# [...]
ssl_cert = </etc/certs/example.com.crt
ssl_key = </etc/certs/example.com.key
ssl_cipher_list = HIGH+kEDH:HIGH+kEECDH:HIGH:!PSK:!SRP:!3DES:!aNULL
Voila. Pour d'autres protocoles/services, je vous invite a RTFM^W vous reporter au manuel approprié.
Cela étant dit, je conseille a tout le monde d'aller voir la conférence dans le disclaimer, et tant qu'a faire la conférence du même hacker SSL and the future of Authenticity qui parle de son implémentation d'une technologie "remplaçant" le système de CAs qui existe actuellement.
Mise en place d'un serveur DNS
Le DNS (Domain Name System) est le service permettant la résolution des noms de domaines en différentes informations : adresses IPv4, adresses IPv6, certificats DNSSEC ou IPsec, localisation géographique, ou encore texte. En général, le DNS est utilisé pour résoudre des noms de domaines en adresses IP, et ainsi pour simplifier la vie de tous les utilisateurs (je doute que tout le monde retienne de se connecter a http://173.194.45.66, ou a http://199.16.156.70. Voire même a http://5.39.76.46).
Cependant, le DNS est un système qui date de 1984, et les exigences de l'époque en termes d'expérience utilisateur n'étaient pas forcément aussi importantes que de nos jours. La configuration des serveurs DNS peut ainsi être assez contre intuitive. Cela étant dit, comprendre le fonctionnement de DNS et contrôler ses enregistrements est important.
Tout d'abord, une petite explication théorique. Le DNS fonctionne de la même
façon que le système de fichiers : en arborescence. Cependant, là ou la racine
du FS est /
, celle de DNS est .
, et là ou il convient d'écrire, par exemple,
/usr/
et ou la progression se fait de gauche a droite pour le FS, pour DNS le
.
n'est pas obligatoire et la progression se fait de droite a gauche. Par
exemple, le tld(top level domain, domaine de haut niveau) com
, et le domaine
google.com
appartient a com
, on écrit donc google.com
sans écrire le point
a la fin de façon courante.
Le reverse DNS est une variante du DNS "classique" permettant de résoudre les
adresses IP en nom de domaine. Ainsi, 5.39.46.76 a pour domaine wxcafe.net.
Cependant, le reverse DNS n'a, par définition, pas de TLD sur lequel se diriger
quand on lui adresse une query. Les "adresses" que l'on query en reverse DNS
sont donc constituées de l'adresse IP, dans le sens contraire a l'ordre
habituel, et du faux domaine .in-addr.arpa
Par exemple, pour connaitre le reverse de 5.39.46.76, il faudra faire dig PTR
76.46.39.5.in-addr.arpa
. La réponse sera, évidemment, wxcafe.net
Voyons maintenant comment mettre en place son propre serveur DNS. Tout d'abord,
quelques informations. DNS fonctionne sur le port 53 en UDP, et la commande
utilisée pour faire des tests DNS est dig
. Le DNS fonctionne avec des
"enregistrements", records en anglais. Par exemple, un record A indique une
adresse IP, un record NS indique un Serveur de nom, etc. dig
se base sur ces
records : par défaut, il ira chercher le(s) record(s) A correspondant(s) au nom
de domaine que vous donnez en argument, mais en précisant un autre type de
record, vous pouvez obtenir n'importe quelle information : par exemple, dig NS
wxcafe.net
devrait vous renvoyer
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> NS wxcafe.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13846
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;wxcafe.net. IN NS
;; ANSWER SECTION:
wxcafe.net. 3600 IN NS ns.wxcafe.net.
wxcafe.net. 3600 IN NS ns.home.wxcafe.net.
;; Query time: 60 msec
;; SERVER: 10.0.42.1#53(10.0.42.1)
;; WHEN: Tue Dec 10 13:31:18 2013
;; MSG SIZE rcvd: 67
Comme vous pouvez le voir, les serveurs DNS principaux pour
wxcafe.net sont ns.wxcafe.net
et ns.home.wxcafe.net
,
qui sont respectivement des alias pour wxcafe.net
et home.wxcafe.net
. Ainsi,
chacun fait autorité pour lui même, et le problème évident est que le résolveur
ne peut résoudre la query si il est renvoyé encore et encore vers le même
serveur. Il convient donc de définir dans le même fichier de configuration
l'adresse de ces deux serveurs. Ainsi, le résolveur, au bout de son deuxième
loop, se rendra compte qu'il est en train de faire une boucle infinie et
demandera l'adresse au serveur auquel il est connecté. La première indication de
direction se fait grâce au serveur du TLD.
La configuration de bind est assez simple dans le principe, le plus complexe
étant en fait d'écrire les fichiers de zone.
La configuration de bind sous debian se fait dans le dossier /etc/bind/. Il
existe 4 fichiers de configuration principaux : named.conf
,
named.conf.default-zones
, named.conf.local
et named.conf.options
.
named.conf
contient les options par défaut de bind, named.conf.default-zones
les déclarations des zones par défaut (auxquelles il vaut mieux ne pas toucher),
named.conf.local
contient les déclarations de vos zones, et
named.conf.options contient les options que vous rajoutez pour changer le
comportement de bind.
Pour commencer, il convient de préciser que nous allons parler ici du cas dans lequel se trouve wxcafe.net: deux domaines dont nous voulons faire l'autorité, deux serveurs DNS, et un service de résolution récursive limitée a quelques IPs (notamment mon accès chez moi).
Examinons tout d'abord les fichiers de configuration de named.
named.conf.local
contient les définitions des zones forward et reverse.
Sur wxcafe.net, les zones wxcafe.net
et 76.46.39.5.in-addr.arpa
sont gérées
en master, et les zones home.wxcafe.net
et 103.177.67.80.in-addr.arpa
sont
gérées en slave. Nous n'examinerons ici que les déclarations de zones sur ce
serveur, et pas sur home., car elles sont sensiblement les mêmes. La différence
principale étant que l'un héberge en slave les masters de l'autre.
Le fichier named.conf.local
sur wxcafe.net contient donc
zone "wxcafe.net" {
type master;
file "/etc/bind/master/wxcafe.net";
allow-transfer {
80.67.177.103;
};
};
zone "home.wxcafe.net" {
type slave;
file "/etc/bind/slave/home.wxcafe.net";
masters {
80.67.177.103;
};
};
zone "46.76.39.5.in-addr.arpa" {
type master;
file "/etc/bind/master/46.76.39.5.in-addr.arpa";
allow-transfer {
80.67.177.103;
};
};
zone "103.177.67.80.in-addr.arpa" {
type slave;
file "/etc/bind/slave/103.177.67.80.in-addr.arpa";
masters {
80.67.177.103;
};
};
Cela devrait être relativement clair. Globalement, les zones master ont un
fichier dans /etc/bind/master/
, et les slaves un fichier dans
/etc/bind/slave/
, les masters autorisent le transfert vers home.wxcafe.net
tandis que les slaves déclarent home.wxcafe.net comme master, et le reste est
assez parlant.
Voyons maintenant le fichier de zone concernant wxcafe.net, soit
/etc/bind/master/wxcafe.net
:
$TTL 3600 ; 1 hour
@ IN SOA ns.wxcafe.net. wxcafe.wxcafe.net. (
2014011001 ; serial
3h ; refresh
1h ; retry
168h ; expire
300 ; negative response ttl
)
; Name servers
IN NS ns.wxcafe.net.
IN NS ns.home.wxcafe.net.
; Mail exchangers
IN MX 10 wxcafe.net.
IN SPF "v=spf1 ip4:5.39.76.46 a -all"
; Main A/AAAA records
IN A 5.39.76.46
ns IN A 5.39.76.46
; Aliases
data IN CNAME wxcafe.net.
; [...]
www IN CNAME wxcafe.net.
; home.wxcafe.net. definition
$ORIGIN home.wxcafe.net.
@ IN NS ns.home.wxcafe.net.
IN NS ns.wxcafe.net.
ns IN A 80.67.177.103
IN A 80.67.177.103
Alors. Expliquons ligne par ligne.
Tout d'abord, le TTL (time to live) est un paramètre définissant le temps
pendant lequel les serveurs récursif (qui font un cache des données) doivent
cacher ce fichier de zone.
Le @ est un raccourci pour exprimer le nom de domaine courant. Ici, donc,
wxcafe.net.
Maintenant, nous arrivons a un record important : SOA (Start of Authority).
Ce record prend de nombreux arguments, dans l'ordre :
- Le nameserver autoritaire pour le nom de domaine en question,
- L'adresse email du responsable de cette zone, avec le premier point
remplacé par un @,
puis entre parenthèses :
- Le numéro de série ("version" du fichier de zone, ici au format
YYYYMMDDNN)
- La période de refresh, période entre chaque mise a jour du nameserver
authoritaire secondaire,
- La période de retry, le temps entre chaque essai de mise a jour si le
nameserveur authoritaire primaire est indisponible,
- La période d'expire, le temps qu'attendra le serveur autoritaire
secondaire avant de supprimer les informations de son cache si le primaire
reste indisponible, et enfin
- La période de TTL négatif, le temps qu'attendra le serveur secondaire
avant de ne plus offrir les informations de cette zone si le serveur
primaire est injoignable.
Bon, tout ceci est peut-être un peu confus, mais ce n'est pas le record le plus important a lire (pour les humains en tout cas). Continuons :
NS (nameserver) permet de désigner les différents nameservers faisant autorité pour ce domaine.
MX permet d'indiquer ou il convient d'envoyer les emails pour ce domaine. SPF est un record d'authentification pour les emails. Les records A désignent l'association entre un nom de domaine et une adresse IPv4. Les records AAAA font de même pour les IPv6, mais malheureusement ce site n'est pas encore en IPv6.
Les CNAME (canonical name) sont en quelque sorte des alias, ils permettent de mettre en place des domaines exactement semblables a d'autre (ce qui permet par exemple de filtrer ensuite avec les Virtual Hosts d'Apache, pour le web)
Enfin, la partie qui suit commence avec une déclaration $ORIGIN, ce qui permet de changer la valeur du @ et des noms de domaine non complets (qui ne se terminent pas avec un .). Ainsi, la partie suivant définit les nameservers et l'adresse IP principale de home.wxcafe.net et de ns.home.wxcafe.net. Comme on l'a vu, étant donné que ce nom de domaine est géré par un autre serveur DNS, cela permet de rediriger les requêtes nous parvenant et demandant un domaine se trouvant sous home.wxcafe.net.
Les autres fichiers de zone sont sensiblement similaires, avec les quelques différences n'étant en fin de compte que des différences de valeurs (dues au fait que, eh bah, c'est pas les mêmes domaines...).
Voila donc une courte explication de ce qu'est le DNS. Bien entendu, tout n'est pas expliqué ici, je ne suis passé que sur ce qui est en place au niveau de wxcafe.net, et encore, rapidement. Si vous voulez en savoir plus, vous pouvez aller vous renseigner directement a la source : le RFC 1034 et le RFC 1035. Dans un autre style (bien plus avancé) le blog de Stéphane Bortzmeyer est interessant aussi.
NAT
NAT (Network Address Translation) in a word?
It's complicated. Very. Don't do it, you'd damage your brain.
Bon, sinon, prochain article serieux vite, bisous.
Plan9 from whichever space
Plan 9 from Outer Space est un film de série Z, produit en 1959 par Edward D. Wood. Il est assez connu comme étant l'un des pires films jamais sortis. Rempli d'erreur de montage, d'effets spéciaux au rabais, et ayant même connu la mort d'un acteur, il a ainsi atteint le statut de film culte grâce a sa médiocrité.
Plan 9 from Bell Labs est un OS venant de Bell Labs (comme son nom l'indique), et qui a été pensé comme le successeur d'Unix. Il est conçu comme une poursuite des concepts unixiens jusqu'à leur but naturel. Ainsi, c'est Plan9 qui a introduit le concept d'UnionFS, le protocole 9P qui permet d'acceder a des ressources appartenant a d'autres ordinateurs a distance, un support de l'unicode par défaut et sur tout le système (a l'inverse d'Unix, qui fonctionne a la base en ASCII), un support de ProcFS amélioré, une interface graphique par défaut, et d'autres améliorations sur les thèmes de base que propose Unix.
Cependant, Plan9 n'a jamais été véritablement utilisé pour quoi que ce soit d'autre que la recherche en systèmes, et c'est dommage, parce que Plan9 a quelque chose de très intéressant à proposer. En effet, en ces jours d'intérêt grandissant pour le klaoude et la délocalisation a la fois du processing et des données, et bien que Plan9 ait été créé bien avant que le terme "cloud computing" n'apparaisse pour la première fois, il semble que ce système ait été conçu pour apporter cette délocalisation tant rêvée.
En effet, même si l'on considère que les nouveautés qu'il apporte par rapport a Unix ne sont pas extraordinaires en soit (alors qu'elles sont déjà conséquentes), lorsqu'on les prend ensemble, elles font de Plan9 le système d'exploitation ultime en terme de partage de ressources et de données. Ainsi, le fait que 9P permette de considérer toutes les ressources d'un système distant comme n'étant qu'une poignée de fichiers permet de le monter comme n'importe quel système de fichier. Le fait que chaque utilisateur puisse accéder a plusieurs namespaces de façon transparente (et donc de démarrer, arrêter et gérer des processus sur chacun de ces namespaces) et que chaque namespace puisse interagir avec les autres, même s'ils sont hétérogènes (c'est a dire provenant de machines différentes), permet d'utiliser les ressources d'une machine distante comme si elle était présente localement. Le mécanisme d'UnionFS permet de rendre tout ça utilisable, en montant plusieurs systèmes de fichiers sur le même point de montage, en même temps, et de pouvoir ainsi accéder aux fichiers de plusieurs machines a la fois (ce qui permet une délocalisation des données bien plus poussée que Dropbox ou Google Drive, et ce en kernelspace).
Le réseau fait donc partie intégrante de Plan9, et il devient plus difficile de parler d'ordinateur lorsque le concept même du système est d'être composé de clusters eux mêmes composés de machines hétérogènes. Le système de fichier virtuel /net fourni par le kernel de Plan9 permet d'implémenter très facilement différents concepts réseaux : en montant le /net d'un ordinateur du réseau local sur celui servant de gateway vers l'internet, on crée un NAT vers cet ordinateur du réseau local. En montant le /net d'un ordinateur distant sur un ordinateur local via le protocole 9P sécurisé, on crée un VPN : les connections locales se font en utilisant l'accès de l'ordinateur distant, et les connections entre les deux sont chiffrées.
Bref, bien avant les clusters de Raspberry Pi qui utilisent une api python pour partager leur "puissance" de calcul en userspace, des superordinateurs pour lesquels le noyau Linux s'est doté du support de jusqu'à 4096 CPUs, des OS tels JoliOS qui promettent une integration du klaoude alors qu'ils ne sont en fait que des navigateurs web a peine améliorés et des services de stockage en ligne qui promettent un accès universel a toutes nos données alors qu'ils ne proposent que de les garder a disposition par le web, Plan9 promettait une technologie de partage des ressources système et de données, une intégration du réseau dans le système particulièrement poussée, un environnement graphique supporté par le basesystem et non greffé par dessus comme l'a été X11, et de nombreuses autres améliorations sur Unix.
Malheureusement, il n'a jamais été adopté de façon véritablement significative, et ce pour une raison très Unixiènne : "worse is better". En effet, le parc de machines Unix déjà installées était suffisamment performant et fonctionnel pour que des solutions soient développées au dessus du système pour remplir les mêmes fonctions que remplit Plan9 via son kernel, tels le nouveau ProcFS de Linux, FUSE, etc...
Sed Basics
sed
est un outil Unix très largement utilisé et très pratique pour manipuler
le texte (ce qui se montre relativement indispensable dans un environnement
Unix, puisque ce système est assez porté sur le texte). Cependant, il assez peu
connu en détail, et la plupart du temps une seule fonction est utilisée : le
remplacement de texte.
Or sed
a bien plus de possibilités que ça, comme nous allons le voir.
Tout d'abord, rappelons les bases : sed
est un programme Unix de base, mais
aussi un langage de manipulation de texte dérivé de ed
, l'éditeur original.
ed
est un éditeur de ligne, conçu a l'époque ou les ordinateurs n'étaient pas
personnels et étaient utilisés avec des téléscripteurs, c'est a dire des
machines dépourvues d'écrans et ne permettant donc pas l'utilisation d'éditeurs
dits "visuels", tels que vim, emacs, et globalement tous les éditeurs ayant un
curseur et affichant plusieurs lignes. sed
est donc une évolution de ed
, le
s signifiant stream, sed
est un éditeur de flux, prenant donc avantage du
concept Unixien de flux de données (voir Flux standards) pour éditer plus d'une ligne a la fois.
En pratique, sed
est principalement utilisé sur des fichiers.
sed
a quelques options pratique, notamment -s
qui permet d'empêcher
l'affichage systématique des lignes traitées, ou bien -i
(pour GNU sed) qui
permet de rediriger l'output dans le fichier d'input. Cela dit, l'intérêt unique
du programme est son langage de manipulation de texte.
ed
, et donc sed
, utilise un langage basé sur les séparations (en général des
/). Ainsi, la commande de base dans sed
est
/[regex]/
qui permet de ne sélectionner que les lignes qui matchent [regex] (et donc de n'exécuter les commandes qui suivent que sur ces lignes.)
La commande sed
la plus utilisée est bien entendu le s, qui s'utilise de
la façon suivante :
s/[old text]/[new text]/[options]
qui se propose donc de remplacer (substitute) [old text] (qui peut être une
regex) par [new text] (qui doit être un texte fixe, avec quelques
exceptions), en appliquant [options], la plus connue des options étant g
,
qui permet d'appliquer la commande affectée a toutes les occurrences du texte
matché sur la/les lignes concernée-s.
Les exceptions a la "fixité" de [new text] sont particulièrement
intéressantes. En effet, sed
utilise un langage de regex plutôt standard,
excepté le fait qu'il permet jusqu'à 9 "holding spaces", qui sont délimités par
\( et \), et qui sont représentées dans le texte de remplacement par \1 à
\9.
Par exemple, la commande
sed 's/\(hello world\) world/\1/'
sur le texte "hello world world" renverrait comme résultat
hello world
De la même façon, le symbole &
dans le texte de remplacement représente le
texte original. Ainsi, la commande
sed 's/hello world/& world/'
sur le texte "hello world" renverrait comme résultat
hello world world
Une autre commande utile est p, qui sert a afficher le texte présent dans l'espace courant :
/[regex]/p
sed
stocke en effet la ligne sur laquelle il travaille dans un espace mémoire
dédié, que j'appelle l'espace courant (pattern space en anglais). La commande
p
affiche (print) ce qui ce trouve dans cet espace. La /[regex]/ réduit
le pattern space de façon a ce qu'il ne contienne que les lignes matchant, et le
p affiche donc ce dernier.
Un autre exemple de commande sont c, i et a, qui s'utilisent ainsi :
c \
[text]
De la même façon, pour le i :
i \
[text]
Et de même pour a.
Ces trois commandes s'utilisent de la même façon pour la bonne raison qu'elles sont très proches. i sert a insérer du texte avant le pattern space. a sert a insérer du texte après le pattern space, et enfin c sert a remplacer tout le pattern space. Les trois utilisent [text] comme remplacement ou insert. Attention, les insertions se font sur la ligne précédant ou suivant le pattern space, et non sur la ligne en question.
Enfin, dernière commande ne fonctionnant que ligne par ligne, d : /[regex]/d d (delete) supprime les contenus du pattern space.
sed
est un outil puissant, mais complexe. Dans un prochain article, je
parlerai des commandes multilignes et des labels.
Le chiffrement de partitions avec dm-crypt et device-mapper
Le chiffrement en tant que concept informatique est traditionnellement associé au chiffrement de fichiers, c'est a dire au fait de passer d'un fichier en clair a un fichier chiffré dit cyphertext. Cependant, il ne se limite pas a ça, et peut aussi servir a garantir l'intégrité d'un système d'exploitation, ou bien la confidentialité d'un support de stockage, par exemple. Nous allons ici voir comment mettre en place un système de ce type sous GNU/Linux. Cet article n'a pas pour but de vous apprendre a mettre en place un système basé sur une procédure de boot sécurisée, mais plutôt d'expliquer les concepts qui entrent en jeu dans l'utilisation du sous-système du noyau Linux dm_crypt et de présenter un rapide tutoriel concernant la création d'un support chiffré sur lequel garder vos informations confidentielles (par exemple, votre clé GPG)
dm-crypt est un sous-système de device-mapper, qui est lui-même un sous-système
du noyau Linux, et s'appuie sur LUKS, un standard de chiffrement
de disques. Comme son nom l'indique, device-mapper est un système qui a pour but
de mapper des block devices. Pour être plus clair, le kernel considère
comme "block device" tout fichier spécial (en gros, les fichiers disques dans
/dev/
, les systèmes de fichiers type LVM, les RAID logiciels, et, dans le
cas qui nous intéresse, les systèmes de fichier chiffrés). Son mode de
fonctionnement est simple : a partir d'un "fichier de périphérique" (trad.
Wikipédia), il en "crée" un nouveau, virtuel, ayant des propriétés différentes.
Par exemple, un disque partitionné via LVM apparaîtra comme un seul disque dans
/dev, et device-mapper est requis pour pouvoir en voir les partitions (qui
apparaîtront donc dans /dev/mapper)
Ainsi, dans le cas qui nous intéresse ici, device-mapper prend un système de fichier chiffré, crée un périphérique virtuel non chiffré dans /dev/mapper, et déchiffre a la volée tous les accès disques a ce périphérique non chiffré en les traduisant sur le système de fichier chiffré, le tout de manière tout a fait transparente pour les applications utilisant le disque en question. Cela induit bien entendu une baisse de performance relativement significative dans le cas d'un chiffrement du système de fichier root, mais quasiment insignifiante dans le cas de chiffrement de partitions de données.
D'ailleurs, certain-e-s se demandent peut-être comment le système peut démarrer si le système de fichier root est chiffré. Dans ce cas précis, la procédure de boot doit s'appuyer sur une image initrd (l'initrd est un système de fichier minimal qui sert uniquement a initialiser le système. Les kernels de base de la plupart des distributions GNU/Linux en utilisent un dans tous les cas, pour des raisons de compatibilité) et sur une partition de boot qui elle n'est pas chiffrée. Ainsi, le bootloader de niveau 2 (grub, syslinux,...) charge en mémoire le kernel depuis la partition de boot, puis ce dernier décompresse et charge l'initrd en RAM, celui-ci a son tour lance un script permettant de charger les modules nécessaires a la suite du boot (que ce soit pour un boot sans disque root local, ou bien comme ici avec un système chiffré), puis le système de fichier "cible" est remonté sur la racine, et l'initrd est démonté est la RAM qu'il occupait est libérée, puis la procédure de boot normale reprend depuis le système de fichier maintenant monté sur la racine.
La méthode la plus évidente pour contourner le chiffrement du disque est alors
de remplacer le fichier compressé initrd dans /boot, qui n'est pas chiffrée, par
un autre modifié, copiant par exemple la phrase de passe permettant de
déchiffrer la partition cible. Plusieurs méthodes permettent de se prémunir
contre ce genre d'attaques : l'une des plus simple est de faire un checksum du
fichier initrd utilisé et reconnu comme sûr, et de vérifier lors du vrai boot
que l'initrd présente toujours le même checksum. Cela dit, cette méthode a
l'inconvénient d'intervenir après les faits, et de nécessiter au moins un accès
a un fichier initrd reconnu comme sûr.
Une autre approche consisterait a placer le système de fichier /boot sur un
périphérique dédié, protégé en écriture de façon matérielle (par exemple, une
carte SD) ou, de façon encore plus efficace, sur un périphérique chiffré et
protégé en écriture de façon matérielle. Ainsi, il n'est pas possible pour un
attaquant de modifier ce système de fichier, et l'initrd est alors toujours de
confiance. Cependant, cela a pour conséquence de rendre la mise a jour de
l'initrd et du noyau beaucoup plus difficile qu'elle ne le serait sans.
Pour en revenir aux systèmes de fichiers chiffrés, leur gestion est faite par un
programme dédié, cryptsetup
. Ce dernier était en charge de cryptoloop,
l'ancien sous-système de chiffrement du kernel Linux (déprécié depuis), et est
maintenant responsable de l'utilisation userspace de dm-crypt, qui pour sa
part est entièrement kernel-space. Cryptsetup permet ainsi le chiffrement, la
manipulation (montage/démontage/...) et la gestion de clé des systèmes de fichier
LUKS. Cryptsetup est cependant conçu pour être utilisé en tant que root, et les
utilisateurs qui veulent monter de systèmes de fichiers chiffrés devront ainsi
obligatoirement être capables de le faire en tant que root.
Voyons comment il faudrait procéder pour créer une image disque chiffrée de 1Go :
Tout d'abord, il nous faut créer le fichier qui contiendra l'image. Pour cela,
dans une situation réelle ou l'on cherche a chiffrer un disque, il convient
d'utiliser /dev/urandom comme source, pour éviter la détection du système de
fichier chiffré sur le disque.
Ici, par exemple, nous allons faire :
dd bs=1000 count=1000000 if=/dev/urandom of=image.img
Maintenant que notre image est créée, nous pouvons la chiffrer :
sudo cryptsetup luksFormat image.img
cryptsetup
va alors nous demander si nous sommes absolument surs de vouloir
formater ce disque (nous allons donc valider en tapant YES), puis une
passphrase. Il convient ici de choisir une passphrase particulièrement sûre,
puisque toute personne ayant accès a la passphrase aura aussi accès au disque et
donc a vos secrets.
Une fois cela fait, nous allons mapper cette image :
sudo cryptsetup luksOpen image.img crypto
cryptsetup
nous redemande la passphrase, charge pendant quelques secondes,
puis nous redonne le prompt. Que s'est-il passé? En cherchant un peu, nous
voyons qu'il n'y a pas de nouveau disque dans /dev. C'est tout a fait normal. En
effet, cryptsetup (et par lui, device-mapper et dm-crypt) ne monte pas les
systèmes de fichiers chiffrés, il les mappe, et ça n'a rien a voir. On remarque
qu'est apparu dans /dev/mapper le fichier crypto. Ce fichier est le disque
virtuel qui correspond a notre image. Il se comporte comme toute partition, et
peut donc être monté, formaté, etc (il ne peut cependant pas être partitionné.
Il se comporte en effet comme une partition, et non comme un véritable disque.)
Bon, ceci fait, notre disque virtuel n'est pas formaté. Il nous reviens donc de
le faire, pour pouvoir l'utiliser.
sudo mkfs.ext4 /dev/mapper/crypto
Maintenant que notre disque est formaté, il peut être monté :
sudo mount /dev/mapper/crypto /mnt
Et voila, nous avons un système de fichier fonctionnel et chiffré! Si vous
voulez vérifier, un mount | grep crypto
devrait vous donner le résultat
suivant :
/dev/mapper/crypto on /mnt type ext4 (rw,relatime,data=ordered)
Vous pouvez maintenant commencer a stocker tous vos secrets sur ce fichier, ils sont (en fonction de votre passphrase) en sécurité.
Pour résumer :
-
Pour monter vos partitions :
sudo cryptsetup luksOpen <fichier chiffré> <nom de disque virtuel> sudo mount /dev/mapper/<nom de disque virtuel> <emplacement>
-
Pour démonter vos partitions :
sudo umount <emplacement> sudo cryptsetup luksClose <nom de disque virtuel>
Pour simplifier la vie de tous, j'ai créé deux petits scripts vous permettant de créer et de monter/démonter vos images/disques chiffré-e-s en une seule commande. Ils se trouvent sur github.
Par ailleurs, si vous comptez transferer votre image disque sur un véritable
disque (ou clé usb, ou autre), il est préférable de créer une partition de
taille appropriée et de faire un dd if=votre_image of=/dev/votre_partition
pour ce faire.
Redesign du blog, etc
Comme vous avez pu le remarquer, ce blog a "un peu" changé récemment.
Du coup, expliquons. J'ai récemment monté serverporn, et ai par la même occasion découvert pelican. J'ai tout de suite accroché a ce générateur de site statique en python, du fait de son efficacité, de sa facilité d'utilisation et de sa grande customisation. En gros, pelican est un logiciel qui prend des fichiers markdown ou reStructuredText, les passe a la moulinette d'un "thème" constitué de templates pour les fichiers html et l'organisation du projet et d'une partie "statique" contenant le css, et les autres fichiers nécessaires au projet, et en fait des pages html.
Globalement, un thème est constitué ainsi :
thème
├── static
│ ├─ css
│ │ └─ [css files]
│ ├─ img
│ │ └─ [image files]
│ └─ js
│ └─ [javascript files]
└── template
├─ base.html
├─ index.html
├─ page.html
├─ [...]
└─ article.html
Sachant que les fichiers .html sont en réalité des fichiers suivant la syntaxe
django, et utilisent des variables particulières telles {{ article.content }}
,
par exemple. La syntaxe complète est très bien documentée dans la doc de
pelican.
L'un des grands avantages de pelican est aussi la facilité qu'il offre quand a
la mise a jour du blog.
En effet, il offre un système de Makefiles permettant, grâce a de nombreuses
cibles de compilation, de régénérer le site entier, de ne générer que les
fichiers modifiés depuis la dernière génération, de générer uniquement les
fichiers n'existant pas la dernière fois, etc...
La gestion du projet en devient donc très simple, puisque après avoir écrit un
article, il suffit de faire un make html
pour mettre a jour le blog.
De plus, le système de wordpress commençait a ne plus me convenir, du fait du manque de customisation, du fait que ça soit du PHP (beurk), etc. La, avec pelican, je contrôle bien plus ce qui est mis sur le serveur (puisque c'est moi qui ait modifié les templates et le css), c'est lisible (puisque c'est du python, par opposition au PHP...), et c'est plus "efficace". Le markdown est très pratique, je peux utiliser mon éditeur de texte de prédilection pour faire les articles, je n'ai pas besoin d'un accès continu au net, bref, c'est plus efficace.
En ce qui concerne les points négatifs :
-
Perte des commentaires: Je vous propose de vous référer a l'article de Gordontesos ici quand a mon avis sur ce sujet.
-
Perte du bouton flattr: Il va bientôt être remis, c'est juste un manque de temps de ma part, mais vu que toutes les pages passent par les mêmes templates, c'est assez facile a faire.
-
Perte du spam: Pourquoi c'est dans les points négatifs, ca?
-
Temps d'adaptation et d'appréhension du système: Oui, pendant encore un certain temps, il y aura des glitchs plus ou moins réguliers sur le blog, c'est parce que j'apprend a me servir de ce système et que j'apprend du css et du html. Ca arrive, ca passera, mais dans tous les cas ca me permet d'apprendre plein de choses, donc je mets plutôt ca dans la catëgorie positive.
Voila, c'est mon retour d'expérience sur pelican. A plus.
Comment Saurik a rooté les Google Glass
Comme vous avez pu le lire dans les médias, Saurik (Jay Freeman, connu pour avoir développé Cydia, un "app store" alternatif pour les iTrucs), après avoir reçu une paire de Google glass de la part de Google (de façon assez évidente...), a trouvé intéressant d'obtenir un accès root sur celles-ci, ce qu'il a accompli très rapidement. Des démentis de la part de Google et de certains autres sites sont vite arrivés, disant que les lunettes possédaient un bootloader débloqué et que de fait, le root était facile a obtenir : il suffisait de débloquer le bootloader, d'extraire l'OS, de le rooter hors-fonctionnement, puis de le réinstaller, rooté, sur les lunettes.
Le fait est que de débloquer le bootloader laisse une trace permanente sur les lunettes, et que Saurik n'a pas utilisé cette technique pour rooter sa paire. Voyons comment il a fait :
Je tiens tout d'abord a préciser que toutes les informations qui vont suivre sont extraites de cet article, et plus précisément de la partie "How does this exploit work". Je tente d'apporter ma maigre contribution a cette explication.
Donc, d'après les témoignages des quelques utilisateurs de Glass dans le monde, il semblerait que ces dernières fonctionnent avec un système d'exploitation Android, avec une nouvelle interface, mais avec les mêmes outils internes: un kernel Linux, des outils userland GNU et une machine virtuelle Java Dalvik pour les applications.
Saurik a donc cherché un exploit connu pour cette version d'android, et l'a appliqué a son problème. L'exploit en question est relativement simple. Depuis la version 4.0 d'android, le système permet la sauvegarde des données des différentes applications, une a une, via ADB (Android Debug Bridge, un protocole USB permettant l'accès a de nombreuses fonctions avancées des machines fonctionnant sous android, dont, entre autre, un shell, un accès au logs de debugging, etc... Cette fonctionnalité est bien entendu désactivable.) Ce backup est très simple : il crée un fichier .tgz contenant le dossier de configuration de l'application. Lors de la restauration, le système supprime la configuration existante, puis la remplace par celle dans l'archive gzip.
Le problème de sécurité vient du fait que les applications android voient leurs données stockées dans /data/data/identifiant/, et que /data/ a pour permissions drwxrwx--x 27 system system, ce qui signifie que seul system et les membres du groupe system peuvent lire dessus. Or, le fichier /data/local.prop définit de nombreux paramètres au démarrage, et notamment un qui permet au système de déterminer s'il fonctionne dans une VM ou sur un véritable appareil. S'il fonctionne sur une machine virtuelle, il donne les droits root a tout utilisateur se connectant via ADB, ce qui est ce que l'on cherche pour l'instant. Le fait que /data/ appartienne a system veut dire que le programme de restauration doit être setuid pour accéder aux données a l’intérieur qui appartiennent a root (soit toutes les applications système d'android, dont l'application paramètres, et, dans ce cas précis, l'application de log système présente sur les google glass de test. Ainsi, nous avons un processus tournant en tant que root, qui va écrire sur une partition qui nous intéresse des données que nous possédons.
Cependant, un problème reste : le système de restauration d'Android vérifie les données avant de restaurer, et ne restaure pas les symlinks, ce qui nous empêche d'avoir accès directement a /data/local.prop, le fichier qu'on cherche a modifier. Cela dit, il nous reste une possiblité. Plaçons un dossier world-writable dans le fichier de backup, et nous pourrons écrire dedans pendant quelques secondes, le temps que la restauration se termine et que le système remette les permissions en place. Ainsi, nous pouvons créer le fichier /data/local/com.google.glass.logging/whatev/x, lien vers /data/local.prop, et nous avons un toujours un processus tournant en tant que root qui est en train d'écrire dans ce dossier.
Donc, nous allons lancer deux processus en même temps :
-
Le premier tentera en boucle de créer le symlink. Il sera consitué de la commande suivante, depuis un shell sur les lunettes :
while ! ln -s /data/local.prop /data/data/com.google.glass.logging/whatev/x 2>/dev/null do : done
-
Le deuxième sera le processus de restauration de notre exploit. Celui ci, pour une plus grande chance de réussite, devra être suffisamment lourd : au moins \~50Mo. Il devra contenir whatev/bigfile et whatev/x, pour qu'il crée whatev, prenne du temps a copier bigfile, puis écrive dans x après que le symlink soit effectif. La commande sera, depuis l'ordinateur host :
adb restore exploit.ab
Ces commandes vont fonctionner de concert pour nous donner un accès root :
- Le processus de restauration va créer le dossier whatev, qui sera world-readable. Il va commencer a copier le fichier bigfile.
- Le processus de symlink va créer le lien /data/data/com.google.glass.logging/whatev/x, pointant vers /data/local.prop, puis rendre l'âme proprement.
- Le processus de restauration, ayant enfin fini de copier whatev/bigfile, copiera les contenus que nous voulons dans whatev/x, qui est lié a /data/local.prop. Comme le processus est setuid root, il ne se rendra compte de rien, et écrira tout dans /data/local.prop.
And voilà! On a écrit ce que l'on veut dans /data/local.prop, ce qui nous permet de faire croire a android qu'il tourne dans une machine virtuelle (ce que l'on veut, c'est en fait "ro.kernel.qemu=1", qui indique au noyau qu'il tourne dans qemu, un système de VM).
Il nous reste a rebooter, depuis l'ordinateur host :
adb reboot
Puis nous remontons la partitions système en lecture/écriture (r/w), depuis le host :
adb shell "mount -o remount,rw /system"
Nous copions le binaire su vers l'appareil :
adb push su /system/xbin
Nous donnons les bonnes permissions a ce binaire, afin de pouvoir l’exécuter plus tard :
adb shell "chmod 6755 /system/xbin/su"
Ensuite, nous supprimons le fichier /data/local.prop, pour pouvoir redémarrer normalement :
adb shell "rm /data/local.prop"
Enfin, nous redemarrons a nouveau :
adb reboot
Et voila, une paire de google glass rootée!
Il est bon de préciser que cette manipulation n'est possible que parce que les lunettes tournent sous une ancienne version d'android, et que ce bug a été fixé depuis.
Il serait aussi interessant de couvrir les problèmes de vie privée qu'engendrent les Google Glass, et ce sera fait dans un autre billet.
A bientôt!