alexandrefimov opened a new pull request, #57892:
URL: https://github.com/apache/spark/pull/57892

   ### What changes were proposed in this pull request?
   
   The four read paths of the Config RPC — `Get`, `GetWithDefault`, `GetOption` 
and `GetAll` — stop returning configuration entries that match 
`spark.redaction.regex`. A withheld entry is reported the way that same 
operation already reports an unset key: `Get` fails with `SQL_CONF_NOT_FOUND`, 
`GetWithDefault` returns the caller's default, `GetOption` returns no value and 
`GetAll` omits the entry.
   
   Three details are worth pointing at.
   
   The pattern is read from the `SparkConf`, not from the session config. The 
session config is client-writable. `requireNonStaticConf` does guard 
`spark.redaction.regex`, but that guard is itself controlled by 
`spark.sql.legacy.setCommandRejectsSparkCoreConfs`, an ordinary non-static SQL 
conf, so two `Set` calls would otherwise be enough to clear the filter before 
reading.
   
   Matching covers the key or the value, following `Utils.redact`. `SetCommand` 
already redacts through `SQLConf.redactOptions`, so a key-only match would 
leave the Config RPC laxer than `SET` over the same configuration — a password 
inside a JDBC URL is the obvious case. Only `spark.redaction.regex` is applied; 
`spark.sql.redaction.options.regex` is deliberately left out, since it exists 
for SQL command output and its default would withhold every key with `url` in 
its name.
   
   `GetAll` filters before the requested prefix is stripped. Filtering 
afterwards would return `spark.my.secret.value` as `value` for prefix 
`spark.my.secret.`, walking straight past the pattern.
   
   `IsModifiable` is left as it is: whether a key is modifiable is a property 
of the name and discloses no value.
   
   ### Why are the changes needed?
   
   The Config RPC discloses anything sensitive that reached `SparkConf`, 
whatever put it there. `spark.connect.authenticate.token` is the one key Spark 
itself puts there, and it looks benign only because it happens to be the 
client's own credential.
   
   Apache Kyuubi makes the general shape visible. Kyuubi passes its own 
configuration to the Spark engine through `--conf` and prefixes every 
non-`spark.` key with `spark.`, so the whole engine configuration ends up in 
the driver's `SparkConf`, and `SQLConf.mergeSparkConf` copies all of it into 
the session config. Some of those entries are secrets shared across the 
deployment rather than owned by the connecting user — a ZooKeeper digest, an 
internal pre-shared secret. That is a plain client-to-server deployment with no 
proxy anywhere, and a client reads back secrets it never held.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. A configuration entry whose key or value matches 
`spark.redaction.regex` is no longer returned by the Config RPC, and each read 
operation reports it as if it were unset.
   
   Three consequences I would like reviewers to look at explicitly.
   
   A client can no longer read back an entry it set itself in its own session: 
after `spark.conf.set("spark.sql.catalog.mycat.password", …)`, reading that key 
back now fails. Classic Spark still returns it. The filter could be narrowed to 
keys present in `sparkContext.conf`, which would keep session-local entries 
readable; I did not do that, because it would let a secret written into the 
session config server-side — by a plugin or an extension rather than through 
`SparkConf` — stay readable. That trade is a judgement call and I am happy to 
switch.
   
   A batched `Get` fails as a whole if any key in the batch is withheld, since 
that is how a single unset key in a batch already behaves. With the default 
pattern none of the keys the clients batch internally match, but an operator 
who widens `spark.redaction.regex` far enough could turn `createDataFrame` into 
an error rather than a hidden value.
   
   An empty `spark.redaction.regex` matches every key, so setting it to an 
empty string — a plausible attempt to turn redaction off — now withholds the 
entire configuration. `Utils.redact` degrades the same way, so I did not 
special-case it here, but it is worth a decision.
   
   ### How was this patch tested?
   
   New `SparkConnectConfigHandlerSuite` covers the five read operations, the 
prefix-stripping order, the value match, and that the pattern is not taken from 
the session config. `SparkConnectAuthSuite` gains an end-to-end assertion that 
the authentication token is not readable while a non-sensitive server-side 
configuration still is.
   
   ```
   build/sbt "connect/testOnly 
org.apache.spark.sql.connect.service.SparkConnectConfigHandlerSuite 
org.apache.spark.sql.connect.service.SparkConnectAuthSuite"
   ```
   
   10 tests, all passing. With the handler reverted to master, 8 of the 10 
fail; the two that still pass are the `IsModifiable` case, whose behaviour is 
deliberately unchanged, and the pre-existing authentication test.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Yes — Claude Code (Opus 5) was used for code reading, drafting and review. 
Every line was reviewed by the author, who takes responsibility for the patch.
   


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