Identity Server 4 can't find Certificate when deployed to Azure AppService

Viewed 711

I have an asp.net core hosted blazor wasm application. I used the default template with authentication via Identity Server 4. When I test it locally in Release Mode it works as expected. But when I deploy to Azure AppService I get this exception:

    2020-05-08 07:45:50.244 +00:00 [ERR] An unhandled exception has occurred while executing the request.
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The system cannot find the file specified.
   at System.Security.Cryptography.CngKey.Open(String keyName, CngProvider provider, CngKeyOpenOptions openOptions)
   at System.Security.Cryptography.CngKey.Open(String keyName, CngProvider provider)
   at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
   at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
   at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
   at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PrivateKey()
   at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PrivateKeyStatus()
   at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.FoundPrivateKey(SecurityKey key)
   at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures)
   at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures, CryptoProviderFactory cryptoProviderFactory)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
   at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
   at IdentityServer4.Services.DefaultTokenCreationService.CreateJwtAsync(JwtSecurityToken jwt)
   at IdentityServer4.Services.DefaultTokenCreationService.CreateTokenAsync(Token token)
   at IdentityServer4.Services.DefaultTokenService.CreateSecurityTokenAsync(Token token)
   at IdentityServer4.ResponseHandling.TokenResponseGenerator.CreateAccessTokenAsync(ValidatedTokenRequest request)
   at IdentityServer4.ResponseHandling.TokenResponseGenerator.ProcessAuthorizationCodeRequestAsync(TokenRequestValidationResult request)
   at IdentityServer4.ResponseHandling.TokenResponseGenerator.ProcessAsync(TokenRequestValidationResult request)
   at IdentityServer4.Endpoints.TokenEndpoint.ProcessTokenRequestAsync(HttpContext context)
   at IdentityServer4.Endpoints.TokenEndpoint.ProcessAsync(HttpContext context)
   at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
   at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
   at IdentityServer4.Hosting.MutualTlsTokenEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
   at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

In my appsettings I have this config:

  "IdentityServer": {
    "Clients": {
      "ApplySupportTool.Client": {
        "Profile": "IdentityServerSPA"
      }
    },
    "Key": {
      "Type": "File",
      "FilePath": "applysupporttool.pfx",
      "Password": "{Password}"
    }
  }

And in my Startup.cs I have this in the ConfigureServices Method:

        services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, SupportToolContext>();

        services.AddAuthentication()
            .AddIdentityServerJwt();

And this in the Configure Method:

        app.UseIdentityServer();
        app.UseAuthentication();
        app.UseAuthorization();

Which I made according to the asp.net core blazor wasm template with individual auth.

The passwod are correctly filled on Azure itself. What is different on Azure than on my System?

1 Answers

I ran into this when setting up IdentityServer on AWS ElasticBeanstalk infrastructure. I found that the app pools on the EC2 instances did not have Load User Profile set true. When set, the permissions model changes and allows the process to load in the cert. You can enable through the IIS management UI on the app pool details, or use a version of the script below.

Import-Module WebAdministration
Set-ItemProperty "IIS:\AppPools\DefaultAppPool" -Name "processModel.loadUserProfile" -Value "True"
Related