SafeChildren Banner

Havoc Oracle Solaris Experts

lunes, 27 de julio de 2009

Introducción a los permisos en HDFS - Problema con DrWho en Solaris 10

Introducción
En la primera parte de la introducción a los permisos en HDFS concluí que era más fácil utilizar IPFilter. La verdad es que esta conclusión la saqué después de mucho tiempo con la configuración a vueltas y un pequeño código que creaba unos archivos y luego los borraba.

El problema de DrWho
Después de un buen rato investigando el código de Hadoop, he encontrado el problema :D y creo que lo he solucionado.

El problema era muy sencillo, cuando ejecutaba un código muy simple que creaba n archivos desde Solaris, siempre me ponía como usuario "DrWho" y como group "" así que por muchos permisos que yo asignaba el código se los saltaba ya que DrWho es supergroup y por lo tanto no evalua los permisos.

Bien, el problema viene por cómo se mira quién es el usuario que está definido en la clase Shell.USER_NAME_COMMAND ($HADOOP_HOME/src/core/org/apache/hadoop/security/) que hace la llamada a "whoami", este comando no existe en Solaris así, sino "who am i", sin embargo, este comando no puede ser llamado si no estás atacado a la consola, así que estoy evaluando las siguientes opciones
  • Modicar el path para incluir los binarios compatibles con BSD que se encuentran en /usr/ucb donde está whoami (Es necesario tener instalado el paquete SUNWscpu)
  • Instalar whoami desde Sunfreeware.
  • Crear un WhoAmI propio utilizando el comando id de Solaris. Esta solución que es la más complicada, es como no la que he seleccionado, ya que creo es más interesante.
Solución al problema
# echo "/usr/xpg4/bin/id -un" > /usr/bin/whoami
# chmod +x /usr/bin/whoami
Con este sencillo cambio, el sistema ya reconoce quien soy y por lo tanto evalúa los permisos correctamente. Por defecto los comando compatibles con BSD se encuentran en /usr/xpg4/, podíamos haber hecho un simple link para solucionar el problema, pero creo que es más correcto hacer que Hadoop se encargue de saber a que id llamar en función del OS.

A continuación os muestro una ejecución sin el parche y otra con el parche
[java] hdfs://namenode.hadoop.test.com:54310/
[java] hdfs://namenode.hadoop.test.com:54311/
[java] Get UserName: hadoop
[java] Creating PATH 1248715418585
[java] Creating FILE 1248715418622
[java] Creating PATH 1248715421131
[java] 27-jul-2009 19:23:41 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 1717833
[java] Creating FILE 1248715421148
[java] Creating PATH 1248715432033
[java] 27-jul-2009 19:23:52 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 8968960
[java] Creating FILE 1248715432055
....

El log del NameNode
$ tail -f $HADOOP_HOME/log/hadoop--namenode*
2009-07-27 19:19:00,082 INFO org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit: ugi=DrWho,postgres,dba ip=/10.80.1.82 cmd=create src=/user/DrWho/testdir/tres/testfile dst=null perm=DrWho:supergroup:rw-r--r--
Y la estructura HDFS que tengo sólo permite la escritura al usuario hadoop de la siguiente forma
$ hadoop fs -lsr /user/DrWho
drwxr-xr-x - hadoop hadoop 0 2009-07-27 19:22 /user/DrWho/testdir
Sin embargo, después de ejecutar el comando (sin el parche) no sólo no falla, sino que se salta la seguridad por completo, aquí está el resultado
$ hadoop fs -lsr /user/DrWho
drwxr-xr-x - hadoop hadoop 0 2009-07-27 19:25 /user/DrWho/testdir
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:25 /user/DrWho/testdir/cuatro
-rw-r--r-- 3 DrWho hadoop 0 2009-07-27 19:25 /user/DrWho/testdir/cuatro/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:24 /user/DrWho/testdir/dos
-rw-r--r-- 3 DrWho hadoop 7731334 2009-07-27 19:24 /user/DrWho/testdir/dos/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:25 /user/DrWho/testdir/tres
-rw-r--r-- 3 DrWho hadoop 9384206 2009-07-27 19:25 /user/DrWho/testdir/tres/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-27 19:24 /user/DrWho/testdir/uno
-rw-r--r-- 3 DrWho hadoop 5752383 2009-07-27 19:24 /user/DrWho/testdir/uno/testfile


Sin embargo, si activo el parche el resultado es muy diferente
[java] hdfs://namenode.hadoop.test.com:54310/
[java] hdfs://namenode.hadoop.test.com:54311/
[java] Get UserName: hadoop
[java] Result 0 Value: postgres
[java] Creating PATH 1248715876078
[java] Creating FILE 1248715876149
[java] 27-jul-2009 19:31:16 com.sfchildren.sbcore.backup.Main main
[java] GRAVE: null
[java] org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security.AccessControlException: Permission denied: user=postgres, access=WRITE, inode="testfile":DrWho:hadoop:rw-r--r--
[java] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[java] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
[java] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
[java] at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
[java] at org.apache.hadoop.ipc.RemoteException.instantiateException(RemoteException.java:96)
[java] at org.apache.hadoop.ipc.RemoteException.unwrapRemoteException(RemoteException.java:58)
[java] at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.(DFSClient.java:2647)
[java] at org.apache.hadoop.hdfs.DFSClient.create(DFSClient.java:463)
[java] at org.apache.hadoop.hdfs.DistributedFileSystem.create(DistributedFileSystem.java:195)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:479)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:460)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:367)
[java] at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:359)
[java] at com.sfchildren.sbcore.backup.Main.createTmpFile(Main.java:171)
[java] at com.sfchildren.sbcore.backup.Main.main(Main.java:100)
[java] Caused by: org.apache.hadoop.ipc.RemoteException: org.apache.hadoop.security.AccessControlException: Permission denied: user=postgres, access=WRITE, inode="testfile":DrWho:hadoop:rw-r--r--
[java] at org.apache.hadoop.hdfs.server.namenode.PermissionChecker.check(PermissionChecker.java:176)
[java] at org.apache.hadoop.hdfs.server.namenode.PermissionChecker.checkPermission(PermissionChecker.java:111)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkPermission(FSNamesystem.java:4486)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkPathAccess(FSNamesystem.java:4446)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFileInternal(FSNamesystem.java:1011)
[java] at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.startFile(FSNamesystem.java:968)
[java] at org.apache.hadoop.hdfs.server.namenode.NameNode.create(NameNode.java:377)
[java] at sun.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:597)
[java] at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:508)
[java] at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:959)
[java] at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:955)
[java] at java.security.AccessController.doPrivileged(Native Method)
[java] at javax.security.auth.Subject.doAs(Subject.java:396)
[java] at org.apache.hadoop.ipc.Server$Handler.run(Server.java:953)
[java]
[java] at org.apache.hadoop.ipc.Client.call(Client.java:739)
[java] at org.apache.hadoop.ipc.RPC$Invoker.invoke(RPC.java:220)
[java] at $Proxy0.create(Unknown Source)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:597)
[java] at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:82)
[java] at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:59)
[java] at $Proxy0.create(Unknown Source)
[java] at org.apache.hadoop.hdfs.DFSClient$DFSOutputStream.(DFSClient.java:2644)
[java] ... 8 more

Conclusión
Voy a abrir un bug en Hadoop para informar de los problemas que tiene el usar "whoami" en Solaris, para que cuando la propiedad os.name de Java sea SunOS entonces que llame a /usr/xpg4/id -un en vez de whoami
if ( System.getProperty("os.name").equals("SunOS") )
shellCommand = "/usr/xpg4/id -un";
else
shellCommand = "/usr/bin/id -un";
Todavía tengo que ver todos los casos en los que se produce y crear un report para crear el bug en Hadoop, de todas formas, espero haber ayudado con el misterio de DrWho.

No hay comentarios:

Publicar un comentario