This is the first part in a series of posts covering new (and old) features of Duende IdentityServer. These posts are not supposed to be super technical deep dives (that’s what documentation is for), but rather explain the feature at a more conceptual level, why it exists, and why it might useful for you.
Obviously, a very important part of a security token service is the key material to sign the actual security tokens. Also, we all know that it would be good security/crypto hygiene to rotate that key material periodically.
In practice (telling from over 15 years of experience with customers of all industries) this is rarely done. The reason for that is not, that people are ignoring best practices, but rather that it is not trivial to do it properly. It needs to be automated, and it needs to work very reliably to not cause issues with production environments.
It turns out OpenID Connect and the discovery mechanism were designed right from the start for both periodic and emergency updates to the key material. Also, IdentityServer always included the primitives to implement any custom rotation logic you might want – but it was pretty low-level. In fact Brock wrote about this back in 2019 already.
While many people consider the signing key for tokens the “crown jewels”, in every ASP.NET Core application, there is another key at play called the “data protection key”. This key is used to protect many features in ASP.NET Core including things like authentication cookies. If you think about it, this key is even more sensitive than your token signing key because if it gets compromised it could be used to create SSO cookies for the token service which in turn would lead to issuing tokens.
So in reality you have to protect two keys. Data protection already has a rich ecosystem of plugins and storage abstractions to find good solution for both on-premise and cloud hosting. This includes support for databases, blob storage and key management services like Azure KeyVault and KMS.
Once data protection is in place, you can use it to – well – protect data, for example your signing keys. So, what we did in Duende IdentityServer key management, is to combine automatic signing key creation, rotation and retirement with ASP.NET Core data protection to also enable secure storage.
What this means in practice is that instead of you dealing with signing keys yourself all you need to define is:
- What types of keys do you want? RSA or elliptic curves?
- What signing algorithm(s) do you need (e.g. RS256, ES256, PS256)?
- Should those keys be wrapped in an X.509 certificate?
- How often should those keys be rotated?
- How long before the rotation should the new keys be announced in discovery?
- How long should the old keys be kept around for validation?
(or you just use our defaults)
In code this could look like this:
var builder = services.AddIdentityServer(options =>
// how often do we want new keys
options.KeyManagement.RotationInterval = TimeSpan.FromDays(90);
// when should the keys disappear from discovery
options.KeyManagement.RetentionDuration = TimeSpan.FromDays(7);
// how long before announcement to rotation
options.KeyManagement.PropagationTime = TimeSpan.FromDays(7);
And all this is combined with our standard configuration storage mechanism (or custom) that in turn is backed by ASP.NET Data Protection.
Key management is included in our preview 1 of Duende IdentityServer and is a feature of the business edition and up. It is enabled by default.
The initial version only manages a single key, but in preview 2 we will publish the multi-key feature. Please give it a try and give us feedback via our issue tracker.