Como restringir os usuários SSH a um conjunto predefinido de comandos após o login?


88

Esta é uma ideia para um segurança. Nossos funcionários devem ter acesso a alguns comandos em um servidor Linux, mas não todos. Eles devem, por exemplo, ter a possibilidade de acessar um arquivo de log ( less logfile) ou iniciar diferentes comandos ( shutdown.sh/ run.sh).

Informações básicas:

Todos os funcionários acessam o servidor com o mesmo nome de usuário: Nosso produto funciona com permissões de usuário "normais", nenhuma "instalação" é necessária. Basta descompactá-lo em seu diretório de usuário e executá-lo. Gerenciamos vários servidores onde nosso aplicativo está "instalado". Em cada máquina existe um usuário johndoe. Nossos funcionários às vezes precisam acessar o aplicativo na linha de comando para acessar e verificar os arquivos de log ou para reiniciar o aplicativo manualmente. Apenas algumas pessoas devem ter acesso total à linha de comando.

Estamos usando autenticação ppk no servidor.

Seria ótimo se o funcionário1 pudesse acessar apenas o arquivo de registro e o funcionário2 também pudesse fazer X etc ...

Solução: Como solução utilizarei a commandopção indicada na resposta aceita . Farei meu próprio pequeno script de shell que será o único arquivo que pode ser executado por alguns funcionários. O script oferecerá vários comandos que podem ser executados, mas nenhum outro. Usarei os seguintes parâmetros authorized_keysde conforme declarado aqui :

command="/bin/myscript.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3....o9M9qz4xqGCqGXoJw= user@host

Isso é segurança suficiente para nós. Obrigado, comunidade!


A segurança baseada em permissão do Linux ACL padrão não é suficiente? Quais recursos extras você precisa?
James Brady

22
É uma ideia horrível, Marcel.
Vinko Vrsalovic

14
@Vinko, @PEZ: Eu adicionei algumas informações básicas. Em vez de dizer "ideia estúpida", você pode fornecer comentários com valor. O que é, em sua opinião, uma ideia melhor?
Marcel

8
Ainda não vejo nenhuma desculpa em ter vários usuários compartilhando o mesmo nome de usuário.
Eldelshell

3
"Meu próprio pequeno script de shell"? Parece muito perigoso. A menos que você seja um especialista, provavelmente há muitas maneiras de escapar por completo. Eu prefiro confiar em um programa bem escrito, depurado e mantido (vários foram mencionados).
bortzmeyer

Respostas:


69

Você também pode restringir as chaves a comandos permitidos (no arquivo authorized_keys).

Ou seja, o usuário não logaria via ssh e teria um conjunto restrito de comandos, mas apenas teria permissão para executar esses comandos via ssh (por exemplo, "ssh somehost bin / showlogfile")


Isso parece interessante. É possível definir vários comandos?
Marcel

12
Este artigo fornece algumas opções para vários comandos usando o arquivo authorized_keys: linuxjournal.com/article/8257
Bash

@ rd834 ...: muito obrigado. Acho que isso me deu uma "boa" solução ... (adicionado à pergunta). Vou aceitar essa resposta como "correta".
Marcel

11
O livro SSH da O'Reilly tem uma excelente explicação de como fazer isso, incluindo a permissão de vários comandos configurando um script que examina a variável de ambiente SSH_ORIGINAL_COMMAND. oreilly.com/catalog/sshtdg/chapter/ch08.html
Alex Dupuy

5
esta resposta de falha do servidor tem uma boa dica sobre como permitir vários comandos usando a variável SSH_ORIGINAL_COMMAND exportada.
MattBianco

33

sshsegue a rshtradição de usar o programa shell do usuário do arquivo de senha para executar comandos.

Isso significa que podemos resolver isso sem envolver a sshconfiguração de forma alguma.

Se você não quiser que o usuário tenha acesso ao shell, basta substituir o shell desse usuário por um script. Se você olhar /etc/passwd, verá que existe um campo que atribui um interpretador de comandos shell para cada usuário. O script é usado como o shell para seu login interativo ssh user@host e também para comandos ssh user@host command arg ....

Aqui está um exemplo. Criei um usuário foocujo shell é um script. O script imprime a mensagem my arguments are:seguida por seus argumentos (cada um em uma linha separada e entre colchetes angulares) e termina. No caso de log, não há argumentos. Aqui está o que acontece:

webserver:~# ssh foo@localhost
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.

Se o usuário tentar executar um comando, terá a seguinte aparência:

webserver:~# ssh foo@localhost cat /etc/passwd
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>

Nosso "shell" recebe uma -cinvocação de estilo, com o comando inteiro como um argumento, da mesma forma que /bin/sho receberia.

Como você pode ver, o que podemos fazer agora é desenvolver ainda mais o script para que ele reconheça o caso quando for invocado com um -cargumento e, então, analise a string (digamos, por correspondência de padrões). As strings permitidas podem ser passadas para o shell real invocando recursivamente /bin/bash -c <string>. O caso de rejeição pode imprimir uma mensagem de erro e encerrar (incluindo o caso em que -cestá faltando).

Você tem que ter cuidado ao escrever isso. Eu recomendo escrever apenas correspondências positivas que permitem apenas coisas muito específicas e não permitem todo o resto.

Nota: se você estiver root, você ainda pode entrar nesta conta substituindo o shell no sucomando, como este su -s /bin/bash foo. (Shell substituto de escolha.) Não-root não pode fazer isso.

Aqui está um script de exemplo: restrinja o usuário a usar apenas sshpara gitacessar os repositórios em /git.

#!/bin/sh

if [ $# -ne 2 ] || [ "$1" != "-c" ] ; then
  printf "interactive login not permitted\n"
  exit 1
fi

set -- $2

if [ $# != 2 ] ; then
  printf "wrong number of arguments\n"
  exit 1
fi

case "$1" in
  ( git-upload-pack | git-receive-pack )
    ;; # continue execution
  ( * )
    printf "command not allowed\n"
    exit 1
    ;;
esac

# Canonicalize the path name: we don't want escape out of
# git via ../ path components.

gitpath=$(readlink -f "$2")  # GNU Coreutils specific

case "$gitpath" in
  ( /git/* )
     ;; # continue execution
  ( * )
    printf "access denied outside of /git\n"
    exit 1
    ;;
esac

if ! [ -e "$gitpath" ] ; then
   printf "that git repo doesn't exist\n"
   exit 1
fi

"$1" "$gitpath"

Claro, estamos confiando que esses programas Git git-upload-packe git-receive-packnão têm buracos ou saídas de emergência que darão aos usuários acesso ao sistema.

Isso é inerente a esse tipo de esquema de restrição. O usuário é autenticado para executar código em um determinado domínio de segurança, e estamos criando uma restrição para limitar esse domínio a um subdomínio. Por exemplo, se você permitir que um usuário execute o vimcomando em um arquivo específico para editá-lo, o usuário pode apenas obter um shell com :!sh[Enter].


6
Sério, isso é MUITO PERIGOSO. O que vai me impedir de executar git-receive-pack '/git/';dd if=/dev/urandom of=/dev/sda?
Yeti

@Yeti Temos um orifício de injeção de comando aqui? Isso precisa ser resolvido. Além disso, o abuso de padrões de arquivo que eu perpetrei no casenão parece correto para mim.
Kaz

1
Sim, /bin/bash -c "$2"é inseguro (semelhante a como funciona a injeção de SQL). Você pode filtrar a string com "aspas mágicas" como PHP. Mas a maneira mais fácil de garantir a segurança absoluta é chamar um comando manualmente e, em seguida, passar os parâmetros entre aspas duplas. Porque a segurança de tudo depende então desse comando ser o elo mais fraco (mais difícil de verificar). O mais interessante é ver como sua resposta tem 22 votos positivos, mas ninguém percebeu isso;) Você atualizará sua própria resposta?
Yeti

1
@Yeti Sim; Eu apenas fiz. Substituí o script por um que quebra o argumento -c com sete, em seguida, pega apenas as duas primeiras palavras dele. O primeiro deve ser um git-comando permitido e o segundo deve ser um caminho canonizado, verificado em relação ao prefixo permitido e também verificado quanto à existência. Você pode pensar em alguma maneira de quebrar isso?
Kaz

1
A menos que alguém crie um apelido (ou substitua um comando) para qualquer um dos comandos fornecidos, então não, as aspas duplas do Bash devem ser seguras (e se não, este é um bug do Bash).
Yeti

15

O que você está procurando é chamado de Shell restrito . O Bash fornece um modo no qual os usuários podem executar apenas comandos presentes em seus diretórios pessoais (e não podem se mover para outros diretórios), o que pode ser bom o suficiente para você.

Achei este tópico muito ilustrativo, embora um pouco datado.


1
E se o usuário fizer "! / Bin / sh" ou algo parecido no prompt do less?
PEZ

3
@Ubersoldat: Por favor, cresça e diminua a agressividade em todas as suas postagens. Ele estava perguntando se a restrição só se aplica a processos bash ou filho (e para responder à sua pergunta, descobri que não).

Um grande problema com o shell restrito é que, para protegê-lo, você deve usar .profile ou .bashrc para restringir o PATH, desabilitar builtins, etc., mas esses arquivos são invocados apenas para shells interativos. Se um usuário usa ssh para executar um comando remoto, ele não é invocado. Isso permite que um usuário com acesso ssh a uma conta com SHELL = / bin / rbash apenas faça algo como "ssh remotehost bash" para obter um shell não interativo, mas irrestrito. Você precisa de comandos SSH forçados como HD sugerido, mas isso pode proteger contra escapes de shell como PEZ solicitado (uma vez que PATH é bloqueado - inclui / bin: / usr / bin por padrão).
Alex Dupuy

2
Retiro o que disse, o bash irá invocar .bashrc (não .profile) durante a execução não interativa sob sshd; entretanto, você deve ter certeza de definir PATH explicitamente e desabilitar builtins e aliases em .bashrc - mudar para um subdiretório que não esteja em / acima de PATH ou .ssh / ou .bashrc também é uma boa idéia. Ter qualquer comando que possa gravar em arquivos arbitrários criará um problema - nem sempre são óbvios, por exemplo, o comando sed 'w' pode ser usado para sobrescrever .bashrc e quebrar. Uma jaula chroot sempre será mais segura se você puder usá-la, e os comandos forçados de ssh serão mais restritos.
Alex Dupuy

5

Por que você não escreve seu próprio shell de login? Seria muito simples usar o Bash para isso, mas você pode usar qualquer linguagem.

Exemplo em Bash

Use seu editor favorito para criar o arquivo /root/rbash.sh(pode ser qualquer nome ou caminho, mas deve ser chown root:roote chmod 700):

#!/bin/bash

commands=("man" "pwd" "ls" "whoami")
timestamp(){ date +'%Y-%m-%s %H:%M:%S'; }
log(){ echo -e "$(timestamp)\t$1\t$(whoami)\t$2" > /var/log/rbash.log; }
trycmd()
{
    # Provide an option to exit the shell
    if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
    then
        exit
        
    # You can do exact string matching for some alias:
    elif [[ "$ln" == "help" ]]
    then
        echo "Type exit or q to quit."
        echo "Commands you can use:"
        echo "  help"
        echo "  echo"
        echo "${commands[@]}" | tr ' ' '\n' | awk '{print "  " $0}'
    
    # You can use custom regular expression matching:
    elif [[ "$ln" =~ ^echo\ .*$ ]]
    then
        ln="${ln:5}"
        echo "$ln" # Beware, these double quotes are important to prevent malicious injection
        
        # For example, optionally you can log this command
        log COMMAND "echo $ln"
    
    # Or you could even check an array of commands:
    else
        ok=false
        for cmd in "${commands[@]}"
        do
            if [[ "$cmd" == "$ln" ]]
            then
                ok=true
            fi
        done
        if $ok
        then
            $ln
        else
            log DENIED "$cmd"
        fi
    fi
}

# Optionally show a friendly welcome-message with instructions since it is a custom shell
echo "$(timestamp) Welcome, $(whoami). Type 'help' for information."

# Optionally log the login
log LOGIN "$@"

# Optionally log the logout
trap "trap=\"\";log LOGOUT;exit" EXIT

# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user@host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
    shift
    trycmd "$@"
else
    while echo -n "> " && read ln
    do
        trycmd "$ln"
    done
fi

Tudo que você precisa fazer é definir este executável como seu shell de login. Por exemplo, edite seu /etc/passwdarquivo e substitua o shell de login atual desse usuário /bin/bashpor /root/rbash.sh.

Este é apenas um exemplo simples, mas você pode torná-lo o mais avançado que quiser, a ideia está aí. Tenha cuidado para não se bloquear alterando o shell de login do seu próprio usuário. E sempre teste símbolos e comandos estranhos para ver se é realmente seguro.

Você pode testá-lo com: su -s /root/rbash.sh.

Cuidado , certifique-se de combinar todo o comando e tome cuidado com os curingas! Melhor excluir Bash-símbolos, como ;, &, &&, ||, $, e backticks para ter certeza.

Dependendo da liberdade que você dá ao usuário, não ficará muito mais seguro do que isso. Descobri que muitas vezes só preciso criar um usuário que tenha acesso a apenas alguns comandos relevantes e, nesse caso, essa é realmente a melhor solução. No entanto, se você deseja dar mais liberdade, uma prisão e permissões podem ser mais adequadas. Erros são cometidos facilmente e só percebidos quando já é tarde demais.


Eu realmente gostei dessa abordagem. Você tem alguma ideia de como podemos lidar com comandos de várias palavras, como "service httpd restart"?
Farzan

2
@Farzan Você pode executar comandos em uma variável, por exemplo ln="service httpd restart", com: ${ln[@]}. Ainda assim, certifique-se de pensar sobre as questões de segurança, uma lista de permissões apenas para caracteres alfanuméricos e espaços em branco seria útil nesse caso. Mas você também pode simplesmente fazer: if [[ "$ln" == "restart-httpd"];then service httpd restart;fie trabalhar com comandos simples como esse.
Yeti

/root/rbash.sh: Permission denied Eu tentei chmod 777 também
Christian,

@Christian, se você adicionar /root/rbash.sha /etc/shells? Depende da distribuição. Você também pode tentar desativar temporariamente selinuxe verificar as mensagens de log em busca de pistas (veja o carimbo de data / hora) nos arquivos do /var/log.
Yeti

@yeti não, foi explicado para adicionar a / root :) Vou tentar agora.
Christian

4

Você deve adquirir `rssh ', o shell restrito

Você pode seguir os guias de restrição mencionados acima, eles são bastante autoexplicativos e simples de seguir. Compreenda os termos `chroot jail 'e como implementar efetivamente as configurações de sshd / terminal e assim por diante.

Visto que a maioria dos seus usuários acessa seus terminais via sshd, você provavelmente também deve olhar o sshd_conifg, o arquivo de configuração daemon SSH, para aplicar certas restrições via SSH. Tenha cuidado, entretanto. Entenda corretamente o que você tenta implementar, pois as ramificações das configurações incorretas são provavelmente terríveis.


1
Observe que pizzashack.org/rssh é uma solução excelente (possivelmente a melhor) para o caso especial em que você deseja permitir scp / sftp / rdist / rsync / cvs (e não precisa de acesso a nada fora de uma jaula chroot) - no entanto , isso não resolve a questão geral do autor original, que queria que os usuários pudessem visualizar arquivos de log e executar determinados scripts de execução / desligamento.
Alex Dupuy

2
rsshfoi removido do Debian Buster. Acho que a nova moda é a corrida do GNU .
Thomas,

1
@Thomas, acredito que rssh agora não tem manutenção e tem um problema de segurança conhecido: sourceforge.net/p/rssh/mailman/message/36519118
Max Barraclough

2

GNU Rush pode ser a maneira mais flexível e segura de fazer isso:

GNU Rush é um shell de usuário restrito, projetado para sites que fornecem acesso remoto limitado a seus recursos, como repositórios svn ou git, scp ou semelhantes. Usando um arquivo de configuração sofisticado, GNU Rush oferece controle completo sobre as linhas de comando que os usuários executam, bem como sobre o uso de recursos do sistema, como memória virtual, tempo de CPU, etc.



0

Outra maneira de ver isso é usando ACLs POSIX, ele precisa ser suportado por seu sistema de arquivos, no entanto, você pode ter um ajuste fino de todos os comandos no Linux da mesma forma que você tem o mesmo controle no Windows (apenas sem a interface do usuário mais agradável ) ligação

Outra coisa a se observar é o PolicyKit .

Você terá que pesquisar bastante no Google para fazer tudo funcionar, pois definitivamente não é um ponto forte do Linux no momento.


0

[Divulgação: escrevi sshdo, que é descrito abaixo]

Se você deseja que o login seja interativo, configurar um shell restrito é provavelmente a resposta certa. Mas se houver um conjunto real de comandos que você deseja permitir (e nada mais) e está tudo bem que esses comandos sejam executados individualmente via ssh (por exemplo, ssh usuário @ host cmd arg blah blah), então um comando genérico que lista o controle para ssh pode ser o que você precisa. Isso é útil quando os comandos são programados de alguma forma na extremidade do cliente e não exige que o usuário realmente digite o comando ssh.

Existe um programa chamado sshdo para fazer isso. Ele controla quais comandos podem ser executados por meio de conexões ssh de entrada. Está disponível para download em:

http://raf.org/sshdo/ (leia as páginas do manual aqui) https://github.com/raforg/sshdo/

Possui um modo de treinamento para permitir todos os comandos que são tentados e uma opção --learn para produzir a configuração necessária para permitir comandos aprendidos permanentemente. Então, o modo de treinamento pode ser desligado e quaisquer outros comandos não serão executados.

Ele também tem uma opção --unlearn para parar de permitir comandos que não estão mais em uso para manter o mínimo de privilégios estritos conforme os requisitos mudam com o tempo.

É muito exigente quanto ao que permite. Não permite um comando com nenhum argumento. Somente comandos shell completos podem ser permitidos.

Mas ele suporta padrões simples para representar comandos semelhantes que variam apenas nos dígitos que aparecem na linha de comando (por exemplo, números de sequência ou carimbos de data / hora).

É como um firewall ou controle de lista branca para comandos ssh.

E ele suporta comandos diferentes sendo permitidos para usuários diferentes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.