Synchroniser un certificat SSL avec reverse proxy et serveur IIS

Dans la continuation de mes articles sur Let’s Encrypt, voici un petit article permettant de résoudre un problème qui se pose lors de l’utilisation d’un reverse proxy.

Soit la situation suivante :

  • un serveur applicatif HTTPS utilisant le magasin de certificat de Windows, accédé en direct par les postes de travail internes
  • un reverse proxy HTTPS permettant d’accéder à ce serveur applicatif depuis Internet

On se retrouve alors avec potentiellement 2 serveurs HTTPS distinct donc deux certificats distincts. On pourrait les aligner, mais les certificats Let’s Encrypt ayant une durée de vie de 3 mois, la surcharge induite pour effectuer ce travail manuellement commence à peser, à moins d’automatiser cette opération avec un simple script.

Initialisation

La première fois est manuelle, et consiste à charger le certificat avec sa clé privée, donc obligatoirement sous forme PFX, depuis le reverse proxy vers le serveur applicatif. Cela va servir à charger la clé privée au niveau du serveur applicatif, opération qui ne sera pas faite ultérieurement, et donc simplifie la maintenance d’un point de vue de la sécurité. En effet il suffira par la suite de récupérer uniquement le certificat, donc la partie publique, ce qui se fait simplement en faisant une requête HTTPS au reverse proxy.

Récursion Répétition

Comme dit au premier paragraphe, la clé privée ne change pas, seul le certificat est renouvelé régulièrement auprès de Let’s Encrypt. Le script va donc :

  1. Effectuer une requête HTTPS au reverse proxy, en spécifiant l’hôte permettant de sélectionner le bon site (via l’extension SNI)
  2. La réponse, quelque soit le résultat HTTP (200, 404, 401…) contient le certificat, qu’on importe dans le magasin de certificat
  3. Le magasin de certificat contient la clé privée, ajouté précédemment, et un certificat sans clé privée mais dont la clé publique correspond à la clé privée. On va exécuter un programme qui va permettre de réassocier ces deux éléments
  4. La dernière étape consiste à reconfigurer IIS pour utiliser le nouveau certificat.

C’est l’objectif du script ci-dessous qui pourra être exécuté de manière périodique via le planificateur de tâches.

# url permettant d'atteindre le reverse proxy
# depuis le serveur applicatif
$address = 'https://rp-out.kveer.fr'
# nom d'hôte à envoyer au reverse proxy pour sélectionner le bon site
$headerHost = 'tfs.dev.kveer.fr'
# nom du site IIS devant utiliser le certificat
$site = 'Team Foundation Server'

$CertStore = 'cert:\LocalMachine\WebHosting'
Import-Module WebAdministration
$tmp = "$env:TEMP\_cert_import_" + (Get-Random) + ".crt"

$wr = [Net.WebRequest]::CreateHttp($address)
$wr.Host=$headerHost
$wr.AllowAutoRedirect=$false
try { $wr.GetResponse() } catch {}
$cert = $wr.ServicePoint.Certificate
$bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
Set-Content -Value $bytes -Encoding Byte -Path $tmp
$c = Import-Certificate -CertStoreLocation $CertStore -FilePath $tmp
certutil -repairstore WebHosting $c.SerialNumber
Remove-Item $tmp

$currentSSLBinding = Get-Item IIS:\SslBindings\* | Where-Object { $_.Port -eq 443 -and $_.Sites -eq $site }
$currentSSLBindingName = $currentSSLBinding.PSChildName

$currentSSLBinding | Remove-Item
Get-Item -Path "$CertStore\$($c.Thumbprint)" | New-Item -Path IIS:\SslBindings\$currentSSLBindingName

Enjoy !