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

   ### What changes were proposed in this pull request?
   
   Log a warning when a submission sets both 
`spark.kubernetes.authenticate.driver.serviceAccountName` and any of the 
driver's own client credentials, since the credentials win and the service 
account is never applied to the driver pod. The message names the account that 
was dropped, the credential configs that took precedence, and the way to have 
both. It stays quiet when the pod spec already names that same account, because 
then nothing was lost. Also spell out the same in `running-on-kubernetes.md`.
   
   Behavior is unchanged. Two supporting bits: collecting the credential config 
names for the message replaces the four-way `isDefined` disjunction that 
computed `shouldMountSecret`, and `CONFIGS` joins `LogKeys` so the joined list 
gets a plural MDC key like `PATHS` and `EXECUTOR_IDS` rather than reusing 
`CONFIG2`, which everywhere else in the tree holds a single key.
   
   ### Why are the changes needed?
   
   `DriverKubernetesCredentialsFeatureStep.configurePod` applies the service 
account only on the branch with no credentials secret to mount:
   
   ```scala
   override def configurePod(pod: SparkPod): SparkPod = {
     if (!shouldMountSecret) {
       pod.copy(pod = buildPodWithServiceAccount(driverServiceAccount, 
pod).getOrElse(pod.pod))
     } else {
       // mounts the credentials secret; driverServiceAccount is never read here
   ```
   
   `shouldMountSecret` is true if any of `oauthToken`, `caCertFile`, 
`clientKeyFile`, `clientCertFile` was given for the driver.
   
   That precedence is intended. `docs/running-on-kubernetes.md` has said since 
2.3.0 that the service account "cannot be specified alongside a CA cert file, 
client key file, client cert file, and/or OAuth token", and the config's own 
doc says the driver "will favor using those credentials instead". But nothing 
enforces it and nothing reports it, so a submission setting both is accepted 
and looks honored, while the driver pod is left with the service account its 
spec already names, or the namespace's `default`, and whatever RBAC that 
carries. `running-on-kubernetes.md` is candid that the default account "may or 
may not have the role that allows driver pods to create pods and services", so 
the mistake can surface much later as an authorization failure when the driver 
requests executors.
   
   `caCertFile` is the easiest of the four to trip over. It only establishes 
TLS trust in the API server, so it is not by itself something the driver 
authenticates with, yet it is enough on its own to drop the account:
   
   ```
   --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \
   --conf spark.kubernetes.authenticate.driver.caCertFile=/path/to/ca.pem
   ```
   
   The driver then reaches the API server as the namespace default account, 
whose in-pod token `Config.autoConfigure` picks up.
   
   The warning points at `spark.kubernetes.authenticate.driver.mounted.*` 
rather than telling the user to drop one of the two. Those configs read paths 
already present in the driver pod, never feed `shouldMountSecret`, and 
therefore keep the service account, so they are the one setting that satisfies 
both intents. "Unset one of them" would have been bad advice in both 
directions: unsetting `caCertFile` gives up TLS trust in a private-CA API 
server, and unsetting the account also moves executor pods off it, since 
`ExecutorKubernetesCredentialsFeatureStep` falls back to the driver's account 
when `spark.kubernetes.authenticate.executor.serviceAccountName` is unset. This 
is not a matter of swapping the prefix, though: there is no 
`mounted.oauthToken`, only `mounted.oauthTokenFile`, so a submitted token has 
to become a file inside the pod first. The message says to put the credentials 
in the pod and point the `mounted.*` configs at them, which covers all four.
   
   One case is worth suppressing. A driver pod template that already names the 
same account in its spec loses nothing on this branch, since the branch keeps 
whatever the spec names, so warning there is only noise. It is also exactly the 
configuration a user lands on after reading the `mounted.*` advice and deciding 
to pin the account in a template instead. Reading the account off the spec 
needs both fields. `serviceAccount` is Kubernetes' deprecated alias of 
`serviceAccountName`, and `serviceAccountName` wins when a spec sets the two to 
different values. A pod template is deserialized straight into the model object 
with no API-server defaulting, so a template naming only one of them leaves the 
other null. An explicitly empty `serviceAccountName` counts as unset, matching 
`SetDefaults_PodSpec`, which copies the alias up in that case.
   
   I went with a warning rather than a `require`. A `require` would match the 
documented "cannot" and is the more honest reading of the docs, but it would 
reject submissions that are accepted today, which needs a release note and a 
deprecation path. Happy to switch if reviewers would rather enforce it.
   
   ### Does this PR introduce _any_ user-facing change?
   
   A new WARN at submit time for submissions that set both. No API, 
configuration, or pod-spec change.
   
   ### How was this patch tested?
   
   Two tests in `DriverKubernetesCredentialsFeatureStepSuite`, split along what 
they pin.
   
   `warn when driver credentials drop the driver service account` sets the 
account plus a `caCertFile` and checks that the pod spec's `serviceAccount` and 
`serviceAccountName` are still null, pinning the behavior the warning 
describes; that exactly one WARN names both configs; that it does *not* name 
the three credential configs which were not set, which pins the filter rather 
than just the fact that something was logged; and that it still points at the 
`mounted.*` prefix, since that sentence is the whole value of the message. It 
then requires the warning for two pod shapes that name a different account, one 
of which sets `serviceAccount` and `serviceAccountName` to different values, so 
reversing the field precedence fails.
   
   `stay quiet when the driver service account survives` covers the three cases 
that must not warn: the account alone, where it *is* applied; the account 
alongside `mounted.caCertFile`, the escape hatch the message and the docs point 
at; and four pod template shapes naming the same account, covering 
`serviceAccountName` only, `serviceAccount` only, both, and the alias plus an 
empty `serviceAccountName`.
   
   Each assertion has a mutation that turns it red, and I ran all of them: 
dropping the new guard; dropping the `mounted.*` sentence; letting the 
`mounted.*` keys feed `shouldMountSecret`; reading only `getServiceAccount`; 
reading only `getServiceAccountName`; widening the guard to "the pod names any 
account"; dropping the empty-string filter; and reversing the two fields. One 
in the other direction as well: adding a `logInfo` to the step keeps all three 
quiet assertions green, since they filter for WARN.
   
   Against `master` the first test fails:
   
   ```
   [info] - SPARK-58872: warn when driver credentials drop the driver service 
account *** FAILED ***
   [info]   0 did not equal 1 expected one warning naming both 
spark.kubernetes.authenticate.driver.serviceAccountName and 
spark.kubernetes.authenticate.driver.caCertFile, got: List()
   ```
   
   `build/sbt -Pkubernetes kubernetes/test`: 386 tests across 42 suites, all 
passing. `common-utils/testOnly org.apache.spark.util.LogKeysSuite` passes, so 
`CONFIGS` is in sorted position. `kubernetes/scalastyle`, 
`kubernetes/Test/scalastyle`, and `common-utils-java/Compile/checkstyle` report 
no issues.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (Opus 5)
   


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