Skip to content

Commit

Permalink
[PLAT-16211] [PLAT-16218] [PLAT-16222] [PLAT-16215] Add support for c…
Browse files Browse the repository at this point in the history
…reating CipherTrust KMS config

Summary:
This diff addresses the following tickets:
1. [PLAT-16211] Added support for creating a CipherTrust KMS config.
2. [PLAT-16218] Add support for refresh token auth flow for CipherTrust KMS.
3. [PLAT-16222] Add validation for CipherTrust KMS.
4. [PLAT-16215] Hide the CipherTrust KMS feature behind a runtime config.

Runtime config: `yb.kms.allow_ciphertrust`.

Sample request:
```
curl --location 'http://localhost:9000/api/v1/customers/<CUSTOMER_UUID>/kms_configs/CIPHERTRUST' \
--header 'Content-Type: application/json' \
--header 'X-AUTH-YW-API-TOKEN: <AUTH_TOKEN>' \
--data '{
    "name": "ct1",
    "CIPHERTRUST_MANAGER_URL": "<CT_MANAGER_URL>",
    "REFRESH_TOKEN": "<REFRESH_TOKEN>",
    "KEY_ALGORITHM": "AES",
    "KEY_SIZE": 256,
    "KEY_NAME": "testkey4"
}'
```

Case 1:
If a key with the name `testkey4` already exists on the ciphertrust manager, we just validate it and reuse the key in the KMS config. We do a test encrypt and decrypt for a small random text.

Case 2:
If a key with the given name doesn't already exist on the ciphertrust manager, we will create it on the ciphertrust manager and use that in the KMS config.

For both the above cases, we will update the local auth config object with the correct details as on the ciphertrust manager.

Test Plan:
Manually tested multiple flows:
1. Create KMS config without pre-existing key on CT manager console.
2. Create KMS config with pre-existing key on CT manager console.
3. Create a KMS config with pre-existing key on CT manager console, but with different key algorithm and key size in the API. (Ensured the correct details are updated locally)

Will add UTs in a separate ticket.
Run UTs.
Run itests.

Reviewers: vkumar

Reviewed By: vkumar

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D41358
  • Loading branch information
Sahith02 committed Jan 27, 2025
1 parent 0290143 commit 17d8237
Show file tree
Hide file tree
Showing 11 changed files with 736 additions and 4 deletions.
2 changes: 2 additions & 0 deletions managed/src/main/java/MainModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import com.yugabyte.yw.common.ha.PlatformReplicationManager;
import com.yugabyte.yw.common.inject.StaticInjectorHolder;
import com.yugabyte.yw.common.kms.EncryptionAtRestManager;
import com.yugabyte.yw.common.kms.util.CiphertrustEARServiceUtil;
import com.yugabyte.yw.common.kms.util.EncryptionAtRestUniverseKeyCache;
import com.yugabyte.yw.common.kms.util.GcpEARServiceUtil;
import com.yugabyte.yw.common.metrics.PlatformMetricsProcessor;
Expand Down Expand Up @@ -227,6 +228,7 @@ public void configure() {
bind(PlatformScheduler.class).asEagerSingleton();
bind(AccessKeyRotationUtil.class).asEagerSingleton();
bind(GcpEARServiceUtil.class).asEagerSingleton();
bind(CiphertrustEARServiceUtil.class).asEagerSingleton();
bind(YbcUpgrade.class).asEagerSingleton();
bind(XClusterScheduler.class).asEagerSingleton();
bind(PerfAdvisorScheduler.class).asEagerSingleton();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,14 @@ public class GlobalConfKeys extends RuntimeConfigKeysModule {
"Default refresh interval for the KMS providers.",
ConfDataType.DurationType,
ImmutableList.of(ConfKeyTags.PUBLIC));
public static final ConfKeyInfo<Boolean> kmsAllowCiphertrust =
new ConfKeyInfo<>(
"yb.kms.allow_ciphertrust",
ScopeType.GLOBAL,
"Allow CipherTrust KMS",
"Allow the usage of CipherTrust KMS.",
ConfDataType.BooleanType,
ImmutableList.of(ConfKeyTags.INTERNAL));
// TODO() Add metadata
public static final ConfKeyInfo<Boolean> startMasterOnStopNode =
new ConfKeyInfo<>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2025 YugaByte, Inc. and Contributors
*
* Licensed under the Polyform Free Trial License 1.0.0 (the "License"); you
* may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* https://github.com/YugaByte/yugabyte-db/blob/master/licenses/
* POLYFORM-FREE-TRIAL-LICENSE-1.0.0.txt
*/

package com.yugabyte.yw.common.kms.algorithms;

import java.util.Arrays;
import java.util.List;

public enum CipherTrustAlgorithm implements SupportedAlgorithmInterface {
AES(Arrays.asList(128, 192, 256));

private final List<Integer> keySizes;

public List<Integer> getKeySizes() {
return this.keySizes;
}

CipherTrustAlgorithm(List<Integer> keySizes) {
this.keySizes = keySizes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.yugabyte.yw.common.kms.services;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yugabyte.yw.common.config.RuntimeConfGetter;
import com.yugabyte.yw.common.kms.algorithms.CipherTrustAlgorithm;
import com.yugabyte.yw.common.kms.util.CiphertrustEARServiceUtil;
import com.yugabyte.yw.common.kms.util.CiphertrustEARServiceUtil.CipherTrustKmsAuthConfigField;
import com.yugabyte.yw.common.kms.util.CiphertrustManagerClient;
import com.yugabyte.yw.common.kms.util.KeyProvider;
import com.yugabyte.yw.forms.EncryptionAtRestConfig;
import com.yugabyte.yw.models.KmsConfig;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CiphertrustEARService extends EncryptionAtRestService<CipherTrustAlgorithm> {
public static final int numBytes = 32;

public CiphertrustEARService(RuntimeConfGetter confGetter) {
super(KeyProvider.CIPHERTRUST);
}

public CiphertrustEARServiceUtil getCiphertrustEARServiceUtil() {
return new CiphertrustEARServiceUtil();
}

@Override
protected CipherTrustAlgorithm[] getSupportedAlgorithms() {
return CipherTrustAlgorithm.values();
}

@Override
protected ObjectNode createAuthConfigWithService(UUID configUUID, ObjectNode config) {
CiphertrustEARServiceUtil ciphertrustEARServiceUtil = getCiphertrustEARServiceUtil();
try {
UUID customerUUID = KmsConfig.getOrBadRequest(configUUID).getCustomerUUID();
CiphertrustManagerClient ciphertrustManagerClient =
ciphertrustEARServiceUtil.getCiphertrustManagerClient(config);

// Check if a key with the given name exists on CipherTrust manager
boolean keyExists = ciphertrustEARServiceUtil.checkifKeyExists(config);
if (keyExists) {
log.info(
"Key already exists on CipherTrust manager. Using the existing key '{}'.",
ciphertrustEARServiceUtil.getConfigFieldValue(
config, CipherTrustKmsAuthConfigField.KEY_NAME.fieldName));
} else {
log.info(
"Key does not exist on CipherTrust manager. Creating a new key '{}'.",
ciphertrustEARServiceUtil.getConfigFieldValue(
config, CipherTrustKmsAuthConfigField.KEY_NAME.fieldName));
// Create a new key on CipherTrust manager.
String newKeyName = ciphertrustEARServiceUtil.createKey(config);
}

// Update the authConfig with the correct key details.
ciphertrustEARServiceUtil.updateAuthConfigFromKeyDetails(config);
UpdateAuthConfigProperties(customerUUID, configUUID, config);
log.info(
"Updated authConfig from key details for CipherTrust KMS configUUID '{}'.", configUUID);

// Test the encryption and decryption of a random key for the KMS config key.
ciphertrustEARServiceUtil.testEncryptAndDecrypt(config);
log.info(
"Successfully tested encryption and decryption of a random key for CipherTrust KMS"
+ " configUUID '{}'.",
configUUID.toString());

return config;
} catch (Exception e) {
final String errMsg =
String.format(
"Error attempting to create or retrieve Key in CIPHERTRUST KMS with config %s.",
configUUID.toString());
LOG.error(errMsg, e);
return null;
}
// return config;
}

@Override
protected byte[] createKeyWithService(
UUID universeUUID, UUID configUUID, EncryptionAtRestConfig config) {
return null;
}

@Override
protected byte[] rotateKeyWithService(
UUID universeUUID, UUID configUUID, EncryptionAtRestConfig config) {
return null;
}

@Override
public byte[] retrieveKeyWithService(UUID configUUID, byte[] keyRef) {
return null;
}

@Override
public byte[] encryptKeyWithService(UUID configUUID, byte[] universeKey) {
return null;
}

@Override
protected byte[] validateRetrieveKeyWithService(
UUID configUUID, byte[] keyRef, ObjectNode authConfig) {
return null;
}

@Override
public void refreshKmsWithService(UUID configUUID, ObjectNode authConfig) {
// TODO: Implement this method.
}

@Override
public ObjectNode getKeyMetadata(UUID configUUID) {
return null;
}
}
Loading

0 comments on commit 17d8237

Please sign in to comment.