Hello,
We do use certificates loaded from azure keyvault in our web.config (.net framework 4.7 app) and have added "WEBSITE_LOAD_USER_PROFILE=1" to the application settings.
We tried to run the application on a F1 plan without success, the application runs properly on a B1 plan.
As per the doc:
" If your app is in Free or Shared tier, you can include the certificate file in your app repository." which refers to loading cerificates from file.
The documentation on loading cerificates from files does indeed advise to set the application setting "WEBSITE_LOAD_USER_PROFILE=1"
In the light of these facts, it seems that the documention is not clear on the conditions necessary to run the application in a Free or Shared Tier.
Could you clarify ?
Can our application run in a Free or Shared Tier ?
Cédric
⚠Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
Thanks for the feedback! We are currently investigating and will update you shortly.
Hi @cblomart, I'm assuming you're using a cert that you've imported and are using the thumbprint in your web.config. What errors/exceptions are you getting? Can you provide a code snippet of how you're loading the cert from Azure Key Vault?
no code :smiling_imp: as far as i know...
<appSettings configBuilders="AzureKeyVault">
<add key="webpages:Version" value="3.0.0.0"/>
<add key="webpages:Enabled" value="false"/>
<!-- ... -->
<add key="cert" value=""/>
<!-- ... -->
</appSettings>
the cert key is they key of the certificate in azure keyvault
Hello,
The error occurs when we try to read the certificate bytes[] retrieved from KeyVault. It has been a when we encountered the issue. So i am not sure about the exact error but it was something like below:
System.Security.Cryptography.CryptographicException: An internal error occurred.
The error occurs mostly at the moment of the initialization of the certificate:
var item = new X509Certificate2(Convert.FromBase64String(ConfigurationManager.AppSettings["certificateKeyName"]));
I had to add "WEBSITE_LOAD_USER_PROFILE=1" to the App Service configuration in order to let it work. But when i am on the free plan the "WEBSITE_LOAD_USER_PROFILE=1" doesn't solve the problem so i had to go to the payed Dev plan in order to let it work.
Best regards,
Emad
If you're retrieving the cert directly from KeyVault then you need to consult the KeyVault documentation on how to do it. It's beyond the scope of this doc. As @RyanHill-MSFT mentioned, this doc is for using certs (including KeyVault certs) that you've imported into App Service, and want to use as a cert in App Service in your code.
If I am not mistaken the title of the doc is « Use an SSL certificate in your code in Azure App Service« which is what we want to accomplish.
We are not reading the certificate from keyvault but from the config which is provided by keyvault. ( notice the byte comes from configmanager app settings).
Mostly this works but we can’t run that on a free/shared tier and that is the reason for the issue.
We could look at importing the certificate in the certificate in the web app but to match the documentation but the certificate may not satisfy requirement (it is only used to sign soap request content).
We still want to be able to use x509 certificate in code with free/shared tiers!
@cblomart were you able to achieve this? I'm trying the same, use a certificate from azure key vault in a an azure app service on free/shared plan
All i could test righ know is load the certificate from keystore.
I will look with the @emadalsous if we can load the certificate from there.
Any pointers on how to load the certificate from that?
@cblomart @cephalin @ryanborMSFT @emadalsous this is what I tried:
var bytes = System.IO.File.ReadAllBytes(Configuration.GetValue<string>("Certificate:Path"));
var cert = new X509Certificate2(bytes);
az webapp config appsettings set --name myapplication --resource-group myresourcegroup --settings WEBSITE_LOAD_USER_PROFILE=1
var cert = new X509Certificate2(bytes); it crash and the ouput is the following:
Application '/LM/W3SVC/1433196852/ROOT' with physical root 'D:\home\site\wwwroot\' hit unexpected managed exception, exception code = '0xe0434352'. First 30KB characters of captured stdout and stderr logs: Unhandled exception. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The system cannot find the file specified.at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] data)at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData)at FunerariaMonteLosOlivos.IdentityServer.Startup.ConfigureServices(IServiceCollection services) in d:\a\1\s\FunerariaMonteLosOlivos.IdentityServer\Startup.cs:line 71at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(Object instance, IServiceCollection services)at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection)at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection services)at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services)at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass12_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services)at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()at Microsoft.Extensions.Hosting.HostBuilder.Build()at FunerariaMonteLosOlivos.IdentityServer.Program.Main(String[] args) in d:\a\1\s\FunerariaMonteLosOlivos.IdentityServer\Program.cs:line 11
My question is: Can you use a certificate created on azure vault on free/shared azure app service via load certificate from a file as I have described?
nvm I found the sad unwanted answer to my question here
😞
Hello Luis,
I encountered the same issue as you. I think the issue is not related to Azure Key Vault.
It's related to the fact that in order to load a certificate you need to have "WEBSITE_LOAD_USER_PROFILE" set to 1 which is not set on Azure App Service by default. So if i want to be more specific with the question. Is it possible to use "WEBSITE_LOAD_USER_PROFILE=1" on free/shared azure app service. If you set "WEBSITE_LOAD_USER_PROFILE" to 1 and upgrade to B1 plan it will work fine.
Hello,
I would like to provide more details about the error. I hope this might help getting better understanding. I get this error when i set my App Service to use Free/Shared plan:
System.InvalidOperationException:
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (System.Web.Http, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (System.Web.Http, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Web.Http.Dispatcher.HttpControllerDispatcher+
Inner exception System.Security.Cryptography.CryptographicException handled at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create:
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor (System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at SPF.DataConnector.WebAPI.WebApiConfig+<>c.
at Unity.UnityContainerExtensions+<>c__DisplayClass30_01.<RegisterFactory>b__0 (Unity.Abstractions, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Injection.InjectionFactory.<AddPolicies>b__3_2 (Unity.Abstractions, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Strategies.BuildPlanStrategy.PreBuildUp (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.UnityContainer+<>c.<.ctor>b__41_3 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Builder.BuilderContext.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Builder.BuilderContext.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Builder.BuilderContext.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Processors.ParametersProcessor1+<>c__DisplayClass7_0.
at Unity.Processors.ConstructorProcessor+<>c__DisplayClass16_0.
at Unity.Processors.MemberProcessor2+<>c__DisplayClass8_0.<GetResolver>b__0 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Processors.MemberProcessor2+<>c__DisplayClass8_0.
at Unity.Processors.MemberProcessor2+<>c__DisplayClass8_0.<GetResolver>b__0 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.UnityContainer+<>c__DisplayClass111_0.<OptimizingFactory>b__0 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Strategies.BuildPlanStrategy.PreBuildUp (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.UnityContainer+<>c.<.ctor>b__41_3 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Builder.BuilderContext.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Builder.BuilderContext.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Builder.BuilderContext.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Processors.ParametersProcessor1+<>c__DisplayClass7_0.
at Unity.Processors.ConstructorProcessor+<>c__DisplayClass16_0.
at Unity.Processors.MemberProcessor2+<>c__DisplayClass8_0.<GetResolver>b__0 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.Processors.MemberProcessor2+<>c__DisplayClass8_0.
at Unity.Processors.MemberProcessor`2+<>c__DisplayClass8_0.
at Unity.UnityContainer+<>c__DisplayClass111_0.
at Unity.Strategies.BuildPlanStrategy.PreBuildUp (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.UnityContainer+<>c.<.ctor>b__41_2 (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.UnityContainer.Unity.IUnityContainer.Resolve (Unity.Container, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at Unity.UnityContainerExtensions.Resolve (Unity.Abstractions, Version=5.11.1.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0)
at SPF.DataConnector.WebAPI.Infrastructure.UnityResolver.GetService (SPF.DataConnector.WebAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nullSPF.DataConnector.WebAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null: C:\Users\ealsous\OneDrive - Business & Decision Benelux S.A\Tasks\2019\SPF\SPF.Entities\SPF.DataConnector\Infrastructure\UnityResolver.csSPF.DataConnector.WebAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null: 26)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator (System.Web.Http, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (System.Web.Http, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
Best regards,
Emad
nvm I found the sad unwanted answer to my question here
😞
@Luis-Palacios It looks like in the rewrite of the article we forgot to include that information. Sorry about that. I've added it in https://github.com/MicrosoftDocs/azure-docs-pr/pull/96600.
@emadalsous I remember now that the reason ASP.NET/Core needs help from App Service because the X509Certificate class requires the use of the certificate store, even if you're just loading them from the file and such. Unfortunately that means that @Luis-Palacios says is true.
@cephalin : i wanted to checkout the PR but i suppose we cannot read it.
I think the limitation should be clear in the documentation.
The take away i have now is that certificate should work on free/shared and dotnet (core) on linux.
(Unfortunaly other limitations concerning soap signing forces us to use dotnet 4.7)
It is a shame that such limitation exists for X509 certificates that are a cornerstone to trusts between computer systems.
@cblomart This has to do with the security architecture of App Service, which locks down the cert store in multitenanted hosting (FREE & SHARED). The limitation is mainly for .NET apps that take a dependency on the X509Certificate class. If you use certificates without using this class, this limitation also goes away. Other languages that don't depend on the cert store doesn't have this limitation in FREE/SHARED tier.
@cephalin thanks for your confirmation. I'm not able to see the link you shared I get a 404, Could you point me in a direction to see how I can use a certificate without the X509Certificate class? I'm trying to load one for Identity Server 4
@cblomart I'm using Dotnet core 3.0 but my app service is on windows I'll try Linux to see if I still run into the issue
@Luis-Palacios For example, you might use a 3rd party .NET library to load certs. Microsoft can't advise you on the selections and it's also beyond the scope of this documentation. Your best bet is StackOverflow, or other forums.
@cblomart I have tested on an azure app service on linux and the code work correctly using dotnet core 3.0 not sure if this make sense to you @cephalin
futhermore I did some more digging and after looking this and this I discovered that if If change my code from
var cert = new X509Certificate2(bytes);
to
var cert = new X509Certificate2(bytes, (string)null, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.EphemeralKeySet);
It also works on windows azure app service on the free plan I have been doing a lot of poking around so if anybody can confirm that my conclusions are correct it would be great maybe you can also try it @emadalsous
@Luis-Palacios 🎉
So i understand that it does work in all situations now !
My reasoning over linux is that it doesn't handle keystore the same way as windows does.
Hell if i know but free/shared tier may run on shared windows vms in azure but might as well be containers for linux.
I would think there is not much way for microsoft to disable machine keystore in a vm. (api doc)
MachineKeySet = "Private keys are stored in the local computer store rather than the current user store."
Altought it might not be best to share keys in there.... ah, but, the key is stored in memory
EphemeralKeySet = "The key associated with a PFX file is created in memory and not persisted on disk when importing a certificate."
I am nevertheless wondering what @cephalin or someone like @bartonjs would have to say to that, security wise... in an app service in a shared/free tier.
@Luis-Palacios @cblomart All I can say is that I've explored that way before with the product team and in any case they gave that method the silent treatment. Probably because of the security ramifications. The Windows doc https://docs.microsoft.com/en-us/windows-hardware/drivers/install/local-machine-and-current-user-certificate-stores indicates the same:
Local machine certificate store
This type of certificate store is local to the computer and is global to all users on the computer. This certificate store is located in the registry under the HKEY_LOCAL_MACHINE root.
Proceeding to close this thread due to https://github.com/MicrosoftDocs/azure-docs/commit/67a4525e5beb92c6d8ebb43db2e8e35ec4ca1b37. Feel free to re-open for further assistance.