(PySpark) on YARN - Behind the Scenes (Teil 4)

pyspark-4

In Teil drei wurde gezeigt, wie unterschiedliche Python Versionen innerhalb eines Hadoop Clusters genutzt werden können. Im letzten Teil dieses Beitrags führt Olaf Hein unter anderem aus, wie mehr Sicherheit mit dem YARN-Container Executor realisiert wird.

Mehr Sicherheit mit dem YARN Container Executor 

In den bisherigen Beispielen wurden die Linux Prozesse der YARN Container als Benutzer yarn ausgeführt. Somit haben die Container im Betriebssystem auch die Rechte des Linux Benutzers yarn. Das ist ein generelles Sicherheitsproblem. Über die Spark Shell erhalten Benutzer somit Zugriff auf das Betriebssystem der Worker Knoten im Cluster. Das ist insbesondere problematisch, da über die Spark Shell, zum Beispiel mit Jupyter Notebooks, interaktiv mit dem Cluster gearbeitet wird. Auch wenn ein böswilliger Angriff unwahrscheinlich wäre, können durch Unachtsamkeit oder Unwissenheit der Anwender Probleme verursacht werden.

Mit dem folgenden kurzen Spark Script kann zum Beispiel schreibend auf Dateien im Betriebssystem des Worker Nodes zugegriffen werden, auf dem der Spark Executor Prozess gestartet wurde.

rdd1 = sc.parallelize([1])
rdd2 = rdd1.map(lambda i: open("/var/log/hadoop-yarn/attack-" + str(i) + ".txt","w").close())
rdd2.collect() 

Im Betriebssystem wird dadurch eine Datei geschrieben, die dem Benutzer yarn gehört:

[cloudera$ ls -ld /var/log/hadoop-yarn/attack*
-rw-r--r-- 1 yarn yarn 0 Jul 21 02:07 /var/log/hadoop-yarn/attack-1.txt 

Mit welchen Benutzerprivilegien die Prozesse des Executors gestartet werden, kann mit dem folgenden Parameter in der core-site.xml festgelegt werden:

yarn.nodemanager.container-executor.class 

Die Default Einstellung ist die Klasse DefaultContainerExecutor. Wird der DefaultContainerExecutor verwendet, dann werden neue Container mit dem Benutzer gestartet, mit dem der NodeManager gestartet wurde. Üblicherweise ist das der Benutzer yarn.

Eine weitere Option ist der Wert LinuxContainerExecutor.

In einem ungesicherten Cluster (d.h. ein Cluster ohne Kerberos), kann mit dem LinuxContainerExcutor dafür gesorgt werden, dass die Prozesse der YARN Container im Linux nicht mehr mit dem Benutzer yarn gestartet werden. Es gibt zwei Optionen:

  • Prozesse werden mit einem definierten Benutzer (local-user) gestartet (Standard ist nobody)
  • Prozesse werden mit dem Benutzer gestartet, der den YARN Job gestartet hat

In einem ungesicherten Cluster sorgt der LinuxContainerExcutor für eine Trennung der Container Prozesse im Betriebssystem vom Hadoop System selbst. Eine verlässliche Absicherung des Clusters ist allerdings nur zusammen mit Kerberos möglich.

LinuxContainerExecutor mit Kerberos Authentifizierung 

In einem abgesicherten Cluster wird Kerberos für die Authentifizierung der Benutzer verwendet. Der LinuxContainerExecutor sorgt in diesem Fall für eine zuverlässige Trennung der Container Prozesse im Betriebssystem vom Rest des Systems. Weiterhin werden die Prozesse der verschiedenen Benutzer des Clusters sauber voneinander getrennt. Der verwendete container-executor wird in der yarn-site.xml konfiguriert:

<property>
  <name>yarn.nodemanager.container-executor.class</name>
  <value>
    org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
  <source>yarn-site.xml</source>
</property> 

Wird der LinuxContainerExecutor verwendet, dann wird zusätzlich die Konfigurationsdatei container-executor.cfg benötigt. Die Dabei enthält Variablen, deren Einstellungen von der Cluster Konfiguration abhängen. Im Folgenden wird die Konfigurationsdatei gezeigt (die mit # markierte Kommentare sind nicht Teil der Datei):

# Linux Gruppe, der das Linux Excecutor Binary gehört
yarn.nodemanager.linux-container-executor.group=yarn
# Minimale UID, die eine YARN Applikation starten darf
min.user.id=500
# Benutezr mit einer UID < 500, die eine YARN Applikation starten dürfen
allowed.system.users=nobody,impala,hive,llama,hbase,cloudera
# Benutzer, die keine YARN Applikation starten dürfen
banned.users=hdfs,yarn,mapred,bin 

Der Benutzer yarn ist bewusst ausgeschlossen. Damit wird zuverlässig verhindert, dass Container Prozesse mit den yarn Rechten ausgeführt werden.

Wird eine YARN Applikation, zum Beispiel durch den Start der Spark Shell, gestartet, dann werden die Prozesse der Container im Betriebssystem mit dem Benutzer des Kerberos Principals ausgeführt. Im folgenden Beispiel wird eine Spark Shell mit dem Benutzer cloudera gestartet. Im Betriebssystem wird anschließend überprüft, mit welchen Rechten die Applikationen bzw. Prozesse ausgeführt werden.

[cloudera@quickstart ~]$ spark-shell --master yarn
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel).
Welcome to

      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 1.6.0
      /_/

Using Scala version 2.10.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_121)
Type in expressions to have them evaluated.
Type :help for more information.
Spark context available as sc (master = yarn-client, app id = application_1563648717138_0004).
SQL context available as sqlContext.

scala> 

In einem zweiten Terminal wird überprüft, welche Prozesse mit welchem Benutzer ausgeführt werden.

[cloudera]$ yarn application -list
19/07/20 21:47:22 INFO client.RMProxy: Connecting to ResourceManager at quickstart.cloudera/10.0.2.15:8032
Total number of applications (application-types: [] and states: [SUBMITTED, ACCEPTED, RUNNING]):1
Application-Id   Application-Name   Application-Type   User   Queue   State   Final-State   Progress   Tracking-URL
application_1563648717138_0004   Spark   shell   SPARK   cloudera   root.users.cloudera   RUNNING   UNDEFINED   10%   http://10.0.2.15:4040 

Als Benutzer wird cloudera angezeigt. Das ist der Benutzer, dessen Rechte innerhalb von Hadoop genutzt werden um auf Ressourcen, wie zum Beispiel Dateien und Verzeichnisse im HDFS, zuzugreifen.

Im Linux Betriebssystem werden die folgenden Prozesse für die Application ID ausgeführt:

[cloudera]$ ps -ef | grep 1563648717138_0004
cloudera10114756 0 21:49 pts/000:00:00 grep 1563648717138_0004
yarn312514134 0 21:41 ? 00:00:00 /opt/cloudera/parcels/CDH-5.10.0-1.cdh5.10.0.p0.41/lib/hadoop-yarn/bin/container-executor cloudera cloudera 1 application_1563648717138_0004 container_1563648717138_0004_01_000001 /yarn/nm/usercache/cloudera/appcache/application_1563648717138_0004/container_1563648717138_0004_01_000001 /yarn/nm/nmPrivate/application_1563648717138_0004/container_1563648717138_0004_01_000001/launch_container.sh /yarn/nm/nmPrivate/application_1563648717138_0004/container_1563648717138_0004_01_000001/container_1563648717138_0004_01_000001.tokens /yarn/nm/nmPrivate/application_1563648717138_0004/container_1563648717138_0004_01_000001/container_1563648717138_0004_01_000001.pid /yarn/nm /var/log/hadoop-yarn/container cgroups=none

cloudera 31254 31251 0 21:41 ? 00:00:00 /bin/bash -c LD_LIBRARY_PATH=/opt/cloudera/parcels/CDH-5.10.0-1.cdh5.10.0.p0.41/lib/hadoop/../../../CDH-5.10.0-1.cdh5.10.0.p0.41/lib/hadoop/lib/native: /usr/java/default/bin/java -server -Xmx512m -Djava.io.tmpdir=/yarn/nm/usercache/cloudera/appcache/application_1563648717138_0004/container_1563648717138_0004_01_000001/tmp -Dspark.yarn.app.container.log.dir=/var/log/hadoop-yarn/container/application_1563648717138_0004/container_1563648717138_0004_01_000001 org.apache.spark.deploy.yarn.ExecutorLauncher --arg '10.0.2.15:45614' --executor-memory 1024m --executor-cores 1 --properties-file /yarn/nm/usercache/cloudera/appcache/application_1563648717138_0004/container_1563648717138_0004_01_000001/__spark_conf__/__spark_conf__.properties 1> /var/log/hadoop-yarn/container/application_1563648717138_0004/container_1563648717138_0004_01_000001/stdout 2> /var/log/hadoop-yarn/container/application_1563648717138_0004/container_1563648717138_0004_01_000001/stderr

cloudera 31256 31254 3 21:41 ? 00:00:19 /usr/java/default/bin/java -server -Xmx512m -Djava.io.tmpdir=/yarn/nm/usercache/cloudera/appcache/application_1563648717138_0004/container_1563648717138_0004_01_000001/tmp -Dspark.yarn.app.container.log.dir=/var/log/hadoop-yarn/container/application_1563648717138_0004/container_1563648717138_0004_01_000001 org.apache.spark.deploy.yarn.ExecutorLauncher --arg 10.0.2.15:45614 --executor-memory 1024m --executor-cores 1 --properties-file /yarn/nm/usercache/cloudera/appcache/application_1563648717138_0004/container_1563648717138_0004_01_000001/__spark_conf__/__spark_conf__.properties 

Der Container Executor wird weiterhin mit dem Benutzer yarn ausgeführt. Beim Einsatz des LinuxContainerExecutors ist es aber kein Bash Script, sondern eine native Linux Anwendung. Die Container selbst werden jetzt mit dem Benutzer cloudera gestartet.

Zu beachten ist, dass Hadoop in einem sicheren Cluster nur den Namen aus dem Kerberos Principal betrachtet. Dieser Name wird vom LinuxContainerExecutor verwendet, um die Prozesse der YARN Container im Betriebssystem zu starten. Des Weiteren können über diesen Namen Ressourcen innerhalb des Hadoop Clusters (HDFS Dateien, Hive Tabellen, etc.) autorisiert werden. Über Auth-to-Local Regeln kann in Hadoop konfiguriert werden, wie genau der Name des Kerberos Principals auf Hadoop Benutzernamen gemappt wird. Details dazu würden aber den Rahmen dieses Artikels sprengen.

Fazit

Bei der Ausführung von Spark bzw. PySpark Jobs in einem YARN Cluster müssen einige Besonderheiten beachtet werden. Für die Cluster Installation und Konfiguration ist es notwendig zu verstehen, wann YARN welche Prozesse startet und was dabei im Linux Betriebssystems geschieht ist. Die wichtigsten Punkte sind:

  • Der verwendete Python Interpreter und die Bibliotheken müssen auf allen Worker und Edge Knoten des Clusters installiert werden.
  • Mehrere unterschiedliche Python Distributionen können in einem Cluster gelichzeitig genutzt werden.
  • Über die Spark Shell haben Benutzer Zugriff auf das Betriebssystem der Worker!
  • Der DefaultContainerExecutor startet Linux Prozesse für YARN Container mit den Rechten des yarn Benutzers!
  • Um YARN Container Prozesse mit den Rechten des authentifizierten Benutzers zu starten, werden Kerberos und der LinuxContainerExecutor verwendet.

Weitere Details werden in der Dokumentation von Hadoop und Spark beschrieben.

 

Kommentare

Derzeit gibt es keine Kommentare. Schreibe den ersten Kommentar!
Gäste
Donnerstag, 17. Oktober 2019

Sicherheitscode (Captcha)