<p>I'm trying to run Spark on Kubernetes, with the aim of processing data from a  Kerberized Hadoop cluster. My application consists of simple SparkSQL transformations. While I'm able to run the process successfully on a single driver pod, I cannot do this when attempting to use any executors. Instead, I get:  </p>

<blockquote>
  <p>org.apache.hadoop.security.AccessControlException: SIMPLE
  authentication is not enabled.  Available:[TOKEN, KERBEROS]</p>
</blockquote>

<p>Since the Hadoop environment is Kerberized, I've provided a valid keytab, as well as the core-site.xml, hive-site.xml, hadoop-site.xml, mapred-site.xml and yarn-site.xml, and a krb5.conf file inside the docker image. </p>

<p>I set up the environment settings with the following method:</p>

<pre><code>trait EnvironmentConfiguration {

def configureEnvironment(): Unit = {
  val conf = new Configuration
  conf.set("hadoop.security.authentication", "kerberos")
  conf.set("hadoop.security.authorization", "true")
  conf.set("com.sun.security.auth.module.Krb5LoginModule", "required")
  System.setProperty("java.security.krb5.conf", ConfigurationProperties.kerberosConfLocation)    
  UserGroupInformation.loginUserFromKeytab(ConfigurationProperties.keytabUser, ConfigurationProperties.keytabLocation)
  UserGroupInformation.setConfiguration(conf)
}
</code></pre>

<p>I also pass the *-site.xml files through the following method: </p>

<pre><code>trait SparkConfiguration {

  def createSparkSession(): SparkSession = {
    val spark = SparkSession.builder
    .appName("MiniSparkK8")
    .enableHiveSupport()
    .master("local[*]")
    .config("spark.sql.hive.metastore.version", ConfigurationProperties.hiveMetastoreVersion)
    .config("spark.executor.memory", ConfigurationProperties.sparkExecutorMemory)
    .config("spark.sql.hive.version", ConfigurationProperties.hiveVersion)
    .config("spark.sql.hive.metastore.jars",ConfigurationProperties.hiveMetastoreJars)
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.coreSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.hiveSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.hdfsSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.yarnSiteLocation))
    spark.sparkContext.hadoopConfiguration.addResource(new Path(ConfigurationProperties.mapredSiteLocation))
  }
}
</code></pre>

<p>I run the whole process with the following spark-submit command:</p>

<pre><code>spark-submit ^
--master k8s://https://kubernetes.example.environment.url:8443 ^
--deploy-mode cluster ^
--name mini-spark-k8 ^
--class org.spark.Driver ^
--conf spark.executor.instances=2 ^
--conf spark.kubernetes.namespace=&lt;company-openshift-namespace&gt; ^
--conf spark.kubernetes.container.image=&lt;company_image_registry.image&gt; ^
--conf spark.kubernetes.driver.pod.name=minisparkk8-cluster ^
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark ^
local:///opt/spark/examples/target/MiniSparkK8-1.0-SNAPSHOT.jar ^
/opt/spark/mini-spark-conf.properties
</code></pre>

<p>The above configurations are enough to get my spark application running and successfully connecting to the Kerberized Hadoop cluster. Although the spark submit command declares the creation of two executor pods, this does not happen because I have set master to <code>local[*]</code>. Consequently, only one pod is created which manages to connect to the Kerberized Hadoop cluster and successfully run my Spark transformations on Hive tables.</p>

<p>However, when I remove <code>.master(local[*])</code>, two executor pods are created. I can see from the logs that these executors connecting successfully to the driver pod, and they are assigned tasks. It doesn't take long after this point for both of them to fail with the error mentioned above, resulting in the failed executor pods to be terminated. 
This is despite the executors already having all the necessary files to create a successful connection to the Kerberized Hadoop inside their image. I believe that the executors are not using the keytab, which they would be doing if they were running the JAR. Instead, they're running tasks given to them from the driver.</p>

<p>I can see from the logs that the driver manages to authenticate itself correctly with the keytab for user, <code>USER123</code>: </p>

<blockquote>
  <p>INFO  SecurityManager:54 - SecurityManager: authentication disabled;
  ui acls disabled; users  with view permissions: Set(spark, USER123);
  groups with view permissions: Set(); users  with modify permissions:
  Set(spark, USER123); groups with modify permissions: Set()</p>
</blockquote>

<p>On the other hand, you get the following from the executor's log, you can see that user, USER123 is not authenticated:</p>

<blockquote>
  <p>INFO  SecurityManager:54 - SecurityManager: authentication disabled;
  ui acls disabled; users  with view permissions: Set(spark); groups
  with view permissions: Set(); users  with modify permissions:
  Set(spark); groups with modify permissions: Set()</p>
</blockquote>

<p>I have looked at various sources, including <a href="https://github.com/apache/spark/blob/master/docs/security.md" rel="nofollow noreferrer">here</a>. It mentions that <code>HIVE_CONF_DIR</code> needs to be defined, but I can see from my program (which prints the environment variables) that this variable is not present, including when the driver pod manages to authenticate itself and run the spark process fine. </p>

<p>I've tried running with the following added to the previous spark-submit command: </p>

<pre><code>--conf spark.kubernetes.kerberos.enabled=true ^
--conf spark.kubernetes.kerberos.krb5.path=/etc/krb5.conf ^
--conf spark.kubernetes.kerberos.keytab=/var/keytabs/USER123.keytab ^
--conf spark.kubernetes.kerberos.principal=USER123@REALM ^
</code></pre>

<p>But this made no difference. </p>

<p>My question is: how can I get the executors to authenticate themselves with the keytab they have in their image? I'm hoping this will allow them to perform their delegated tasks. </p>

<p>First get the delegation token from hadoop using the below command . </p>

<ol>
<li>Do a kinit -kt with your keytab and principal</li>
<li>Execute the below to store the hdfs delegation token in a tmp path
<code>spark-submit --class org.apache.hadoop.hdfs.tools.DelegationTokenFetcher "" --renewer null /tmp/spark.token</code></li>
<li>Do your actual spark submit with the adding this configuration .
<code>--conf spark.executorEnv.HADOOP_TOKEN_FILE_LOCATION=/tmp/spark.token \</code></li>
</ol>

<p>The above is how yarn executors authenticate. Do the same for kubernetes executors too. </p>
