Sudo en cascada para la elevación de privilegios

6

Tengo la intención de usar el usuario con menos privilegios para realizar una tarea determinada. El problema es que involucra un tipo de cadena de responsabilidad y se traduce como una cadena sudo en mis scripts, distribuyendo la tarea general en muchos lugares.

archivo de Sudoer

"www-data"      ALL = (webadmin) NOPASSWD: /home/webadmin/scripts/git-deploy.sh
"webadmin"      ALL = (root) NOPASSWD: /root/scripts/copy-deploy ""

Detalles

Para hacer más tangible el párrafo anterior: Alguna solicitud es enviada a Apache. El trabajador se ejecuta como www-data A través de mod_php, el script /home/webadmin/scripts/git-deploy.sh se inicia utilizando

<?php
exec('/'.escapeshellarg($gitRepo))

$gitRepo se alimenta de la siguiente secuencia de comandos:

    $bitBucketUrl=json_decode($request->getContent(),true);

    if(isset($bitBucketUrl['url'])){
        $bitBucketUrl=$bitBucketUrl['url'];
        if(!preg_match('/\.git$/',$bitBucketUrl)){
            $bitBucketUrl.='.git';
        }
    }else{
        $result='bad url';
    }

    if(preg_match('/^[email protected]:TEAM\/[a-zA-Z0-9\.-]+\.git$/',$bitBucketUrl)){
        exec(escapeshellcmd('sudo -u webadmin /home/webadmin/scripts/git-deploy.sh '.escapeshellarg($bitBucketUrl)),$results);
        $result=$results;
    }else{
        $result=$bitBucketUrl;
    }

Por supuesto, el script /home/webadmin/scripts/git-deploy.sh check $1

#!/bin/bash
valid=^[email protected]:TEAM/[a-zA-Z0-9-]+\.git$
if [[ $1 =~ $valid  ]]; then
  name=${1#[email protected]:TEAM/}
  name=${name%.git}
  fullName=/home/webadmin/websites/$name
  if [[ -e $fullName ]] ; then
    echo "$fullName exists, will do a git pull instead"
    echo "cd $fullName && git pull"
  else
    echo "/usr/bin/git clone $1"
  fi
  if [[ -e $fullName/deploy/apache-conf/ ]]; then
    #sudo -u root /root/scripts/copy-deploy
  fi
fi

Nota: Sé que solo se está haciendo eco, esta es la versión de prueba con usuarios ficticios.

Cada secuencia de comandos solo es u+rwx por su propietario (700).

Pregunta

  1. ¿La distribución de los scripts en varios lugares juega en contra de la seguridad? (Más difícil de entender lo que está pasando)
  2. ¿Ves algo más mal?
pregunta programaths 26.03.2014 - 17:36
fuente

1 respuesta

2

En primer lugar, ¿qué estás tratando de hacer ? Usted está explicando cómo lo está haciendo, pero no cuál es su objetivo final. Considere revisar su pregunta para agregar más detalles sobre esto.

Dicho esto, para el resto de esta respuesta asumiré que estás haciendo algún tipo de proxy (?) para reflejar los repositorios GIT. Lo que suena como un problema ya resuelto, por ejemplo. utilizando git hooks .

Sin embargo, conteste sus preguntas específicas en orden:

  

¿La propagación de los scripts en varios lugares juega en contra de la seguridad? (Más difícil de entender lo que está pasando)

Sí. En este momento tienes las siguientes "partes móviles":

  1. Un script PHP que analiza lo que parece ser la URL del repositorio enviada a través de una solicitud HTTP
  2. Un script de shell que llama a otros binarios (git)
  3. Todo envuelto en sudo
  4. Difunde en muchos servidores, como dijiste

Un error en cualquiera de lo anterior podría resultar en un compromiso del sistema.

Además, un problema podría surgir en una etapa posterior: ¿qué sucede si encuentra un error en una copia del script y se olvida de replicarlo en los otros servidores? ¿Qué sucede si git devuelve un error oscuro que no puede analizar y termina con una corrupción de los datos del usuario (que luego se hace una copia de seguridad dañada)? ¿Cómo se reportan los errores? ¿Existe un sistema de registro centralizado y, lo que es más importante, hay alguien que lo supervise?

  

¿Ves algo más mal?

Sí y no. Su secuencia de comandos PHP comprueba si hay una clave 'url' en la entrada JSON, y si no hay alguna, establece un 'retorno' a 'valor malo'. Luego continúa . Esta es una mala práctica: no es un error en sí mismo en este momento, sino un error que está por ocurrir. En lugar de continuar, debe detener el flujo de trabajo del programa aquí y devolver un error.

Por ejemplo, ¿qué sucede si en pocos meses alguien más agrega algún código como:

/* previous code */
if(preg_match('/^[email protected]:TEAM\/[a-zA-Z0-9\.-]+\.git$/',$bitBucketUrl)){
    exec(escapeshellcmd('sudo -u webadmin /home/webadmin/scripts/git-deploy.sh '.escapeshellarg($bitBucketUrl)),$results);
    $result=$results;
}else{
    $result=$bitBucketUrl;
}

/* new code */
[...]
exec('sudo -u webadmin /home/webadmin/scripts/new-stuff.sh', $bitBucketURL);

El código que agregué tiene dos errores: ¿puedes detectarlos?

  • Uno podría pensar que el script new-stuff.sh se ejecuta solo si bitBucketURL contiene datos válidos. En su lugar, se ejecuta independientemente de lo que ocurra de antemano, ya que no se rescata en las ramas else .
  • No hay escapeshellarg

Si tardaste más de unos segundos en detectar los errores, imagina a alguien que nunca haya visto tu código antes.

Omití a propósito el escape de mi ejemplo de código por una razón: debes sanear tu entrada de una vez por todas y seguir usándola en lugar de tener que llamar La familia de funciones escape cada vez que necesite utilizar la entrada del usuario. Es demasiado fácil olvidar una llamada a escapeshellargs , especialmente si requiere más esfuerzo (= escribir). En su lugar, intente hacer el uso correcto de su código el camino de menor resistencia . Por ejemplo,

$bitBucketUrl=json_decode($request->getContent(),true);

podría convertirse en:

$unsafe_user_input=json_decode($request->getContent(),true);
$safe_user_input = escapeshellarg($bitBucketUrl);
[...]
res = do_stuff(safe_user_input);
if (check_error(res))
{
    stop_with_error_message(message);

De esta forma es obvio lo que son unsafe_user_input y safe_user_input .

Puede que haya otros problemas con su enfoque; La idea de ejecutar el código con el menor privilegio es buena, pero está sobre-diseñada aquí y puede tener efectos secundarios desagradables.

    
respondido por el lorenzog 03.06.2014 - 17:05
fuente

Lea otras preguntas en las etiquetas