Safari (sous iOS 12) ne supporte pas l’authentification mutuelle par certificat sur websocket, un cookie et des scripts LUA le générant, vont nous permettre de contourner de manière sure cette limitation.
Quoi de plus solide qu’une authentification par certificat client ? Si dans la configuration de reverse proxy Apache proposée pour Home assistant nous procédons comme dans l’article reverse proxy pour la maison, cela fonctionne très bien pour Firefox sur PC, mais pas sur Safari pour iOS. Ce dernier ne supporte pas l’authentification par certificat sur Websocket. Nous allons alors mettre en place un micro serveur d’authentification qui va fournir un cookie signé. Ce cookie sera contrôle à chaque requête pour le reverse proxy.
La mécanique générale
Le cookie contient une date d’expiration et un pseudo HMAC de celle-ci. Le pseudo HMAC est obtenu en calculant le condensat SHA1 de la date concaténée à une clé secrète : SHA1(Date & Clé). Un site (virtual host) n’est là que pour délivrer ce cookie, après authentification par certificat, le reverse proxy à chaque requête contrôlera celui-ci.
Deux Scripts LUA
Cette mécanique n’est pas disponible en standard dans Apache. Un script LUA (source ici) implémente les deux fonctions nécessaires.
Les variables
Je ne suis pas arrivé à passer des variables aux scripts lors de l’appel. Du coup, elles sont positionnées en dur dans le fichier de configuration Apache par un » setEnv » et récupérées dans les scripts par la fonction lua « r.subprocess_env[‘nom_variable’] ». Ces six variables étant communes aux deux « virtual hosts », il est préférable de les positionner dans un fichier à part qui sera chargé dans un « include » dans chaque « virtual host ».
setEnv AUTH_SECRET BigSecretAmoiQueJeNeDoisPasDivulguer setEnv AUTH_NOM_COOKIE CookieHauteSecurite setEnv AUTH_URL_RETOUR_AUTH https://ha.example.tld/ setEnv AUTH_DUREE_VALIDE 3600 setEnv AUTH_DOMAIN ha.example.tld setEnv AUTH_URL_AUTH https://auth.ha.example.tld/
- SECRET : la clé du pseudo HMAC
- NOM_COOKIE : le nom du cookie
- AUTH_URL_RETOUR_AUTH : l’URL du reverse proxy
- AUTH_DUREE_VALIDE : la durée de validité du cookie en seconde
- AUTH_DOMAIN : le domaine du cookie
- AUTH_URL_AUTH : l’URL du mini site d’authentification.
Le mini site d’authentification doit être un sous-domaine du reverse proxy et AUTH_DOMAIN doit être le FQDN du reverse proxy, afin que le cookie soit correctement transmis.
creerCookie
Cette fonction crée le cookie et renvoie l’utilisateur sur le reverse proxy par une redirection 302. S’il manque une variable, elle renvoie une erreur 500.
verifCookie
Cette fonction renvoie :
- une redirection 302 vers le site d’authentification ( AUTH_URL_AUTH ) si la vérification échoue,
- une erreur 500 si une variable est manquante,
- laisse passer la requête si la vérification est correcte.
La vérification du cookie consiste en :
- présence du cookie,
- format du cookie, (expiration:hash)
- non expiré,
- calcul du hash en fonction de l’expiration égal à celui du cookie.
Intégration dans Apache
Vous devez générer deux certificats ‘ha.example.tld’ et ‘auth.ha.example.tld’ comme décrit dans Une autorité de certification ou mini PKI
Le reverse proxy
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName ha.example.tld
ServerAdmin webmaster@localhost
DocumentRoot /var/www/ha-html
ErrorLog ${APACHE_LOG_DIR}/ha-error.log
CustomLog ${APACHE_LOG_DIR}/ha-access.log combined
SSLEngine on
SSLOpenSSLConfCmd MinProtocol TLSv1.2
SSLCertificateKeyFile /etc/apache2/my-certs/keys/ha.example.tld.pkey
SSLCertificateFile /etc/apache2/mycerts/ha.example.tld.cert
# le positionnement des variables d'environnements
# depuis un fichier qui contient les setEnv
Include sites-enabled/envvar.incl
# l'appel au script de verfication
LuaHookFixups /var/www/lua-scripts/auth.lua verifCookie
<Location "/">
ProxyPass http://hass.home:8123/
ProxyPassReverse http://hass.home:8123/
</Location>
<Location "/api/websocket" >
ProxyPass ws://hass.home:8123/api/websocket
ProxyPassReverse ws://hass.home:8123/api/websocket
</Location>
# là le niveau de log est élevé, remplacer notice par warn,
# une fois les tests faits.
LogLevel alert lua:notice
</VirtualHost>
</IfModule>
Le mini-site d’authentification
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName auth.ha.example.tld
ServerAdmin webmaster@localhost
DocumentRoot /var/www/ha-auth-docroot
ErrorLog ${APACHE_LOG_DIR}/ha-error.log
CustomLog ${APACHE_LOG_DIR}/ha-access.log combined
LogFormat "%h %t \"%{SSL_CLIENT_S_DN}x\" \"%u\"" dn-client
CustomLog ${APACHE_LOG_DIR}/dn-client.log dn-client
SSLEngine on
SSLOpenSSLConfCmd MinProtocol TLSv1.2
# on exige l'authentification par certification
# on peut mettre aussi SSLVerifyClient require
SSLOpenSSLConfCmd VerifyMode Require
SSLCertificateKeyFile /etc/apache2/my-certs/key/auth.ha.example.tld.pkey
SSLCertificateFile /etc/apache2/my-certs/auth.ha.example.tld.cert
# mon repertoire d'autorité de certification
# avec des liens symboliques générés par openssl x509 -noout -in <fichier-CA>.pem -hash
SSLCACertificatePath /etc/apache2/myclientsCA
SSLVerifyDepth 10
# le positionnement des variables d'environnements
# depuis un fichier qui contient les setEnv
Include sites-enabled/envvar.incl
# l'appel au script de création du cookie
LuaHookFixups /var/www/lua-scripts/auth.lua creerCookie
# un peu de contrôle d'accès
<Location />
SSLUserName SSL_CLIENT_S_DN_CN
LogMessage "RemoteUser:%{REMOTE_USER}- CN:%{SSL_CLIENT_S_DN_CN}-"
AuthGroupFile /etc/apache2/my-auth-conf/cert-groupe
Require group mon-groupe
</Location>
# là le niveau de log est élevé, remplacer notice par warn,
# une fois les tests faits.
LogLevel alert lua:notice
</VirtualHost>
</IfModule>
Le contrôle d’accès est décrit dans l’article reverse proxy. Il est nécessaire de charger quelques modules apache supplémentaires :
sudo a2enmod proxy_http proxy_wstunnel ssl
sudo a2enmod authz_groupfile
sudo a2enmod http2
sudo a2enmod lua
Bon normalement avec un sudo apachectl restart tout baigne. Vous pouvez ajouter des éléments de logs dans le script lua avec la fonction r:notice
. Cela écrit dans le fichier ha-error.log.