Skip to content

[SPARK-59118][SQL] Error when doAs is used and not supported - #58414

Closed
holdenk wants to merge 8 commits into
apache:masterfrom
holdenk:SPARK-59118-doAs-warn
Closed

holdenk wants to merge 8 commits into
apache:masterfrom
holdenk:SPARK-59118-doAs-warn

Conversation

@holdenk

@holdenk holdenk commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

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

@HyukjinKwon HyukjinKwon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 HyukjinKwon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One design follow-up on the default behavior (see inline).

.version("5.0.0")
.withBindingPolicy(ConfigBindingPolicy.NOT_APPLICABLE)
.booleanConf
.createWithDefault(false)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 dongjoon-hyun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread project/SparkBuild.scala Outdated
"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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 jzhan-2026 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on the feedbacks from prior reviewers. Happy to review again once those comments are resolved.

sfc-gh-hkarau and others added 5 commits September 22, 2026 01:08
…, 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]>
@holdenk
holdenk force-pushed the SPARK-59118-doAs-warn branch from 681e1d1 to bcca8a6 Compare September 22, 2026 01:11

@dongjoon-hyun dongjoon-hyun left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, LGTM (Pending CIs). Thank you, @holdenk .

@holdenk

holdenk commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

Merged for master, the backport remains #58438

cloud-fan added a commit that referenced this pull request Oct 27, 2026
### 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]>
cloud-fan added a commit that referenced this pull request Oct 28, 2026
….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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants