This is an automated email from the ASF dual-hosted git repository.
Yukang-Lian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 1089bfa95d0 [feat](tde) Add KMS provider metadata (#64561)
1089bfa95d0 is described below
commit 1089bfa95d032d52296151cd88aa531bc0fe6982
Author: Jamie <[email protected]>
AuthorDate: Tue Aug 18 17:16:09 2026 +0800
[feat](tde) Add KMS provider metadata (#64561)
## Proposed changes
- Add public TDE provider identifiers for `aliyun_kms`, `ranger_kms`,
`gcp_kms`, and `azure_kms`.
- Add shared Ranger/Hadoop KMS endpoint and authentication config
placeholders.
- Parse provider and algorithm identifiers locale-independently.
This PR only aligns the public FE metadata/config contract. KMS runtime
implementations, SDKs, and credentials remain outside Apache Doris.
---
.../main/java/org/apache/doris/common/Config.java | 19 +++-
.../org/apache/doris/encryption/RootKeyInfo.java | 19 +++-
.../commands/AdminSetEncryptionRootKeyCommand.java | 5 +-
.../apache/doris/encryption/RootKeyInfoTest.java | 34 +++++++
.../AdminSetEncryptionRootKeyCommandTest.java | 108 +++++++++++++++++++++
5 files changed, 178 insertions(+), 7 deletions(-)
diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
index de7a2a2aefa..b451dac0241 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java
@@ -3575,16 +3575,29 @@ public class Config extends ConfigBase {
+ "data keys")
public static String doris_tde_key_id = "";
- @ConfField(mutable = true, description = "The endpoint of the KMS service,
should match the region of the key")
+ @ConfField(mutable = true, description = "The endpoint of the KMS service.
For cloud KMS, it should match the "
+ + "region of the key. For Ranger KMS, use a Hadoop KMS URI or
HTTP(S) URL.")
public static String doris_tde_key_endpoint = "";
@ConfField(mutable = true, description = "The region where the KMS key is
located, used for SDK configuration")
public static String doris_tde_key_region = "";
- @ConfField(mutable = true, description = "The key provider for TDE
(Transparent Data Encryption), currently "
- + "supports aws_kms")
+ @ConfField(mutable = true, description = "The key provider identifier for
TDE (Transparent Data Encryption). "
+ + "Recognized values include aws_kms, aliyun_kms, ranger_kms,
gcp_kms, and azure_kms.")
public static String doris_tde_key_provider = "";
+ @ConfField(mutable = true, description = "The simple authentication user
name for TDE Hadoop KMS")
+ public static String doris_tde_hadoop_user_name = "hadoop";
+
+ @ConfField(mutable = true, description = "The Kerberos principal for TDE
Hadoop KMS")
+ public static String doris_tde_kerberos_principal = "";
+
+ @ConfField(mutable = true, description = "The Kerberos keytab path for TDE
Hadoop KMS")
+ public static String doris_tde_kerberos_keytab = "";
+
+ @ConfField(mutable = true, description = "The Hadoop XML configuration
directory for TDE Hadoop KMS")
+ public static String doris_tde_hadoop_conf_dir = "";
+
@ConfField(mutable = true, description = "The encryption algorithm used
for data. Default is AES256; may be set "
+ "to empty later for KMS to decide.")
public static String doris_tde_algorithm = "PLAINTEXT";
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/encryption/RootKeyInfo.java
b/fe/fe-core/src/main/java/org/apache/doris/encryption/RootKeyInfo.java
index e2aa248ce2e..d282e2a3eab 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/encryption/RootKeyInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/encryption/RootKeyInfo.java
@@ -24,7 +24,11 @@ import java.util.Objects;
public class RootKeyInfo {
public enum RootKeyType {
LOCAL("local"),
- AWS_KMS("aws_kms");
+ AWS_KMS("aws_kms"),
+ ALIYUN_KMS("aliyun_kms"),
+ RANGER_KMS("ranger_kms"),
+ GCP_KMS("gcp_kms"),
+ AZURE_KMS("azure_kms");
public static RootKeyType tryFrom(String name) {
Objects.requireNonNull(name);
@@ -34,6 +38,18 @@ public class RootKeyInfo {
if (AWS_KMS.name.equalsIgnoreCase(name)) {
return AWS_KMS;
}
+ if (ALIYUN_KMS.name.equalsIgnoreCase(name)) {
+ return ALIYUN_KMS;
+ }
+ if (RANGER_KMS.name.equalsIgnoreCase(name)) {
+ return RANGER_KMS;
+ }
+ if (GCP_KMS.name.equalsIgnoreCase(name)) {
+ return GCP_KMS;
+ }
+ if (AZURE_KMS.name.equalsIgnoreCase(name)) {
+ return AZURE_KMS;
+ }
throw new IllegalArgumentException("invalid name: " + name);
}
@@ -81,4 +97,3 @@ public class RootKeyInfo {
@SerializedName(value = "password")
public String password;
}
-
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommand.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommand.java
index 0e969799c2d..cea5aefc7fc 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommand.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommand.java
@@ -33,6 +33,7 @@ import com.google.common.base.Strings;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
@@ -81,7 +82,7 @@ public class AdminSetEncryptionRootKeyCommand extends Command
implements Forward
throw new AnalysisException("The type field cannot be empty.");
}
try {
- rootKeyInfo.type =
RootKeyInfo.RootKeyType.valueOf(typeValue.toUpperCase());
+ rootKeyInfo.type = RootKeyInfo.RootKeyType.tryFrom(typeValue);
} catch (IllegalArgumentException e) {
throw new AnalysisException("invalid root key type: " + typeValue);
}
@@ -91,7 +92,7 @@ public class AdminSetEncryptionRootKeyCommand extends Command
implements Forward
throw new AnalysisException("The encryption_algorithm field cannot
be empty.");
}
try {
- rootKeyInfo.algorithm =
EncryptionKey.Algorithm.valueOf(encryptionAlgorithmValue.toUpperCase());
+ rootKeyInfo.algorithm =
EncryptionKey.Algorithm.valueOf(encryptionAlgorithmValue.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
throw new AnalysisException("invalid encryption algorithm: " +
encryptionAlgorithmValue);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/encryption/RootKeyInfoTest.java
b/fe/fe-core/src/test/java/org/apache/doris/encryption/RootKeyInfoTest.java
new file mode 100644
index 00000000000..fd9dd89423d
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/encryption/RootKeyInfoTest.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.encryption;
+
+import org.apache.doris.persist.gson.GsonUtils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class RootKeyInfoTest {
+ @Test
+ public void testDeserializeGcpAndAzureKmsTypes() {
+ RootKeyInfo gcpInfo =
GsonUtils.GSON.fromJson("{\"type\":\"GCP_KMS\"}", RootKeyInfo.class);
+ Assertions.assertEquals(RootKeyInfo.RootKeyType.GCP_KMS, gcpInfo.type);
+
+ RootKeyInfo azureInfo =
GsonUtils.GSON.fromJson("{\"type\":\"AZURE_KMS\"}", RootKeyInfo.class);
+ Assertions.assertEquals(RootKeyInfo.RootKeyType.AZURE_KMS,
azureInfo.type);
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommandTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommandTest.java
new file mode 100644
index 00000000000..5c244e9ad5a
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AdminSetEncryptionRootKeyCommandTest.java
@@ -0,0 +1,108 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.commands;
+
+import org.apache.doris.catalog.Env;
+import org.apache.doris.encryption.EncryptionKey;
+import org.apache.doris.encryption.RootKeyInfo;
+import org.apache.doris.mysql.privilege.AccessControllerManager;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.lang.reflect.Field;
+import java.util.Locale;
+
+public class AdminSetEncryptionRootKeyCommandTest {
+ private Env env;
+ private ConnectContext connectContext;
+ private AccessControllerManager accessControllerManager;
+ private MockedStatic<Env> envMockedStatic;
+ private MockedStatic<ConnectContext> ctxMockedStatic;
+
+ @BeforeEach
+ public void setUp() {
+ env = Mockito.mock(Env.class);
+ connectContext = Mockito.mock(ConnectContext.class);
+ accessControllerManager = Mockito.mock(AccessControllerManager.class);
+ envMockedStatic = Mockito.mockStatic(Env.class);
+ ctxMockedStatic = Mockito.mockStatic(ConnectContext.class);
+ envMockedStatic.when(Env::getCurrentEnv).thenReturn(env);
+ ctxMockedStatic.when(ConnectContext::get).thenReturn(connectContext);
+
Mockito.when(env.getAccessManager()).thenReturn(accessControllerManager);
+ Mockito.when(accessControllerManager.checkGlobalPriv(connectContext,
PrivPredicate.ADMIN)).thenReturn(true);
+ }
+
+ @AfterEach
+ public void tearDown() {
+ ctxMockedStatic.close();
+ envMockedStatic.close();
+ }
+
+ @Test
+ public void testValidateAliyunKmsUnderTurkishLocale() throws Exception {
+ Locale originalLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(Locale.forLanguageTag("tr-TR"));
+ AdminSetEncryptionRootKeyCommand command = new
AdminSetEncryptionRootKeyCommand(ImmutableMap.of(
+ AdminSetEncryptionRootKeyCommand.PROPERTIES_TYPE,
"aliyun_kms",
+
AdminSetEncryptionRootKeyCommand.PROPERTIES_ENCRYPTION_ALGORITHM, "aes256",
+ AdminSetEncryptionRootKeyCommand.PROPERTIES_REGION,
"cn-hangzhou",
+ AdminSetEncryptionRootKeyCommand.PROPERTIES_CMK_ID,
"test-cmk"));
+
+ command.validate();
+
+ Assertions.assertEquals(RootKeyInfo.RootKeyType.ALIYUN_KMS,
getRootKeyInfo(command).type);
+ Assertions.assertEquals(EncryptionKey.Algorithm.AES256,
getRootKeyInfo(command).algorithm);
+ } finally {
+ Locale.setDefault(originalLocale);
+ }
+ }
+
+ @Test
+ public void testValidateGcpAndAzureKms() throws Exception {
+ AdminSetEncryptionRootKeyCommand gcpCommand = createCommand("gcp_kms");
+ gcpCommand.validate();
+ Assertions.assertEquals(RootKeyInfo.RootKeyType.GCP_KMS,
getRootKeyInfo(gcpCommand).type);
+
+ AdminSetEncryptionRootKeyCommand azureCommand =
createCommand("azure_kms");
+ azureCommand.validate();
+ Assertions.assertEquals(RootKeyInfo.RootKeyType.AZURE_KMS,
getRootKeyInfo(azureCommand).type);
+ }
+
+ private AdminSetEncryptionRootKeyCommand createCommand(String type) {
+ return new AdminSetEncryptionRootKeyCommand(ImmutableMap.of(
+ AdminSetEncryptionRootKeyCommand.PROPERTIES_TYPE, type,
+
AdminSetEncryptionRootKeyCommand.PROPERTIES_ENCRYPTION_ALGORITHM, "aes256",
+ AdminSetEncryptionRootKeyCommand.PROPERTIES_REGION,
"test-region",
+ AdminSetEncryptionRootKeyCommand.PROPERTIES_CMK_ID,
"test-cmk"));
+ }
+
+ private RootKeyInfo getRootKeyInfo(AdminSetEncryptionRootKeyCommand
command) throws Exception {
+ Field field =
AdminSetEncryptionRootKeyCommand.class.getDeclaredField("rootKeyInfo");
+ field.setAccessible(true);
+ return (RootKeyInfo) field.get(command);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]