Pour présenter plusieurs ressources web domestiques sur internet de manière sure, je vous propose une implémentation simple sous apache 2.4. Nous allons utiliser les certificats générés précédemment. Mon FAI me fournissant qu’une seule adresse IP v4, j’ai retenu la solution du reverse-proxy.
Un raspberry pi s’acquittera très bien de cette charge pour l’affichage de quelques pages. Je n’ai pas tester sur un accès à un NAS.
La présentation d’un serveur web perso sur internet étant abondamment documentée, je ne la traiterai pas ici. En résumé, il vous faut :
- éventuellement, acquérir un nom de domaine via un bureau d’enregistrement (ex chez Gandi),
- configurer votre routeur d’accès internet ou « box », pour rediriger le trafic http et https vers votre nouveau serveur,
- associer votre adresse IP publique fournie par votre FAI à votre nom de domaine. Votre box sait probablement gérer des services de type DynDNS. Vous pouvez aussi utiliser l’API de votre bureau d’enregistrement.
Reverse proxy
Le reverse proxy permet de présenter un seul « site web » à l’extérieur et de distribuer les requêtes vers plusieurs serveurs internes. Il va servir d’aiguillage. Dans l’exemple ci-dessous, il s’appelle domperso.fr. Lorsqu’il reçoit une requête /s1/trucmachin/bidule.html, il va émettre une requête http://serv1.home/trucmachin/bidule.html.
mod_proxy d’apache propose cette fonction de mandataire inverse (c’est la traduction de reverse proxy) de plusieurs manières. J’ai choisi de mettre une directive ProxyPass dans une section Location comme ceci :
<Location "/s1/" > ProxyPass "http://serv1.home/" </location>
l’ajout d’une petite redirection permet de traiter le cas : /s1 (sans slash à la fin)
RedirectMatch "^/s1$" "/s1/"
On peut naturellement faire plus court. Mais, je souhaite pouvoir positionner des paramètres différents en fonction du serveur interne (changer de mode d’authentification, gérer des droits d’accès différents, …)
authentification par certificat client sur apache 2.4
Ce mécanisme d’authentification est fourni par le module mod_ssl. Il nous faudra contrôler le certificat et vérifier ses droits.
Le client doit présenter un certificat.
SSLVerifyClient optional Require ssl-verify-client
Ce certificat doit être émis par une autorité que le serveur connait. Ici, le répertoire /etc/apache2/myclientsCA contiendra les certificats des autorités reconnues. Le nom des fichiers devront être le ‘hash’ du certificat. Dans notre cas, nous n’aurons que la nôtre.
SSLCACertificatePath /etc/apache2/myclientsCA
Nous pourrions nous arrêter là. Néanmoins, je propose d’ajouter un contrôle sur les utilisateurs. Si le certificat de l’un de vos proche vient à compromis (vol du téléphone par exemple), vous le supprimerez du groupe d’autorisation et génèrerez un autre certificat avec un nom différent.
Le nom d’un utilisateur est son CN (Common Name)
SSLUserName SSL_CLIENT_S_DN_CN
Le fichier des groupes d’autorisations est /etc/apache2/my-auth-conf/cert-groupe et l’utilisateur doit être dans le groupe mon-groupe
AuthGroupFile /etc/apache2/my-auth-conf/cert-groupe Require group mon-groupe
Allons-y
Après déploiement du package apache2 sous debian ou raspbian, l’arborescence de la configuration apache ressemble à ceci :
/etc/apache2/ |-- apache2.conf | `-- ports.conf |-- mods-enabled | |-- *.load | `-- *.conf |-- conf-enabled | `-- *.conf |-- sites-enabled | `-- *.conf
Toutes les manipulations sont réalisées sous root.
Activons les modules nécessaires
Pour TLS, le module s’appelle toujours mod_ssl, bien que SSL soit désormais obsolète.
root@deby:~# cd /etc/apache2/mods-enabled/ root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/ssl.load ssl.load root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/ssl.conf ssl.conf root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/socache_shmcb.load socache_shmcb.load root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/authz_groupfile.load authz_groupfile.load
Pour le reverse proxy :
root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/proxy.load proxy.load root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/proxy_http.load proxy_http.load root@deby:/etc/apache2/mods-enabled# ln -s ../mods-available/rewrite.load rewrite.load
Interdisons http
On pourrait supprimer la ligne Listen 80 dans ports.conf. Il est d’usage de rediriger les requêtes arrivant en http vers https. Avec un éditeur de texte, dans le fichier /etc/apache2/sites-enabled/000-default.conf ajouter une règle de réécriture à la fin de la section VirtualHost.
# Modif MF renvoi vers https RewriteEngine on RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=308] </VirtualHost>
Pour comprendre les différents code de redirection (3xx).
Configurons https
certificat du serveur
Comme nous seront les seuls à utiliser notre mandataire inverse inutile de recourir à une autorité de certification externe (ex let’s encrypt), utilisons la nôtre. Nous allons stocker notre clé et notre certificat dans un répertoire dédié.
root@deby:/etc/apache2# mkdir keys root@deby:/etc/apache2# cd keys root@deby:/etc/apache2/keys# openssl genrsa -out serverkey.pem 2048 Generating RSA private key, 2048 bit long modulus ...........+++ ................................................................................................................................................................+++ e is 65537 (0x10001) root@deby:/etc/apache2/keys# chmod 600 serverkey.pem
Pour protéger la clé privée, le chmod ci-dessus la rend lisible uniquement l’utilisateur root.
Générons la requête de certification en ne renseignant que le ‘Common Name’ avec le nom de notre serveur.
root@deby:/etc/apache2/keys# openssl req -new -out servercsr.pem -key serverkey.pem You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:domperso.fr Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
Copions la requête de certification sur notre serveur d’autorité de certification dans /home/ac/certs (bon là je triche chez moi, c’est très sale : c’est sur le même serveur 🙂 et j’ouvre une session sur celui-ci. Munissez-vous du mot de passe de la clé privée de votre AC.
ac@deby:~$ openssl ca -in certs/servercsr.pem -out certs/servercert.pem -config monac.cnf Using configuration from monac.cnf Enter pass phrase for /home/ac/private/cakey.pem: Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: May 17 20:40:23 2017 GMT Not After : May 17 20:40:23 2020 GMT Subject: commonName = domperso.fr X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: AC:1E:49:A5:DF:AB:C3:93:F2:FD:90:0D:B8:68:1D:6B:F5:65:8D:BC X509v3 Authority Key Identifier: DirName:/CN=A la maison/emailAddress=marc@alamaison.com serial:DA:BB:D5:B1:11:4C:F4:75 Certificate is to be certified until May 17 20:40:23 2020 GMT (1096 days) Sign the certificate? [y/n]:Y 1 out of 1 certificate requests certified, commit? [y/n]Y Write out database with 1 new entries Data Base Updated
Copions le nouveau certificat dans /etc/apache2/keys de notre reverse proxy.
Configuration TLS/SSL
Dans /etc/apache2/sites-enabled activons la configuration ssl par défaut
root@deby:/etc/apache2/sites-enabled# ln -s ../sites-available/default-ssl.conf 001-ssl.conf
Éditons ce fichier pour référencer notre clé et notre certificat. La directive SSLCertificateFile pointe vers le certificat du serveur et SSLCertificateKeyFile vers la clé privée. Commentons les directives existantes et ajoutons les nôtres.
#Modif MF : ma clé à moi #SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key SSLCertificateFile /etc/apache2/keys/servercert.pem SSLCertificateKeyFile /etc/apache2/keys/serverkey.pem
A ce stade le serveur doit fonctionner en https sans contrôle d’accès. Redémarrons le et testons.
root@deby:/etc/apache2/sites-enabled# apachectl restart
Entrons l’adresse http://domperso.fr, nous devrions être redirigés vers https. (pour ma démo, mon serveur s’appelle deby.home).
Si cela ne fonctionne pas, jetons un oeil dans /var/log/apache2/error.log.
Configuration authentification
Dans /etc/apache2/sites-enabled/001-ssl.conf ajoutons nos directives dans la section <VirtualHost>
SSLCACertificatePath /etc/apache2/myclientsCA SSLUserName SSL_CLIENT_S_DN_CN SSLVerifyClient optional <Location /> Require ssl-verify-client AuthGroupFile /etc/apache2/my-auth-conf/cert-groupe Require group groupe-defaut </Location> IncludeOptional /etc/apache2/my-dir/*.conf
Je propose de mettre ces trois directives dans une section <location> afin de pouvoir afiner les droits d’accès pour nos différents serveurs web internes que nous allons déclarer dans /etc/apache2/my-dir
edit – 5 Août 2019 : après montée de version vers buster « SSLVerifyClient require » dans un scope Location provoque des erreurs de négociation TLS. En positionnant SSLVerifyClient Optional dans le scope du virtual host et Require ssl-verify-client dans celui de Location : cela fonctionne.
Pour référencer l’autorité de certification créons le répertoire /etc/apache2/myclientsCA et copions l’autorité de certification cacert.pem dans celui-ci. Puis créons le lien « hash » calculé avec un commande openssl. Nous concaténons l’indice ‘.0’ à celui-ci. Comme ceci :
root@deby:/etc/apache2/myclientsCA# openssl x509 -noout -in cacert.pem -hash 7fd27545 root@deby:/etc/apache2/myclientsCA# ln -s cacert.pem 7fd27545.0
Pour les besoins de la démo j’ai créé trois certificats : Mon premier utilisateur, Power user et no-user. Tous les trois importés dans un navigateur.
Créons le répertoire /etc/apache2/my-auth-conf et le fichier cert-groupe avec le contenu suivant :
groupe-defaut : "Power user" \ "Mon premier utilisateur"
Puis créons le répertoire /etc/apache2/my-dir.
Relançons le serveur par apachectl restart. Normalement, deux de nos trois utilisateurs ont accès à la racine du serveur. Effectuez vos tests avec des fenêtres de navigation privée ou incognito.
Configurons notre reverse proxy
Un premier accès avec un groupe différent
Dans /etc/apache/my-dir créons un fichier lamp.conf avec le contenu suivant :
RedirectMatch "^/lampe$" "lampe" <Location "/lampe/" > AuthGroupFile /etc/apache2/my-auth-conf/cert-groupe Require group groupe-lampe ProxyPass "http://terrasse.home/" </Location>
Attention : le slash à la fin des l’URI ou répertoire sont importantes.
Éditons le fichier cert-groupe avec le contenu suivant :
groupe-defaut : "Power user" \ "Mon premier utilisateur" groupe-lampe : "Power user" \ no-user
Redémarrons le serveur et effectuons de nouveaux tests vers http://domperso.fr/lampe. Nous constatons que seuls deux utilisateurs ont accès.
Un second accès sans authentification
Dans /etc/apache/my-dir créons un second fichier anon.conf avec le contenu suivant :
RedirectMatch "^/anon$" "/anon/" <Location "/anon/" > ProxyPass "http://terrasse.home/" SSLVerifyClient none Require all granted </Location>
Redémarrons le serveur apache, aucune authentification n’est alors requise pour accéder à http://domperso.fr/anon.
Voilà, vous avez un mandataire inverse avec une authentification fiable et sans mot de passe. Ici nous avons utiliser beaucoup de paramètres par défaut d’Apache. Il est tout à fait possible de durcir la configuration. Je ne juge pas cela nécessaire dans le cadre d’un usage domestique.
Bonjour et merci pour cet article,
En complément de celui-ci je vous conseille cet article : https://www.proxyvpn.fr/reverse-proxy
Merci, cela généralise mon propos.