2

Using Rest Management APIS that are backed by Azure Resource Manager the following code adds a certificate from keyvault to ARM.

var secret = keyvaultClient.GetSecretAsync(vaultUri, options.CertificateName).GetAwaiter().GetResult();

var certUploaded = client.Certificates.CreateOrUpdateCertificateWithHttpMessagesAsync(
    options.ResourceGroupName, options.CertificateName,
    new Certificate {
        PfxBlob = secret.Value,
        Location = app.Body.Location
    }).GetAwaiter().GetResult();

var appSettings = client.Sites.ListSiteAppSettingsWithHttpMessagesAsync(options.ResourceGroupName, options.WebAppName).GetAwaiter().GetResult();
var existing = (appSettings.Body.Properties["WEBSITE_LOAD_CERTIFICATES"] ?? "").Split(',').ToList();
if (!existing.Contains(certUploaded.Body.Thumbprint))
    existing.Add(certUploaded.Body.Thumbprint);

appSettings.Body.Properties["WEBSITE_LOAD_CERTIFICATES"] = string.Join(",",existing);
appSettings.Body.Properties[$"CN_{options.CertificateName}"] = certUploaded.Body.Thumbprint;

var result = client.Sites.UpdateSiteAppSettingsWithHttpMessagesAsync(options.ResourceGroupName, options.WebAppName, appSettings.Body).GetAwaiter().GetResult();

the problem is that when loading it in the webapp

        X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        certStore.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certCollection = certStore.Certificates.Find(
                                   X509FindType.FindByThumbprint,
                             // Replace below with your cert's thumbprint
                             "0CE28C6246317AEB00B88C88934700865C71CBE0",
                                   false);

        Trace.TraceError($"{certCollection.Count}");
        Console.WriteLine($"{certCollection.Count}");
        // Get the first cert with the thumbprint
        if (certCollection.Count > 0)
        {
            X509Certificate2 cert = certCollection[0];
            // Use certificate
            Console.WriteLine(cert.FriendlyName);
        }
        certStore.Close();

it is not loaded.

If I instead upload it using the portal, everything works as expected. enter image description here

I also noticed that the certificates uploaded in the portal do not exist in ARM, only the certs added with the code in the start of the post exists.: enter image description here

So what do we need to do to make a certificate available to webapp that do not involve manual uploading to portal?

Poul K. Sørensen
  • 16,950
  • 21
  • 126
  • 283
  • I have had a similar problem lately - see [How to add a certificate to an Azure RM website with Powershell](http://stackoverflow.com/questions/34727287/how-to-add-a-certificate-to-an-azure-rm-website-with-powershell) (while I'm figuring your code out!) – Michael B Jan 20 '16 at 11:14
  • Did you get that code from elsewhere? The appsettings part 'feels' wrong to me (but I'm not sure how / why - So am likely completely wrong) – Michael B Jan 20 '16 at 11:32
  • I just hacked it together. Anyway, did you succed with teh Azure RM website powersell? Then I will just see how they did it – Poul K. Sørensen Jan 20 '16 at 11:40
  • I can see that its related to adding SSL. I am not adding SSL. I just need the certificate from the application to decrypt some values. – Poul K. Sørensen Jan 20 '16 at 11:41
  • I mostly hacked my answer to that from Resource Explorer, Resource Templates and the source of Azure Powershell. If you start with what a configured solution looks like in Resource Explorer, and then try to push that in with a snippet of template. I can't see there being a huge difference between adding an SSL cert and a normal one - but yes the answer I wrote on there works perfectly. – Michael B Jan 20 '16 at 11:47
  • The difference is that it works fine for SSL, but when one do not make the SSL binding azure website is not loading the certificate. – Poul K. Sørensen Jan 20 '16 at 11:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101183/discussion-between-michael-b-and-pksorensen). – Michael B Jan 20 '16 at 11:50

1 Answers1

4

The problem was that the certificates should be added to the resource group of the serverfarm that the webapp is hosted within and not the resourcegroup of the webapp.

Changing the code to deploy to the correct resourcegroup solved everything.

For reference my updated code is here:

var vaultUri = $"https://{options.VaultName}.vault.azure.net";
var keyvaultClient = new KeyVaultClient((_, b, c) => Task.FromResult(options.VaultAccessToken));

using (var client = new WebSiteManagementClient(
    new TokenCredentials(cred.AccessToken)))
{
    client.SubscriptionId = cred.SubscriptionId;

    var app = client.Sites.GetSite(options.ResourceGroupName, options.WebAppName);
    var serverFarmRG = Regex.Match(app.ServerFarmId, "resourceGroups/(.*?)/").Groups[1];

    var secret = keyvaultClient.GetSecretAsync(vaultUri, options.CertificateName).GetAwaiter().GetResult();

    var certUploaded = client.Certificates.CreateOrUpdateCertificate(
        serverFarmRG.Value, options.CertificateName,
        new Certificate
        {
            PfxBlob = secret.Value,
            Location = app.Location
        });

    var appSettings = client.Sites.ListSiteAppSettings(options.ResourceGroupName, options.WebAppName);
    appSettings.Properties["WEBSITE_LOAD_CERTIFICATES"] = string.Join(",", client.Certificates.GetCertificates(serverFarmRG.Value).Value.Select(k => k.Thumbprint));
    appSettings.Properties[$"CN_{options.CertificateName}"] = certUploaded.Thumbprint;

    var result = client.Sites.UpdateSiteAppSettings(options.ResourceGroupName, options.WebAppName, appSettings);
Poul K. Sørensen
  • 16,950
  • 21
  • 126
  • 283