Gestion des clés dans ASP.NET Core

Le système de protection des données gère automatiquement la durée de vie des clés master utilisées pour protéger et annuler la protection des charges utiles. Chaque clé peut exister dans l’une des quatre étapes suivantes :

  • Créé : la clé existe dans l’anneau de clés, mais n’a pas encore été activée. La clé ne doit pas être utilisée pour les nouvelles opérations De protection tant que la clé n’a pas eu la possibilité de se propager à toutes les machines qui consomment cet anneau de clés.

  • Active : la clé existe dans l’anneau de clés et doit être utilisée pour toutes les nouvelles opérations De protection.

  • Expiré : la clé a exécuté sa durée de vie naturelle et ne doit plus être utilisée pour les nouvelles opérations de protection.

  • Révoqué : la clé est compromise et ne doit pas être utilisée pour les nouvelles opérations de protection.

Les clés créées, actives et expirées peuvent toutes être utilisées pour annuler la protection des charges utiles entrantes. Les clés révoquées par défaut ne peuvent pas être utilisées pour annuler la protection des charges utiles, mais le développeur d’application peut remplacer ce comportement si nécessaire.

Avertissement

Le développeur peut être tenté de supprimer une clé de l’anneau de clés (par exemple, en supprimant le fichier correspondant du système de fichiers). À ce stade, toutes les données protégées par la clé sont indéchiffrables en permanence, et il n’y a pas de remplacement d’urgence comme il y a des clés révoquées. La suppression d’une clé est un comportement vraiment destructeur.

Sélection de clé par défaut

Lorsque le système de protection des données lit l’anneau de clés à partir du dépôt de stockage, il tente de localiser une clé « par défaut » à partir de l’anneau de clés. La clé par défaut est utilisée pour les nouvelles opérations de protection.

L’heuristique générale est que le système de protection des données choisit la clé avec la date d’activation la plus récente comme clé par défaut. (Il existe un petit facteur de décalage pour permettre l’asymétrie de l’horloge de serveur à serveur.) Si la clé a expiré ou est révoquée et si l’application n’a pas désactivé la génération automatique de clé, une nouvelle clé est générée avec une activation immédiate conformément à l’expiration de la clé et à la stratégie propagée ci-dessous.

La raison pour laquelle le système de protection des données génère une nouvelle clé immédiatement plutôt que de revenir à une autre clé est que la nouvelle génération de clé doit être traitée comme une expiration implicite de toutes les clés qui ont été activées avant la nouvelle clé. L’idée générale est que les nouvelles clés peuvent avoir été configurées avec des algorithmes ou des mécanismes de chiffrement au rest différents de ceux des anciennes clés, et que le système doit préférer la configuration actuelle à la restauration.

Il y a une exception. Si le développeur d’applications a désactivé la génération automatique de clés, le système de protection des données doit choisir quelque chose comme clé par défaut. Dans ce scénario de secours, le système choisit la clé non révoquée avec la date d’activation la plus récente, en préférant les clés qui ont eu le temps de se propager à d’autres ordinateurs du cluster. Le système de secours peut donc choisir une clé par défaut expirée. Le système de secours ne choisira jamais de clé révoquée comme clé par défaut, et si l’anneau de clés est vide ou si chaque clé a été révoquée, le système génère une erreur lors de l’initialisation.

Expiration et déploiement de clé

Lorsqu’une clé est créée, elle reçoit automatiquement une date d’activation de { maintenant + 2 jours } et une date d’expiration de { maintenant + 90 jours }. Le délai de 2 jours avant l’activation donne le temps clé de propagation à travers le système. Autrement dit, il permet à d’autres applications pointant vers le magasin de stockage d’observer la clé à leur prochaine période d’actualisation automatique, maximisant ainsi les chances que, lorsque le anneau de clés devient actif, il s’est propagé à toutes les applications qui pourraient avoir besoin de l’utiliser.

Si la clé par défaut expire dans un délai de 2 jours et si l’anneau de clés n’a pas encore de clé qui sera active à l’expiration de la clé par défaut, le système de protection des données conserve automatiquement une nouvelle clé dans l’anneau de clés. Cette nouvelle clé a une date d’activation de { date d’expiration de la clé par défaut } et une date d’expiration de { maintenant + 90 jours }. Cela permet au système de restaurer automatiquement des clés sur une base régulière sans interruption du service.

Il peut arriver qu’une clé soit créée avec une activation immédiate. Par exemple, lorsque l’application n’a pas été exécutée depuis un certain temps et que toutes les clés de l’anneau de clés ont expiré. Dans ce cas, la clé reçoit une date d’activation de { maintenant } sans délai d’activation normal de 2 jours.

La durée de vie de la clé par défaut est de 90 jours, bien que celle-ci soit configurable comme dans l’exemple suivant.

services.AddDataProtection()
       // use 14-day lifetime instead of 90-day lifetime
       .SetDefaultKeyLifetime(TimeSpan.FromDays(14));

Un administrateur peut également modifier la valeur par défaut à l’échelle du système, bien qu’un appel explicite à remplace toute stratégie à SetDefaultKeyLifetime l’échelle du système. La durée de vie de la clé par défaut ne peut pas être inférieure à 7 jours.

Actualisation automatique du porte-clés

Lorsque le système de protection des données s’initialise, il lit l’anneau de clés à partir du dépôt sous-jacent et le met en cache en mémoire. Ce cache permet aux opérations de protection et d’annulation de la protection de se poursuivre sans atteindre le magasin de stockage. Le système case activée automatiquement le magasin de stockage pour les modifications apportées environ toutes les 24 heures ou à l’expiration de la clé par défaut actuelle, selon la première éventualité.

Avertissement

Les développeurs doivent très rarement (voire jamais) utiliser directement les API de gestion des clés. Le système de protection des données effectue la gestion automatique des clés comme décrit ci-dessus.

Le système de protection des données expose une interface IKeyManager qui peut être utilisée pour inspecter et apporter des modifications au anneau de clés. Le système DI qui a fourni le instance de IDataProtectionProvider peut également fournir un instance de IKeyManager pour votre consommation. Vous pouvez également extraire la IKeyManager ligne droite de l’exemple IServiceProvider ci-dessous.

Toute opération qui modifie l’anneau de clés (création explicite d’une clé ou révocation) invalide le cache en mémoire. L’appel suivant à Protect ou Unprotect oblige le système de protection des données à relire l’anneau de clés et à recréer le cache.

L’exemple ci-dessous illustre l’utilisation de l’interface IKeyManager pour inspecter et manipuler l’anneau de clés, notamment la révocation de clés existantes et la génération manuelle d’une nouvelle clé.

using System;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection()
            // point at a specific folder and use DPAPI to encrypt keys
            .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
            .ProtectKeysWithDpapi();
        var services = serviceCollection.BuildServiceProvider();

        // perform a protect operation to force the system to put at least
        // one key in the key ring
        services.GetDataProtector("Sample.KeyManager.v1").Protect("payload");
        Console.WriteLine("Performed a protect operation.");
        Thread.Sleep(2000);

        // get a reference to the key manager
        var keyManager = services.GetService<IKeyManager>();

        // list all keys in the key ring
        var allKeys = keyManager.GetAllKeys();
        Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
        foreach (var key in allKeys)
        {
            Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
        }

        // revoke all keys in the key ring
        keyManager.RevokeAllKeys(DateTimeOffset.Now, reason: "Revocation reason here.");
        Console.WriteLine("Revoked all existing keys.");

        // add a new key to the key ring with immediate activation and a 1-month expiration
        keyManager.CreateNewKey(
            activationDate: DateTimeOffset.Now,
            expirationDate: DateTimeOffset.Now.AddMonths(1));
        Console.WriteLine("Added a new key.");

        // list all keys in the key ring
        allKeys = keyManager.GetAllKeys();
        Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
        foreach (var key in allKeys)
        {
            Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
        }
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Performed a protect operation.
 * The key ring contains 1 key(s).
 * Key {1b948618-be1f-440b-b204-64ff5a152552}: Created = 2015-03-18 22:20:49Z, IsRevoked = False
 * Revoked all existing keys.
 * Added a new key.
 * The key ring contains 2 key(s).
 * Key {1b948618-be1f-440b-b204-64ff5a152552}: Created = 2015-03-18 22:20:49Z, IsRevoked = True
 * Key {2266fc40-e2fb-48c6-8ce2-5fde6b1493f7}: Created = 2015-03-18 22:20:51Z, IsRevoked = False
 */

Si vous souhaitez voir les commentaires de code traduits dans une langue autre que l’anglais, dites-le nous dans cette discussion GitHub.

Stockage des clés

Le système de protection des données a une heuristique dans laquelle il tente de déduire automatiquement un emplacement de stockage de clé approprié et un mécanisme de chiffrement au rest. Le mécanisme de persistance de clé est également configurable par le développeur d’application. Les documents suivants traitent des implémentations in-box de ces mécanismes :