Skip to content

Allow deletion of Data Protection keys #53502

@amcasey

Description

@amcasey

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.

Metadata

Metadata

Assignees

Labels

api-needs-workAPI needs work before it is approved, it is NOT ready for implementationarea-dataprotectionIncludes: DataProtection

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions