markhoerth opened a new issue, #14437:
URL: https://github.com/apache/gravitino/issues/14437

   ### Version
   main branch, commit bb634defdc5663a8124be5fca1c8d9e52ac096ac (2.0.0-SNAPSHOT)
   
   ### Describe what's wrong
   Every read path shows a secret-backed property as the placeholder `******`. 
Alter refuses that placeholder as a new secret value: a `setSecretBinding` 
change with `"plaintext":"******"` is rejected with 400 "Property 'api-token' 
cannot be set to the masked placeholder value '******'". Create does not apply 
the same check. A catalog (or schema) created with 
`"secretBindings":{"api-token":{"provider":"memory","plaintext":"******"}}` is 
accepted with 200, and the literal string `******` is written to the secret 
provider as the secret value. The user expects the same 400 as on alter. It 
shows up when a user copies an object's definition from a GET response (where 
the secret is already masked) and creates a new object from it: the create 
succeeds, the new object reports `"api-token":"******"` like any healthy 
secret, and the connector later receives `******` as the credential.
   
   Cause (defect in Gravitino's own code):
   - Alter: 
`core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java:1715-1720` 
puts the `setSecretBinding` plaintext into the upserts map, and 
`CatalogManager.java:1031-1036` passes it to `validatePropertyForAlter`, which 
calls `HiddenPropertyMaskUtils.validateNoMaskedPlaceholders` 
(`core/src/main/java/org/apache/gravitino/catalog/PropertiesMetadataHelpers.java:93`,
 check at 
`core/src/main/java/org/apache/gravitino/connector/HiddenPropertyMaskUtils.java:93-106`).
   - Create: `CatalogManager.java:832-839` merges the bindings into the catalog 
configuration as secret URNs and calls `SecretManager.assembleSecretMaterials`. 
`core/src/main/java/org/apache/gravitino/secret/SecretManager.java:139-158` and 
`toSecretMaterials` (`SecretManager.java:546-556`) turn each 
`binding.plaintext()` into secret material with no placeholder check, and 
`checkSecretKeys` (`SecretManager.java:81`) only checks keys and raw URNs. The 
create-time `validatePropertyForCreate` (`PropertiesMetadataHelpers.java:52`) 
runs on the property map, where the binding value has already been replaced by 
its URN, so it never sees the plaintext.
   - Schema and fileset create share the same path through 
`assembleSecretMaterials` 
(`core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java:160`,
 
`core/src/main/java/org/apache/gravitino/catalog/FilesetOperationDispatcher.java:166`).
 Schema create was confirmed to accept `******` as well.
   
   Validating every `SecretBinding.plaintext()` with 
`HiddenPropertyMaskUtils.isMaskedPlaceholder` inside `assembleSecretMaterials` 
would cover catalog, schema and fileset create at once.
   
   ### Error message and/or stacktrace
   Create with the placeholder is accepted:
   
   ```
   POST /api/metalakes/kms_ml/catalogs -> 200
   
{"code":0,"catalog":{"name":"c_mask","type":"fileset","provider":"fileset","comment":"","properties":{"location":"file:///tmp/kms_c_mask","api-token":"******","in-use":"true"},"audit":{"creator":"admin",...}}}
   ```
   
   The same value on alter is refused:
   
   ```
   PUT /api/metalakes/kms_ml/catalogs/c_ok -> 400
   {"code":1001,"type":"IllegalArgumentException","message":"Failed to operate 
catalog(s) [c_ok] operation [ALTER] under metalake [kms_ml], reason [Property 
'api-token' cannot be set to the masked placeholder value 
'******']","stack":["java.lang.IllegalArgumentException: Property 'api-token' 
cannot be set to the masked placeholder value '******'","\tat 
org.apache.gravitino.connector.HiddenPropertyMaskUtils.validateNoMaskedPlaceholders(...)",
 ...]}
   ```
   
   ### How to reproduce
   Server with a secret provider configured, for example:
   
   ```
   gravitino.secret.providers = memory
   gravitino.secret.provider.memory.className = 
org.apache.gravitino.secret.memory.InMemorySecretsProvider
   ```
   
   ```
   A="Authorization: Basic $(printf 'admin:x' | base64)"
   G=http://127.0.0.1:8090/api; J='Content-Type: application/json'
   ```
   
   1. Create a clean metalake and check the provider:
      ```
      curl -s -H "$A" -H "$J" -X POST $G/metalakes -d 
'{"name":"kms_ml","comment":"","properties":{}}'
      curl -s -H "$A" $G/metalakes/kms_ml/secrets/providers
      ```
   2. Create a catalog whose secret binding plaintext is the placeholder 
(returns 200):
      ```
      curl -s -w '\n%{http_code}\n' -H "$A" -H "$J" -X POST 
$G/metalakes/kms_ml/catalogs -d 
'{"name":"c_mask","type":"FILESET","provider":"fileset","comment":"","properties":{"location":"file:///tmp/kms_c_mask"},"secretBindings":{"api-token":{"provider":"memory","plaintext":"******"}}}'
      ```
   3. Create a catalog with a real secret, then try to set the placeholder 
through alter (returns 400):
      ```
      curl -s -H "$A" -H "$J" -X POST $G/metalakes/kms_ml/catalogs -d 
'{"name":"c_ok","type":"FILESET","provider":"fileset","comment":"","properties":{"location":"file:///tmp/kms_c_ok"},"secretBindings":{"api-token":{"provider":"memory","plaintext":"real-value-1"}}}'
      curl -s -w '\n%{http_code}\n' -H "$A" -H "$J" -X PUT 
$G/metalakes/kms_ml/catalogs/c_ok -d 
'{"updates":[{"@type":"setSecretBinding","property":"api-token","provider":"memory","plaintext":"******"}]}'
      ```
   4. Schema create behaves like step 2 (returns 200):
      ```
      curl -s -w '\n%{http_code}\n' -H "$A" -H "$J" -X POST 
$G/metalakes/kms_ml/catalogs/c_ok/schemas -d 
'{"name":"s_mask","comment":"","properties":{},"secretBindings":{"api-token":{"provider":"memory","plaintext":"******"}}}'
      ```
   
   ### Additional context
   - Related: #12581 (masked placeholder for hidden credential properties), 
#12381 (setSecretBinding and setSecretReference on alter), #14396 (KMS-backed 
secret encryption epic).
   - Found by the 2.0 OSS test suite check 
`test_mask_as_plaintext_rejected_on_create`.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to