27

Most (all?) the sample code on the IdentityServer4 docs site uses AddDeveloperSigningCredential(), but recommends using AddSigningCredential() instead in production. I spent more hours than I care to think about trying to figure out how to do that.

How do I create a signing certificate and use it in IdentityServer4 in production?

jww
  • 97,681
  • 90
  • 411
  • 885
Rob
  • 1,214
  • 1
  • 11
  • 20

1 Answers1

44

Create certificate and add to machine's certificate store

I decided to create a certificate and add it to the machine's certificate store. Brock Allen has a 2015 blog post here describing how to create the certificate using MakeCert. However according to the Microsoft MakeCert documentation it is now deprecated. So I decided to use the PowerShell New-SelfSignedCertificate applet instead (MS docs). I translated Brock's MakeCert command to use the New-SelfSignedCertificate parameters and ended up with this PowerShell command:

    New-SelfsignedCertificate 
      -KeyExportPolicy Exportable 
      -Subject "CN=MyIdsvCertificate" 
      -KeySpec Signature 
      -KeyAlgorithm RSA 
      -KeyLength 2048 
      -HashAlgorithm SHA256 
      -CertStoreLocation "cert:\LocalMachine\My"

If you want to check the certificate has been installed correctly, from the Run prompt launch "mmc", go to File, "Add/Remove Snap-in", select "Certificates", click Add, select "Computer account", Next, "Local computer", Finish, OK. Then browse to Certificates\Personal\Certificates, there should be one issued to MyIdsvCertificate.

Grant permissions on the certificate

Once the certificate has been created you need to grant read permission to whatever Windows identity is running IIS (or whatever is serving your IdentityServer app) otherwise you get a "Keyset does not exist" error when IdentityServer tries to use the key. To do this locate the folder %ALLUSERSPROFILE%\Microsoft\Crypto\RSA\MachineKeys find the file with a timestamp matching the time you created the certificate, then grant read access (no need for anything else) to the Windows identity running IIS. This issue is discussed on the IdentityServer4 GitHub Issues forum and explained by Brock Allen and Dominick Baier. If you're a genius like Brock or Dominick then that explanation might have been enough, but dummies like me might find the clearer explanation and solution provided to a very similar issue on the Microsoft Support site more useful.

Tell IdentityServer to use the certificate

The hard work is now done. All that remains is to tell IdentityServer to use the certificate when not in development:

    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        // Configure some awesome services
        // ...

        var identityServer = services.AddIdentityServer(...options...)...AddStuff()...;

        if (_env.IsDevelopment())
        {
            identityServer.AddDeveloperSigningCredential();
        }
        else
        {
            identityServer.AddSigningCredential("CN=MyIdsvCertificate");
        }

        // ...
        // Configure more awesome services
        // ...
    }

Note that the "CN=" bit is required in the call to AddSigningCredential(), that cost me some time too. I actually get the name from a config file at runtime, but we don't need to go into those details here.

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
Rob
  • 1,214
  • 1
  • 11
  • 20
  • 2
    It's not required to install the *signing* cert into CertStore. It's enough to read it as a file from filesystem. However the powershell approach does not provide a way to create a file in one step. However it's possible to export it into file from the store. An alternative is OpenSSL. And still MakeCert. More options [here](https://medium.com/the-new-control-plane/generating-self-signed-certificates-on-windows-7812a600c2d8) – d_f Sep 27 '19 at 15:43
  • 2
    Thanks, that's a useful reference. I decided using the certificate store would be safer as there's less chance of a system admin saving the certificate files in an inappropriate location or with an insecure password. Also, now that I know how it's done it actually seems more straightforward. – Rob Sep 27 '19 at 19:22
  • heh, in production admins usually use proven scripts and images, and file approach is more straightforward when we consider cross platform, but on windows, stores are probably still valid : ) – d_f Sep 27 '19 at 20:18
  • Just different horses for different courses I guess. – Rob Sep 28 '19 at 07:49
  • 1
    thanks, this was very helpful. You can alternatively specify the signing certificate in the appsetting.json file – dobestar May 11 '21 at 07:14
  • @Rob how did you plan the certificate rotation on expiry? – Jay Nov 04 '21 at 03:47
  • @Jay sorry, I can't help you there. We have a relatively small number of users in Europe, a very short token expiry time for security reasons, and the guy who updates certificates for us lives in the far East. So certificate rotation hasn't been an issue for us yet. – Rob Nov 11 '21 at 16:21
  • 1
    Just a note about the permission. Instead of modifying MachineKeys directly, you can also use the Certificates snap-in. Right-click the new certificate, go to "All Tasks" > "Manage Private Keys." From there, add the app pool user and remove full control to grant only read. – Rand.Function Oct 24 '22 at 17:28