Azure web app "ERR: Cert with thumbprint: ...' not found in local machine cert store." - azure

I'm trying to use an Apple push certificate in an Asp.NET Core 1.1 app but it cannot find any certificates.
I uploaded the cert and set WEBSITE_LOAD_CERTIFICATES to *(all).
The following code is what I use to get the certificate
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (signingCert.Count == 0)
{
throw new FileNotFoundException(string.Format("Cert with thumbprint: '{0}' not found in local machine cert store.", thumbprint));
}
return signingCert[0];
}
What am I missing?

It seems that you'd like to upload your certificate to the certificates collection in Azure Websites and consume it in your web application from your site’s personal certificate store. I'm upload my certificate and use the following code to consume it in Asp.NET Core 1.1 app, the code works for me.
X509Certificate2 retVal = null;
var thumbprint = "{cert_thumbprint}";
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (signingCert.Count > 0)
{
retVal = signingCert[0];
}
Remote debug the code and the code works fine on azure website

Related

IIS https hosting - to get mmc installed certificate by code

I got success in checking cert is present in my current user by local execution process. But when I publish the same code on IIS, I am unable to get a certificate.
Please guide changes in code or settings for code publish on IIS.
using System;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
string certThumbprint = "E661583E8FABEF4C0BEF694CBC41C28FB81CD870";
bool validOnly = false;
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
// Replace below with your certificate's thumbprint
certThumbprint,
validOnly);
// Get the first cert with the thumbprint
X509Certificate2 cert = certCollection.OfType<X509Certificate>().FirstOrDefault();
if (cert is null)
throw new Exception($"Certificate with thumbprint {certThumbprint} was not found");
// Use certificate
Console.WriteLine(cert.FriendlyName);
// Consider to call Dispose() on the certificate after it's being used, available in .NET 4.6 and later
}

Azure app services does it have a certificate store?

I have a project that communicates with a client server, the client server sends a self-signed certificate and I should trust him in order the continue the connection.
private bool VerifyServerCertificate(LdapConnection ldapConnection, X509Certificate certificate)
{
foreach (var cert in CertificateFileNames)
{
var certPath = Directory.GetFiles($#"{AppDomain.CurrentDomain.BaseDirectory}", $"{cert}",System.IO.SearchOption.AllDirectories);
X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.CurrentUser);
try
{
if (File.Exists(certPath.FirstOrDefault()))
{
var certToAdd = new X509Certificate2(X509Certificate.CreateFromCertFile(certPath.FirstOrDefault()));
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, certToAdd.SubjectName.Name, true);
if (certs.Count.Equals(0))
{
store.Open(OpenFlags.ReadWrite);
store.Add(new X509Certificate2(X509Certificate.CreateFromCertFile(cert)));
store.Close();
}
}
}
catch
{
throw new Exception("Cannot install the certificate.");
}
}
X509Certificate2 certificate2 = new X509Certificate2(certificate);
return certificate2.Verify();
}
This works fine but the project needs to be deployed as a Azure app service. So my question is, the app service environment does it have a "Trusted People" storage ?
The method receives de X509certificate from the connection and verify against the trusted people storage so I need to install the certificates before the validation.
Thanks.

Programmatically getting the list of azure virtual machine sizes

I am new to Azure management libraries for .net. How can we enumerate VM instance sizes available with respect to subscription or in general using Azure Management libraries for .Net or Rest APIs?
Please suggest.
You can get a list of VM sizes for a region by calling
https://management.azure.com/subscriptions/{subscription-id}/providers/Microsoft.Compute/locations/{location}/vmSizes?api-version={api-version}
As documented here - List all available virtual machine sizes in a region
There is also a .Net Class for the same, but I've not found any examples of it being used - documented here - VirtualMachineSizeOperationsExtensions.List
You can get list of VM sizes by region fillter
AuthenticationContext authenticationContext = new AuthenticationContext("https://login.windows.net/tenantdomainname.onmicrosoft.com"]);
UserCredential uc = new UserCredential(authusername,authpassword);
token = authenticationContext.AcquireToken("https://management.core.windows.net/", nativetenantid, uc);
var credentials = new TokenCredentials(token);
var computeClient = new ComputeManagementClient(credentials) { SubscriptionId = subscriptionid};
var virtualMachineSize = computeClient.VirtualMachineSizes.List(region_name).ToList();
you must need create one native client api on Azure Active Directory for token base authentication otherwise you can also use certification base authentication for client authorization.
i am using Microsoft.Azure.Management.Compute.dll, v10.0.0.0 for compute resources.
you can download here: https://www.nuget.org/packages/Microsoft.Azure.Management.Compute/13.0.4-prerelease
You can get list of VM Size by using Certificate Base Authentication
Get Certificate method
private static X509Certificate2 GetStoreCertificate(string subscriptionId, string thumbprint)
{
List<StoreLocation> locations = new List<StoreLocation>
{
StoreLocation.CurrentUser,
StoreLocation.LocalMachine
};
foreach (var location in locations)
{
X509Store store = new X509Store(StoreName.My, location);
try
{
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certificates = store.Certificates.Find(
X509FindType.FindByThumbprint, thumbprint, false);
if (certificates.Count == 1)
{
return certificates[0];
}
}
finally
{
store.Close();
}
}
throw new ArgumentException(string.Format("A Certificate with Thumbprint '{0}' could not be located.",thumbprint));
}
here i describe same way to get VM size
private static X509Certificate2 Certificate = GetStoreCertificate(Your-subscriptionid,Your-thumbprint);
Microsoft.Azure.CertificateCloudCredentials credentials = new Microsoft.Azure.CertificateCloudCredentials(Your-subscriptionid, Certificate);
var computeClient = new ComputeManagementClient(credentials) { SubscriptionId = Your-subscriptionid};
var virtualMachineSize = computeClient.VirtualMachineSizes.List(Your-region_name).ToList();

Add PFX Certificate to Azure WebApp using ARM (not for ssl)

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?
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);

Creating Azure Traffic Manager through REST API - unexpected behaviour

I created Traffic Manager throught its REST API using 2011-10-01 MS verion.
Resources I followed -
Create Profile -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758254.aspx
Create Definition -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758257.aspx
Traffic Manager got created successfully. All happies.
But after 30mins of time, traffic manager is going to INACTIVE status and all its endpoints are GONE. It shows there are no endpoints associated with it.
I am not sure what is happening around. Is it Azure problem? or is it REST API problem? or is it my way of creating Traffic manager problem.
PS - I followed this sample for making REST API calls - http://msdn.microsoft.com/en-us/library/windowsazure/gg651127.aspx
Any help would be highly appreciated.
UPDATE1
Parameters
SubscriptionID - a Valid GUID from publishsettings
Certificate - I cross checked a valid certificate present in the local cert store
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name - JASH23.CLOUDAPP.NET
There is no error at REST API calls level. Everything worked seamlessly.
Profile Creation -
// X.509 certificate variables.
X509Store certStore = null;
X509Certificate2Collection certCollection = null;
X509Certificate2 certificate = null;
// Request and response variables.
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
// Stream variables.
Stream responseStream = null;
StreamReader reader = null;
// URI variable.
Uri requestUri = null;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// Open the certificate store for the current user.
certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbPrint,
false);
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (0 == certCollection.Count)
{
throw new Exception("No certificate found containing thumbprint " + thumbPrint);
}
// A matching certificate was found.
certificate = certCollection[0];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Profile xmlns=""http://schemas.microsoft.com/windowsazure""><DomainName>" + ProfileDomain + "</DomainName><Name>" + ProfileName + "</Name></Profile>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
Definition Creation-
// X.509 certificate variables.
X509Store certStore = null;
X509Certificate2Collection certCollection = null;
X509Certificate2 certificate = null;
// Request and response variables.
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
// Stream variables.
Stream responseStream = null;
StreamReader reader = null;
// URI variable.
Uri requestUri = null;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// Open the certificate store for the current user.
certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbPrint,
false);
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (0 == certCollection.Count)
{
throw new Exception("No certificate found containing thumbprint " + thumbPrint);
}
// A matching certificate was found.
certificate = certCollection[0];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles/" + ProfileName + "/definitions");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Definition xmlns=""http://schemas.microsoft.com/windowsazure""><DnsOptions><TimeToLiveInSeconds>300</TimeToLiveInSeconds></DnsOptions><Monitors><Monitor><IntervalInSeconds>30</IntervalInSeconds><TimeoutInSeconds>10</TimeoutInSeconds><ToleratedNumberOfFailures>3</ToleratedNumberOfFailures><Protocol>HTTP</Protocol><Port>80</Port><HttpOptions><Verb>GET</Verb><RelativePath>/</RelativePath><ExpectedStatusCode>200</ExpectedStatusCode></HttpOptions></Monitor></Monitors><Policy><LoadBalancingMethod>RoundRobin</LoadBalancingMethod><Endpoints><Endpoint><DomainName>" + PrimaryService + "</DomainName><Status>Enabled</Status></Endpoint><Endpoint><DomainName>" + SecondaryService + "</DomainName><Status>Enabled</Status></Endpoint></Endpoints></Policy></Definition>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
UPDATE2
Once the TM went into Inactive State, I checked the profile definition using REST API. In there I was not able to find any endpoints. They are missing.
<Definitions xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Definition>
<DnsOptions>
<TimeToLiveInSeconds>300</TimeToLiveInSeconds>
</DnsOptions>
<Status>Enabled</Status>
<Version>1</Version>
<Monitors>
<Monitor>
<IntervalInSeconds>30</IntervalInSeconds>
<TimeoutInSeconds>10</TimeoutInSeconds>
<ToleratedNumberOfFailures>3</ToleratedNumberOfFailures>
<Protocol>HTTP</Protocol>
<Port>80</Port>
<HttpOptions>
<Verb>GET</Verb>
<RelativePath>/</RelativePath>
<ExpectedStatusCode>200</ExpectedStatusCode>
</HttpOptions>
</Monitor>
</Monitors>
<Policy>
<LoadBalancingMethod>Performance</LoadBalancingMethod>
<Endpoints/>
<MonitorStatus>Inactive</MonitorStatus>
</Policy>
</Definition>
</Definitions>
UPDATE3
This sporadic behavior is ONLY happening with the specific cloud services and TM profile/definitiona. When I create new set of cloud services and TM profile, then everything seems to be working fine. I tested this multiple times. So the only problem is with following parameters.
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name -JASH23.CLOUDAPP.NET
TM Domain - ramitm.trafficmanager.net
TM profilename - ramitm
This seems like some DNS Problems for very fast REST API Operations. I was not able to get the crux of the problem, but this is how I solved it.
Previously I was getting this problem for this patter - Create -> Delete -> Re-Create
Now I made it this way - Create -> Delete -> Delay -> Re-Create
I think by introducing delay component, I am giving enough time for Azure to settle down all the DNS and infrastructure and there by update them. So after introducing delay, I was not experiencing the problem. Delay can be 5 - 10 mins.

Resources