-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Background and Motivation
Data Protection has no facility for deleting keys. The design assumes that they will simply accumulate forever so that data protected with old keys will always be decryptable in an emergency. Per our docs:
Deleting a key is truly destructive behavior, and consequently the data protection system exposes no first-class API for performing this operation.
However, for a very long-running application, there's a risk of long-defunct keys consuming too many resources. As part of #52916, we should consider allowing deletion.
Proposed API
namespace Microsoft.AspNetCore.DataProtection.KeyManagement;
public interface IKeyManager
{
+ /// <summary>
+ /// Indicates whether this key manager supports key deletion.
+ /// </summary>
+ /// <remarks>
+ /// Deletion is stronger than revocation. A revoked key is retained and can even be (forcefully) applied.
+ /// A deleted key is indistinguishable from a key that never existed.
+ /// </remarks>
+ bool CanDeleteKeys => false;
+ /// <summary>
+ /// Deletes a specific key and its revocations.
+ /// </summary>
+ /// <param name="keyId">The id of the key to delete.</param>
+ /// <param name="evenIfActive">True to force deletion of still-active keys. Subsequent consumers of the key will throw.</param>
+ /// <remarks>
+ /// Generally, keys should only be deleted to save space. If space is not a concern, keys
+ /// should be revoked or allowed to expire instead.
+ ///
+ /// This method will not mutate existing IKey instances. After calling this method,
+ /// all existing IKey instances should be discarded, and GetAllKeys should be called again.
+ /// </remarks>
+ /// <exception cref="NotSupportedException">
+ /// If <see cref="CanDeleteKeys"/> is false.
+ /// </exception>
+ /// <exception cref="InvalidOperationException">
+ /// If the key is not found or if the key is active and <paramref name="evenIfActive"/> is false.
+ /// </exception>
+ void DeleteKey(Guid keyId, bool evenIfActive = false) => throw new NotSupportedException();
}
Usage Examples
if (keyManager.CanDeleteKeys)
{
keyManager.DeleteKey(keyId, evenIfActive: true); // Force deletion of active key
}
Alternative Designs
We talked about TryDelete
, but I didn't like that it was returning a value for all keys, rather than the specific argument.
We don't presently see a need for DeleteAllKeys
and it could be added later as a default interface method.
Risks
As with revocation, in memory representations of the deleted key will be unaffected.
We'll have to be careful how we revise/supplement the docs, since key deletion is a foot-gun.