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]

Reply via email to