FANNG1 commented on issue #66772:
URL: https://github.com/apache/doris/issues/66772#issuecomment-5299773752

   ## Correction to the fix guidance above
   
   Digging further into how Lance actually consumes `storage_options`, the 
suggestion in the issue body — teach `LanceStorageOptions.forBackend` to accept 
the unprefixed aliases — is **necessary but not sufficient**, and one of its 
premises was wrong. Everything below is verified against the exact Lance 
revision that `lance-c` v0.1.6 pins (`f69324596`), i.e. what the BE on 
`branch-4.1` actually compiles, not a newer release.
   
   ### 1. The outbound spelling is wrong too, so an inbound-only fix still 
breaks
   
   The BE emits `aws_`-prefixed option names (`kStorageKeys` in 
`be/src/format_v2/table/lance_reader.cpp`). Those silently stop working the 
moment Lance takes its OpenDAL path:
   
   ```rust
   // rust/lance-io/src/object_store/providers/aws.rs  —  build_opendal_s3_store
   let mut config_map: HashMap<String, String> = storage_options.0.clone();
   config_map.insert("bucket".to_string(), bucket);
   let operator = Operator::from_iter::<S3>(config_map)
   ```
   
   There is no alias normalization on this path — the map goes straight into 
OpenDAL's `S3Config`, whose field names are unprefixed, and OpenDAL's 
deserializer ignores unknown keys without error.
   
   | | object_store path (default) | OpenDAL path (`use_opendal=true`) |
   |---|---|---|
   | `access_key_id` | works | works |
   | `aws_access_key_id` | works | **silently dropped** |
   
   To be precise about the current blast radius: `use_opendal` is itself read 
from the storage options (`aws.rs:139-143`), and the same five-key filter drops 
it, so **this path is not reachable through Doris today** — the prefixed 
spelling is a latent hazard rather than a live bug. It becomes live exactly 
when the filter is opened up, which is what any real fix to this issue does. 
That is why it belongs in the same change: widening the inbound aliases while 
continuing to emit the prefixed form outbound would make `use_opendal=true` 
reachable and silently credential-less at the same moment.
   
   The unprefixed short names are the only spelling both paths accept, so 
`forJavaSdk` and the BE's `kStorageKeys` are the place to converge.
   
   ### 2. Both spellings have first-party sources — the real principle is that 
the consumer must be permissive
   
   The issue body implied Gravitino's unprefixed spelling is the more standard 
one. That is not accurate, and the correct argument is stronger.
   
   Lance's own credential vendor emits the **prefixed** form:
   
   ```rust
   // rust/lance-namespace-impls/src/credentials/aws.rs
   storage_options.insert("aws_access_key_id".to_string(), access_key_id);
   storage_options.insert("aws_session_token".to_string(), session_token);
   ```
   
   while Lance's own consumer accepts **both**, prefixed first:
   
   ```rust
   // rust/lance-io/src/object_store/dynamic_credentials.rs:172-186
   .get("aws_access_key_id").or_else(|| credentials.0.get("access_key_id"))
   .get("aws_session_token")
       .or_else(|| credentials.0.get("session_token"))
       .or_else(|| credentials.0.get("token"))
   ```
   
   So both spellings legitimately occur in the wild from first-party sources, 
and Lance's answer is: vendors emit one, consumers accept all of them. Doris is 
a consumer that accepts one. That is the defect, and it holds regardless of 
which namespace server is on the other end — this is not a Gravitino-specific 
quirk.
   
   Worth noting the spec is explicit that this field is opaque: *"Configuration 
options to be used to access storage… These will be **passed directly to 
Lance** to initialize storage access."* The namespace protocol deliberately 
does not define the key vocabulary, so a client cannot assume one.
   
   ### 3. The bigger loss: the filter also discards Lance's credential 
auto-refresh
   
   I under-reported `expires_at_millis` above as merely another dropped key. It 
is the entry point to a subsystem that is present in the revision the BE builds:
   
   ```
   rust/lance-io/src/object_store/storage_options.rs
     EXPIRES_AT_MILLIS_KEY (:31), REFRESH_OFFSET_MILLIS_KEY (:34)
     LanceNamespaceStorageOptionsProvider  -> issues its own 
DescribeTableRequest
     StorageOptionsAccessor                -> caches, and refreshes 
refresh_offset_millis
                                              (60s default) before expiry
   ```
   
   Lance already re-vends expiring credentials through the namespace by itself. 
Because the five-key filter drops `expires_at_millis`, Doris silently opts out 
of it: vended short-lived credentials expire mid-scan with no renewal. That is 
a limitation Lance does not actually have — Doris introduces it by filtering.
   
   ### 4. The filter also locks the Lance catalog to S3
   
   `S3_KEYS` (FE) and `kStorageKeys` (BE) are both S3-only, five entries each. 
Lance vends Azure and GCP credentials as well (`azure_storage_sas_token`, 
`google_storage_token` — `credentials/azure.rs`, `credentials/gcp.rs`). Against 
a namespace serving Lance tables on Azure or GCS, **100% of the vended 
credentials are dropped** — not a spelling mismatch, simply no entry in the 
table. As written, the Lance catalog cannot support a non-S3 backend through 
credential vending at all.
   
   ### 5. Revised suggestion
   
   Rather than widening the lookup table, stop translating server-supplied 
options at all:
   
   - **FE** — pass `DescribeTable`'s `storage_options` through untranslated.
   - **BE** — hand them to `lance-c` as-is and drop the second translation. 
Note today's round trip is `access_key_id` → `AWS_ACCESS_KEY` → 
`aws_access_key_id`: Lance vocabulary out, Lance vocabulary back in, with a 
lossy filter in between and no information gained.
   - **Static catalog properties** (`s3.access_key` and friends) keep their 
conversion — they genuinely are in Doris vocabulary — but should emit the 
unprefixed spelling.
   
   On the safety concern that presumably motivated an allowlist in the first 
place: Lance's own model for exactly this problem is a **denylist of 
location-controlling keys**, not an allowlist of credential keys.
   
   ```rust
   // rust/lance-io/src/object_store/dynamic_opendal.rs
   protected_keys: Vec<&'static str>,   // stripped from server-supplied options
   ```
   
   That defends the thing actually worth defending — a namespace server 
redirecting where data is read from — while scaling to other clouds and to keys 
added later, which an allowlist cannot.
   
   If a smaller change is preferred for now, widening `forBackend`'s aliases 
still fixes the immediate breakage and is worth doing on its own; it just 
leaves items 1, 3 and 4 open.
   
   ### Testing note
   
   The coverage gap noted in the issue body is a little wider than described: 
`lance_rest_server.py` vends only `aws_`-prefixed keys, so neither the 
unprefixed alias path nor `expires_at_millis` is exercised anywhere today.
   


-- 
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]


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

Reply via email to