IdentityServer and Signing Key Rotation
When maintaining keys used for cryptographic operations (such as when running a token server that maintains keys used to sign tokens), a good security practice is to periodically rotate your keys. This is the process of retiring one key and onboarding another.
Within IdentityServer, the way you indicate your primary signing key is with the AddSigningCredential extension method we provide that adds IdentityServer to the ASP.NET dependency injection system. AddSigningCredential can accept an X509 certificate, the subject distinguished name or thumbprint of a X509 certificate stored in the windows certificate store, or just a plain old RSA key. The public portion of the key used for signing will be included in the discovery document.
We also provide an AddValidationKey extension method to allow additional keys to be included, such as those that are pre-active, or deactivated. In other words, the keys that you plan to use, or that were recently used for signing.
All of those calls might look like this in your ConfigureServices in Startup:
services.AddIdentityServer() .AddSigningCredential("CN=currentKeyName") .AddValidationKey("CN=lastKeyName") .AddValidationKey("CN=nextKeyName")
So, what’s the process for performing key rotation?
When you first deploy your IdentityServer, you will have your first signing key (let’s call it key1). You will run with this in production for some amount of time (say 90 days, or 9 months, or whatever you deem the acceptable duration your key should be in use). This is what the AddSigningCredential API is for.
You will then prepare key2 as the next key to be used, but you can’t switch immediately to using it. The reason is that normally OpenID Connect and/or OAuth2 consumers will cache your token server’s key material from the discovery document. If you were to immediately change keys, then new tokens signed with key2 would be delivered to consumers that have only key1 in their cache. What is needed is to introduce key2 into the discovery document prior to the switch over to using key2. This is what the AddValidationKey API is for.
Now in your discovery document you still have key1 as the active signing credential, and additionally key2 as a validation credential. You will leave this running for some amount of time (say 2-5 days or longer depending on cache durations) to allow consumers to update their caches from your updated discovery document. Then you can switch over and promote key2 to your active signing credential.
But what about key1? Well, you need to maintain it in the discovery document even though you won’t be using it anymore for signing. Why?
Let’s say that you just issued a token signed with key1, and then you switch keys (and drop key1 from your discovery document), and then at that exact moment a consumer reloads their cache. This would mean that the consumer would then only have key2 in their cache and would not be able find the correct key to validate the token signed with key1.
In short, when you retire a key, you need to keep it in discovery. This means when you retire a key you will just switch the two keys used in the calls to AddSigningCredential and AddValidationKey.
Then after some more amount of time (longer than the expiration of any issued token), you can finally remove key1 from discovery.
Given the above workflow, it’s possible that you could have two keys in discovery (if not three or more, depending on how narrow your window of rotation). Just as a means to validate my point, here is a screen shot of Azure Active Directory’s key materials from its discovery document. As you can see, there are three signing keys:
This also means there are three steps in a key rotation lifecycle. Depending on how your build and deploy your IdentityServer, this might be a manual (and potentially tedious) process. But in short, the primitives are in place for you to implement key rotation in IdentityServer.
HTH
Update:
Rock Solid Knowledge and I have teamed up to release a commercial component that performs key management and key rotation automatically. It can be found here. Enjoy!
Nice explanation. I am also trying to do same thing with Identity server but i have some questions.
1>As per above explanation do we have to create 2-3 keys in advance and put it in AddValidation keys call
.AddValidationKey(“CN=lastKeyName”).AddValidationKey(“CN=nextKeyName”) for key roatation or do we have to insert it at runtime?
2>In above blog you mentioned that “Then you can switch over and promote key2 to your active signing credential.” How this will happen as
AddSigningCredential and AddValidation Keys method gets called in ConfigureServices method which get executed at startup time only.
3>I got confused here as AddSigningCredential and AddValidation Keys method get called only one time. How this things will work automatically means after certain interval like 90 days?
Is there any option?
4>Does Identity server support automatic key rollover?
All the built-in APIs are done in Startup, so it’s static config. So all those steps I described would require a restart. As for something automatic, we will be releasing at the end of the month (Aug, 2019) a commercial component that provides automatic key management. See: https://www.identityserver.com/products for more info.