GridGain Developers Hub

Transparent Data Encryption

Overview

Transparent data encryption (TDE) allows users to encrypt their data at rest.

When Ignite persistence is turned on, encryption can be enabled per cache/table, in which case the following data will be encrypted:

  • Data on disk

  • WAL records

If you enable cache/table encryption, the cluster will generate a key (called cache encryption key) and will use this key to encrypt/decrypt the cache’s data. The cache encryption key is held in the system internal memory and cannot be accessed by users. When the key needs to be sent to other nodes or saved to disk (when the node goes down), it is encrypted using the user-provided key — the master key.

The master key must be specified via the configuration in every server node. One way to ensure you are using the same key is to copy the JKS file from one node to the other nodes. In an attempt to enable TDE, the node, which key is different, will not be able to join the cluster.

The GridGain cluster supports only one implementation of Encryption SPI is KeystorageEncryptionSPI. It uses a JKS file key storage and supports encryption algorithms: "AES/CBC/PKCS5Padding" to encrypt WAL records and "AES/CBC/NoPadding" to encrypt data pages on disk. To learn more about implementation details, see KeystoreEncryptionSpi.

Master Key Generation Example

A keystore with a master key can be created using keytool as follows:

Master Key Generation Example
user:~/tmp:[]$ java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

user:~/tmp:[]$ keytool -genseckey \
-alias ignite.master.key \
-keystore ./ignite_keystore.jks \
-storetype PKCS12 \
-keyalg aes \
-storepass mypassw0rd \
-keysize 256

user:~/tmp:[]$ keytool \
-storepass mypassw0rd \
-storetype PKCS12 \
-keystore ./ignite_keystore.jks \
-list

Keystore type: PKCS12
Keystore provider: SunJSSE

Your keystore contains 1 entry

ignite.master.key, 12.01.2020, SecretKeyEntry,

Configuration

To enable encryption in the cluster, you should determine an Encryption SPI through Ignite configuration and enable encryption at the last one cache that will be encrypted. A configuration example is shown below.

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <!-- We need to configure EncryptionSpi to enable encryption feature. -->
    <property name="encryptionSpi">
        <!-- Using EncryptionSpi implementation based on java keystore. -->
        <bean class="org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi">
            <!-- Path to the keystore file. -->
            <property name="keyStorePath" value="ignite_keystore.jks"/>
            <!-- Password for keystore file. -->
            <property name="keyStorePassword" value="mypassw0rd"/>
            <!-- Name of the key in keystore to be used as a master key. -->
            <property name="masterKeyName" value="ignite.master.key"/>
            <!-- Size of the cache encryption keys in bits. Can be 128, 192, or 256 bits.-->
            <property name="keySize" value="256"/>
        </bean>
    </property>
    <property name="cacheConfiguration">
        <bean class="org.apache.ignite.configuration.CacheConfiguration">
            <property name="name" value="encrypted-cache"/>
            <property name="encryptionEnabled" value="true"/>
        </bean>
    </property>

</bean>
IgniteConfiguration cfg = new IgniteConfiguration();

KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi();

encSpi.setKeyStorePath("/home/user/ignite-keystore.jks");
encSpi.setKeyStorePassword("secret".toCharArray());

cfg.setEncryptionSpi(encSpi);

When the master key is configured, you can enable encryption for a cache as follows:

<property name="cacheConfiguration">
    <bean class="org.apache.ignite.configuration.CacheConfiguration">
        <property name="name" value="encrypted-cache"/>
        <property name="encryptionEnabled" value="true"/>
    </bean>
</property>
CacheConfiguration<Long, String> ccfg = new CacheConfiguration<Long, String>("encrypted-cache");

ccfg.setEncryptionEnabled(true);

ignite.createCache(ccfg);
CREATE TABLE encrypted(
  ID BIGINT,
  NAME VARCHAR(10),
  PRIMARY KEY (ID))
WITH "ENCRYPTED=true";

Source Code Example

Master Key Rotation

Master key rotation is required at the end of the crypto period (key validity period) or if the master key has been compromised.

Prerequisites:

  • A new master key must be available to EncryptionSPI for each server node.

  • The cluster must be active.

Available Interfaces

The GridGain cluster enables you to rotate the master key via the following interfaces:

  • Command-line utility

To start master key rotation:

control.sh --encryption change_master_key newMasterKeyName

To display the cluster’s current master key name:

control.sh --encryption get_master_key_name
  • JMX

To start master key rotation:

changeMasterKey(String masterKeyName)

Get the current master key name:

String getMasterKeyName()
  • Java API

To start master key rotation:

ignite.encryption().changeMasterKey(String masterKeyName)

Get the current master key name:

String ignite.encryption().getMasterKeyName()

Master Key Change Procedure

Each server node performs the following actions:

  1. A node checks that the cluster is active. Otherwise, the process completes with an error.

  2. It verifies that the master key name and digest are the same as those taken from the prepare phase. Otherwise, the process is canceled.

  3. The creation of encrypted group keys is blocked.

  4. All cache group keys are re-encrypted with the new master key in a temporary data structure. No changes in MetaStore are made.

  5. The node creates a WAL logical record (ChangeMasterKeyRecord ) that consist of:

    • New master key name

    • Re-encrypted cache group keys

  6. The node writes cache group keys to MetaStore.

  7. The creation of encrypted group keys is unblocked.

Cache Key Rotation

Cache encryption key rotation is required if the key is compromised or at the end of the crypto period (key validity period). This feature is also needed to provide support for encrypting and decrypting existing caches in the future.

Note that the old keys will no longer be used to write new data to the storage. Reading can be done using the old key.

The process of cache encryption key rotation consists of the following steps:

  1. Rotate cache group key - add a new encryption key on each node and set it for writing.

  2. Schedule background re-encryption for archived data and clean up the old key when it completes.

You can manage the process of cache key rotation (and cache re-encryption) through the command line by executing the following commands:

  • Launch cache key rotation:

control.(sh|bat) --encryption change_cache_key cacheGroupName
  • View key identifiers of the cache group:

control.(sh|bat) --encryption cache_key_ids cacheGroupName
  • View re-encryption status for the cache group:

control.(sh|bat) --encryption reencryption_status cacheGroupName
  • Suspend/resume the cache group re-encryption:

control.(sh|bat) --encryption suspend_reencryption cacheGroupName
  • View/change the re-encryption rate limit:

control.(sh|bat) --encryption reencryption_rate [--limit limit]
Parameters:
limit  - Decimal value to change the re-encryption rate limit (MB/s).

Note: Old cache group encryption key will be removed when:

  • The cache group’s re-encryption process is finished, and then at least one checkpoint is successfully completed as well.

  • The last WAL segment, in which the encryption key was used, is removed.