This is an automated email from the ASF dual-hosted git repository.
diqiu50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 2d7607f77b [#13353] fix(connector): Declare shared cloud credential
properties on every catalog (#13354)
2d7607f77b is described below
commit 2d7607f77bc15ddd6848cc481907e4546a094b93
Author: MaSai <[email protected]>
AuthorDate: Mon Sep 21 20:28:45 2026 +0800
[#13353] fix(connector): Declare shared cloud credential properties on
every catalog (#13354)
### What changes were proposed in this pull request?
Declare the shared S3, OSS, Azure, GCS, COS, and AWS credential property
entries on every catalog from `BaseCatalogPropertiesMetadata`. A catalog
that already declares a key keeps its own entry.
- Add `AWSPropertiesMetadata` for `aws-access-key-id` (`hidden=false`)
and `aws-secret-access-key` (`hidden=true`). Glue references these
entries. `aws-region`, `aws-glue-catalog-id`, and `aws-glue-endpoint`
stay on the Glue catalog. `aws-region` is required and is not merged
into other catalogs.
- `FallbackPropertiesMetadata` also registers the AWS entries, alongside
the cloud entries it already had. That path is only used when a catalog
does not implement properties metadata for an entity type.
- JDBC `jdbc-user` / `jdbc-password` and Paimon REST/DLF keys stay on
their own catalogs. Engine runtime keys are not registered.
### Why are the changes needed?
Fix: #13353
`HiddenPropertyMaskUtils` fuzzy-masks a key only when the catalog has
not declared it and the name looks sensitive. Glue stores
`aws-access-key-id` (declared, cleartext) and can also have
`s3-access-key-id`. Iceberg already declares `s3-access-key-id` with
`hidden=false`, so the same name was cleartext there and `******` on
Glue. Declaring the shared cloud entries makes those official keys
follow their existing `hidden` flag on every catalog.
### Does this PR introduce _any_ user-facing change?
Catalogs that did not already declare these keys (Glue, JDBC, Kafka,
Model, Hudi, and the generic catalog) now treat the shared cloud keys as
known properties. Keys with `hidden=false` whose names contain words
such as `access`, `token`, or `account` are returned in cleartext
instead of being fuzzy-masked. Secret keys such as
`s3-secret-access-key` stay masked as `******`. No new property is
required. Hive, Iceberg, Paimon, and Fileset already declared the
S3/OSS/Azure/GCS/COS entries; they gain the AWS access-key pair.
### How was this patch tested?
- `./gradlew :core:test --tests
org.apache.gravitino.connector.TestBaseCatalogPropertiesMetadata --tests
org.apache.gravitino.secret.TestSecretPropertyOperationDispatcher
-PskipITs`
- `./gradlew :common:test --tests
org.apache.gravitino.credential.TestCredentialPropertiesUtils -PskipITs`
- `./gradlew :catalogs:catalog-glue:test --tests
org.apache.gravitino.catalog.glue.TestGlueCatalogPropertiesMetadata
-PskipITs`
---------
Co-authored-by: Cursor <[email protected]>
---
.../gravitino/catalog/glue/GlueConstants.java | 11 ++-
.../apache/gravitino/storage/AWSProperties.java | 31 +++++++++
.../fileset/FilesetCatalogPropertiesMetadata.java | 11 ---
.../catalog/fileset/FilesetPropertiesMetadata.java | 12 +---
.../fileset/FilesetSchemaPropertiesMetadata.java | 12 +---
.../TestFilesetCloudPropertiesMetadata.java | 14 ++++
.../glue/GlueCatalogPropertiesMetadata.java | 21 +-----
.../glue/TestGlueCatalogPropertiesMetadata.java | 8 +++
.../hive/HiveCatalogPropertiesMetadata.java | 10 ---
.../iceberg/IcebergCatalogPropertiesMetadata.java | 10 ---
.../paimon/PaimonCatalogPropertiesMetadata.java | 10 ---
.../cloud/storage/AWSPropertiesMetadata.java | 59 ++++++++++++++++
.../cloud/storage/CloudPropertiesMetadata.java | 54 +++++++++++++++
.../connector/BaseCatalogPropertiesMetadata.java | 25 ++++++-
.../secret/FallbackPropertiesMetadata.java | 29 ++++----
.../cloud/storage/TestCloudPropertiesMetadata.java | 39 +++++++++++
.../TestBaseCatalogPropertiesMetadata.java | 80 ++++++++++++++++++++++
.../TestSecretPropertyOperationDispatcher.java | 8 +++
design-docs/gravitino-glue-catalog.md | 18 ++---
19 files changed, 351 insertions(+), 111 deletions(-)
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/glue/GlueConstants.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/glue/GlueConstants.java
index 2cd1f32cf3..7e1c6d4791 100644
---
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/glue/GlueConstants.java
+++
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/glue/GlueConstants.java
@@ -18,6 +18,8 @@
*/
package org.apache.gravitino.catalog.glue;
+import org.apache.gravitino.storage.AWSProperties;
+
/** Constant keys for the AWS Glue Data Catalog connector configuration and
table properties. */
public final class GlueConstants {
@@ -34,11 +36,14 @@ public final class GlueConstants {
*/
public static final String AWS_GLUE_CATALOG_ID = "aws-glue-catalog-id";
- /** AWS access key ID for static credential authentication (optional,
sensitive). */
- public static final String AWS_ACCESS_KEY_ID = "aws-access-key-id";
+ /**
+ * AWS access key ID for static credential authentication (optional, not
hidden). This is an
+ * account identifier, not a secret; {@link #AWS_SECRET_ACCESS_KEY} is the
hidden half.
+ */
+ public static final String AWS_ACCESS_KEY_ID =
AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID;
/** AWS secret access key for static credential authentication (optional,
sensitive). */
- public static final String AWS_SECRET_ACCESS_KEY = "aws-secret-access-key";
+ public static final String AWS_SECRET_ACCESS_KEY =
AWSProperties.GRAVITINO_AWS_SECRET_ACCESS_KEY;
/**
* Custom Glue endpoint URL (optional). Used for VPC endpoints or LocalStack
testing. Example:
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/AWSProperties.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/AWSProperties.java
new file mode 100644
index 0000000000..e42842b4f6
--- /dev/null
+++
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/AWSProperties.java
@@ -0,0 +1,31 @@
+/*
+ * 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.gravitino.storage;
+
+/** Property names for AWS static credentials shared across catalogs. */
+public final class AWSProperties {
+
+ /** AWS access key ID. Not hidden. */
+ public static final String GRAVITINO_AWS_ACCESS_KEY_ID = "aws-access-key-id";
+
+ /** AWS secret access key. Hidden. */
+ public static final String GRAVITINO_AWS_SECRET_ACCESS_KEY =
"aws-secret-access-key";
+
+ private AWSProperties() {}
+}
diff --git
a/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetCatalogPropertiesMetadata.java
b/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetCatalogPropertiesMetadata.java
index b71a3a34ac..346170a276 100644
---
a/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetCatalogPropertiesMetadata.java
+++
b/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetCatalogPropertiesMetadata.java
@@ -33,11 +33,6 @@ import com.google.common.collect.ImmutableMap;
import java.util.Map;
import org.apache.gravitino.catalog.hadoop.fs.FileSystemProvider;
import org.apache.gravitino.catalog.hadoop.fs.LocalFileSystemProvider;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
import org.apache.gravitino.connector.BaseCatalogPropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
@@ -227,12 +222,6 @@ public class FilesetCatalogPropertiesMetadata extends
BaseCatalogPropertiesMetad
// The following two are about authentication.
.putAll(KERBEROS_PROPERTY_ENTRIES)
.putAll(AUTHENTICATION_PROPERTY_ENTRIES)
- // CREDENTIAL_PROPERTY_ENTRIES are registered in
BaseCatalogPropertiesMetadata.
- .putAll(S3PropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(COSPropertiesMetadata.PROPERTY_ENTRIES)
.build();
@Override
diff --git
a/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetPropertiesMetadata.java
b/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetPropertiesMetadata.java
index bc722f5060..8f01268adf 100644
---
a/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetPropertiesMetadata.java
+++
b/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetPropertiesMetadata.java
@@ -28,11 +28,7 @@ import static
org.apache.gravitino.file.Fileset.PROPERTY_SCHEMA_PLACEHOLDER;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
+import org.apache.gravitino.cloud.storage.CloudPropertiesMetadata;
import org.apache.gravitino.connector.BasePropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
@@ -79,11 +75,7 @@ public class FilesetPropertiesMetadata extends
BasePropertiesMetadata {
false /* hidden */))
.putAll(KERBEROS_PROPERTY_ENTRIES)
.putAll(AUTHENTICATION_PROPERTY_ENTRIES)
- .putAll(S3PropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(COSPropertiesMetadata.PROPERTY_ENTRIES);
+ .putAll(CloudPropertiesMetadata.STORAGE_PROPERTY_ENTRIES);
return builder.build();
}
}
diff --git
a/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetSchemaPropertiesMetadata.java
b/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetSchemaPropertiesMetadata.java
index 7515d90556..4cd4d285d3 100644
---
a/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetSchemaPropertiesMetadata.java
+++
b/catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetSchemaPropertiesMetadata.java
@@ -25,11 +25,7 @@ import static
org.apache.gravitino.file.Fileset.PROPERTY_MULTIPLE_LOCATIONS_PREF
import com.google.common.collect.ImmutableMap;
import java.util.Map;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
+import org.apache.gravitino.cloud.storage.CloudPropertiesMetadata;
import org.apache.gravitino.connector.BasePropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
@@ -72,11 +68,7 @@ public class FilesetSchemaPropertiesMetadata extends
BasePropertiesMetadata {
false /* reserved */))
.putAll(KERBEROS_PROPERTY_ENTRIES)
.putAll(AUTHENTICATION_PROPERTY_ENTRIES)
- .putAll(S3PropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(COSPropertiesMetadata.PROPERTY_ENTRIES)
+ .putAll(CloudPropertiesMetadata.STORAGE_PROPERTY_ENTRIES)
.build();
@Override
diff --git
a/catalogs/catalog-fileset/src/test/java/org/apache/gravitino/catalog/fileset/TestFilesetCloudPropertiesMetadata.java
b/catalogs/catalog-fileset/src/test/java/org/apache/gravitino/catalog/fileset/TestFilesetCloudPropertiesMetadata.java
index 515d6849ae..fe20c37d71 100644
---
a/catalogs/catalog-fileset/src/test/java/org/apache/gravitino/catalog/fileset/TestFilesetCloudPropertiesMetadata.java
+++
b/catalogs/catalog-fileset/src/test/java/org/apache/gravitino/catalog/fileset/TestFilesetCloudPropertiesMetadata.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableMap;
import java.util.Map;
import org.apache.gravitino.connector.HiddenPropertyMaskUtils;
import org.apache.gravitino.connector.PropertiesMetadata;
+import org.apache.gravitino.storage.AWSProperties;
import org.apache.gravitino.storage.AzureProperties;
import org.apache.gravitino.storage.COSProperties;
import org.apache.gravitino.storage.GCSProperties;
@@ -89,4 +90,17 @@ public class TestFilesetCloudPropertiesMetadata {
HiddenPropertyMaskUtils.MASKED_VALUE,
response.get(S3Properties.GRAVITINO_S3_SECRET_ACCESS_KEY));
}
+
+ @Test
+ void testAwsAccessKeyIsDeclaredOnlyOnTheFilesetCatalog() {
+ assertTrue(
+ new FilesetCatalogPropertiesMetadata()
+ .containsProperty(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+ assertFalse(
+ new FilesetSchemaPropertiesMetadata()
+ .containsProperty(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+ assertFalse(
+ new FilesetPropertiesMetadata()
+ .containsProperty(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+ }
}
diff --git
a/catalogs/catalog-glue/src/main/java/org/apache/gravitino/catalog/glue/GlueCatalogPropertiesMetadata.java
b/catalogs/catalog-glue/src/main/java/org/apache/gravitino/catalog/glue/GlueCatalogPropertiesMetadata.java
index 1b485374ee..5e3f6ea92e 100644
---
a/catalogs/catalog-glue/src/main/java/org/apache/gravitino/catalog/glue/GlueCatalogPropertiesMetadata.java
+++
b/catalogs/catalog-glue/src/main/java/org/apache/gravitino/catalog/glue/GlueCatalogPropertiesMetadata.java
@@ -33,6 +33,7 @@ import static
org.apache.gravitino.connector.PropertyEntry.stringRequiredPropert
import com.google.common.collect.ImmutableMap;
import java.util.Map;
+import org.apache.gravitino.cloud.storage.AWSPropertiesMetadata;
import org.apache.gravitino.connector.BaseCatalogPropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
@@ -57,24 +58,8 @@ public class GlueCatalogPropertiesMetadata extends
BaseCatalogPropertiesMetadata
true /* immutable */,
null /* defaultValue */,
false /* hidden */))
- .put(
- AWS_ACCESS_KEY_ID,
- stringOptionalPropertyEntry(
- AWS_ACCESS_KEY_ID,
- "AWS access key ID for static credential authentication."
- + " When omitted the default credential chain is used.",
- false /* immutable */,
- null /* defaultValue */,
- false /* hidden */))
- .put(
- AWS_SECRET_ACCESS_KEY,
- stringOptionalPropertyEntry(
- AWS_SECRET_ACCESS_KEY,
- "AWS secret access key paired with aws-access-key-id."
- + " When omitted the default credential chain is used.",
- false /* immutable */,
- null /* defaultValue */,
- true /* hidden */))
+ .put(AWS_ACCESS_KEY_ID, AWSPropertiesMetadata.AWS_ACCESS_KEY_ID)
+ .put(AWS_SECRET_ACCESS_KEY,
AWSPropertiesMetadata.AWS_SECRET_ACCESS_KEY)
.put(
AWS_GLUE_ENDPOINT,
stringOptionalPropertyEntry(
diff --git
a/catalogs/catalog-glue/src/test/java/org/apache/gravitino/catalog/glue/TestGlueCatalogPropertiesMetadata.java
b/catalogs/catalog-glue/src/test/java/org/apache/gravitino/catalog/glue/TestGlueCatalogPropertiesMetadata.java
index 328b02bb0e..eed35fa2fc 100644
---
a/catalogs/catalog-glue/src/test/java/org/apache/gravitino/catalog/glue/TestGlueCatalogPropertiesMetadata.java
+++
b/catalogs/catalog-glue/src/test/java/org/apache/gravitino/catalog/glue/TestGlueCatalogPropertiesMetadata.java
@@ -30,8 +30,10 @@ import static
org.apache.gravitino.catalog.glue.GlueConstants.TABLE_FORMAT_FILTE
import static org.apache.gravitino.catalog.glue.GlueConstants.WAREHOUSE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.apache.gravitino.cloud.storage.AWSPropertiesMetadata;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -76,6 +78,12 @@ class TestGlueCatalogPropertiesMetadata {
// Access key ID is an identifier, same as s3-access-key-id; only the
secret is hidden.
assertFalse(metadata.isHiddenProperty(AWS_ACCESS_KEY_ID));
assertTrue(metadata.isHiddenProperty(AWS_SECRET_ACCESS_KEY));
+ // Same PropertyEntry instances as the shared definition, not a Glue-local
copy.
+ assertSame(
+ AWSPropertiesMetadata.AWS_ACCESS_KEY_ID,
metadata.propertyEntries().get(AWS_ACCESS_KEY_ID));
+ assertSame(
+ AWSPropertiesMetadata.AWS_SECRET_ACCESS_KEY,
+ metadata.propertyEntries().get(AWS_SECRET_ACCESS_KEY));
}
@Test
diff --git
a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMetadata.java
b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMetadata.java
index 889e450ea1..2577bdf944 100644
---
a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMetadata.java
+++
b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogPropertiesMetadata.java
@@ -23,11 +23,6 @@ import static
org.apache.gravitino.catalog.hive.HiveConstants.HIVE_DEFAULT_CATAL
import com.google.common.collect.ImmutableMap;
import java.util.Map;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
import org.apache.gravitino.connector.BaseCatalogPropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
import org.apache.gravitino.hive.ClientPropertiesMetadata;
@@ -128,11 +123,6 @@ public class HiveCatalogPropertiesMetadata extends
BaseCatalogPropertiesMetadata
DEFAULT_LIST_ALL_TABLES,
false /* hidden */,
false /* reserved */))
- .putAll(S3PropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(COSPropertiesMetadata.PROPERTY_ENTRIES)
.putAll(CLIENT_PROPERTIES_METADATA.propertyEntries())
.build();
diff --git
a/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogPropertiesMetadata.java
b/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogPropertiesMetadata.java
index 4383b8672c..407af67a33 100644
---
a/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogPropertiesMetadata.java
+++
b/catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergCatalogPropertiesMetadata.java
@@ -29,11 +29,6 @@ import com.google.common.collect.Maps;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
import org.apache.gravitino.connector.BaseCatalogPropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
import org.apache.gravitino.iceberg.common.authentication.AuthenticationConfig;
@@ -140,11 +135,6 @@ public class IcebergCatalogPropertiesMetadata extends
BaseCatalogPropertiesMetad
false /* hidden */));
HashMap<String, PropertyEntry<?>> result = Maps.newHashMap();
result.putAll(Maps.uniqueIndex(propertyEntries, PropertyEntry::getName));
- result.putAll(S3PropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(COSPropertiesMetadata.PROPERTY_ENTRIES);
result.putAll(KerberosConfig.KERBEROS_PROPERTY_ENTRIES);
result.putAll(AuthenticationConfig.AUTHENTICATION_PROPERTY_ENTRIES);
PROPERTIES_METADATA = ImmutableMap.copyOf(result);
diff --git
a/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalogPropertiesMetadata.java
b/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalogPropertiesMetadata.java
index 5398d71d3b..2092d53ced 100644
---
a/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalogPropertiesMetadata.java
+++
b/catalogs/catalog-lakehouse-paimon/src/main/java/org/apache/gravitino/catalog/lakehouse/paimon/PaimonCatalogPropertiesMetadata.java
@@ -32,11 +32,6 @@ import java.util.Map;
import
org.apache.gravitino.catalog.lakehouse.paimon.authentication.AuthenticationConfig;
import
org.apache.gravitino.catalog.lakehouse.paimon.authentication.kerberos.KerberosConfig;
import org.apache.gravitino.catalog.lakehouse.paimon.utils.CatalogUtils;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
import org.apache.gravitino.connector.BaseCatalogPropertiesMetadata;
import org.apache.gravitino.connector.PropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
@@ -217,11 +212,6 @@ public class PaimonCatalogPropertiesMetadata extends
BaseCatalogPropertiesMetada
result.putAll(Maps.uniqueIndex(propertyEntries, PropertyEntry::getName));
result.putAll(KerberosConfig.KERBEROS_PROPERTY_ENTRIES);
result.putAll(AuthenticationConfig.AUTHENTICATION_PROPERTY_ENTRIES);
- result.putAll(S3PropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES);
- result.putAll(COSPropertiesMetadata.PROPERTY_ENTRIES);
result.putAll(REST_PROPERTY_ENTRIES);
PROPERTIES_METADATA = ImmutableMap.copyOf(result);
}
diff --git
a/core/src/main/java/org/apache/gravitino/cloud/storage/AWSPropertiesMetadata.java
b/core/src/main/java/org/apache/gravitino/cloud/storage/AWSPropertiesMetadata.java
new file mode 100644
index 0000000000..4c8cb94df4
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/cloud/storage/AWSPropertiesMetadata.java
@@ -0,0 +1,59 @@
+/*
+ * 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.gravitino.cloud.storage;
+
+import static
org.apache.gravitino.connector.PropertyEntry.stringOptionalPropertyEntry;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.apache.gravitino.connector.PropertyEntry;
+import org.apache.gravitino.storage.AWSProperties;
+
+/** Shared AWS credential {@link PropertyEntry} definitions for catalog
properties metadata. */
+public final class AWSPropertiesMetadata {
+
+ /** AWS access key ID. Not hidden. */
+ public static final PropertyEntry<String> AWS_ACCESS_KEY_ID =
+ stringOptionalPropertyEntry(
+ AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID,
+ "AWS access key ID for static credential authentication."
+ + " When omitted the default credential chain is used.",
+ false /* immutable */,
+ null /* defaultValue */,
+ false /* hidden */);
+
+ /** AWS secret access key. Hidden. */
+ public static final PropertyEntry<String> AWS_SECRET_ACCESS_KEY =
+ stringOptionalPropertyEntry(
+ AWSProperties.GRAVITINO_AWS_SECRET_ACCESS_KEY,
+ "AWS secret access key paired with aws-access-key-id."
+ + " When omitted the default credential chain is used.",
+ false /* immutable */,
+ null /* defaultValue */,
+ true /* hidden */);
+
+ /** AWS credential keys merged into every catalog's properties metadata. */
+ public static final Map<String, PropertyEntry<?>> PROPERTY_ENTRIES =
+ ImmutableMap.<String, PropertyEntry<?>>builder()
+ .put(AWS_ACCESS_KEY_ID.getName(), AWS_ACCESS_KEY_ID)
+ .put(AWS_SECRET_ACCESS_KEY.getName(), AWS_SECRET_ACCESS_KEY)
+ .build();
+
+ private AWSPropertiesMetadata() {}
+}
diff --git
a/core/src/main/java/org/apache/gravitino/cloud/storage/CloudPropertiesMetadata.java
b/core/src/main/java/org/apache/gravitino/cloud/storage/CloudPropertiesMetadata.java
new file mode 100644
index 0000000000..384ef4ed76
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/cloud/storage/CloudPropertiesMetadata.java
@@ -0,0 +1,54 @@
+/*
+ * 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.gravitino.cloud.storage;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.apache.gravitino.connector.PropertyEntry;
+
+/**
+ * Combined cloud {@link PropertyEntry} maps so callers do not repeat the same
{@code putAll} list.
+ */
+public final class CloudPropertiesMetadata {
+
+ /**
+ * S3, OSS, Azure, GCS, and COS entries. Fileset and schema metadata use
this set. It does not
+ * include the AWS access-key pair, which is a Glue catalog property.
+ */
+ public static final Map<String, PropertyEntry<?>> STORAGE_PROPERTY_ENTRIES =
+ ImmutableMap.<String, PropertyEntry<?>>builder()
+ .putAll(S3PropertiesMetadata.PROPERTY_ENTRIES)
+ .putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES)
+ .putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES)
+ .putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES)
+ .putAll(COSPropertiesMetadata.PROPERTY_ENTRIES)
+ .build();
+
+ /**
+ * Storage entries plus the AWS access-key pair. Merged into every catalog.
A catalog that already
+ * declares a key keeps its own entry.
+ */
+ public static final Map<String, PropertyEntry<?>> ALL_PROPERTY_ENTRIES =
+ ImmutableMap.<String, PropertyEntry<?>>builder()
+ .putAll(STORAGE_PROPERTY_ENTRIES)
+ .putAll(AWSPropertiesMetadata.PROPERTY_ENTRIES)
+ .build();
+
+ private CloudPropertiesMetadata() {}
+}
diff --git
a/core/src/main/java/org/apache/gravitino/connector/BaseCatalogPropertiesMetadata.java
b/core/src/main/java/org/apache/gravitino/connector/BaseCatalogPropertiesMetadata.java
index 5e7e660504..bee325129b 100644
---
a/core/src/main/java/org/apache/gravitino/connector/BaseCatalogPropertiesMetadata.java
+++
b/core/src/main/java/org/apache/gravitino/connector/BaseCatalogPropertiesMetadata.java
@@ -29,9 +29,12 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.annotation.Evolving;
+import org.apache.gravitino.cloud.storage.CloudPropertiesMetadata;
@Evolving
public abstract class BaseCatalogPropertiesMetadata extends
BasePropertiesMetadata {
@@ -102,21 +105,37 @@ public abstract class BaseCatalogPropertiesMetadata
extends BasePropertiesMetada
true /* hidden */)),
PropertyEntry::getName);
+ /**
+ * Cloud credential keys merged into every catalog. A catalog that already
declares a key wins.
+ */
+ private static final Map<String, PropertyEntry<?>> CLOUD_PROPERTY_ENTRIES =
+ CloudPropertiesMetadata.ALL_PROPERTY_ENTRIES;
+
@Override
public Map<String, PropertyEntry<?>> propertyEntries() {
if (propertyEntries == null) {
synchronized (this) {
if (propertyEntries == null) {
- // Reuse BasePropertiesMetadata (specific + BASIC +
CredentialConfig), then add
- // catalog-only entries.
+ // Reuse BasePropertiesMetadata (specific + BASIC +
CredentialConfig), then add shared
+ // cloud credential keys and catalog-only entries.
Map<String, PropertyEntry<?>> base = buildBasePropertyEntries();
ImmutableMap.Builder<String, PropertyEntry<?>> builder =
ImmutableMap.builder();
builder.putAll(base);
+ // Track keys already placed so a later collision reports "Property
metadata already
+ // exists" instead of Guava's "Multiple entries with same key" from
builder.build().
+ Set<String> placed = new HashSet<>(base.keySet());
+
+ CLOUD_PROPERTY_ENTRIES.forEach(
+ (name, entry) -> {
+ if (placed.add(name)) {
+ builder.put(name, entry);
+ }
+ });
BASIC_CATALOG_PROPERTY_ENTRIES.forEach(
(name, entry) -> {
Preconditions.checkArgument(
- !base.containsKey(name), "Property metadata already
exists: " + name);
+ placed.add(name), "Property metadata already exists: " +
name);
builder.put(name, entry);
});
propertyEntries = builder.build();
diff --git
a/core/src/main/java/org/apache/gravitino/secret/FallbackPropertiesMetadata.java
b/core/src/main/java/org/apache/gravitino/secret/FallbackPropertiesMetadata.java
index ba76bdd687..e7c334d269 100644
---
a/core/src/main/java/org/apache/gravitino/secret/FallbackPropertiesMetadata.java
+++
b/core/src/main/java/org/apache/gravitino/secret/FallbackPropertiesMetadata.java
@@ -18,13 +18,8 @@
*/
package org.apache.gravitino.secret;
-import com.google.common.collect.ImmutableMap;
import java.util.Map;
-import org.apache.gravitino.cloud.storage.AzurePropertiesMetadata;
-import org.apache.gravitino.cloud.storage.COSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.GCSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.OSSPropertiesMetadata;
-import org.apache.gravitino.cloud.storage.S3PropertiesMetadata;
+import org.apache.gravitino.cloud.storage.CloudPropertiesMetadata;
import org.apache.gravitino.connector.BasePropertiesMetadata;
import org.apache.gravitino.connector.PropertyEntry;
@@ -32,23 +27,23 @@ import org.apache.gravitino.connector.PropertyEntry;
* Fallback {@link org.apache.gravitino.connector.PropertiesMetadata} when a
catalog does not
* support properties metadata for an entity type ({@link
UnsupportedOperationException}).
*
- * <p>Registers the shared base + credential-vending + cloud-storage property
entries so officially
- * non-hidden keys (for example {@code credential-providers}, {@code
s3-access-key-id}) are not
- * fuzzy-recovered into {@code getSecrets}. Undeclared sensitive-named keys
still use fuzzy
- * recovery; declared hidden secrets (for example {@code
s3-secret-access-key}) remain recoverable.
+ * <p>Registers shared base + credential-vending + cloud-storage entries
({@link
+ * CloudPropertiesMetadata#STORAGE_PROPERTY_ENTRIES}) so officially non-hidden
keys (for example
+ * {@code credential-providers}, {@code s3-access-key-id}) are not
fuzzy-recovered into {@code
+ * getSecrets}. Undeclared sensitive-named keys still use fuzzy recovery;
declared hidden secrets
+ * (for example {@code s3-secret-access-key}) remain recoverable.
+ *
+ * <p>Does not include the AWS access-key pair. That pair is a Glue catalog
property merged only via
+ * {@link org.apache.gravitino.connector.BaseCatalogPropertiesMetadata},
matching fileset and schema
+ * metadata which also omit it. A catalog path that hits this fallback
therefore treats {@code
+ * aws-access-key-id} as undeclared (fuzzy mask / recover), the same as a
fileset or schema.
*/
final class FallbackPropertiesMetadata extends BasePropertiesMetadata {
static final FallbackPropertiesMetadata INSTANCE = new
FallbackPropertiesMetadata();
private static final Map<String, PropertyEntry<?>> CLOUD_PROPERTY_ENTRIES =
- ImmutableMap.<String, PropertyEntry<?>>builder()
- .putAll(S3PropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(OSSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(AzurePropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(GCSPropertiesMetadata.PROPERTY_ENTRIES)
- .putAll(COSPropertiesMetadata.PROPERTY_ENTRIES)
- .build();
+ CloudPropertiesMetadata.STORAGE_PROPERTY_ENTRIES;
private FallbackPropertiesMetadata() {}
diff --git
a/core/src/test/java/org/apache/gravitino/cloud/storage/TestCloudPropertiesMetadata.java
b/core/src/test/java/org/apache/gravitino/cloud/storage/TestCloudPropertiesMetadata.java
index 7704948ae7..87234c9793 100644
---
a/core/src/test/java/org/apache/gravitino/cloud/storage/TestCloudPropertiesMetadata.java
+++
b/core/src/test/java/org/apache/gravitino/cloud/storage/TestCloudPropertiesMetadata.java
@@ -19,13 +19,17 @@
package org.apache.gravitino.cloud.storage;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.apache.gravitino.catalog.glue.GlueConstants;
import org.apache.gravitino.credential.CredentialConstants;
import org.apache.gravitino.credential.config.CredentialConfig;
import org.apache.gravitino.secret.SecretPropertyUtils;
+import org.apache.gravitino.storage.AWSProperties;
import org.apache.gravitino.storage.AzureProperties;
import org.apache.gravitino.storage.COSProperties;
+import org.apache.gravitino.storage.GCSProperties;
import org.apache.gravitino.storage.OSSProperties;
import org.apache.gravitino.storage.S3Properties;
import org.junit.jupiter.api.Test;
@@ -104,4 +108,39 @@ public class TestCloudPropertiesMetadata {
SecretPropertyUtils.isSensitivePropertyKey(
AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME));
}
+
+ @Test
+ void testAwsCredentialPropertiesAreDeclared() {
+ var metadata = AWSPropertiesMetadata.PROPERTY_ENTRIES;
+
assertTrue(metadata.containsKey(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+
assertTrue(metadata.containsKey(AWSProperties.GRAVITINO_AWS_SECRET_ACCESS_KEY));
+
assertFalse(metadata.get(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID).isHidden());
+
assertFalse(metadata.get(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID).isRequired());
+
assertTrue(metadata.get(AWSProperties.GRAVITINO_AWS_SECRET_ACCESS_KEY).isHidden());
+
assertFalse(metadata.get(AWSProperties.GRAVITINO_AWS_SECRET_ACCESS_KEY).isRequired());
+ }
+
+ @Test
+ void testCombinedCloudEntriesKeepAwsOffStorageMetadata() {
+ var storage = CloudPropertiesMetadata.STORAGE_PROPERTY_ENTRIES;
+ var all = CloudPropertiesMetadata.ALL_PROPERTY_ENTRIES;
+
+ assertTrue(storage.containsKey(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+ assertTrue(storage.containsKey(OSSProperties.GRAVITINO_OSS_ACCESS_KEY_ID));
+
assertTrue(storage.containsKey(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME));
+
assertTrue(storage.containsKey(GCSProperties.GRAVITINO_GCS_SERVICE_ACCOUNT_FILE));
+ assertTrue(storage.containsKey(COSProperties.GRAVITINO_COS_ACCESS_KEY_ID));
+
assertFalse(storage.containsKey(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+ assertFalse(storage.containsKey(GlueConstants.AWS_REGION));
+
+ assertTrue(all.containsKey(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+ assertTrue(all.containsKey(AWSProperties.GRAVITINO_AWS_SECRET_ACCESS_KEY));
+ assertSame(
+
S3PropertiesMetadata.PROPERTY_ENTRIES.get(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID),
+ all.get(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+ assertSame(
+
AWSPropertiesMetadata.PROPERTY_ENTRIES.get(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID),
+ all.get(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID));
+
assertFalse(all.get(AWSProperties.GRAVITINO_AWS_ACCESS_KEY_ID).isRequired());
+ }
}
diff --git
a/core/src/test/java/org/apache/gravitino/connector/TestBaseCatalogPropertiesMetadata.java
b/core/src/test/java/org/apache/gravitino/connector/TestBaseCatalogPropertiesMetadata.java
index 3e7c801e2f..4baa7a51f6 100644
---
a/core/src/test/java/org/apache/gravitino/connector/TestBaseCatalogPropertiesMetadata.java
+++
b/core/src/test/java/org/apache/gravitino/connector/TestBaseCatalogPropertiesMetadata.java
@@ -18,12 +18,15 @@
*/
package org.apache.gravitino.connector;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.Map;
import org.apache.gravitino.credential.CredentialConstants;
+import org.apache.gravitino.storage.S3Properties;
import org.junit.jupiter.api.Test;
public class TestBaseCatalogPropertiesMetadata {
@@ -43,4 +46,81 @@ public class TestBaseCatalogPropertiesMetadata {
assertFalse(metadata.isHiddenProperty(CredentialConstants.CREDENTIAL_PROVIDERS));
assertFalse(metadata.isHiddenProperty(CredentialConstants.S3_TOKEN_EXPIRE_IN_SECS));
}
+
+ @Test
+ void testSharedCloudCredentialKeysAreDeclaredForAllCatalogs() {
+
assertTrue(metadata.containsProperty(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+
assertTrue(metadata.containsProperty(S3Properties.GRAVITINO_S3_SECRET_ACCESS_KEY));
+
assertFalse(metadata.isHiddenProperty(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+
assertTrue(metadata.isHiddenProperty(S3Properties.GRAVITINO_S3_SECRET_ACCESS_KEY));
+ }
+
+ @Test
+ void testConnectorCredentialKeysAreDeclaredForAllCatalogs() {
+ assertTrue(metadata.containsProperty("aws-access-key-id"));
+ assertFalse(metadata.isHiddenProperty("aws-access-key-id"));
+ assertTrue(metadata.isHiddenProperty("aws-secret-access-key"));
+ assertFalse(metadata.containsProperty("jdbc-user"));
+ assertFalse(metadata.containsProperty("jdbc-password"));
+ assertFalse(metadata.containsProperty("token-provider"));
+ assertFalse(metadata.containsProperty("gcs.oauth2.token"));
+ assertFalse(metadata.containsProperty("s3.session-token"));
+ assertFalse(metadata.containsProperty("jdbc.user"));
+ }
+
+ @Test
+ void testRuntimeCopiedS3AccessKeyUsesSharedCloudMetadata() {
+ PropertiesMetadata glueLikeMetadata =
+ new BaseCatalogPropertiesMetadata() {
+ @Override
+ protected Map<String, PropertyEntry<?>> specificPropertyEntries() {
+ return ImmutableMap.of(
+ "aws-access-key-id",
+ PropertyEntry.stringOptionalPropertyEntry(
+ "aws-access-key-id", "AWS access key ID", false, null,
false),
+ "aws-secret-access-key",
+ PropertyEntry.stringOptionalPropertyEntry(
+ "aws-secret-access-key", "AWS secret access key", false,
null, true));
+ }
+ };
+
+ Map<String, String> properties =
+ ImmutableMap.of(
+ "aws-access-key-id",
+ "AKIAEXAMPLE",
+ S3Properties.GRAVITINO_S3_ACCESS_KEY_ID,
+ "AKIAEXAMPLE",
+ S3Properties.GRAVITINO_S3_SECRET_ACCESS_KEY,
+ "secret-value");
+ Map<String, String> masked =
+ HiddenPropertyMaskUtils.maskHiddenProperties(properties,
glueLikeMetadata);
+
+ assertEquals("AKIAEXAMPLE", masked.get("aws-access-key-id"));
+ assertEquals("AKIAEXAMPLE",
masked.get(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+ assertEquals(
+ HiddenPropertyMaskUtils.MASKED_VALUE,
+ masked.get(S3Properties.GRAVITINO_S3_SECRET_ACCESS_KEY));
+ }
+
+ @Test
+ void testCatalogDeclarationWinsOverSharedCloudEntry() {
+ PropertiesMetadata catalogMetadata =
+ new BaseCatalogPropertiesMetadata() {
+ @Override
+ protected Map<String, PropertyEntry<?>> specificPropertyEntries() {
+ return ImmutableMap.of(
+ S3Properties.GRAVITINO_S3_ACCESS_KEY_ID,
+ PropertyEntry.stringOptionalPropertyEntry(
+ S3Properties.GRAVITINO_S3_ACCESS_KEY_ID,
+ "Catalog-owned S3 access key ID",
+ false,
+ null,
+ true));
+ }
+ };
+
+
assertTrue(catalogMetadata.containsProperty(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+
assertTrue(catalogMetadata.isHiddenProperty(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+
assertFalse(metadata.isHiddenProperty(S3Properties.GRAVITINO_S3_ACCESS_KEY_ID));
+ }
}
diff --git
a/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyOperationDispatcher.java
b/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyOperationDispatcher.java
index be0d093cb0..7a6f10325f 100644
---
a/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyOperationDispatcher.java
+++
b/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyOperationDispatcher.java
@@ -197,5 +197,13 @@ public class TestSecretPropertyOperationDispatcher extends
TestOperationDispatch
SecretPropertyUtils.shouldRecoverSensitiveNamedSecret("s3-secret-access-key",
metadata));
Assertions.assertTrue(
SecretPropertyUtils.shouldRecoverSensitiveNamedSecret("custom-token",
metadata));
+ // AWS access-key pair is catalog-only (BaseCatalogPropertiesMetadata),
not in this entity
+ // fallback — same exclusion as fileset/schema STORAGE_PROPERTY_ENTRIES.
+ Assertions.assertFalse(metadata.containsProperty("aws-access-key-id"));
+ Assertions.assertFalse(metadata.containsProperty("aws-secret-access-key"));
+ Assertions.assertTrue(
+
SecretPropertyUtils.shouldRecoverSensitiveNamedSecret("aws-access-key-id",
metadata));
+ Assertions.assertTrue(
+
SecretPropertyUtils.shouldRecoverSensitiveNamedSecret("aws-secret-access-key",
metadata));
}
}
diff --git a/design-docs/gravitino-glue-catalog.md
b/design-docs/gravitino-glue-catalog.md
index 1b420ab432..1dc1b19456 100644
--- a/design-docs/gravitino-glue-catalog.md
+++ b/design-docs/gravitino-glue-catalog.md
@@ -124,15 +124,15 @@ Extend existing Hive and Iceberg catalogs with
`metastore-type=glue` / `catalog-
Glue is a separate AWS service from S3. The Glue region and credentials may
differ from S3 storage credentials, so Glue properties use their own `aws-*`
namespace:
-| Property | Required | Default | Description |
-|---|---|---|---|
-| `aws-region` | Yes | — | AWS region for the Glue Data Catalog |
-| `aws-access-key-id` | No | Default credential chain | AWS access key for
Glue API authentication. **Sensitive**: not visible to catalog readers via
Gravitino API. |
-| `aws-secret-access-key` | No | Default credential chain | AWS secret key for
Glue API authentication. **Sensitive**: not visible to catalog readers via
Gravitino API. |
-| `aws-glue-catalog-id` | Yes | — | Glue catalog ID. Required because an AWS
account can have multiple Glue catalogs (e.g., default catalog and federated S3
Tables catalog). |
-| `aws-glue-endpoint` | No | AWS default regional endpoint | Custom Glue
endpoint URL (for VPC endpoints or LocalStack testing). |
-| `default-table-format` | No | `iceberg` | Default format for tables created
via Gravitino's `createTable()` API. Accepted values: `iceberg`, `hive`. |
-| `table-type-filter` | No | `all` | Comma-separated list of table types
exposed by `listTables()` and `loadTable()`. Accepted values: `all`, `hive`,
`iceberg`, `delta`, `parquet`. Use to restrict visible table types for
backwards compatibility with existing systems that cannot handle mixed-format
catalogs. |
+| Property | Required | Default |
Description
|
+| ----------------------- | -------- | ----------------------------- |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
+| `aws-region` | Yes | — | AWS
region for the Glue Data Catalog
|
+| `aws-access-key-id` | No | Default credential chain | AWS
access key for Glue API authentication. Visible in cleartext to catalog
readers.
|
+| `aws-secret-access-key` | No | Default credential chain | AWS
secret key for Glue API authentication. Hidden from catalog readers; returned
as `******`.
|
+| `aws-glue-catalog-id` | Yes | — | Glue
catalog ID. Required because an AWS account can have multiple Glue catalogs
(e.g., default catalog and federated S3 Tables catalog).
|
+| `aws-glue-endpoint` | No | AWS default regional endpoint | Custom
Glue endpoint URL (for VPC endpoints or LocalStack testing).
|
+| `default-table-format` | No | `iceberg` | Default
format for tables created via Gravitino's `createTable()` API. Accepted values:
`iceberg`, `hive`.
|
+| `table-type-filter` | No | `all` |
Comma-separated list of table types exposed by `listTables()` and
`loadTable()`. Accepted values: `all`, `hive`, `iceberg`, `delta`, `parquet`.
Use to restrict visible table types for backwards compatibility with existing
systems that cannot handle mixed-format catalogs. |
**Authentication priority**: Static credentials (`aws-access-key-id` +
`aws-secret-access-key`) → Default credential chain (environment variables,
instance profile, container credentials). STS AssumeRole (`aws-role-arn`) is a
future enhancement — static credentials are sufficient for the initial release,
including cross-account access.