AWS KMSPortachiavi gerarchici - AWS Encryption SDK

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

AWS KMSPortachiavi gerarchici

Importante

Il portachiavi AWS KMS Hierarchical è supportato solo dalla versione 4. x di AWS Encryption SDK per .NET e versione 3. x delSDK di crittografia AWS per Java.

Con il portachiavi AWS KMS Hierarchical, puoi proteggere i tuoi materiali crittografici con una chiave KMS a crittografia simmetrica senza chiamare AWS KMS ogni volta che crittografi o decrittografi i dati. È una buona scelta per le applicazioni che devono ridurre al minimo le chiamate e le applicazioni che possono riutilizzare alcuni materiali crittografici AWS KMS senza violare i requisiti di sicurezza.

Il portachiavi Hierarchical è una soluzione di memorizzazione nella cache dei materiali crittografici che riduce il numero di AWS KMS chiamate utilizzando chiavi branch AWS KMS protette persistenti in una tabella Amazon DynamoDB e quindi memorizzando nella cache locale i materiali chiave delle branch utilizzati nelle operazioni di crittografia e decrittografia. La tabella DynamoDB funge da archivio delle chiavi di filiale che gestisce e protegge le chiavi delle filiali. Memorizza la chiave di ramo attiva e tutte le versioni precedenti della chiave di ramo. La chiave di ramo attiva è la versione più recente della chiave di filiale. Il portachiavi Hierarchical utilizza una chiave dati unica per crittografare ogni messaggio e crittografa ogni chiave di dati con una chiave di wrapping unica derivata dalla chiave branch attiva. Il portachiavi Hierarchical dipende dalla gerarchia stabilita tra le chiavi branch attive e le relative chiavi di wrapping derivate.

Il portachiavi Hierarchical utilizza in genere ogni versione della chiave branch per soddisfare più richieste. Tuttavia, puoi controllare la misura in cui le chiavi di ramo attive vengono riutilizzate e determinare la frequenza con cui la chiave di ramo attiva viene ruotata. La versione attiva della chiave di ramo rimane attiva finché non viene ruotata. Le versioni precedenti della chiave branch attiva non verranno utilizzate per eseguire operazioni di crittografia, ma potranno comunque essere interrogate e utilizzate nelle operazioni di decrittografia.

Quando si crea un'istanza del portachiavi Hierarchical, viene creata una cache locale. Si specifica un limite di cache che definisce la quantità massima di tempo in cui i materiali chiave del branch vengono archiviati nella cache locale prima che scadano e vengano rimossi dalla cache. Il portachiavi Hierarchical effettua una AWS KMS chiamata per decrittografare la chiave del ramo e assemblare i materiali delle chiavi del ramo la prima volta che a viene specificato in un'operazione. branch-key-id I materiali delle chiavi di filiale vengono quindi archiviati nella cache locale e riutilizzati per tutte le operazioni di crittografia e decrittografia che lo specificano fino alla scadenza del limite di cache. branch-key-id L'archiviazione dei materiali chiave della filiale nella cache locale riduce le chiamate. AWS KMS Ad esempio, si consideri un limite di cache di 15 minuti. Se si eseguono 10.000 operazioni di crittografia entro tale limite di cache, il AWS KMSportachiavi tradizionale dovrebbe effettuare 10.000 AWS KMS chiamate per soddisfare 10.000 operazioni di crittografia. Se ne hai uno attivobranch-key-id, il portachiavi Hierarchical deve effettuare solo una AWS KMS chiamata per soddisfare 10.000 operazioni di crittografia.

La cache locale è composta da due partizioni, una per le operazioni di crittografia e una seconda per le operazioni di decrittografia. La partizione di crittografia memorizza i materiali delle chiavi di branch assemblati dalla chiave branch attiva e li riutilizza per tutte le operazioni di crittografia fino alla scadenza del limite della cache. La partizione di decrittografia memorizza i materiali delle chiavi di filiale assemblati per altre versioni di chiavi di filiale identificate nelle operazioni di decrittografia. La partizione di decrittografia può memorizzare più versioni di materiali chiave di filiale attivi contemporaneamente. Se è configurata per utilizzare un fornitore di ID di chiavi di filiale per un ambiente multitenant, la partizione encrypt può anche archiviare più versioni di materiali relativi alle chiavi di filiale contemporaneamente. Per ulteriori informazioni, consulta Utilizzo del portachiavi Hierarchical in ambienti multitenant.

Nota

Tutte le menzioni del portachiavi gerarchico si riferiscono al portachiavi gerarchico. AWS Encryption SDK AWS KMS

Come funziona

Le procedure dettagliate seguenti descrivono come il portachiavi Hierarchical assembla i materiali di crittografia e decrittografia e le diverse chiamate che il portachiavi effettua per le operazioni di crittografia e decrittografia. Per i dettagli tecnici sulla derivazione delle chiavi di wrapping e sui processi di crittografia delle chiavi di dati in chiaro, consulta Dettagli tecnici del portachiavi gerarchico. AWS KMS

Crittografa e firma

La procedura dettagliata seguente descrive come il portachiavi Hierarchical assembla i materiali di crittografia e ricava una chiave di avvolgimento univoca.

  1. Il metodo di crittografia richiede al portachiavi Hierarchical i materiali di crittografia. Il portachiavi genera una chiave di dati in testo semplice, quindi verifica se nella cache locale sono presenti materiali branch validi per generare la chiave di wrapping. Se sono presenti materiali validi per le chiavi di filiale, il portachiavi passa alla Fase 5.

  2. Se non ci sono materiali validi per le chiavi di filiale, il portachiavi Hierarchical interroga l'archivio delle chiavi di filiale per trovare la chiave di filiale attiva.

    1. L'archivio delle chiavi di filiale chiama AWS KMS per decrittografare la chiave di ramo attiva e restituisce la chiave di ramo attiva in testo semplice. I dati che identificano la chiave di ramo attiva vengono serializzati per fornire dati autenticati aggiuntivi (AAD) nella chiamata di decrittografia a. AWS KMS

    2. L'archivio delle chiavi di filiale restituisce la chiave di ramo in testo semplice e i dati che la identificano, ad esempio la versione della chiave di filiale.

  3. Il portachiavi Hierarchical assembla i materiali chiave del ramo (la chiave di ramo in testo semplice e la versione della chiave di ramo) e ne archivia una copia nella cache locale.

  4. Il portachiavi Hierarchical ricava una chiave di avvolgimento unica dalla chiave branch in testo semplice e un sale casuale a 16 byte. Utilizza la chiave di wrapping derivata per crittografare una copia della chiave di dati in testo non crittografato.

Il metodo di crittografia utilizza i materiali di crittografia per crittografare i dati. Per ulteriori informazioni, consulta Come AWS Encryption SDK crittografa i dati.

Decrittografa e verifica

La procedura dettagliata seguente descrive come il portachiavi gerarchico assembla i materiali di decrittografia e decrittografa la chiave di dati crittografata.

  1. Il metodo di decrittografia identifica la chiave di dati crittografata dal messaggio crittografato e la passa al portachiavi Hierarchical.

  2. Il portachiavi Hierarchical deserializza i dati che identificano la chiave dati crittografata, inclusa la versione della chiave branch, il salt da 16 byte e altre informazioni che descrivono come è stata crittografata la chiave dati.

    Per ulteriori informazioni, consulta AWS KMSDettagli tecnici del portachiavi gerarchico.

  3. Il portachiavi Hierarchical verifica se nella cache locale sono presenti materiali chiave di filiale validi che corrispondono alla versione della chiave di filiale identificata nel passaggio 2. Se sono presenti materiali validi per le chiavi di filiale, il portachiavi passa alla Fase 6.

  4. Se non ci sono materiali validi per le chiavi di filiale, il portachiavi Hierarchical interroga l'archivio delle chiavi di filiale per trovare la chiave di filiale che corrisponde alla versione della chiave di filiale identificata nello Step 2.

    1. L'archivio delle chiavi di filiale chiama AWS KMS per decrittografare la chiave di ramo e restituisce la chiave di ramo attiva in testo semplice. I dati che identificano la chiave di ramo attiva vengono serializzati per fornire dati autenticati aggiuntivi (AAD) nella chiamata di decrittografia a. AWS KMS

    2. L'archivio delle chiavi di filiale restituisce la chiave di ramo in testo semplice e i dati che la identificano, ad esempio la versione della chiave di filiale.

  5. Il portachiavi Hierarchical assembla i materiali chiave del ramo (la chiave di ramo in testo semplice e la versione della chiave di ramo) e ne archivia una copia nella cache locale.

  6. Il portachiavi Hierarchical utilizza i materiali delle chiavi branch assemblate e il sale da 16 byte identificato nella fase 2 per riprodurre la chiave di avvolgimento univoca che crittografava la chiave dati.

  7. Il portachiavi Hierarchical utilizza la chiave di wrapping riprodotta per decrittografare la chiave dati e restituisce la chiave dati in testo semplice.

Il metodo di decrittografia utilizza i materiali di decrittografia e la chiave di dati in testo semplice per decrittografare il messaggio crittografato. Per ulteriori informazioni, consulta Come decripta un messaggio crittografato. AWS Encryption SDK

Prerequisiti

AWS Encryption SDKNon richiede un file Account AWS e non dipende da nessuno. Servizio AWS Tuttavia, il portachiavi gerarchico dipende da Amazon AWS KMS DynamoDB.

Per utilizzare un portachiavi gerarchico, è necessaria una crittografia simmetrica con autorizzazioni KMS:Decrypt. AWS KMS key È inoltre possibile utilizzare una chiave multiregionale con crittografia simmetrica. Per informazioni dettagliate sulle autorizzazioni perAWS KMS keys, consulta Autenticazione e controllo degli accessi nella Guida per gli sviluppatori. AWS Key Management Service

Prima di poter creare e utilizzare un portachiavi gerarchico, è necessario creare l'archivio delle chiavi della filiale e compilarlo con la prima chiave di filiale attiva.

Fase 1: Configurare un nuovo servizio di archiviazione delle chiavi

Il servizio di archiviazione delle chiavi fornisce diverse operazioni API, come CreateKeyStore eCreateKey, per aiutarti a assemblare i prerequisiti del portachiavi gerarchico e a gestire l'archivio delle chiavi della filiale.

L'esempio seguente crea un servizio di archiviazione delle chiavi. È necessario specificare un nome di tabella DynamoDB che funga da nome dell'archivio chiavi della filiale, un nome logico per l'archivio chiavi della filiale e l'ARN della chiave KMS che identifica la chiave KMS che proteggerà le chiavi della filiale.

Il nome dell'archivio di chiavi logiche è associato crittograficamente a tutti i dati memorizzati nella tabella per semplificare le operazioni di ripristino di DynamoDB. Il nome dell'archivio di chiavi logiche può essere lo stesso del nome della tabella DynamoDB, ma non è necessario. Si consiglia di specificare il nome della tabella DynamoDB come nome della tabella logica quando si configura per la prima volta il servizio di archiviazione delle chiavi. È necessario specificare sempre lo stesso nome di tabella logica. Nel caso in cui il nome dell'archivio chiavi della filiale cambi dopo il ripristino della tabella DynamoDB da un backup, il nome dell'archivio di chiavi logico viene mappato al nome della tabella DynamoDB specificato per garantire che il portachiavi Hierarchical possa ancora accedere all'archivio delle chiavi della filiale.

Nota

Il nome dell'archivio logico delle chiavi è incluso nel contesto di crittografia di tutte le operazioni API del servizio di archiviazione chiavi che effettuano la chiamata. AWS KMS Il contesto di crittografia non è segreto, i suoi valori, incluso il nome dell'archivio di chiavi logiche, vengono visualizzati in testo semplice nei log. AWS CloudTrail

C# / .NET
var kmsConfig = new KMSConfiguration { KmsKeyArn = kmsKeyArn }; var keystoreConfig = new KeyStoreConfig { KmsClient = new AmazonKeyManagementServiceClient(), KmsConfiguration = kmsConfig, DdbTableName = keyStoreName, DdbClient = new AmazonDynamoDBClient(), LogicalKeyStoreName = logicalKeyStoreName }; var keystore = new KeyStore(keystoreConfig);
Java
final KeyStore keystore = KeyStore.builder().KeyStoreConfig( KeyStoreConfig.builder() .ddbClient(DynamoDbClient.create()) .ddbTableName(keyStoreName) .logicalKeyStoreName(logicalKeyStoreName) .kmsClient(KmsClient.create()) .kmsConfiguration(KMSConfiguration.builder() .kmsKeyArn(kmsKeyArn) .build()) .build()).build();
Fase 2: Chiama per creare un archivio di chiavi in filiale CreateKeyStore

La seguente operazione crea l'archivio delle chiavi della filiale che persisterà e proteggerà le chiavi della filiale.

C# / .NET
var createKeyStoreOutput = keystore.CreateKeyStore(new CreateKeyStoreInput());
Java
keystore.CreateKeyStore(CreateKeyStoreInput.builder().build());

L'CreateKeyStoreoperazione crea una tabella DynamoDB con il nome della tabella specificato nel passaggio 1 e i seguenti valori obbligatori.

Chiave di partizione Chiave di ordinamento
Tabella di base branch-key-id type
Nota

È possibile creare manualmente la tabella DynamoDB che funge da archivio delle chiavi della filiale anziché utilizzare l'operazione. CreateKeyStore Se scegli di creare manualmente l'archivio delle chiavi di filiale, devi specificare i seguenti valori di stringa per le chiavi di partizione e ordinamento:

  • Chiave di partizione: branch-key-id

  • Chiave di ordinamento: type

Passaggio 3: Chiama CreateKey per creare una nuova chiave di ramo attiva

La seguente operazione crea una nuova chiave di ramo attiva utilizzando la chiave KMS specificata nel passaggio 1 e aggiunge la chiave di ramo attiva alla tabella DynamoDB creata nel passaggio 2.

Quando si chiamaCreateKey, è possibile scegliere di specificare i seguenti valori opzionali.

C# / .NET
var additionalEncryptionContext = new Dictionary<string, string>(); additionalEncryptionContext.Add("Additional Encryption Context for", "custom branch key id"); var branchKeyId = keystore.CreateKey(new CreateKeyInput { BranchKeyIdentifier = "custom-branch-key-id", // OPTIONAL EncryptionContext = additionalEncryptionContext // OPTIONAL });
Java
final Map<String, String> additionalEncryptionContext = Collections.singletonMap("Additional Encryption Context for", "custom branch key id"); final String BranchKey = keystore.CreateKey( CreateKeyInput.builder() .branchKeyIdentifier(custom-branch-key-id) //OPTIONAL .encryptionContext(additionalEncryptionContext) //OPTIONAL .build()).branchKeyIdentifier();

Innanzitutto, l'CreateKeyoperazione genera i seguenti valori.

Quindi, l'CreateKeyoperazione chiama kms: GenerateDataKeyWithoutPlaintext utilizzando la seguente richiesta.

{ "EncryptionContext": { "branch-key-id" : "branch-key-id", "type" : "type", "create-time" : "timestamp", "logical-key-store-name" : "the logical table name for your branch key store", "kms-arn" : the KMS key ARN, "hierarchy-version" : "1", "aws-crypto-ec:contextKey": "contextValue" }, "KeyId": "the KMS key ARN you specified in Step 1", "NumberOfBytes": "32" }

Successivamente, l'CreateKeyoperazione chiama kms: ReEncrypt per creare un record attivo per la chiave branch aggiornando il contesto di crittografia.

Infine, l'CreateKeyoperazione chiama ddb: TransactWriteItems per scrivere un nuovo elemento che mantenga la chiave di ramo nella tabella creata nel passaggio 2. L'elemento ha i seguenti attributi.

{ "branch-key-id" : branch-key-id, "type" : "branch:ACTIVE", "enc" : the branch key returned by the GenerateDataKeyWithoutPlaintext call, "version": "branch:version:the branch key version UUID", "create-time" : "timestamp", "kms-arn" : "the KMS key ARN you specified in Step 1", "hierarchy-version" : "1", "aws-crypto-ec:contextKey": "contextValue" }

Crea un portachiavi gerarchico

Per inizializzare il portachiavi gerarchico, è necessario fornire i seguenti valori:

  • Il nome di un archivio di chiavi della filiale

    Il nome della tabella DynamoDB che hai creato per fungere da archivio delle chiavi della filiale.

  • Un limite di durata della cache (TTL)

    La quantità di tempo, in secondi, durante la quale una chiave di filiale deve essere inserita nella cache locale può essere utilizzata prima della scadenza. Questo valore deve essere maggiore di zero. Quando il limite di cache TTL scade, la voce viene rimossa dalla cache locale.

  • Un identificatore di chiave di ramo

    Il branch-key-id che identifica la chiave di filiale attiva nell'archivio delle chiavi della filiale.

    Nota

    Per inizializzare il portachiavi Hierarchical per l'uso multitenant, è necessario specificare un fornitore di ID di chiavi di filiale anziché un. branch-key-id Per ulteriori informazioni, consulta Utilizzo del portachiavi Hierarchical in ambienti multitenant.

  • (Facoltativo) Una cache

    Se desideri personalizzare il tipo di cache o il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale, specifica il tipo di cache e la capacità di accesso quando inizializzi il portachiavi.

    Il tipo di cache definisce il modello di threading. Il portachiavi Hierarchical fornisce tre tipi di cache che supportano ambienti multitenant: Default,,. MultiThreaded StormTracking

    Se non si specifica una cache, il portachiavi Hierarchical utilizza automaticamente il tipo di cache predefinito e imposta la capacità di ingresso su 1000.

    Default (Recommended)

    Per la maggior parte degli utenti, la cache predefinita soddisfa i requisiti di threading. La cache predefinita è progettata per supportare ambienti con molti multithread. Quando scade l'immissione di materiali relativi a una chiave di filiale, la cache predefinita impedisce la chiamata a più thread AWS KMS e Amazon DynamoDB notificando a un thread che l'immissione dei materiali chiave del ramo sta per scadere con 10 secondi di anticipo. Ciò garantisce che solo un thread invii una richiesta di aggiornamento della cache. AWS KMS

    Per inizializzare il tuo portachiavi gerarchico con una cache predefinita, specifica il seguente valore:

    • Capacità di accesso: limita il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale.

    C# /.NET
    CacheType defaultCache = new CacheType { Default = new DefaultCache{EntryCapacity = 100} };
    Java
    .cache(CacheType.builder() .Default(DefaultCache.builder() .entryCapacity(100) .build())

    Il valore predefinito e le StormTracking cache supportano lo stesso modello di threading, ma è sufficiente specificare la capacità di ingresso per inizializzare il portachiavi gerarchico con la cache predefinita. Per personalizzazioni più granulari della cache, usa la cache. StormTracking

    MultiThreaded

    La MultiThreaded cache è sicura da usare in ambienti multithread, ma non fornisce alcuna funzionalità per ridurre al minimo AWS KMS le chiamate Amazon DynamoDB. Di conseguenza, quando scade l'immissione di materiali chiave in una filiale, tutti i thread verranno avvisati contemporaneamente. Ciò può comportare più AWS KMS chiamate per aggiornare la cache.

    Per inizializzare il tuo portachiavi Hierarchical con una MultiThreaded cache, specifica i seguenti valori:

    • Capacità di ingresso: limita il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale.

    • Entry Poting Tail Size: definisce il numero di elementi da potare se viene raggiunta la capacità di ingresso.

    C# /.NET
    CacheType multithreadedCache = new CacheType { MultiThreaded = new MultiThreadedCache { EntryCapacity = 100, EntryPruningTailSize = 1 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .build())
    StormTracking

    La StormTracking cache è progettata per supportare ambienti con molti multithread. Quando una voce relativa ai materiali delle chiavi di filiale scade, la StormTracking cache impedisce a più thread di richiamare AWS KMS Amazon DynamoDB notificando in anticipo a un thread che l'immissione dei materiali chiave del ramo sta per scadere. Ciò garantisce che solo un thread invii una richiesta di aggiornamento della cache. AWS KMS

    Per inizializzare il tuo portachiavi Hierarchical con una StormTracking cache, specifica i seguenti valori:

    • Capacità di ingresso: limita il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale.

    • Dimensione della coda di potatura d'ingresso: definisce il numero di materiali chiave del ramo da potare alla volta.

      Valore predefinito: 1 voce

    • Periodo di tolleranza: definisce il numero di secondi prima della scadenza in cui viene effettuato un tentativo di aggiornare i materiali chiave della filiale.

      Valore predefinito: 10 secondi

    • Intervallo di grazia: definisce il numero di secondi tra i tentativi di aggiornamento dei materiali chiave del ramo.

      Valore predefinito: 1 secondo

    • Fan out: definisce il numero di tentativi simultanei che è possibile effettuare per aggiornare i materiali chiave della filiale.

      Valore predefinito: 20 tentativi

    • In flight time to live (TTL): definisce il numero di secondi che mancano al timeout di un tentativo di aggiornamento dei materiali chiave della filiale. Ogni volta che la cache ritorna NoSuchEntry in risposta a unaGetCacheEntry, quella chiave di ramo viene considerata in esecuzione finché la stessa chiave non viene scritta con una PutCache voce.

      Valore predefinito: 20 secondi

    • Sospensione: definisce il numero di secondi in cui un thread deve essere sospeso se fanOut viene superato il limite.

      Valore predefinito: 20 millisecondi

    C#/.NET
    CacheType stormTrackingCache = new CacheType { StormTracking = new StormTrackingCache { EntryCapacity = 100, EntryPruningTailSize = 1, FanOut = 20, GraceInterval = 1, GracePeriod = 10, InFlightTTL = 20, SleepMilli = 20 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .gracePeriod(10) .graceInterval(1) .fanOut(20) .inFlightTTL(20) .sleepMilli(20) .build())
  • (Facoltativo) Un elenco di token di concessione

    Se controlli l'accesso alla chiave KMS nel tuo portachiavi gerarchico con le concessioni, devi fornire tutti i token di concessione necessari quando inizializzi il portachiavi.

L'esempio seguente inizializza un portachiavi Hierarchical con un TLL limite di cache di 600 secondi e una capacità di ingresso di 1000.

C# / .NET
// Instantiate the AWS Encryption SDK and material providers var mpl = new MaterialProviders(new MaterialProvidersConfig()); var esdk = new ESDK(new AwsEncryptionSdkConfig()); // Instantiate the keyring var createKeyringInput = new CreateAwsKmsHierarchicalKeyringInput { KeyStore = branchKeyStoreName, BranchKeyId = branch-key-id, Cache = new CacheType { Default = new DefaultCache{EntryCapacity = 1000} }, TtlSeconds = 600 };
Java
final MaterialProviders matProv = MaterialProviders.builder() .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) .build(); final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder() .keyStore(branchKeyStoreName) .branchKeyId(branch-key-id) .ttlSeconds(600) .cache(CacheType.builder() //OPTIONAL .Default(DefaultCache.builder() .entryCapacity(1000) .build()) .build(); final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);

Ruota la chiave branch attiva

Può esserci una sola versione attiva per ogni chiave di ramo alla volta. Il portachiavi Hierarchical utilizza in genere ogni versione di chiave branch attiva per soddisfare più richieste. Ma sei tu a controllare la misura in cui le chiavi branch attive vengono riutilizzate e a determinare la frequenza con cui la chiave branch attiva viene ruotata.

Le chiavi branch non vengono utilizzate per crittografare le chiavi di dati in testo semplice. Vengono utilizzate per derivare le chiavi di wrapping univoche che crittografano le chiavi di dati in testo non crittografato. Il processo di derivazione della chiave di wrapping produce una chiave di wrapping unica da 32 byte con 28 byte di casualità. Ciò significa che una chiave branch può derivare più di 79 ottilioni, o 2 96, chiavi di wrapping uniche prima che si verifichi l'usura crittografica. Nonostante questo rischio di esaurimento molto basso, potrebbe essere necessario ruotare le chiavi di filiale attive a causa di norme aziendali o contrattuali o normative governative.

La versione attiva della chiave di filiale rimane attiva finché non viene ruotata. Le versioni precedenti della chiave branch attiva non verranno utilizzate per eseguire operazioni di crittografia e non possono essere utilizzate per derivare nuove chiavi di wrapping. Tuttavia, possono comunque essere interrogate e fornire chiavi di wrapping per decrittografare le chiavi di dati che hanno crittografato mentre erano attive.

Utilizza il servizio di archiviazione delle chiavi per ruotare VersionKey la chiave branch attiva. Quando si ruota la chiave di ramo attiva, viene creata una nuova chiave di ramo per sostituire la versione precedente. Non branch-key-id cambia quando si ruota la chiave di ramo attiva. È necessario specificare la chiave branch-key-id che identifica la chiave di ramo attiva corrente quando si chiama. VersionKey

C# / .NET
keystore.VersionKey(new VersionKeyInput{BranchKeyIdentifier = branchKeyId});
Java
keystore.VersionKey( VersionKeyInput.builder() .branchKeyIdentifier("branch-key-id") .build() );

Utilizzo del portachiavi Hierarchical in ambienti multitenant

È possibile utilizzare la gerarchia di chiavi stabilita tra le chiavi branch attive e le relative chiavi di wrapping derivate per supportare ambienti multitenant creando una chiave branch per ogni tenant del proprio ambiente. Il portachiavi Hierarchical crittografa quindi tutti i dati di un determinato tenant con la relativa chiave branch distinta. Ciò consente di isolare i dati del tenant per chiave di filiale.

Ogni tenant ha la propria chiave di filiale definita da un'unica. branch-key-id Può esserci solo una versione attiva di ciascuno branch-key-id alla volta.

Prima di poter inizializzare il portachiavi Hierarchical per l'uso multitenant, è necessario creare una chiave di filiale per ogni tenant e creare un fornitore di ID di chiavi di filiale. Utilizza il fornitore di ID della chiave di filiale per creare un nome descrittivo per facilitare il riconoscimento di branch-key-ids quello corretto per un tenant. branch-key-id Ad esempio, il nome descrittivo consente di fare riferimento a una chiave di filiale come tenant1 invece dib3f61619-4d35-48ad-a275-050f87e15122.

Per le operazioni di decrittografia, è possibile configurare staticamente un singolo portachiavi gerarchico per limitare la decrittografia a un singolo tenant, oppure è possibile utilizzare il fornitore di ID della chiave di filiale per identificare quale tenant è responsabile della decrittografia di un messaggio.

Per prima cosa, segui la Fase 1 e la Fase 2 delle procedure relative ai prerequisiti. Quindi, utilizzate le seguenti procedure per creare una chiave di filiale per ogni tenant, creare un fornitore di ID di chiavi di filiale e inizializzare il portachiavi Hierarchical per l'uso multitenant.

Passaggio 1: crea una chiave di filiale per ogni tenant nel tuo ambiente

Chiama CreateKey per ogni inquilino.

La seguente operazione crea due chiavi di ramo utilizzando la chiave KMS specificata durante la creazione del servizio di archivio chiavi e aggiunge le chiavi di ramo alla tabella DynamoDB creata per fungere da archivio chiavi di filiale. La stessa chiave KMS deve proteggere tutte le chiavi di filiale.

C# / .NET
var branchKeyId1 = keystore.CreateKey(new CreateKeyInput()); var branchKeyId2 = keystore.CreateKey(new CreateKeyInput());
Java
CreateKeyOutput branchKeyId1 = keystore.CreateKey(CreateKeyInput.builder().build()); CreateKeyOutput branchKeyId2 = keystore.CreateKey(CreateKeyInput.builder().build());
Fase 2: Creare un fornitore di chiavi di filiale (ID)

L'esempio seguente crea un fornitore di ID chiave di filiale.

C# / .NET
var branchKeySupplier = new ExampleBranchKeySupplier(branchKeyId1.BranchKeyIdentifier, branchKeyId2.BranchKeyIdentifier);
Java
IBranchKeyIdSupplier branchKeyIdSupplier = new ExampleBranchKeyIdSupplier( branchKeyId1.branchKeyIdentifier(), branchKeyId2.branchKeyIdentifier());
Passaggio 3: inizializza il tuo portachiavi gerarchico con il fornitore dell'ID della chiave di filiale

Per inizializzare il portachiavi gerarchico è necessario fornire i seguenti valori:

  • Il nome di un archivio di chiavi della filiale

  • Un limite di durata della cache (TTL)

  • Un fornitore di codici identificativi per filiali

  • (Facoltativo) Una cache

    Se desideri personalizzare il tipo di cache o il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale, specifica il tipo di cache e la capacità di accesso quando inizializzi il portachiavi.

    Il tipo di cache definisce il modello di threading. Il portachiavi Hierarchical fornisce tre tipi di cache che supportano ambienti multitenant: Default,,. MultiThreaded StormTracking

    Se non si specifica una cache, il portachiavi Hierarchical utilizza automaticamente il tipo di cache predefinito e imposta la capacità di ingresso su 1000.

    Default (Recommended)

    Per la maggior parte degli utenti, la cache predefinita soddisfa i requisiti di threading. La cache predefinita è progettata per supportare ambienti con molti multithread. Quando scade l'immissione di materiali relativi a una chiave di filiale, la cache predefinita impedisce la chiamata a più thread AWS KMS e Amazon DynamoDB notificando a un thread che l'immissione dei materiali chiave del ramo sta per scadere con 10 secondi di anticipo. Ciò garantisce che solo un thread invii una richiesta di aggiornamento della cache. AWS KMS

    Per inizializzare il tuo portachiavi gerarchico con una cache predefinita, specifica il seguente valore:

    • Capacità di accesso: limita il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale.

    C# /.NET
    CacheType defaultCache = new CacheType { Default = new DefaultCache{EntryCapacity = 100} };
    Java
    .cache(CacheType.builder() .Default(DefaultCache.builder() .entryCapacity(100) .build())

    Il valore predefinito e le StormTracking cache supportano lo stesso modello di threading, ma è sufficiente specificare la capacità di ingresso per inizializzare il portachiavi gerarchico con la cache predefinita. Per personalizzazioni più granulari della cache, usa la cache. StormTracking

    MultiThreaded

    La MultiThreaded cache è sicura da usare in ambienti multithread, ma non fornisce alcuna funzionalità per ridurre al minimo AWS KMS le chiamate Amazon DynamoDB. Di conseguenza, quando scade l'immissione di materiali chiave in una filiale, tutti i thread verranno avvisati contemporaneamente. Ciò può comportare più AWS KMS chiamate per aggiornare la cache.

    Per inizializzare il tuo portachiavi Hierarchical con una MultiThreaded cache, specifica i seguenti valori:

    • Capacità di ingresso: limita il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale.

    • Entry Poting Tail Size: definisce il numero di elementi da potare se viene raggiunta la capacità di ingresso.

    C# /.NET
    CacheType multithreadedCache = new CacheType { MultiThreaded = new MultiThreadedCache { EntryCapacity = 100, EntryPruningTailSize = 1 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .build())
    StormTracking

    La StormTracking cache è progettata per supportare ambienti con molti multithread. Quando l'immissione di materiali chiave di filiale scade, la StormTracking cache impedisce a più thread di richiamare AWS KMS Amazon DynamoDB notificando in anticipo a un thread che l'immissione dei materiali chiave del ramo sta per scadere. Ciò garantisce che solo un thread invii una richiesta di aggiornamento della cache. AWS KMS

    Per inizializzare il tuo portachiavi Hierarchical con una StormTracking cache, specifica i seguenti valori:

    • Capacità di ingresso: limita il numero di voci relative ai materiali chiave della filiale che possono essere archiviate nella cache locale.

    • Dimensione della coda di potatura d'ingresso: definisce il numero di materiali chiave del ramo da potare alla volta.

      Valore predefinito: 1 voce

    • Periodo di tolleranza: definisce il numero di secondi prima della scadenza in cui viene effettuato un tentativo di aggiornare i materiali chiave della filiale.

      Valore predefinito: 10 secondi

    • Intervallo di grazia: definisce il numero di secondi tra i tentativi di aggiornamento dei materiali chiave del ramo.

      Valore predefinito: 1 secondo

    • Fan out: definisce il numero di tentativi simultanei che è possibile effettuare per aggiornare i materiali chiave della filiale.

      Valore predefinito: 20 tentativi

    • In flight time to live (TTL): definisce il numero di secondi che mancano al timeout di un tentativo di aggiornamento dei materiali chiave della filiale. Ogni volta che la cache ritorna NoSuchEntry in risposta a unaGetCacheEntry, quella chiave di ramo viene considerata in esecuzione finché la stessa chiave non viene scritta con una PutCache voce.

      Valore predefinito: 20 secondi

    • Sospensione: definisce il numero di secondi in cui un thread deve essere sospeso se fanOut viene superato il limite.

      Valore predefinito: 20 millisecondi

    C#/.NET
    CacheType stormTrackingCache = new CacheType { StormTracking = new StormTrackingCache { EntryCapacity = 100, EntryPruningTailSize = 1, FanOut = 20, GraceInterval = 1, GracePeriod = 10, InFlightTTL = 20, SleepMilli = 20 } };
    Java
    .cache(CacheType.builder() .MultiThreaded(MultiThreadedCache.builder() .entryCapacity(100) .entryPruningTailSize(1) .gracePeriod(10) .graceInterval(1) .fanOut(20) .inFlightTTL(20) .sleepMilli(20) .build())
  • (Facoltativo) Un elenco di token di concessione

    Se controlli l'accesso alla chiave KMS nel tuo portachiavi gerarchico con le concessioni, devi fornire tutti i token di concessione necessari quando inizializzi il portachiavi.

L'esempio seguente inizializza un portachiavi Hierarchical con il branch key ID supplier creato nel passaggio 2, un TLL con limite di cache di 600 secondi e una capacità di ingresso di 1000.

C# / .NET
var createKeyringInput = new CreateAwsKmsHierarchicalKeyringInput { KeyStore = keystore, BranchKeyIdSupplier = branchKeySupplier, Cache = new CacheType { Default = new DefaultCache{EntryCapacity = 1000} }, TtlSeconds = 600 }; var keyring = mpl.CreateAwsKmsHierarchicalKeyring(createKeyringInput);
Java
final MaterialProviders matProv = MaterialProviders.builder() .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) .build(); final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder() .keyStore(branchKeyStoreName) .branchKeyIdSupplier(branchKeyIdSupplier) .ttlSeconds(600) .cache(CacheType.builder() //OPTIONAL .Default(DefaultCache.builder() .entryCapacity(100) .build()) .build(); final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
Passaggio 4: Creare nomi descrittivi per ogni chiave di filiale

L'esempio seguente crea nomi descrittivi per le due chiavi di ramo create nel passaggio 1. AWS Encryption SDKUtilizza contesti di crittografia per mappare il nome descrittivo definito dall'utente a quello associatobranch-key-id.

C# / .NET
// Create encryption contexts for the two branch keys created in Step 1 var encryptionContextA = new Dictionary<string, string>() { // We will encrypt with branchKeyTenantA {"tenant", "TenantA"}, {"encryption", "context"}, {"is not", "secret"}, {"but adds", "useful metadata"}, {"that can help you", "be confident that"}, {"the data you are handling", "is what you think it is"} }; var encryptionContextB = new Dictionary<string, string>() { // We will encrypt with branchKeyTenantB {"tenant", "TenantB"}, {"encryption", "context"}, {"is not", "secret"}, {"but adds", "useful metadata"}, {"that can help you", "be confident that"}, {"the data you are handling", "is what you think it is"} }; // Instantiate the AWS Encryption SDK var esdk = new ESDK(new AwsEncryptionSdkConfig()); var encryptInputA = new EncryptInput { Plaintext = plaintext, Keyring = keyring, // Encrypt with branchKeyId1 EncryptionContext = encryptionContextA }; var encryptInputB = new EncryptInput { Plaintext = plaintext, Keyring = keyring, // Encrypt with branchKeyId2 EncryptionContext = encryptionContextB }; var encryptOutput = esdk.Encrypt(encryptInputA); encryptOutput = esdk.Encrypt(encryptInputB); // Use the encryption contexts to define friendly names for each branch key public class ExampleBranchKeySupplier : IBranchKeyIdSupplier { private string branchKeyTenantA; private string branchKeyTenantB; public ExampleBranchKeySupplier(string branchKeyTenantA, string branchKeyTenantB) { this.branchKeyTenantA = branchKeyTenantA; this.branchKeyTenantB = branchKeyTenantB; } public GetBranchKeyIdOutput GetBranchKeyId(GetBranchKeyIdInput input) { Dictionary<string, string> encryptionContext = input.EncryptionContext; if (!encryptionContext.ContainsKey("tenant")) { throw new Exception("EncryptionContext invalid, does not contain expected tenant key value pair."); } string tenant = encryptionContext["tenant"]; string branchkeyId; if (tenant.Equals("TenantA")) { GetBranchKeyIdOutput output = new GetBranchKeyIdOutput(); output.BranchKeyId = branchKeyTenantA; return output; } else if (tenant.Equals("TenantB")) { GetBranchKeyIdOutput output = new GetBranchKeyIdOutput(); output.BranchKeyId = branchKeyTenantB; return output; } else { throw new Exception("Item does not have a valid tenantID."); } } }
Java
// Create encryption context for branchKeyTenantA Map<String, String> encryptionContextA = new HashMap<>(); encryptionContextA.put("tenant", "TenantA"); encryptionContextA.put("encryption", "context"); encryptionContextA.put("is not", "secret"); encryptionContextA.put("but adds", "useful metadata"); encryptionContextA.put("that can help you", "be confident that"); encryptionContextA.put("the data you are handling", "is what you think it is"); // Create encryption context for branchKeyTenantB Map<String, String> encryptionContextB = new HashMap<>(); encryptionContextB.put("tenant", "TenantB"); encryptionContextB.put("encryption", "context"); encryptionContextB.put("is not", "secret"); encryptionContextB.put("but adds", "useful metadata"); encryptionContextB.put("that can help you", "be confident that"); encryptionContextB.put("the data you are handling", "is what you think it is"); // Instantiate the AWS Encryption SDK final AwsCrypto crypto = AwsCrypto.builder().build(); final CryptoResult<byte[], ?> encryptResultA = crypto.encryptData(keyring, plaintext, encryptionContextA); final CryptoResult<byte[], ?> encryptResultB = crypto.encryptData(keyring, plaintext, encryptionContextB); // Use the encryption contexts to define friendly names for each branch key public class ExampleBranchKeyIdSupplier implements IBranchKeyIdSupplier { private static String branchKeyIdForTenantA; private static String branchKeyIdForTenantB; public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) { this.branchKeyIdForTenantA = tenant1Id; this.branchKeyIdForTenantB = tenant2Id; } @Override public GetBranchKeyIdOutput GetBranchKeyId(GetBranchKeyIdInput input) { Map<String, String> encryptionContext = input.encryptionContext(); if (!encryptionContext.containsKey("tenant")) { throw new IllegalArgumentException("EncryptionContext invalid, does not contain expected tenant key value pair."); } String tenantKeyId = encryptionContext.get("tenant"); String branchKeyId; if (tenantKeyId.equals("TenantA")) { branchKeyId = branchKeyIdForTenantA; } else if (tenantKeyId.equals("TenantB")) { branchKeyId = branchKeyIdForTenantB; } else { throw new IllegalArgumentException("Item does not contain valid tenant ID"); } return GetBranchKeyIdOutput.builder().branchKeyId(branchKeyId).build(); } }