Reputation: 17530
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.
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.:
So what do we need to do to make a certificate available to webapp that do not involve manual uploading to portal?
Upvotes: 2
Views: 1872
Reputation: 17530
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);
Upvotes: 4