This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 20c1b0a7a98 [feature](tde) Support rotating root key command (#55901)
20c1b0a7a98 is described below

commit 20c1b0a7a98eb5ede2bf420ebc607c90e4518bd6
Author: Siyang Tang <[email protected]>
AuthorDate: Fri Sep 12 10:45:47 2025 +0800

    [feature](tde) Support rotating root key command (#55901)
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |  2 +
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  7 +++
 .../doris/encryption/KeyManagerInterface.java      |  8 +++
 .../org/apache/doris/encryption/RootKeyInfo.java   | 35 ++++++++++-
 .../doris/nereids/parser/LogicalPlanBuilder.java   |  8 +++
 .../apache/doris/nereids/trees/plans/PlanType.java |  1 +
 .../commands/AdminRotateTdeRootKeyCommand.java     | 69 ++++++++++++++++++++++
 .../doris/nereids/parser/NereidsParserTest.java    | 17 ++++++
 8 files changed, 146 insertions(+), 1 deletion(-)

diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index 3ac6f9c4460..06c6ac6a082 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -466,6 +466,7 @@ ROLES: 'ROLES';
 ROLLBACK: 'ROLLBACK';
 ROLLUP: 'ROLLUP';
 ROOT: 'ROOT';
+ROTATE: 'ROTATE';
 ROUTINE: 'ROUTINE';
 ROW: 'ROW';
 ROWS: 'ROWS';
@@ -520,6 +521,7 @@ TABLETS: 'TABLETS';
 TAG: 'TAG';
 TASK: 'TASK';
 TASKS: 'TASKS';
+TDE: 'TDE';
 TEMPORARY: 'TEMPORARY';
 TERMINATED: 'TERMINATED';
 TEXT: 'TEXT';
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index 1c2c5e52e98..3b81a902670 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -59,6 +59,7 @@ statementBase
     | supportedDropStatement            #supportedDropStatementAlias
     | supportedShowStatement            #supportedShowStatementAlias
     | supportedKillStatement            #supportedKillStatementAlias
+    | supportedAdminStatement           #supportedAdminStatementAlias
     | unsupportedStatement              #unsupported
     ;
 
@@ -502,6 +503,10 @@ unsupportedAdminStatement
     | ADMIN SET TABLE name=multipartIdentifier STATUS 
properties=propertyClause?    #adminSetTableStatus
     ;
 
+supportedAdminStatement
+    : ADMIN ROTATE TDE ROOT KEY properties=propertyClause?                     
     #adminRotateTdeRootKey
+    ;
+
 baseTableRef
     : multipartIdentifier optScanParams? tableSnapshot? specifiedPartition?
         tabletList? tableAlias sample? relationHint?
@@ -2074,6 +2079,7 @@ nonReserved
     | ROLLBACK
     | ROLLUP
     | ROOT
+    | ROTATE
     | ROUTINE
     | S3
     | SAMPLE
@@ -2109,6 +2115,7 @@ nonReserved
     | TAG
     | TASK
     | TASKS
+    | TDE
     | TEMPORARY
     | TEXT
     | THAN
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/encryption/KeyManagerInterface.java 
b/fe/fe-core/src/main/java/org/apache/doris/encryption/KeyManagerInterface.java
index ea0e71e458e..a4c97b53e92 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/encryption/KeyManagerInterface.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/encryption/KeyManagerInterface.java
@@ -20,6 +20,7 @@ package org.apache.doris.encryption;
 import org.apache.doris.persist.KeyOperationInfo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * Interface for managing cryptographic keys, including root key setup,
@@ -64,4 +65,11 @@ public interface KeyManagerInterface {
      *         (may include versioning or metadata as part of each key object)
      */
     public List<EncryptionKey> getAllMasterKeys();
+
+    /**
+     * Rotate root key
+     *
+     * @param properties rotate info
+     */
+    void rotateRootKey(Map<String, String> properties) throws Exception;
 }
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 a379a125707..f056a5a95fe 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
@@ -19,9 +19,42 @@ package org.apache.doris.encryption;
 
 import com.google.gson.annotations.SerializedName;
 
+import java.util.Objects;
+
 public class RootKeyInfo {
     public enum RootKeyType {
-        LOCAL, AWS_KMS;
+        LOCAL("local"),
+        AWS_KMS("aws_kms");
+
+        public static RootKeyType tryFrom(String name) {
+            Objects.requireNonNull(name);
+            if (LOCAL.name.equalsIgnoreCase(name)) {
+                return LOCAL;
+            }
+            if (AWS_KMS.name.equalsIgnoreCase(name)) {
+                return AWS_KMS;
+            }
+            throw new IllegalArgumentException("invalid name" + name);
+        }
+
+        RootKeyType(String name) {
+            this.name = name;
+        }
+
+        String name;
+    }
+
+    public RootKeyInfo() {}
+
+    public RootKeyInfo(RootKeyInfo info) {
+        this.type = info.type;
+        this.algorithm = info.algorithm;
+        this.region = info.region;
+        this.endpoint = info.endpoint;
+        this.cmkId = info.cmkId;
+        this.ak = info.ak;
+        this.sk = info.sk;
+        this.password = info.password;
     }
 
     @SerializedName(value = "type")
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index 1f3ff990004..867dc525683 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -46,6 +46,7 @@ import org.apache.doris.mtmv.MTMVRefreshSchedule;
 import org.apache.doris.mtmv.MTMVRefreshTriggerInfo;
 import org.apache.doris.nereids.DorisParser;
 import org.apache.doris.nereids.DorisParser.AddConstraintContext;
+import org.apache.doris.nereids.DorisParser.AdminRotateTdeRootKeyContext;
 import org.apache.doris.nereids.DorisParser.AdminSetEncryptionRootKeyContext;
 import org.apache.doris.nereids.DorisParser.AggClauseContext;
 import org.apache.doris.nereids.DorisParser.AggStateDataTypeContext;
@@ -342,6 +343,7 @@ import 
org.apache.doris.nereids.trees.plans.algebra.Aggregate;
 import org.apache.doris.nereids.trees.plans.algebra.InlineTable;
 import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier;
 import org.apache.doris.nereids.trees.plans.commands.AddConstraintCommand;
+import 
org.apache.doris.nereids.trees.plans.commands.AdminRotateTdeRootKeyCommand;
 import 
org.apache.doris.nereids.trees.plans.commands.AdminSetEncryptionRootKeyCommand;
 import org.apache.doris.nereids.trees.plans.commands.AlterMTMVCommand;
 import org.apache.doris.nereids.trees.plans.commands.AlterStorageVaultCommand;
@@ -968,6 +970,12 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return new AdminSetEncryptionRootKeyCommand(properties);
     }
 
+    @Override
+    public LogicalPlan visitAdminRotateTdeRootKey(AdminRotateTdeRootKeyContext 
ctx) {
+        Map<String, String> properties = 
visitPropertyClause(ctx.propertyClause());
+        return new AdminRotateTdeRootKeyCommand(properties);
+    }
+
     @Override
     public LogicalPlan visitShowConstraint(ShowConstraintContext ctx) {
         List<String> parts = visitMultipartIdentifier(ctx.table);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
index 1aee0ddbdae..0f2384fe141 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
@@ -179,6 +179,7 @@ public enum PlanType {
     KILL_QUERY_COMMAND,
     KILL_CONNECTION_COMMAND,
     ADMIN_SET_ENCRYPTION_ROOT_KEY_COMMAND,
+    ADMIN_ROTATE_TDE_ROOT_KEY,
     KILL_ANALYZE_JOB_COMMAND,
     DROP_ANALYZE_JOB_COMMAND,
     CREATE_INDEX_ANALYZER_COMMAND,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminRotateTdeRootKeyCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminRotateTdeRootKeyCommand.java
new file mode 100644
index 00000000000..2d2dbbe3996
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AdminRotateTdeRootKeyCommand.java
@@ -0,0 +1,69 @@
+// 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.common.AnalysisException;
+import org.apache.doris.encryption.KeyManagerInterface;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.StmtExecutor;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Rotate TDE root key command
+ */
+public class AdminRotateTdeRootKeyCommand extends Command implements 
ForwardWithSync {
+
+    public static final String DORIS_TDE_KEY_PROVIDER = 
"doris_tde_key_provider";
+
+    public static final String DORIS_TDE_KEY_PASSWORD = 
"doris_tde_key_password";
+
+    public static final String DORIS_TDE_KEY_ORIGINAL_PASSWORD = 
"doris_tde_key_original_password";
+
+    public static final String DORIS_TDE_KEY_ID = "doris_tde_key_id";
+
+    public static final String DORIS_TDE_KEY_ENDPOINT = 
"doris_tde_key_endpoint";
+
+    public static final String DORIS_TDE_KEY_REGION = "doris_tde_key_region";
+
+    private final Map<String, String> properties;
+
+    public AdminRotateTdeRootKeyCommand(Map<String, String> properties) {
+        super(PlanType.ADMIN_ROTATE_TDE_ROOT_KEY);
+        Objects.requireNonNull(properties, "properties are required");
+        this.properties = properties;
+    }
+
+    @Override
+    public void run(ConnectContext ctx, StmtExecutor executor) throws 
Exception {
+        KeyManagerInterface keyManager = ctx.getEnv().getKeyManager();
+        if (keyManager != null) {
+            keyManager.rotateRootKey(properties);
+        } else {
+            throw new AnalysisException("TDE is disabled, cannot rotate root 
key");
+        }
+    }
+
+    @Override
+    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+        return visitor.visitCommand(this, context);
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
index 6d1979092bb..18bce009623 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
@@ -873,4 +873,21 @@ public class NereidsParserTest extends ParserTestBase {
         LogicalPlan logicalPlan = parser.parseSingle(sql);
         Assertions.assertInstanceOf(UnsupportedCommand.class, logicalPlan);
     }
+
+    @Test
+    public void testAdminRotateTdeRootKey() {
+        NereidsParser nereidsParser = new NereidsParser();
+        String sql = "admin rotate tde root key";
+        nereidsParser.parseSingle(sql);
+
+        sql = "admin rotate tde root key properties(\"k\" = \"v\")";
+        nereidsParser.parseSingle(sql);
+
+        sql = "admin rotate tde root key properties(\"k0\" = \"v0\", \"k1\" = 
\"v1\")";
+        nereidsParser.parseSingle(sql);
+
+        parsePlan("admin rotate tde root key properties()")
+                .assertThrowsExactly(ParseException.class)
+                .assertMessageContains("mismatched input ')' expecting");
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to