Reverse proxy pour la maison

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.

Schéma reverse proxy

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).

un premier test

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.

2 réponses sur “Reverse proxy pour la maison”

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *