Repository navigation
Conversation
HyukjinKwon
left a comment
There was a problem hiding this comment.
Clean, well-scoped startup guard with a thorough test matrix (per-auth-type coverage, the doAs-disabled and untouched-config cases, the allow-flag escape hatch, and a wiring test through init). Both server entry points route through the single init() call site, so the guard can't be bypassed. Two non-blocking points below: one documentation question and one optional test-coverage suggestion.
| } | ||
|
|
||
| test("SPARK-59118 an unrecognized auth type fails closed") { | ||
| intercept[IllegalArgumentException](check(hiveConf("NOT_AN_AUTH_TYPE", doAs = true))) |
There was a problem hiding this comment.
The guard's comment calls out that authType is null when the auth is explicitly set empty and that the constant-on-left comparison must not NPE. That branch isn't exercised — the closest case here uses a non-null unknown string. A case like check(hiveConf("", doAs = true)) asserting it fails closed without an NPE would lock in the null-safety you flagged.
HyukjinKwon
left a comment
There was a problem hiding this comment.
One design follow-up on the default behavior (see inline).
| .version("5.0.0") | ||
| .withBindingPolicy(ConfigBindingPolicy.NOT_APPLICABLE) | ||
| .booleanConf | ||
| .createWithDefault(false) |
There was a problem hiding this comment.
Defaulting this to false means the Thrift Server refuses to start for any existing hive.server2.enable.doAs=true + verifying-auth (Kerberos/LDAP) deployment once it upgrades to 5.0. The SPARK-5159 rationale is sound, and the escape hatch + migration-guide entry + the 4.x warn-first #58438 are the right scaffolding. The open question is whether refuse-to-start is the right default for 5.0: it turns a long-latent, silently-"working" config into an immediate startup outage on upgrade. If the hard-fail default is intended, it's worth a prominent release-note callout (beyond the migration guide) given how many secured HS2 deployments run doAs=true; if not, a loud startup warning that only escalates to a hard error under an explicit opt-in would be less disruptive while still closing the security gap.
dongjoon-hyun
left a comment
There was a problem hiding this comment.
Thank you for the PR. A few inline comments on the guard's wording and the test setup; none of them change the overall direction.
| val authVerifiesUser = !unverifiedAuthTypes.exists(_.equalsIgnoreCase(authType)) | ||
| if (authVerifiesUser && hiveConf.getBoolVar(ConfVars.HIVE_SERVER2_ENABLE_DOAS) && | ||
| !allowIneffectiveDoAs) { | ||
| throw new IllegalArgumentException( |
There was a problem hiding this comment.
This is a user-facing error, so it should go through the error-class framework rather than a raw IllegalArgumentException with a prose message (common/utils/src/main/resources/error/README.md: "developers should specify a standardized SQLSTATE, an error condition, and message parameters rather than an arbitrary error message"). The sibling startup check in SparkSQLCLIService.init already does this via QueryExecutionErrors.invalidKerberosConfigForHiveServer2Error. Could you add an error condition to error-conditions.json and throw it via QueryExecutionErrors / HiveThriftServerErrors, so the exception is a SparkThrowable with a SQLSTATE and can be asserted with checkError?
| !allowIneffectiveDoAs) { | ||
| throw new IllegalArgumentException( | ||
| s"${ConfVars.HIVE_SERVER2_ENABLE_DOAS.varname} is set to true, but the Spark Thrift " + | ||
| "Server impersonates the connecting user only for Hive metastore calls: queries and " + |
There was a problem hiding this comment.
"queries and the storage access they perform still run as the server's own service identity" is only true on the executor side. HiveSessionProxy wraps executeStatementAsync in the session UGI's doAs, so SparkExecuteStatementOperation.runInternal calls Utils.getUGI() while already impersonating the connecting user, and the background action runs under that proxy UGI on the driver. Driver-side FileSystem calls (e.g. InMemoryFileIndex listing) are therefore impersonated; only executor task I/O runs as the service principal. Since operators will read this text (and the conf doc / migration note, which repeat it) to decide whether to set allowIneffectiveDoAs=true, it would be better to say executor-side data access is not impersonated rather than "queries" as a whole.
| hiveConf: HiveConf, | ||
| allowIneffectiveDoAs: Boolean): Unit = { | ||
| val authType = hiveConf.getVar(ConfVars.HIVE_SERVER2_AUTHENTICATION) | ||
| val unverifiedAuthTypes = Seq(AuthTypes.NONE, AuthTypes.NOSASL).map(_.getAuthName) |
There was a problem hiding this comment.
The comment above says NONE/NOSASL "have nothing to impersonate", but that is not what Hive does. ThriftCLIService.getSessionHandle opens the session with impersonation whenever doAs is true and a username exists, and under NONE getUserName falls back to the client-supplied req.getUsername(). So with NONE + doAs=true (Hive's out-of-the-box config) metastore calls are impersonated as an unverified, client-chosen name while storage still runs as the service principal, which is the same SPARK-5159 gap this guard describes. Exempting NONE may still be the right call (there is no security expectation without a verified identity), but the rationale should say that rather than "nothing to impersonate". Alternatively, keying on doAs alone or on UserGroupInformation.isSecurityEnabled would avoid a hand-maintained AuthTypes list.
| allowIneffectiveDoAs: Boolean): Unit = { | ||
| val authType = hiveConf.getVar(ConfVars.HIVE_SERVER2_AUTHENTICATION) | ||
| val unverifiedAuthTypes = Seq(AuthTypes.NONE, AuthTypes.NOSASL).map(_.getAuthName) | ||
| // Constant on the left: authType is null when explicitly set empty, and this must not NPE. |
There was a problem hiding this comment.
I don't think authType can be null here. HiveConf.getVar returns "" when the value is explicitly set empty and the default NONE for an empty <value/> in hive-site.xml (Hadoop Configuration.get(name, default) semantics), and Configuration.set(name, null) is rejected. So the constant-on-the-left is harmless but the comment is misleading. Separately, an empty or misspelled auth type is classified as "verifies user" and reported as a doAs problem; following the advice to set allowIneffectiveDoAs=true then does not help, because HiveAuthFactory.getAuthTransFactory fails with Unsupported authentication type. Either correct the comment, or leave invalid auth types to Hive's own error.
| "org.apache.spark.sql.SQLQueryTestSuite", | ||
| "org.apache.spark.sql.hive.client.HadoopVersionInfoSuite", | ||
| "org.apache.spark.sql.hive.thriftserver.SparkExecuteStatementOperationSuite", | ||
| // Constructs a HiveThriftServer2, which flips HiveConf's static loadHiveServer2Config. |
There was a problem hiding this comment.
ThriftServerWithSparkContextInBinarySuite / InHttpSuite already construct a HiveThriftServer2 in-process via SharedThriftServer.startWithSparkSession, and they run in the default test group without a dedicated JVM. If the static loadHiveServer2Config flip were a real hazard, those suites would need this too. Unless there is an observed failure, I'd drop this entry so we don't fork an extra JVM for a suite of eight short tests.
| * Tests for the SPARK-59118 startup guard: the Thrift Server refuses to start when | ||
| * `hive.server2.enable.doAs` is on but impersonation does not reach query execution. | ||
| */ | ||
| class HiveThriftServer2DoAsSuite extends QueryTest with SharedSparkSession { |
There was a problem hiding this comment.
Only the last test (init refuses to start the server) uses spark; the other seven call failIfIneffectiveDoAs directly on a HiveConf, and the branch-4.x sibling in #58438 uses SparkFunSuite for the same cases. Could we keep this suite on SparkFunSuite and move the single init() wiring test into an existing session-backed thrift-server suite? That avoids paying SharedSparkSession setup for pure-function tests and keeps the 4.x and master suites aligned.
jzhan-2026
left a comment
There was a problem hiding this comment.
+1 on the feedbacks from prior reviewers. Happy to review again once those comments are resolved.
…, docs Extract the guard into checkImpersonationIsEnforced so it can be tested without standing up the Thrift services, and use AuthTypes.NONE/NOSASL instead of matching the literal strings. The old message told users to unset hive.server2.enable.doAs, which does not help -- Hive's own default is true. Say "set it to false" instead, and note the escape hatch is a Spark conf (--conf), not a --hiveconf. Target 4.4.0 rather than 5.0.0: this backports to branch-4.x, matching the sibling allowSettingSystemProperties conf. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Refusing to start breaks deployments that have been accepted for years, so it lands in the next major rather than a minor. branch-4.x logs a warning for the same configuration; the migration note points at both. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Two claims in the error message were wrong. doAs is not ignored outright -- HiveSessionProxy runs every session call under UGI.doAs, so metastore calls are impersonated and only query execution and storage access are not. That also makes "just set doAs=false" a downgrade rather than a no-op, since it drops metastore impersonation too, so the message and docs now say so. And --hiveconf does reach a spark.* conf (ServerOptionsProcessor turns it into a system property), so the "not --hiveconf" advice was simply false; the real caveat is that a static conf has to be set before the session is created. Nothing proved init() called the guard -- deleting that line left every test green, which is the whole security value of the change. Tests now go through init(), cover every verifying AuthTypes value, and pin that an untouched Hive config (doAs=true, auth=NONE) still starts. Moved the guard to the companion object so the tests do not construct a HiveServer2, whose constructor flips HiveConf's process-wide loadHiveServer2Config, and so the escape hatch is a plain argument rather than a deep-stubbed SparkSession. The tests move to their own suite, since they are about server startup rather than SparkExecuteStatementOperation. Co-Authored-By: Claude Sonnet 5 <[email protected]>
681e1d1 to
bcca8a6
Compare
…, executor-side wording Co-authored-by: Cursor <[email protected]>
|
Merged for master, the backport remains #58438 |
### What changes were proposed in this pull request? This is a softer follow on of #58414 for 4.X branch which warns when doAs is enabled but not enforced. We should log rather than fail a previously running job. ### Why are the changes needed? People might expect doAs to run as a different user, which is not supported. ### Does this PR introduce _any_ user-facing change? The Spark Thrift Server logs a startup warning when `hive.server2.enable.doAs` is enabled with an authenticating auth type, unless the new static conf `spark.sql.hive.thriftServer.allowIneffectiveDoAs` is set to `true`. ### How was this patch tested? New unit test. ### Was this patch authored or co-authored using generative AI tooling? Yes, claude Closes #58438 from holdenk/SPARK-59118-doAs-warn-4.x-r2. Lead-authored-by: Holden Karau <[email protected]> Co-authored-by: Holden Karau <[email protected]> Co-authored-by: Wenchen Fan <[email protected]> Signed-off-by: Wenchen Fan <[email protected]>
….4 migration note with branch-4.x ### What changes were proposed in this pull request? A follow-up to #58414, now that its `branch-4.x` backport #58438 has shipped `spark.sql.hive.thriftServer.allowIneffectiveDoAs` in 4.4.0 (as a warn-only gate): - Change the conf's `.version("5.0.0")` to `.version("4.4.0")`, since 4.4.0 is the first release with this key. - Add the backport's 4.4 migration note to the "Upgrading from Spark SQL 4.3 to 4.4" section, at the same position as on `branch-4.x`. That section is otherwise identical between `master` and `branch-4.x`, and the 5.0 note added by #58414 already says "Spark 4.4 logs a warning for the same configuration." ### Why are the changes needed? A conf's version should record the first release that has it, and master's 4.3 to 4.4 migration section should match `branch-4.x`'s. ### Does this PR introduce _any_ user-facing change? No. Behavior is unchanged; the generated conf docs list the conf as available since 4.4.0 instead of 5.0.0. ### How was this patch tested? No new tests: the change is a version string and one documentation line. Checked that master's "Upgrading from Spark SQL 4.3 to 4.4" section is now identical to `branch-4.x`'s. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Isaac (Claude Opus 5.5) This pull request and its description were written by Isaac. Closes #59831 from cloud-fan/wenchen/spark-59118-doas-version-4.4. Authored-by: Wenchen Fan <[email protected]> Signed-off-by: Wenchen Fan <[email protected]>
What changes were proposed in this pull request?
Add a config param for enabling hard failure on doAs in Thriftserver when we do not support it.
Why are the changes needed?
People might expect doAs to run as a different user, which is not supported.
Does this PR introduce any user-facing change?
Explicit error unless config flag is disabled.
How was this patch tested?
New unit test.
Was this patch authored or co-authored using generative AI tooling?
Yes, claude