diff --git a/hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java b/hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java index 4d382f8d388e..f3aab3c20ad8 100644 --- a/hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java +++ b/hive-metastore/src/main/java/org/apache/iceberg/hive/HiveTableOperations.java @@ -34,6 +34,7 @@ import org.apache.hadoop.hive.metastore.api.Table; import org.apache.iceberg.BaseMetastoreOperations; import org.apache.iceberg.BaseMetastoreTableOperations; +import org.apache.iceberg.CatalogProperties; import org.apache.iceberg.ClientPool; import org.apache.iceberg.LocationProviders; import org.apache.iceberg.TableMetadata; @@ -55,8 +56,9 @@ import org.apache.iceberg.io.FileIO; import org.apache.iceberg.io.LocationProvider; import org.apache.iceberg.relocated.com.google.common.annotations.VisibleForTesting; +import org.apache.iceberg.relocated.com.google.common.base.Preconditions; +import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap; import org.apache.iceberg.relocated.com.google.common.collect.Lists; -import org.apache.iceberg.relocated.com.google.common.collect.Maps; import org.apache.iceberg.util.PropertyUtil; import org.apache.thrift.TException; import org.slf4j.Logger; @@ -146,15 +148,17 @@ public EncryptionManager encryption() { } if (tableKeyId != null) { - if (keyManagementClient == null) { - throw new RuntimeException( - "Cant create encryption manager, because key management client is not set"); - } - - Map encryptionProperties = Maps.newHashMap(); - encryptionProperties.put(TableProperties.ENCRYPTION_TABLE_KEY, tableKeyId); - encryptionProperties.put( - TableProperties.ENCRYPTION_DEK_LENGTH, String.valueOf(encryptionDekLength)); + Preconditions.checkArgument( + keyManagementClient != null, + "Cannot create encryption manager without a key management client. Consider setting the '%s' catalog property", + CatalogProperties.ENCRYPTION_KMS_IMPL); + + Map encryptionProperties = + ImmutableMap.of( + TableProperties.ENCRYPTION_TABLE_KEY, + tableKeyId, + TableProperties.ENCRYPTION_DEK_LENGTH, + String.valueOf(encryptionDekLength)); List keys = Lists.newLinkedList(); encryptedKeysFromMetadata.ifPresent(keys::addAll); @@ -318,17 +322,16 @@ protected void doCommit(TableMetadata base, TableMetadata metadata) { base.properties().keySet().stream() .filter(key -> !metadata.properties().containsKey(key)) .collect(Collectors.toSet()); - } - if (removedProps.contains(TableProperties.ENCRYPTION_TABLE_KEY)) { - throw new IllegalArgumentException("Cannot remove key in encrypted table"); - } + Preconditions.checkArgument( + !removedProps.contains(TableProperties.ENCRYPTION_TABLE_KEY), + "Cannot remove key ID from an encrypted table"); - if (base != null - && !Objects.equals( - base.properties().get(TableProperties.ENCRYPTION_TABLE_KEY), - metadata.properties().get(TableProperties.ENCRYPTION_TABLE_KEY))) { - throw new IllegalArgumentException("Cannot modify key in encrypted table"); + Preconditions.checkArgument( + Objects.equals( + base.properties().get(TableProperties.ENCRYPTION_TABLE_KEY), + metadata.properties().get(TableProperties.ENCRYPTION_TABLE_KEY)), + "Cannot modify key ID of an encrypted table"); } HMSTablePropertyHelper.updateHmsTableForIcebergTable( diff --git a/spark/v4.0/spark/src/test/java/org/apache/iceberg/spark/sql/TestTableEncryption.java b/spark/v4.0/spark/src/test/java/org/apache/iceberg/spark/sql/TestTableEncryption.java index 8f0552a37877..6c7828e1e869 100644 --- a/spark/v4.0/spark/src/test/java/org/apache/iceberg/spark/sql/TestTableEncryption.java +++ b/spark/v4.0/spark/src/test/java/org/apache/iceberg/spark/sql/TestTableEncryption.java @@ -50,6 +50,7 @@ import org.apache.iceberg.spark.SparkCatalogConfig; import org.apache.iceberg.types.Types; import org.apache.parquet.crypto.ParquetCryptoRuntimeException; +import org.apache.spark.SparkException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestTemplate; @@ -166,14 +167,28 @@ public void testInsertAndDelete() { public void testKeyDelete() { assertThatThrownBy( () -> sql("ALTER TABLE %s UNSET TBLPROPERTIES (`encryption.key-id`)", tableName)) - .hasMessageContaining("Cannot remove key in encrypted table"); + .isInstanceOf(SparkException.class) + .hasMessage("Unsupported table change: Cannot remove key ID from an encrypted table"); } @TestTemplate public void testKeyAlter() { assertThatThrownBy( () -> sql("ALTER TABLE %s SET TBLPROPERTIES ('encryption.key-id'='abcd')", tableName)) - .hasMessageContaining("Cannot modify key in encrypted table"); + .isInstanceOf(SparkException.class) + .hasMessage("Unsupported table change: Cannot modify key ID of an encrypted table"); + } + + @TestTemplate + public void testReplaceKeyChange() { + // Replacing a table with a different encryption key is disallowed + assertThatThrownBy( + () -> + sql( + "REPLACE TABLE %s (id bigint) USING iceberg TBLPROPERTIES ('encryption.key-id'='%s')", + tableName, UnitestKMS.MASTER_KEY_NAME2)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Cannot modify key ID of an encrypted table"); } @TestTemplate