Permitir que usuários regulares façam SSH usando uma chave privada que eles não podem ler

8

Digamos que eu tenha um conjunto de máquinas (chamadas aqui de máquinas dos clientes) que somente uma pequena lista de pessoas (chamada de equipe de suporte) pode usar SSH, usando apenas uma conta por máquina (a conta de acesso ao suporte) .

A equipe de suporte só deve entrar nas máquinas dos clientes usando chaves. Além disso, a equipe de suporte pode evoluir, portanto, alguém que deixa a equipe de suporte não pode fazer login em nenhuma máquina do cliente. Portanto, as pessoas da equipe estão proibidas de ler as chaves privadas usadas para fazer login nas máquinas dos clientes. Além disso, é proibido modificar o arquivo authorized_keys nas máquinas dos clientes.

Para realizar essa configuração, tive a ideia de usar um proxy SSH em que a equipe de suporte fará login (com autenticação LDAP, mas isso é outro problema) e que contém as chaves privadas.

A pergunta é: como permitir que a equipe de suporte use a chave privada do SSH sem poder lê-la?

Eu acredito que tenho que fazer um daemon rodando como root na máquina proxy que aceitará a requisição de um usuário e abrirá uma sessão SSH para eles, mas não tenho idéia de como fazê-lo. Alguma idéia?

    
por Raspbeguy 03.09.2015 / 13:16

6 respostas

6

Eu sugeriria algumas opções.

  1. Proteja a chave ssh e exija o uso de sudo no lado da sua equipe de suporte. Você poderia fazer isso de forma transparente com um invólucro. Chame o wrapper, digamos, /usr/local/bin/ssh-support e faça com que ele seja assim (não testado):

    #!/bin/bash
    export PATH=/usr/local/bin:/usr/bin:/bin
    export IFS=$' \t\n'
    export SUSER=ssupport
    
    # Restart if not running under sudo
    test "X$1" != 'X-S' && exec sudo -u "$SUSER" /usr/local/bin/ssh-support -S "$@"
    shift
    export SHOME="$(getent passwd "$SUSER" | cut -d: -f6)"
    
    # Extract single argument as hostname LABEL and validate that we have
    # an RSA private key for it. The target username, real hostname, port,
    # etc. can be defined in ~/.ssh/config for the user $SUSER (ssupport)
    label="$1"
    idfile="$SUSER/.ssh/id_rsa_for_$label"
    cgfile="$SUSER/.ssh/config"
    
    ok=true
    [[ "$label" =~ '/' ]] && { echo "Invalid label: $label" >&2; ok=; }
    [[ ! -s "$idfile" ]] && { echo "Missing identity file: $idfile" >&2; ok=; }
    [[ ! -s "$cgfile" ]] && { echo "Missing configuration file: $cgfile" >&2; ok=; }
    
    if test -n "$ok"
    then
        logger -t ssh-support "$SUDO_USER requested ssh to $label"
        exec ssh -i "$idfile" -F "$cgfile" "$label"
    fi
    exit 1
    

    Isso exigiria uma entrada no arquivo sudoers que permitisse que os usuários do grupo support usassem a ferramenta. Esse comando permite que eles executem a ferramenta ssh-support como ssupport user - que você deve criar. não confere nenhum privilégio de root.

    %support ALL = (ssupport) /usr/local/bin/ssh-support
    

    Se você está feliz que os usuários de suporte não precisem fornecer sua própria senha para executar a ferramenta (conforme solicitado pela invocação sudo dentro do próprio script), você pode alterar a definição sudoers assim:

    %support ALL = (ssupport) NOPASSWD: /usr/local/bin/ssh-support
    

    Supondo que PATH continha /usr/local/bin/ , você o chamaria com ssh-support clientname . Além disso, supondo que você tenha criado o ssupport user como /home/ssupport , crie /home/ssupport/.ssh/id_rsa_clientname e /home/ssupport/.ssh/id_rsa_clientname.pub como o par de certificados e tenha uma entrada de host em /home/ssupport/.ssh/config para clientname que definiu o usuário, host, porta , etc. para a máquina de destino. Você provavelmente desabilitará o encaminhamento do X11, o redirecionamento de portas, etc. explicitamente. Como de costume, o diretório /home/ssupport/.ssh precisaria ser protegido com permissões 0700 .

  2. Conceda a cada membro de suporte sua própria conta de usuário local e peça a cada pessoa que use sua própria chave ssh privada para acessar os servidores do cliente. Quando uma pessoa deixa o grupo de suporte, você remove a chave ssh dos servidores do cliente. Isso significa que você não precisa mais se preocupar em impedir que sua equipe saiba a chave ssh privada.

por 03.09.2015 / 13:42
11

O que você realmente quer fazer é usar SSH CA e assinar chaves usadas por cada pessoa de suporte (elas devem ter suas próprias chaves ssh, como passaportes) e configurar os servidores de seus clientes para usar TrustedUserCAKeys /etc/ssh/users_ca.pub no / etc / ssh / sshd_config. Dessa forma, o servidor aceitará qualquer chave assinada pela chave da AC (à qual você tem acesso) e poderá revogar chaves de pessoas que não estão mais no suporte sem nem mesmo tocar em authorized_keys.

Uma busca rápida por "ssh ca" apontou para este tutorial: link (role para baixo até" Como configurar as teclas do usuário ") - embora o tutorial mencione o Ubuntu é independente da distribuição, mas você precisa de uma nova versão do OpenSSH que suporte SSH CA

Outra boa entrada no blog sobre o tema é o link (role para baixo até "Certificados SSH").

Preste especial atenção que você pode assinar a chave para ser válida por um tempo limitado, para que ela expire automaticamente!

    
por 03.09.2015 / 14:04
2

Existem algumas respostas diferentes envolvendo um script wrapper para ssh invocado através de sudo ou setuid-executable (para uma conta não-raiz de propósito especial). Como o nkms diz , passando por todos os args para ssh permite ao usuário fazer coisas arbitrárias com as chaves ssh que estamos tentando proteger. O outro extremo que alguns sugeriram foi permitir apenas um nome de host.

O OP diz que os administradores precisam fazer upload de itens.

Você pode ter dois wrappers fixos de args-para-ssh diferentes. Um para um shell de login, outro para scp. Nenhum argumento fornecido pelo usuário além do nome do host (e nome do arquivo para upload).

Ou um script de wrapper que usa o getopt para analisar opções muito limitadas e conectá-las a um comando ssh principalmente fixo. Ignorar (ou errar) em opções não reconhecidas seria o caminho a seguir.

Não tente filtrar as opções ssh "perigosas", apenas escreva um wrapper que possa fazer duas coisas: login interativo ou fazer o upload de um arquivo (nomes de arquivos locais e remotos). Você ainda precisa fazer algum saneamento lá, eu acho.

Na verdade, ainda é fácil errar. Você precisa encontrar uma maneira de impedir que o usuário forneça o arquivo que contém as chaves ssh como o arquivo local. Então você ainda está tentando pensar em tudo que precisa ser desaprovado, em vez de começar por não permitir nada. Seria um começo para garantir que os nomes dos arquivos não contenham @ ou : .

    
por 04.09.2015 / 11:40
1

Se você configurar um servidor proxy SSH, poderá organizar que o shell dos usuários da equipe (em /etc/passwd ) não esteja definido para um shell como o bash, mas sim para um script simples que não permita acesso ao shell . Em vez disso, ele solicitaria um nome de host de destino ( read target ) e, em seguida, exec ssh "support@$target" .

Observe que o uso de um proxy como esse pode dificultar o uso de ferramentas como scp para transferir arquivos de / para as máquinas do cliente. Isso pode ser um problema ou uma vantagem!

    
por 03.09.2015 / 19:55
0

Seu pessoal de suporte sempre se conecta por meio dessa máquina proxy, e somente dela, para que os clientes possam simplesmente autenticar a máquina proxy usando HostA base de Autenticação .

Digamos que a máquina proxy seja supporters.pc e você forneça suporte a customer.pc

customer.pc terá HostbasedAuthentication yes em /etc/ssh/ssd_config , supporters.pc listados em /etc/ssh/shosts.equiv e sua chave pública em /etc/ssh/ssh_known_hosts .

Quando sua equipe de suporte entrar em [email protected], e executar ssh customer.pc , ela irá gerar ssh-keysign(8) (que precisa ser setuid), que manipulará a assinatura de chave com o arquivo-you- não pode ler e fornecer provas para supporters.pc que a conexão está realmente vindo de supporters.pc . Como customer.pc confia em supporters.pc , seu membro da equipe fica logado como suporte .

    
por 04.09.2015 / 00:07
0

Use um binário wrapper

Para este caso de uso específico (veja a observação importante abaixo), uma possibilidade é criar um usuário (digamos support-ssh ) especificamente para essas conexões SSH de saída e instalar um pequeno binário wrapper que execs /usr/bin/ssh .

  • Não copie + chmod o próprio binário ssh , porque você não se lembrará de copiá-lo toda vez que aplicar as atualizações de segurança.
  • E não use root como o usuário com mais privilégios, por motivos que acredito serem óbvios.

Esta é uma alternativa funcionalmente equivalente ao uso de sudo para elevar privilégios para o da conta support-ssh com as seguintes compensações:

  • Isso é menor e mais fino que sudo , portanto, há menos risco de erro de configuração se abrindo mais do que você pretendia.
  • É sua responsabilidade codificá-lo corretamente - faça isso apenas se for extremamente cuidadoso e (idealmente) tiver experiência em codificação de segurança crítica.
  • Pode ser personalizado para ser mais específico do que sudo (mas quanto mais código você escreve, mais você precisa auditar por segurança).

O binário do invólucro deve definir HOME como o diretório base do usuário support-ssh , de forma que ssh obtenha a% de chave e a chave privada apropriadas de ssh_config . Mas o usuário solicitante não deve ter permissão para ler ~support-ssh/.ssh/ ou seu conteúdo.

O wrapper pode ser tão simples como:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    setenv("HOME", "/home/support-ssh", 1);
    /* allow only a single, non-option argument */
    if (argc!=2 || *argv[1]=='-') {
        fprintf(stderr, "Usage: %s <hostname>", argv[0]);
        exit(EXIT_FAILURE);
    }
    execv("/usr/bin/ssh", argv);
    return EXIT_FAILURE;
}

Você pode querer ser mais restritivo e verificar se o argumento argv[1] está em um conjunto de nomes de host permitidos. Ou menos restritivo, e permitir (um subconjunto de) argumentos de opção. Você pode querer substituir completamente variáveis de ambiente (mas manter variáveis importantes como TERM , LC_* , etc); observe que LD_LIBRARY_PATH e LD_PRELOAD são particularmente perigosos.

Um programa wrapper semelhante pode ser fornecido para scp , se necessário.

Uma nota sobre aplicabilidade

Esta resposta aborda as circunstâncias específicas da questão, onde os usuários são contratualmente obrigados a seguir os procedimentos, e há sanções (por exemplo, demissão) por violá-las. Supõe que você queira evitar que os funcionários copiem casualmente chaves privadas, em vez de impedir que um invasor determinado obtenha acesso não autorizado.

Estou assumindo que a segurança é alcançada por meio de defesas técnicas e não-técnicas, e que o equilíbrio obtido aqui ou usando sudo é apropriado para a situação apresentada.

    
por 03.09.2015 / 19:44