I have an Azure Worker Role that I wish to call the Management Service (e.g. REST API) and collect information regarding related services. However, when I try to load my certificate it fails to find it. Here are the steps I followed:
1. I created a certificate using MakeCert and registered it as my Management Certificate via the portal
makecert -r -pe -a sha1 -n "CN=MyCnName" -ss My -len 2048
-sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 MyCert.cer
2. Installed the cert on my local machine and everything works fine. When running the Worker Role locally I can call the Management Service with no problems.
3. Exported the cert from my machine and registered the exported certificate under the target Hosted Service via the portal
4. Deployed the Role. When the Role starts it fails to find the cert.
Here is an extract of the code I'm using to find the cert.
// Open the certificate store for the current user.
var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); // I also tried localmachine
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified subject.
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindBySubjectName,
_myConfiguration.SubjectName,
false);
if (certCollection == null || certCollection.Count < 1)
{
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
_myConfiguration.ThumbPrint,
false);
}
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (certCollection.Count == 0)
{
_logger.Warn("No certificate found");
}
There is no exception, just no cert is found. Can anyone shed some light I what I need to do?
Figured out the problem... In addition to configuring the cert in the portal, I needed to add the certificate details (e.g. Name, Store, and Thumbprint) to the Azure Project Role settings under the Certificates Tab.
I have a similar problem for a web role, i have applied a workaround.
Connect with remote desktop to the VM where the service and
certificate are deployed
List item
Copy your cert or pfx on your
VM local disk (e.g C:)
Click on your pfx or .cert file and
install it on the specific certificate store "Trusted People")
Run your service, even if you are configured for search on a different
store you will find on trusted people
I don't know why my web role try to find the cert on this location if I am forcing to search on "My Store" location but the search method retrieve info from trusted people store.
The problem with this workaround is when you delete your deployment the cert and any other configuration will be wiped.
This piece of code could give you some information:
//the certificate must be in the Trusted People Store
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
//Commented
//Get the first available match from cert store
//X509Certificate2 cert = store.Certificates.Find(X509FindType.FindBySubjectName,
// subjectname,
// false)
// .Cast<X509Certificate2>()
// .FirstOrDefault();
X509Certificate2 cert = new X509Certificate2();
foreach (var ct in store.Certificates)
{
//Logger.TraceInformation(string.Format("Cert found: Subject {0} Tumbprt:{1}", ct.FriendlyName, ct.Thumbprint));
if (ct.SubjectName.Name.ToString().Contains("*.certnamexx.extensionxx"))
{
return new X509SecurityToken(ct);
}
}
}
Related
I have an Azure app service I did not create but now maintain. The app service finds a certificate in a Key Vault by thumbprint and in turn uses that to get a token for doing some SQL work via nightly jobs.
It appears the certificate was set to auto renew after 80% of its valid date (12 months). The day the cert renewed my nightly jobs started to fail. I'm reasonably certain the new certificate is at the root of the problem.
As best I can tell it designed to work like this:
Job fires via Azure Logic App
annomyous POST to a reports processing API (end result should be .PDF report creation for email atachment)
API has Appsetting.json that contains the current certificates thumbprint
Thumbprint is used in the line of code below to find the certificate in the cert store
Cert is used to aquire access token and perform work
When I install both the old certificate and the new certificate on my local machine and run the entire process it works find with the old certificate and fails on this line with the new auto-generated certificate. It also fails with any new certificates I try to make in Azure and export from Azure and import to my dev machine. I've double/triple checked the appsettings to make sure the Thumbprint in question is correct and updated.
var signingCert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.Thumbprint == _appSettings.AzureAD.CertificateThumbprint);
When this was configured a year ago the process was to go into App Service, TLS/SSL setting blade, select Private Key Certificates (.pfx) and finally + Import Key Vault Certificate.
From there you selected the Key Vault and Certificate, then changed the Appsettings.Json to have the new Thumbprint.
Why will it work with the old (soon to expire) certificate and corresponding Thumbprint entry into appsettings but fails to work with any newly created certificates and corresponding correct Thumbprint entry?
I've looked at the Configuration for the App Service in question and it has the following setting when I understand is supposed to let the app service see all certificates registered to it, right?
WEBSITE_LOAD_CERTIFICATES = *
EDIT:
After some more testing I find that any cert I export form Azure and import on my computer will successfully iterate the cert store and find any Certificate I provide a valid Thumbprint. What it won't do is use that cert to obtain a access token. The complete code is below.
The certificate that is due to expire soon will get a proper access token and run the rest of the process by getting the proper data from the DB.
The exception I get with all the other certificates suggest something about base64 encoding but I can't quite figure that out. Any ideas?
Exception for all but the original certificate:
Client assertion contains an invalid signature
Successful Access token with this code only with original certificate:
private async Task<string> GetDatabaseTokenFromCert()
{
X509Certificate2 cert;
var store = new X509Store(StoreLocation.CurrentUser);
var authContext = new AuthenticationContext(_appSettings.AzureAD.AADInstance + _appSettings.AzureAD.TenantId);
try
{
store.Open(OpenFlags.ReadOnly);
var signingCert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.Thumbprint == _appSettings.AzureAD.CertificateThumbprint);
if (signingCert == null)
{
throw new FileNotFoundException("Cannot locate certificate for DB access!", _appSettings.AzureAD.CertificateThumbprint);
}
cert = signingCert;
}
finally
{
store.Close();
}
var certCred = new ClientAssertionCertificate(_appSettings.AzureAD.ClientId, cert);
var result = await Retry(() => authContext.AcquireTokenAsync(_appSettings.SqlConfig.ResourceId, certCred));
return result?.AccessToken;
}
Turns out you need to also add the new certificate to the app registration. As a .cer file without the private key, obviously.
So if you get the error message:
AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client: 'YourNewCert'
Go to Key Vault, export new cert as .cer file and import it into the App Service that is trying to obtain the Access token from AcquireTokenAsync
In my case the order of operation is:
Logic app fires off anonymous call as a POST to web API
Web API uses Thumbprint of Cert in question via appsetting.json
Finds cert with thumbprint that is in App Registration of the web API
AcquireTokenAsync takes Azure info and Cert and returns Access Token
This will work or fail on this line of original post
var result = await Retry(() => authContext.AcquireTokenAsync(_appSettings.SqlConfig.ResourceId, certCred));
I am working on Azure Functions App on Consumption Plan. The Func App required to load a specific signed certificate.
In local machine I setup the certificate as personal certificate and everything works fine.
After publishing on azure, I am getting this error:
There are 0 certificates with the subject name cert.name in LocalMachine, MyUse scripts/certificates/ to generate this
Nothing helpful on SO or even in Azure Func documentation on how to use certificate with azure functions.
Anyone has experience with that?
I got it and it's pretty straight forward.
First go to platform features under your Function App and you should find SSL as shown below.
Then you can add a public, private or SSL certificate based on your needs. In my case I want to add a private Certificate which i already exported and have it's private key.
After uploading your certificate, go to your app settings and add this key/value:
WEBSITE_LOAD_CERTIFICATES: "Your Cert Thumbprint"
You should be able to load the certificate using this Thumbprint like this:
using System;
using System.Security.Cryptography.X509Certificates;
...
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
"000000000000000000000000000000000000000",
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
X509Certificate2 cert = certCollection[0];
// Use certificate
Console.WriteLine(cert.FriendlyName);
}
certStore.Close();
...
I'm putting up a staging environment in an Azure App Service. That sits under the Free Tier, where you cannot upload custom SSL certificates. In order to test my ASP.NET Core application setup, and specifically if it can correctly load a certificate from store, I'd like to try that without having to satisfy all requirements for a trusted certificate (change tier, get domain, get certificate, ...).
I'm aware about Let's Encrypt, but that would still force me to switch tier in order to add a certificate to Azure app service. Plus, I'm not sure you can create a certificate for a domain some-site.azurewebsites.net (I've read something somewhere against using anything related to azurewebsites.net for a custom certificate), so maybe that would also need a custom domain anyway.
I was wondering if there's a way to access, from application code, the default wildcard certificate that MS owns for *.azurewebsites.net. So something like grabbing MS Azure certificate thumbprint, storing it in WEBSITE_LOAD_CERTIFICATES app setting, then load it from store as done here in chapter 3. Access from app".
X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
"insert-here-thumbprint-of-azure-default-cert",
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
X509Certificate2 cert = certCollection[0];
// Use certificate
Console.WriteLine(cert.FriendlyName);
}
certStore.Close();
Is this doable? TA.
Apparently, another SO thread has the answer. The gist of it is:
You will not be able to access this certificate programmatically in your WebApp as this certificate is not really installed on the Azure WebApp.
Not sure if this should be closed as duplicate.
I have a .NET Core application that I'm trying to deploy to Azure App Service. When I deploy and try to load the site I'm getting a 502.5 error response. From what I've read that means it's a permissions issue. I've tried printing the logs with stdout, but while it physically creating the log files, they are all empty.
So I started eliminating the problem by commenting out code. On ConfigureServices I'm loading a certificate:
var certificate = new X509Certificate2("mycertificate.pfx", "**********");
If I comment out this line, then the application loads. Once returned it gives the error again.
From console in the Azure portal I've tried giving mycertificate.pfx permissions using chmod 777 mycertificate.pfx, but it didn't seem to have any affect.
I'm not sure if the problem is loading that specific file or using X509Certificate2 at all.
How can I set it up to work?
How can I set it up to work?
1.Upload pfx Certificate to the Azure with azure portal. It is required service plan B or above. How to change service plan please refer to this document
Add an App setting named WEBSITE_LOAD_CERTIFICATES with its value set to the thumbprint of the certificate will make it accessible to your web application.
You can have multiple comma-separated thumbprint values or can set this value to “ * “ (without quotes) in which case all your certificates will be loaded to your web applications personal certificate store
3.Access from WebApp
using System;
using System.Security.Cryptography.X509Certificates;namespace UseCertificateInAzureWebsiteApp
{
class Program
{
static void Main(string[] args)
{
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
“E661583E8FABEF4C0BEF694CBC41C28FB81CD870”,
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
X509Certificate2 cert = certCollection[0];
// Use certificate
Console.WriteLine(cert.FriendlyName);
}
certStore.Close();
}
}
}
We could get more info from document.
I have a very strange problem. I published a webrole to azure cloud service. In this project, it requires webrole call a Azure Rest API, I can get the response in local emulator but, if I publish it to Azure I get the 403 forbidden Error. I am sure that I installed the certificate to Azure.
This error can be reproduced with following steps:
First create a certificate with link below: http://msdn.microsoft.com/en-us/library/windowsazure/gg651127.aspx
Create a cloud service with a webrole, and the certificate in Azure portal, cloud service Certificate and webrole->property->certificate.
Publish the project.
Remote log in to the web role instance.
Create a console application at local then copy the debug folder to remote instance and run the exe in remote application. you can find the application can run perfect in local, but in Azure instance, it seems like it can find certificate, but still get 403 forbidden error.
Console app code:
static void Main(string[] args)
{
try
{
// 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;
// Specify operation to use for the service management call.
// This sample will use the operation for listing the hosted services.
string operation = "hostedservices";
// The ID for the Windows Azure subscription.
string subscriptionId = "";
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = "";
// 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];
Console.WriteLine("Using certificate with thumbprint: " + thumbPrint);
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ subscriptionId
+ "/services/"
+ operation);
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
// Specify the version information in the header.
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Display the web response status code.
Console.WriteLine("Response status code: " + httpWebResponse.StatusCode);
// Display the request ID returned by Windows Azure.
if (null != httpWebResponse.Headers)
{
Console.WriteLine("x-ms-request-id: "
+ httpWebResponse.Headers["x-ms-request-id"]);
}
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Display the raw response.
Console.WriteLine("Response output:");
Console.WriteLine(reader.ReadToEnd());
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
}
catch (Exception e)
{
Console.WriteLine("Error encountered: " + e.Message);
// Exit the application with exit code 1.
Console.ReadLine();
System.Environment.Exit(1);
}
finally
{
// Exit the application.
Console.ReadLine();
System.Environment.Exit(0);
}
}
I was running into the same issue using the azure create cert link you provided. I found out that when creating the certificate using that method, the private key was not being uploaded to the cloud service. Even though the service was able to find the certificate, it was still unauthorized when submitting requests.
Using the following method to create a private and public key certificate worked. In the Visual Studio Command Prompt, create a .cer and .pfx file:
makecert -r -pe -n "CN=AzureManage" -sky exchange "AzureManage.cer" -sv "AzureManage.pvk"
pvk2pfx -pvk "AzureManage.pvk" -spc "AzureManage.cer" -pfx "AzureManage.pfx" -pi password
The first command creates a private and public key file. You will be prompted for a password a few times. The second command combines the two into a pfx file. If you leave -pi password off, then you will be prompted for the password instead of entering it in the terminal.
You'll then want to import the files appropriately:
Import the pfx into your Local Machine / Personal certificate store using mmc.
Upload the pfx to the Azure Cloud Service.
Upload the cer to the Azure Management Certificates store.
Add the thumbprint of the pfx to your Azure Role Certificates property.
You can then use the Azure management REST API as follows:
X509Certificate2 GetCertificate(string thumbprint)
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certs.Count == 0) return null;
var cert = certs[0];
store.Close();
return cert;
}
HttpWebRequest request = WebRequest.CreateHttp(apiUrl);
request.ClientCertificates.Add(cert);
request.Headers.Add("x-ms-version", "2012-03-01");
I believe your problem lies with this line of code:
certStore = new X509Store(StoreName.My, **StoreLocation.CurrentUser**);
I would expect that a properly uploaded certificate (assuming it was a .pfx that uploaded properly thru the management portal) is stored in the LocalMachine store, not CurrentUser.
Also, in order to read the certificate from the certificate store, your Role needs to run in Full Trust (this can be specified/validated in the Role's project properties in visual studio)
+1 #Igorek. I faced similar problem. If I specify that the certificate should be installed in CurrentUser store in my configuration, I found that for a Web role the certifcate installs there but for the Worker role the certificate is installed in the LocalUser store.
However looks like this is not the root cause of the problem. Can you ensure that the same certificate is there under Management Certificates section in the portal (exporting it 1st in cer file format and uploading it there) and the certificate installed in the role has private properties attached to it. These two reasons are primary cause of 403 error.