Showing posts with label IIS. Show all posts
Showing posts with label IIS. Show all posts

Thursday, 25 January 2018

Reverse Proxying Kestrel with URL Rewrite for IIS

As said in previous posts, we have been developing new services using Asp.net Core and self-hosting as Windows services using Kestrel. A new interesting problem arised, as Kestrel can not share the Http/Https port with IIS or Owin self hosted services we had to use a different port to host each service. In he past we had this problem when hosting APIs with f# suave, and had overcome it redirecting the requests in the F5 Big Ip load balancer. That solution works, but sometimes I feel like it crosses in to the domain of infrastructure instead of development. So in order to contain all the deployment and configuration in TeamCity/Octopus, I decided to use IIS to reverse proxy the calls made to these microservices as explained in: https://weblogs.asp.net/owscott/creating-a-reverse-proxy-with-url-rewrite-for-iis
Basically requests coming to http://+/newmicroserviceapi/ will be rewritten to http://localhost:<microserviceport>/
This is the Octopus Deploy step I created to automate all this:

PowerShell Script:
$siteName = $OctopusParameters['ReverseProxy.IISSiteName']
$pathBase = $OctopusParameters['ReverseProxy.PathBase']
$port = [int] $OctopusParameters['ReverseProxy.Port']
$site = "iis:\sites\$siteName"
$filterName="Reverse proxy inbound $pathBase"
$filterPath = "system.webServer/rewrite/rules/rule[@name='$filterName']"
Write-Host 'Adding reverse proxy rule to '$siteName' for '$pathBase'/*'
Clear-WebConfiguration -pspath $site -filter $filterPath
Add-WebConfigurationProperty -pspath $site -filter "system.webServer/rewrite/rules" -name "." -value @{name=$filterName; patternSyntax='Regular Expressions'; stopProcessing='True';}
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/match" -name "url" -value "$pathBase/(.*)"
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/conditions" -name "logicalGrouping" -value "MatchAny"
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/action" -name "type" -value "Rewrite"
Set-WebConfigurationProperty -pspath $site -filter "$filterPath/action" -name "url" -value "http://localhost:$port/{R:1}"


Octopus Step:




Note that the Application Request Routing IIS pluging is needed.

Tuesday, 19 December 2017

IIS and certificates

The other day the last "pure" DevOps engineer in our team left the company, so what is left of the team is filling that role.
One of the tasks that was left pending was to use SSL termination instead of having the certificates installed in each server, and surprise, surprise, the expiration date of the active certificate is within a week of writing this post.
So instead of addressing this issue properly, we decided to just add the new certificate. For that I created an Octopus Deploy project that simply runs the following powershell script:

$base64Certificate = $OctopusParameters['Base64Certificate']
$password = $OctopusParameters['Password']
Write-Host "Adding/updating certificate in store"
$certBytes = [System.Convert]::FromBase64String($base64Certificate)
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certBytes, $password, "Exportable,PersistKeySet,MachineKeySet")
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My", "LocalMachine")
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()

I had worked previously with certificates to sign and validate requests in webservices, and we simply referred to the certificate using distinct properties but not the certificate thumbprint, as that would force configuration to be updated when the certificate expires. That is why I was surprised of not finding a way to do the same in IIS, originally, the only way I found to bind the SSL port to a certificate was to specify the thumbprint. So I added the following step using netsh (https://msdn.microsoft.com/en-us/library/windows/desktop/cc307236(v=vs.85).aspx).

$port = [int] $OctopusParameters['Port']
$certThumbprint = $OctopusParameters['CertThumbprint']
$output = netsh http show sslcert ipport=0.0.0.0:$port | Out-String
Write-Host "Previous configuration: $output"
Write-Host "Remove ssl certificate port binding"
$output = netsh http delete sslcert ipport=0.0.0.0:$port | Out-String
if(($output -like "*Error*") -and ($output -notlike "*Error: 183*"))
{
    exit 1
}
Write-Host "Ensuring ssl certificate port binding"
$guid = [guid]::NewGuid()
$guidStr = "{$guid}"
$output = netsh http add sslcert ipport=0.0.0.0:$port certhash=$certThumbprint appid=$guidStr | Out-String
Write-Host $output
if(($output -like "*Error*") -and ($output -notlike "*Error: 183*"))
{
    exit 1
}
$output = netsh http show sslcert ipport=0.0.0.0:$port | Out-String
Write-Host "New configuration: $output"
exit 0

Later I found that IIS provides an option to automatically rebind renewed certificates, but I didn't went for that option as it would mean enabling it and wait for the expiration date to trigger the switch over without having seen it working beforehand. Instead, I have set up one of the lower environment boxes to use this method.