Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Meetup: Spark + Kerberos

519 vues

Publié le

Los proyectos de Big Data han pasado de sus fases de POC, donde la seguridad ha sido, en el mejor de los casos, un aspecto secundario. Por ello las herramientas Big Data y más concretamente las usadas para procesar datos, deben ponerse al día en seguridad.

Las herramientas como Spark, no están pensados para la seguridad. Por eso Abel y Jorge quieren compartir los hacks que han sido necesarios hacer a Spark para poder usar Kerberos para autenticarse contra servicios securizados.

Publié dans : Technologie
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Meetup: Spark + Kerberos

  1. 1. Spark + Kerberos Noviembre 2016 Meetup
  2. 2. Jorge López-Malla Matute INDEX jlopezm@stratio.com Abel Rincón Matarranz arincon@stratio.com Introducción al Big Data y la seguridad ● Seguridad Perimetral 1 3 Kerberos ● Introducción ● El protocolo 2 4Arquitectura Spark y Seguridad ● Standalone ● YARN/Mesos clietn ● Mesos Cluster ● YARN/Mesos y Kerberos. ● Spark y seguridad RoadTrip ● Stratio Requirements ● Spark Package ● Añadiendo user a RDD ● Task/Scheduler ● Kerberos User ● SaveAs… ● Wrappers ● SparkSQL ● Spark 2.0
  3. 3. Presentación Presentación JORGE LÓPEZ-MALLA Tras trabajar con algunas metodologías tradicionales empecé a centrarme en el mundo del Big Data, del cual me enamoré. Ahora soy arquitecto Big Data en Stratio y he puesto proyectos en producción en distintas partes del mundo. SKILLS
  4. 4. Presentación Presentación ABEL RINCÓN MATARRANZ SKILLS
  5. 5. Introducción al Big Data y la seguridad1
  6. 6. Seguridad y Big Data • La mayoría de las tecnologías Big Data se toman la seguridad como algo secundario, en el mejor de los casos • Una prueba de esto es: ¿habéis visto al claim de seguridad en estas tecnologías? • Los cluster de Big Data normalmente relegan la seguridad en poner una barrera alrededor del cluster. • Desde que HDFS se integró con Kerberos, Kerberos es el protocolo de autenticación por defecto para tecnologías Big Data Introducción al Big Data y la seguridad
  7. 7. Seguridad Perimetral Introducción al Big Data y la seguridad
  8. 8. Seguridad Perimetral Introducción al Big Data y la seguridad • Se establece una única máquina de acceso y se securiza la entrada a esa máquina • Segundo inconveniente: Los datos no se pueden poder usar desde fuera del cluster. Gran lastre con las herramientas de BI y analiticas actuales. • Primer inconveniente: No suelen permitir multitud de usuarios concurrente operando a la vez en el cluster
  9. 9. Kerberos2
  10. 10. Kerberos Kerberos • ¿Qué es Kerberos? ○ Servicio de autenticación ■ Seguro ■ Single-sign-on ■ Basado en confianza ■ Autenticación mutua
  11. 11. Kerberos-Terminología Kerberos • Principal → Nombre (userName / serviceName) • Realm → Entorno( DEMO.MEETUP.COM) • Cliente/Servicio → usuario a nivel de kerberos • KDC → servicio de distribución de claves • TGT → contiene la sesión del cliente • TGS → contiene la sesión del servicio
  12. 12. Kerberos Protocolo Kerberos 1. Se especifica el nombre del cliente 2. Petición de TGT 3. KDC envía la clave de sesión con el TGT 4. El cliente manda el TGT y la petición de TGS 5. KDC devuelve el TGS 6. El cliente manda el TGS al servicio 7. Se establece la conexión entre cliente y servicio cifrada con la clave de sesión del servicio
  13. 13. Kerberos-Impersonación Kerberos
  14. 14. Arquitectura Spark3
  15. 15. Arquitectura Spark • Un cluster de Spark puede ser gestionado de tres maneras distintas: ○ Standalone: Denominado así porque el propio Spark se gestiona su cluster. ■ Master y Workers. ■ No tiene ninguna implementación con Kerberos. ○ Mesos: Gestor de recursos por el que nace Spark. ■ Master y Agents. ■ Mesosphere añade una implementación con Kerberos. ○ YARN: Gestor de trabajos de Hadoop. ■ Resource Manager y Node Managers. ■ Tiene una implementación con Kerberos que depende de HDFS. Arquitectura Spark
  16. 16. Standalone Arquitectura Spark Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Driver Master Worker-1 Worker-2 Executor-0 Executor-1 Task-0 Task-1Task-2 Task-3 HDFS
  17. 17. Mesos/YARN - client Arquitectura Spark Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Driver Mesos Master/Resource Manager Agent/ NodeManager-1 Executor-0 Executor-1 Task-0 Task-1Task-2 Task-3 HDFS Agent/ NodeManager-2 Executor-0 Executor-1
  18. 18. Mesos - Cluster Arquitectura Spark Mesos Master Agent-2 Executor-1 Executor-2 Task-0 Task-1Task-2 Task-3 HDFS Agent-3 Executor-0 Executor-1 Agent-1 Executor-0 Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Spark dispatcher Driver Driver
  19. 19. Mesos y Kerberos Arquitectura Spark Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Driver Mesos Master/Resource Manager Agent/ NodeManager-1 Executor-0 Executor-1 Task-0 Task-1Task-2 Task-3 HDFS Agent/ NodeManager-2 Executor-0 Executor-1 tgt/keytab 64
  20. 20. Spark y seguridad • Kerberos no es la única medida de seguridad de Spark • ACLs para modificación de Jobs. • Securización de comunicaciones mediante TLS. ○ Driver con Executors -> Sólo en versiones anteriores a la 2.0. ○ File Server: files y broadcast -> todas las versiones. ○ Webs: Standalone Master/Slave, history Server y Application UI. • La seguridad mejora en cada nueva versión de Spark. Arquitectura Spark
  21. 21. Spark y Seguridad Arquitectura Spark Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Driver Mesos Master Agent-1 Executor-0 Executor-1 Task Task-1 HDFS Agent-2 Executor-0 Executor-1 encriptación TLS Kerberos file1 file1 file1
  22. 22. Spark y Seguridad Arquitectura Spark Main { ….. …. sc = new SparkContext() rdd1 = sc.textFile.map() rdd1.saveAs…. } Driver Mesos Master Agent-1 Executor-0 Executor-1 Task Task-1 HDFS Agent-2 Executor-0 Executor-1 encriptación TLS Kerberos file1 file1 file1
  23. 23. Road Trip 4
  24. 24. XData • XData es un framework distribuido con tecnología de Apache Spark. • Tiene dos modos Server y librería. • Puede usarse con herramientas BI, mediante una API Java/Scala y con una shell interactiva. • no hay tls y tienen plugin de AAA. • Cuando usa un Cluster de Spark es agnóstico de Cluster Manager. • Puede mezclar Streaming con Batch. StratioRequirements Road Trip
  25. 25. StratioRequirements Impersonación en tiempo real • Como Usuario Final de Crossdata necesito autenticarme contra el backend de datos en mi nombre para tener una gestión de permisos individualizada en él. • Crossdata en modo servidor tiene como particularidad, el uso de un contexto “infinito” • Crossdata usará un principal propio para el servicio • Crossdata da soporte a varios usuarios sobre la misma sesión • Spark se debe autenticar sobre hdfs como el usuario final no como crossdata Road Trip
  26. 26. ¿Por qué no nos valen las soluciones actuales? • CrossData es agnóstico al cluster manager, ergo debería poder usar cualquiera de los tres. • Ninguna de las dos soluciones actuales (YARN ni Mesos) permite la impersonación • Sólo se permite un usuario por Executor/YARN Containner • Además de autenticar en los Executors hay que autenticar en el Driver • No deberíamos limitarnos a Hadoop ni a Kerberos. StratioRequirements Road Trip
  27. 27. Consideraciones Previas • Se va a usar un Único Principal/Keytab y se usarán Usuarios Proxyficados • Se tiene que permitir ejecuciones de varios usuarios en el mismo cluster con la mínima intervención de los mismos • La solución no puede ser dependiente de particularidades de Cluster Managers StratioRequirements Road Trip
  28. 28. • Primera Idea ○ El primer intento fue hacer un SecuredRDD. ○ Se añadiría al Spark Packages ○ Sólo se permite un usuario por Executor/YARN Containner Spark Packages Road Trip • Resultado ○ Aunque podíamos autentificar en el Driver NO se puede hacer nada en los Executor -> Hay que tocar el API de Task ○ Se aprende que hay que meter el usuario en los RDD para poder pasarlos del Driver a los executors
  29. 29. Task/Scheduler Road Trip private[spark] abstract class Task[T]( val stageId: Int, val stageAttemptId: Int, val partitionId: Int, internalAccumulators: Seq[Accumulator[Long]], proxyUser: Option[String]) extends Serializable with Logging{
  30. 30. class DAGScheduler(...){ … … val tasks: Seq[Task[_]] = try { val stageUser = KerberosUser.getMaybeUser stage match { case stage: ShuffleMapStage => partitionsToCompute.map { id => val locs = taskIdToLocations(id) val part = stage.rdd.partitions(id) new ShuffleMapTask(stage.id, stage.latestInfo.attemptId, taskBinary, part, locs, stage.internalAccumulators, stageUser) } case stage: ResultStage => val job = stage.activeJob.get partitionsToCompute.map { id => val p: Int = stage.partitions(id) val part = stage.rdd.partitions(p) val locs = taskIdToLocations(id) new ResultTask(stage.id, stage.latestInfo.attemptId, taskBinary, part, locs, id, stage.internalAccumulators, stageUser) } } Task/Scheduler Road Trip
  31. 31. • Se vio que era necesario añadir un usuario a cada RDD para controlar los accesos en Driver/Executor • Primero se optó por añadir campos a los métodos que crean RDD provenientes de Hadoop • Primera prueba con usuarios dentro de RDDs: ○ Resultado: Añadiendo Usuarios a RDD Road Trip ¡Éxito!
  32. 32. • No termina de ser una solución “limpia” ○ Si se crea un método para crear RDDs lo deberíamos sobreescribir • Se opta por añadir un método setUser a nivel de RDD que configura los usuarios antes de calcular sus particiones • Primera prueba con usuarios en un método de RDD: ○ Resultado: Añadiendo Usuarios a RDD Road Trip ¡Fracaso!
  33. 33. user = user1user = None • Se necesita calcular el usario en el base RDD Añadiendo Usuarios a RDD Road Trip scala:> sc.texFile(“numbers.txt”).map(string => string.toInt).setUser(“user1”).collect HDFS map setUser user = None user = None user = user1 map setUser user = None user = None
  34. 34. • Segunda prueba con usuarios en un método de RDD: ○ Resultado: Añadiendo Usuarios a RDD Road Trip ¡Éxito! • Primera prueba con larga duración (Streaming) ○ Resultado: ¡Fracaso! • Errores de renovación de credenciales
  35. 35. KerberosUser (Utils) object KerberosUser extends Logging with UserCache { private lazy val getConfiguration: Option[(String, String)] = { val principal = env.conf.getOption("spark.executor.kerberos.principal") val keytab = env.conf.getOption("spark.executor.kerberos.keytab") (principal, keytab) match { case (Some(p), Some(k)) => Option(p, k) case _ => None } } def setProxyUser(user: String): Unit = proxyUser = Option(user) private def userFromKeyTab(proxyUser: Option[String]): Option[UserGroupInformation] = { val keytab = getConfiguration.get._2 val realUser = Try(UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal.get, keytab)).toOption realUser.get.setAuthenticationMethod(AuthenticationMethod.KERBEROS) val user = (realUser, proxyUser) match { case (Some(real), Some(proxy)) => Option(UserGroupInformation.createProxyUser(proxy, real)) case (Some(real), None) => realUser case (None, None) => None } if (user.isDefined) putCacheUser(proxyUser.getOrElse(principal.get),user) user } Configuración Set del proxy user Decide si usa el usuario real o el proxy y alimenta / usa la caché de usuarios Road Trip
  36. 36. class PairRDDFunctions[K, V](self: RDD[(K, V)]) (implicit kt: ClassTag[K], vt: ClassTag[V], ord: Ordering[K] = null) ... def saveAsHadoopDataset(conf: JobConf): Unit = self.withScope { val internalSave: (JobConf => Unit) = (conf: JobConf) => { // Rename this as hadoopConf internally to avoid shadowing (see SPARK-2038). val hadoopConf = conf ... val writeToFile = (context: TaskContext, iter: Iterator[(K, V)]) => { …. } self.context.runJob(self, writeToFile) writer.commitJob() } KerberosUser.getUserByName(self.user) match { case Some(user) => { user.doAs(new PrivilegedExceptionAction[Unit]() { @throws(classOf[Exception]) def run: Unit = internalSave(conf) }) } case None => internalSave(conf) } } saveAs…. Road Trip Método real de guardado con Spark wrapper de método de guardar hecho por Spark ejecución autentificada con Kerberos
  37. 37. • Segunda prueba EndToEnd ○ Se prueba el mismo fichero con SparkSQL ○ Resultado: ¡Fracaso! • Primera prueba EndToEnd ○ Se prueba una lectura de un fichero txt para luego escribirlo tras ordenarlo en otro fichero ○ Resultado: ¡Éxito! SparkSQL Road Trip
  38. 38. • Al ser los Datasources de Spark “cajas negras” cada uno hace lo que considera necesario para funcionar ○ Ej: Parquet lanza un trabajo de Spark sólo para leer el esquema. • Ya no vale con tener un usuario dentro del RDD, tenemos que tener control sobre el usuario actual (se cambia en SQL mediante Options) • ¡Kerberos User! • Idéntico resultado al guardar (Fallo) • No sólo tenemos que controlar la carga de datos sino que también la ejecución de queries SparkSQL Road Trip
  39. 39. • Métodos que requieren autentificarse con Kerberos: DataframeReader: ■ load-> carga un RDD desde un Datasource ○ QueryExecution: ■ toRDD -> ejecuta un queryPlan y lo transforma en RDD[Row] ○ ResolvedDataSource: ■ apply -> crea un nuevo Resolved Datasource para poder leerlo. SparkSQL Road Trip • Segunda prueba EndToEnd ○ Se prueba el mismo fichero con SparkSQL dos veces cambiando el usario ○ Resultado: ¡Éxito!
  40. 40. Wrappers (Utils) def executeSecure[U, T](proxyUser: Option[String], funct: (U => T), inputParameters: U): T = { KerberosUser.getUserByName(proxyUser) match { case Some(user) => { user.doAs(new PrivilegedExceptionAction[T]() { @throws(classOf[Exception]) def run: T = { funct(inputParameters) } }) } case None => { funct(inputParameters) } } } def executeSecure[T](exe: ExecutionWrp[T]): T = { KerberosUser.getUser match { case Some(user) => { user.doAs(new PrivilegedExceptionAction[T]() { @throws(classOf[Exception]) def run: T = { exe.value } }) } case None => exe.value } } class ExecutionWrp[T](wrp: => T) { lazy val value: T = wrp } Road Trip
  41. 41. • Cambios principales: ○ Los Task tiene un properties dentro -> NO SE TOCA SU API ○ La lectura de los Datasources en SQL se hace principalmente en una clase ○ Se intenta guardar el catálogo de SparkSQL en HDFS. Spark 2.0. Road Trip
  42. 42. Spark 2.0. private[spark] abstract class Task[T]( val stageId: Int, val stageAttemptId: Int, val partitionId: Int, internalAccumulators: Seq[Accumulator[Long]], proxyUser: Option[String]) extends Serializable with Logging{ Road Trip Task * @param localProperties copy of thread-local properties set by the user on the driver side. */ private[spark] abstract class Task[T]( val stageId: Int, val stageAttemptId: Int, val partitionId: Int, // The default value is only used in tests. val metrics: TaskMetrics = TaskMetrics.registered, @transient var localProperties: Properties = new Properties) extends Serializable {
  43. 43. Spark 2.0. override def createDatabase( dbDefinition: CatalogDatabase, ignoreIfExists: Boolean): Unit = synchronized { def inner: Unit = { ... val location = new Path(dbDefinition.locationUri) val fs = location.getFileSystem(hadoopConfig) fs.mkdirs(location) } catch { case e: IOException => throw new SparkException(s"Unable to create database ${dbDefinition.name} as failed " + s"to create its directory ${dbDefinition.locationUri}", e) } catalog.put(dbDefinition.name, new DatabaseDesc(dbDefinition)) } } KerberosFunction.executeSecure(KerberosUser.principal, new ExecutionWrp(inner)) } Road Trip InMemoryCatalog crea directorio en HDFS
  44. 44. def resolveRelation(checkPathExist: Boolean = true): BaseRelation = { val caseInsensitiveOptions = new CaseInsensitiveMap(options) val maybeUser = caseInsensitiveOptions.get("user") match { case user if user.isDefined => user case _ => KerberosUser.getMaybeUser } def inner: BaseRelation = { ... // This is a non-streaming file based datasource. case (format: FileFormat, _) => val allPaths = caseInsensitiveOptions.get("path") ++ paths ... val fs = hdfsPath.getFileSystem(sparkSession.sessionState.newHadoopConf()) val qualified = hdfsPath.makeQualified(fs.getUri, fs.getWorkingDirectory) ... } } val relation = KerberosFunction.executeSecure(maybeUser, new ExecutionWrp(inner)) relation } Spark 2.0. - DataSource Road Trip lee el usuario del options del DF crea directorio en HDFS Datasources con path
  45. 45. • Segunda prueba EndToEnd ○ Se prueba el mismo fichero con SparkSQL dos veces cambiando el usario ○ Resultado: • Primera prueba EndToEnd ○ Se prueba una lectura de un fichero txt para luego escribirlo tras ordenarlo en otro fichero ○ Resultado: Spark 2.0 Road Trip ¡Éxito! ¡Éxito!
  46. 46. tgstgt read.format(parquet).path(“/use r1/b”).option(“user”, “user2”) read.format(parquet).path(“b”). option(“user”, “user2”) toDF.saveAsParquet(“b”)textFile(“a”) saveAsTextFile(“a”) Imagen final Road Trip Driver Executor sparkUser user1 user2 HDFS tgttgs ¿Se cumplen los requistos iniciales?
  47. 47. • Entrar en Apache Spark* • Asociar la creación del RDD al “usuario activo” • Kerberizar sólo las acciones que requieran ser Kerberizadas • ¿Siempre Kerberos? ¿Por qué? • Caché de usuarios distribuida • La dominación mundial Y después de esto, ¿qué viene? Road Trip
  48. 48. Ruegos y preguntas Ruegos y preguntas
  49. 49. ¡Esto es todo amigos! MUCHAS GRACIAS Y ANIMAROS A COMPARTIR CONOCIMIENTO
  50. 50. people@stratio.com WE ARE HIRING @StratioBD

×