8
votes

Our situation is that we expect to be frequently adding new custom sub-domains to a number of Azure Websites and we need to be able to automate the process so we can minimize any need for manual intervention and the risk of screwing something up.

The Azure Cross-Platform CLI tools and PowerShell cmdlets provide enough functionality for me to script it all out, with the apparent exception of the SSL bindings... The websites are all HTTPS-only, and every domain that we add requires an SNI SSL binding.

The Azure management portals allow you to manually configure the SSL bindings for a website's domains. How can I achieve the same using the PowerShell cmdlets or the cross-platform CLI tools? If it's not possible using either of those tools, is there some other way I can script out the process for when we add/remove domains to the sites?

2

2 Answers

7
votes

I've finally managed to successfully do this by using the Azure Web Sites Management REST API.

The original documentation which I based my example code below on back in 2014 is no longer available, but the Azure Resource Explorer which Zain mentioned and linked to a blog post about in the comments is in my opinion a superior resource. Direct link: https://resources.azure.com/

The Service Management REST API Reference appears to be the closest thing to the original documentation I used but presently lacks anything specifically about Azure Web Apps (previously known as Azure Websites): https://msdn.microsoft.com/library/azure/ee460799.aspx

E.g.:

using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

private const string managementThumbprint = "0000000000000000000000000000000000000000";
private const string subscriptionId = "00000000-0000-0000-0000-000000000000";

private const string sslThumbprint = "0000000000000000000000000000000000000000";
private const string webspace = "eastasiawebspace";
private const string websiteName = "myWebsite";
private const string websiteDomain = "myDomain";
private const SslState sslState = SslState.SniEnabled;

public async Task SetSslState()
{
    //Retrieve management certificate
    var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadOnly);
    var certificate = store.Certificates.Cast<X509Certificate2>().First(xc => xc.Thumbprint.Equals(managementThumbprint, StringComparison.OrdinalIgnoreCase));

    //Setup http client
    var handler = new WebRequestHandler();
    handler.ClientCertificates.Add(certificate);
    var client = new HttpClient(handler) {
        BaseAddress = new Uri("https://management.core.windows.net/" + subscriptionId + "/services/WebSpaces/")
    };
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Add("x-ms-version", "2014-06-01");

    var requestData = new {
        HostNameSslStates = new[] {
            new {
                Name = websiteDomain,
                SslState = (long)sslState,
                Thumbprint = sslThumbprint,
                ToUpdate = true
            }
        }
    };
    var response = await client.PutAsJsonAsync(webspace + "/sites/" + websiteName, requestData);
}

public enum SslState
{
    Disabled = 0,
    SniEnabled = 1,
    IpBasedEnabled = 2
}
4
votes

This action is now possible using the Azure Resource Manager mode of the Azure Powershell library. This also assumes the chosen certficate is already available within Azure, I already had the certificate in use on other websites, so didn't need to upload it before adding it to a new site.

First, set the library to use the Azure Resource Manager mode. This article contains a good introduction to what this mode provides.

Switch-AzureMode -Name AzureResourceManager
Add-AzureAccount
Select-AzureSubscription -SubscriptionId $subscriptionId

The following variables are used in the code below:

$apiVersion = "2015-08-01"
$subscriptionId = "" #The ID of your Azure subscription
$siteName = "myWebApp"
$resGroup = "myResourceGroup"
$appServicePlan = "myAppServicePlan"
$location = "East US" #Select the appropriate Azure data centre.
$hostName = "mywebapp.mydomain.com"
$sslThumbprint = "" # Thumbprint of SSL certificate uploaded for use in Azure.

Once the correct mode is selected, the following code block will retrieve the current site info. The new SSL info can then be added into a new object which can be added onto the end of the current HostNameSslStates array.

Finally, this can be pushed back into Azure with the Set-AzureResource cmdlet.

# Add SSL binding to custom domain
$r = Get-AzureResource -Name $siteName -ResourceGroupName $resGroup -ResourceType Microsoft.Web/sites -ApiVersion $apiVersion -OutputObjectFormat New
# Create an object containing the desired new SSL configuration
$newSSL = @(
    @{
        "Name" = $hostName;
        "SslState" = 1;
        "Thumbprint" = $sslThumbprint;
        "ToUpdate" = $true;
    }
)
# Create an object which concatenates the existing SSL config with the new config object.
$ssl = @{
    "HostNameSslStates" = $r.Properties.HostNameSslStates + $newSSL
}
# Upload the new configuration into the web app.
Set-AzureResource -ApiVersion $apiVersion -Name $siteName -ResourceGroupName $resGroup -ResourceType Microsoft.Web/sites -PropertyObject $ssl -OutputObjectFormat New