Home Assistant et Safari

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.

Laisser un commentaire

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