[SPARK-57098][UI][4.2] Worker UI JSON endpoint redaction#56147
Closed
peter-toth wants to merge 1 commit into
Closed
[SPARK-57098][UI][4.2] Worker UI JSON endpoint redaction#56147peter-toth wants to merge 1 commit into
peter-toth wants to merge 1 commit into
Conversation
### What changes were proposed in this pull request? The standalone Worker UI serves `GET /json/`, which returns `JsonProtocol.writeWorkerState(...)` and includes each executor's `ApplicationDescription.command` rendered as `Command.toString`. Since `Command` is a case class, that string contains the full `environment` map and `javaOpts` sequence. This PR redacts `Command.environment` via `Utils.redact(conf, ...)` and `Command.javaOpts` via `Utils.redactCommandLineArgs(conf, ...)` before calling `toString`, reusing the same redaction APIs already applied to the launch command in `ExecutorRunner` logging (`ExecutorRunner.scala:162-164`). The `command` field stays a string rendered from a redacted `Command.copy(...)`, so the JSON schema is unchanged. `ExecutorRunner.conf` is promoted to `val` so `JsonProtocol.writeExecutorRunner` can plumb the worker's `SparkConf` into `writeApplicationDescription` for `spark.redaction.regex` lookups. ### Why are the changes needed? `environment` and `javaOpts` routinely carry secrets: JDBC passwords, AWS credentials, SSL keystore passwords, Hadoop credential store passwords, `spark.executorEnv.*` values, etc. `ExecutorRunner` already redacts the same content when writing the launch command to logs, but `JsonProtocol` emits it unredacted over the Worker UI HTTP endpoint. The Worker UI listens on port 8081 with no authentication by default, so any caller with network access to the worker can read the secrets with a single `curl worker:8081/json | jq .executors[].appdesc.command`. The fix removes the inconsistency between log-path and HTTP-path redaction. ### Does this PR introduce _any_ user-facing change? Yes. The `command` field returned by `GET /json/` on the standalone Worker UI now has secret-bearing values in `environment` and `javaOpts` replaced with `*********(redacted)` when they match `spark.redaction.regex` (the default pattern matches keys like `secret`, `password`, `token`, etc.). The JSON schema is unchanged -- `command` remains a single string in `Command.toString` format -- so existing tooling that parses this endpoint continues to work; only the sensitive values that were previously leaked are now masked. ### How was this patch tested? - Added `SPARK-57098: secrets in executor command are redacted in worker JSON endpoint` to `JsonProtocolSuite`, covering both environment-variable and `-D` java-opt secret carriers, asserting that redacted values are scrubbed while non-sensitive values (`JAVA_HOME`, `-Xmx2g`) pass through. - `build/sbt 'core/testOnly org.apache.spark.deploy.JsonProtocolSuite'` -- 11/11 tests pass. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Claude Opus 4.7 Closes apache#56139 from peter-toth/SPARK-57098-worker-ui-json-redaction. Authored-by: Peter Toth <peter.toth@gmail.com> Signed-off-by: Peter Toth <peter.toth@gmail.com>
Contributor
Author
|
@huaxingao , this is identical to #56139. Please merge to 4.2 whenever convenient. |
dongjoon-hyun
approved these changes
May 27, 2026
huaxingao
approved these changes
May 27, 2026
Member
|
Thank you for fixing this security issue for Apache Spark 4.2.0, @peter-toth . |
dongjoon-hyun
pushed a commit
that referenced
this pull request
May 27, 2026
### What changes were proposed in this pull request? The standalone Worker UI serves `GET /json/`, which returns `JsonProtocol.writeWorkerState(...)` and includes each executor's `ApplicationDescription.command` rendered as `Command.toString`. Since `Command` is a case class, that string contains the full `environment` map and `javaOpts` sequence. This PR redacts `Command.environment` via `Utils.redact(conf, ...)` and `Command.javaOpts` via `Utils.redactCommandLineArgs(conf, ...)` before calling `toString`, reusing the same redaction APIs already applied to the launch command in `ExecutorRunner` logging (`ExecutorRunner.scala:162-164`). The `command` field stays a string rendered from a redacted `Command.copy(...)`, so the JSON schema is unchanged. `ExecutorRunner.conf` is promoted to `val` so `JsonProtocol.writeExecutorRunner` can plumb the worker's `SparkConf` into `writeApplicationDescription` for `spark.redaction.regex` lookups. ### Why are the changes needed? `environment` and `javaOpts` routinely carry secrets: JDBC passwords, AWS credentials, SSL keystore passwords, Hadoop credential store passwords, `spark.executorEnv.*` values, etc. `ExecutorRunner` already redacts the same content when writing the launch command to logs, but `JsonProtocol` emits it unredacted over the Worker UI HTTP endpoint. The Worker UI listens on port 8081 with no authentication by default, so any caller with network access to the worker can read the secrets with a single `curl worker:8081/json | jq .executors[].appdesc.command`. The fix removes the inconsistency between log-path and HTTP-path redaction. ### Does this PR introduce _any_ user-facing change? Yes. The `command` field returned by `GET /json/` on the standalone Worker UI now has secret-bearing values in `environment` and `javaOpts` replaced with `*********(redacted)` when they match `spark.redaction.regex` (the default pattern matches keys like `secret`, `password`, `token`, etc.). The JSON schema is unchanged -- `command` remains a single string in `Command.toString` format -- so existing tooling that parses this endpoint continues to work; only the sensitive values that were previously leaked are now masked. ### How was this patch tested? - Added `SPARK-57098: secrets in executor command are redacted in worker JSON endpoint` to `JsonProtocolSuite`, covering both environment-variable and `-D` java-opt secret carriers, asserting that redacted values are scrubbed while non-sensitive values (`JAVA_HOME`, `-Xmx2g`) pass through. - `build/sbt 'core/testOnly org.apache.spark.deploy.JsonProtocolSuite'` -- 11/11 tests pass. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Claude Opus 4.7 Closes #56147 from peter-toth/SPARK-57098-worker-ui-json-redaction-4.2. Authored-by: Peter Toth <peter.toth@gmail.com> Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
Member
|
Merged to branch-4.2 for Apache Spark 4.2.0. |
Member
|
Thank you, @peter-toth and @huaxingao . |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
The standalone Worker UI serves
GET /json/, which returnsJsonProtocol.writeWorkerState(...)and includes each executor'sApplicationDescription.commandrendered asCommand.toString. SinceCommandis a case class, that string contains the fullenvironmentmap andjavaOptssequence.This PR redacts
Command.environmentviaUtils.redact(conf, ...)andCommand.javaOptsviaUtils.redactCommandLineArgs(conf, ...)before callingtoString, reusing the same redaction APIs already applied to the launch command inExecutorRunnerlogging (ExecutorRunner.scala:162-164). Thecommandfield stays a string rendered from a redactedCommand.copy(...), so the JSON schema is unchanged.ExecutorRunner.confis promoted tovalsoJsonProtocol.writeExecutorRunnercan plumb the worker'sSparkConfintowriteApplicationDescriptionforspark.redaction.regexlookups.Why are the changes needed?
environmentandjavaOptsroutinely carry secrets: JDBC passwords, AWS credentials, SSL keystore passwords, Hadoop credential store passwords,spark.executorEnv.*values, etc.ExecutorRunneralready redacts the same content when writing the launch command to logs, butJsonProtocolemits it unredacted over the Worker UI HTTP endpoint. The Worker UI listens on port 8081 with no authentication by default, so any caller with network access to the worker can read the secrets with a singlecurl worker:8081/json | jq .executors[].appdesc.command. The fix removes the inconsistency between log-path and HTTP-path redaction.Does this PR introduce any user-facing change?
Yes. The
commandfield returned byGET /json/on the standalone Worker UI now has secret-bearing values inenvironmentandjavaOptsreplaced with*********(redacted)when they matchspark.redaction.regex(the default pattern matches keys likesecret,password,token, etc.). The JSON schema is unchanged --commandremains a single string inCommand.toStringformat -- so existing tooling that parses this endpoint continues to work; only the sensitive values that were previously leaked are now masked.How was this patch tested?
SPARK-57098: secrets in executor command are redacted in worker JSON endpointtoJsonProtocolSuite, covering both environment-variable and-Djava-opt secret carriers, asserting that redacted values are scrubbed while non-sensitive values (JAVA_HOME,-Xmx2g) pass through.build/sbt 'core/testOnly org.apache.spark.deploy.JsonProtocolSuite'-- 11/11 tests pass.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Opus 4.7