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

8

Digamos que eu tenho um conjunto de máquinas (chamado aqui de máquinas dos clientes) em que apenas uma pequena lista de pessoas (chamada equipe de suporte) pode fazer o SSH, usando apenas uma conta por máquina (a conta de acesso ao suporte).

A equipe de suporte deve fazer login apenas nas máquinas dos clientes usando chaves. Além disso, a equipe de suporte pode evoluir; portanto, alguém que sai da equipe de suporte não tem permissão para efetuar login em qualquer máquina do cliente. Portanto, as pessoas da equipe são proibidas de ler as chaves privadas usadas para fazer login nas máquinas dos clientes. Além disso, é proibido modificar o authorized_keysarquivo nas máquinas dos clientes.

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

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

Acredito que tenho que criar um daemon em execução como root na máquina proxy que aceitará a solicitação de um usuário e abrirá uma sessão SSH para eles, mas não tenho idéia de como fazê-lo. Alguma ideia?

Raspbeguy
fonte
Editou a pergunta porque "máquinas clientes" pode ser difícil de entender (não significa o oposto do servidor).
Raspbeguy
Isso é muito ousado, e a maioria parece estranha. Isso é perturbador. Você acha que no futuro você poderia usar muito menos ousado? Obrigado.
DW
Presumo que o authorized_keys restrição só se refere a dinâmicas mudanças (ex. Quando um novo membro se junta o apoio / folhas), desde que você precisa uma configuração inicial na máquina do cliente.
Ángel

Respostas:

6

Eu sugeriria algumas opções.

  1. Proteja a chave ssh e exija o uso de sudosua equipe de suporte. Você pode fazer isso de forma transparente com um invólucro. Chame o wrapper, digamos, /usr/local/bin/ssh-supporte faça com que ele contenha algo como isto (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 sudoersarquivo que permitisse aos usuários do supportgrupo usar a ferramenta. Este comando permite que eles executem a ssh-supportferramenta como o ssupportusuário - que você deve criar. Ele não confere qualquer privilégio raiz.

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

    Se você estiver satisfeito com o fato de os usuários do suporte não precisarem fornecer sua própria senha para executar a ferramenta (conforme solicitado pela sudochamada no próprio script), você poderá alterar a sudoersdefinição assim:

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

    Supondo PATHque /usr/local/bin/você contenha você chamaria com ssh-support clientname. Supondo também que você tenha criado o ssupportusuário como /home/ssupportvocê criaria /home/ssupport/.ssh/id_rsa_clientnamee /home/ssupport/.ssh/id_rsa_clientname.pubcomo o par de certificados, e terá uma entrada de host /home/ssupport/.ssh/configpara clientnamedefinir o usuário, host, porta etc. para a máquina de destino. Você provavelmente desativaria o encaminhamento X11, encaminhamento de porta etc. explicitamente. Como de costume, o /home/ssupport/.sshdiretório precisaria ser protegido com permissões 0700.

  2. Dê a cada membro do suporte sua própria conta de usuário local e faça com que cada pessoa use sua própria chave ssh privada para acessar os servidores do cliente. Quando uma pessoa sai do 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 conheça a chave ssh privada.

roaima
fonte
A segunda opção não é válida. Como eu disse, há apenas uma conta de suporte nos servidores dos clientes e você não pode adicionar chaves públicas à configuração do ssh, essas são as regras. De fato, você não pode modificar nada sobre a configuração ssh nas máquinas dos clientes.
Raspbeguy
4
A propósito, esta resposta é um exemplo típico de (ab) usando o sudo. Eu escrevi um artigo sobre o tema ( dmitry.khlebnikov.net/2015/07/… ), parece que existe uma tendência para tentar resolver qualquer coisa usando o sudo. No entanto, isso apenas enfraquece a segurança dos seus sistemas e não a melhora.
galaxy
1
@Raspbeguy é claro que não. O sudoersacesso limites de linha para o comando único
roaima
1
Você passa opções desmarcadas para o ssh com "$ @", que roda como root! Não consigo pensar em maneiras diferentes de arquivos de sistema corrompidos éter (uso -Epara anexar), encaminhar portas privilegiadas ( -L,-R,-D) ou raiz simplesmente ganho ( -o PermitLocalCommand=yes -o 'LocalCommand=/bin/bash'o comentário de galáxia a cerca de abusar sudo está no local correto.!
nkms
1
@roaima: Então, de qualquer maneira, sua ideia de sudo para raiz tem problemas, mas são problemas diferentes dos mencionados no blog da galáxia. Ele está falando ssh root@somewherecom chaves, vs. ssh user@somewheresudo. Na verdade, é um ponto muito bom. No entanto, a única maneira de ser aplicável a esse caso ssh keyowner@localhost ssh_to_client client.example.org é uma alternativa sudo -u keyowner ssh_to_client client.example.org. Semelhante ao sudo, o SSH pode limitar os comandos que um usuário pode executar. Estamos falando de sudo sem senha para não-root, não para o caso de uso do Galaxy.
Peter Cordes
11

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

Uma pesquisa rápida por "ssh ca" apontou para este tutorial: https://www.digitalocean.com/community/tutorials/how-to-create-an-ssh-ca-to-validate-hosts-and-clients-with -ubuntu (role para baixo até "Como configurar as chaves do usuário") - embora o tutorial mencione o Ubuntu como independente de distribuição, mas você precisa de uma nova versão do OpenSSH que suporte SSH CA

Outra boa entrada de blog sobre o assunto é https://ef.gy/hardening-ssh (role para baixo até "Certificados SSH").

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

galáxia
fonte
Seria uma boa idéia se as máquinas dos clientes tivessem acesso à Internet (para atualizar a validade de uma assinatura), o que nem sempre é o caso. Nós nos conectamos a essas máquinas por meio de uma VPN fornecida pelo cliente.
Raspbeguy
Bem, isso é o mais próximo que você pode chegar sem deixar escapar uma chave com uma pessoa que sai da sua empresa. Forneci o mecanismo, você pode automatizá-lo, por exemplo, você pode ter um oficial de serviço que está apoiando seu RH quando as pessoas saem da empresa e você pode definir um procedimento para revogar chaves.
Galaxy #
1
Além disso, você pode assinar uma chave (da pessoa de suporte) por um tempo limitado - por exemplo, você pode assiná-la apenas por 8 horas (para o turno), após 8 horas expirará e o servidor não as deixará entrar.
galaxy
3
Com relação à sua parte LDAP - atualmente estou trabalhando em uma empresa que gerencia centenas de instâncias e estamos trabalhando em uma solução de código aberto para integrar SAML 2.0 e SSH CA. A idéia é que uma pessoa se autentique usando o SSO e, se autorizada, assine suas chaves por um período de tempo definido (por exemplo, 5 minutos). Tudo isso é bastante transparente para o usuário e é implementado usando o ProxyCommand do ~ / .ssh / config.
Galaxy #
2

Existem algumas respostas diferentes que envolvem um script de wrapper para ssh chamado por meio do sudo ou do setuid-executável (para uma conta não raiz de finalidade especial ). Como diz o nkms , passar todos os argumentos para ssh permite que o usuário faça coisas arbitrárias com as chaves ssh que estamos tentando proteger. O outro extremo que alguns surgiram é permitir apenas um nome de host.

O OP diz que os administradores precisam poder fazer o upload de coisas.

Você pode ter dois wrappers diferentes de args fixos para ssh. Um para um shell de login, outro para scp. Nenhum argumento fornecido pelo usuário que não seja o nome do host (e o nome do arquivo a ser carregado).

Ou um script de wrapper que se utiliza getoptpara analisar opções muito limitadas e conectar as coisas a um comando ssh na maior parte fixo. Ignorar (ou errar) as opções não reconhecidas seria o caminho a percorrer.

Não tente filtrar as opções ssh "perigosas", basta escrever um wrapper que pode fazer duas coisas: login interativo ou fazer upload de um arquivo (nomes de arquivos locais e remotos). Você ainda precisa higienizar 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 teclas ssh como o arquivo local. Então você ainda está tentando pensar em tudo o que precisa ser proibido, em vez de começar a não permitir nada. Seria um começo para garantir que os nomes de arquivos não contenham nenhum @ou :.

Peter Cordes
fonte
A idéia do invólucro é a solução, mas implica uma violação de segurança que precisa ser preenchida.
Raspbeguy
Estou surpreso como as pessoas estão reinventando a roda quando não há necessidade dela. A funcionalidade SSH CA foi introduzida no OpenSSH exatamente pelas razões e situações como a pergunta original. Minha solução não utilizou nenhum invólucro e obteve exatamente o que foi solicitado, mas, por algum motivo, o @Raspbeguy decidiu seguir o caminho DIY com implicações questionáveis ​​de segurança. :)
galaxy
@ galaxy: sim, sua solução SSH CA é a melhor, com certeza, a menos que você tenha um requisito absoluto de que não pode fazer uma alteração única nos sistemas remotos para configurar seu sshd para usá-lo. Parece perfeito e fácil de acertar.
Peter Cordes
@ galaxy: sua solução é realmente elegante, mas não aplicável no meu caso, como eu disse anteriormente. Eu realmente gosto da idéia, falei sobre isso com meu chefe, mas ainda é impossível. Não há necessidade de ficar chateado.
Raspbeguy 4/09/15
1
@Raspbeguy, não estou chateado, apenas não entendo por que sua empresa deseja sacrificar sua segurança e implementar algo usando "fita adesiva" quando existe uma maneira adequada de fazê-lo. E seu comentário foi que seria uma boa solução, mas você não gostou do fato de não poder automatizar a revogação - e eu também forneci a solução para isso (assinando chaves apenas para o turno). De qualquer forma, você escolheu a sua resposta, vamos seguir em frente :)
galáxia
1

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

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

Toby Speight
fonte
Essa é a idéia do wrapper-script é semelhante à idéia do @ roaima. Você está dando acesso a ele com ssh, mas sudotambém funciona. Sua resposta está sugerindo o uso do usuário raiz local, mas um usuário não raiz também funcionaria. Veja meus comentários sobre a resposta dele para discutir isso. (Minha ssh keyowner@localhostidéia é a mesma que a sua ideia.)
Peter Cordes
@ Peter - muito bem: root é absolutamente o usuário errado para isso!
Toby Speight
Suporta que os caras precisem fazer o upload de coisas, portanto essa solução pode não funcionar.
Raspbeguy
@Raspbeguy: postou uma resposta que aborda isso. Use em combinação com a configuração não raiz do roaima sudo.
Peter Cordes
0

Seu pessoal de suporte sempre se conecta através dessa máquina proxy e somente a partir dela, para que os clientes possam simplesmente autenticar a máquina proxy usando o HostbasedAuthentication .

Digamos que a máquina proxy seja supporters.pce você fornece suporte paracustomer.pc

customer.pc terá HostbasedAuthentication sim em /etc/ssh/ssd_config, supporters.pc listado em /etc/ssh/shosts.equive sua chave pública em /etc/ssh/ssh_known_hosts.

Quando sua equipe de suporte efetua login em [email protected] e executa ssh customer.pc, ele gera o ssh-keysign (8) (que precisa ser configurado), que manipulará a assinatura da chave com o arquivo que você não pode ler e forneça ao supporters.pc uma prova de que a conexão realmente está vindo do supporters.pc . Como o customer.pc confia no supporters.pc , seu membro da equipe é logado como suporte .

Anjo
fonte
Essa é uma solução terrível do ponto de vista da segurança, pois se você estiver concedendo acesso a uma máquina como um todo e perder a responsabilidade de quem fez o quê. A confiança de máquina a máquina deve ser banida do mundo moderno, onde a segurança de TI começou a emergir como um tópico bastante popular.
Galaxy
@ galaxy, do OP, meu entendimento é que eles já estão fazendo basicamente isso. A confiança nessa máquina está na especificação . Observe especificamente que eles estão "usando apenas uma conta por máquina (a conta de acesso ao suporte)"; é possível que estejam usando uma conta compartilhada no customer.pc, mas se conectem ao servidor como seu próprio usuário. Alterar as permissões de ssh e ssh-keygen para forçar um sudo -u support ssh… resolveria isso e também adicionaria uma entrada de log.
Ángel
0

Use um binário de invólucro

Para esse caso de uso específico (consulte a observação importante abaixo), uma possibilidade é criar um usuário (por exemplo support-ssh) especificamente para essas conexões SSH de saída e instalar um binário pequeno do wrapper que os executivos executam /usr/bin/ssh.

  • Não copie + chmod o sshpróprio binário, porque você não se lembrará de copiá-lo toda vez que aplicar atualizações de segurança.
  • E não use rootcomo o usuário mais privilegiado, por razões que confio que são óbvias.

Essa é uma alternativa funcionalmente equivalente à utilização sudopara elevar privilégios à support-sshconta com as seguintes compensações:

  • Como é menor e mais enxuto do que sudohá, há menos risco de um erro de configuração abrir mais do que você pretendia.
  • É de sua responsabilidade codificá-lo corretamente - somente faça isso se você for extremamente cuidadoso e (idealmente) tiver experiência em codificação crítica à segurança.
  • Ele pode ser adaptado para ser mais específico do que sudo(mas quanto mais código você escreve, mais você precisa auditar para segurança).

O binário do invólucro deve ser definido HOMEcomo o support-sshdiretório inicial do usuário, para sshselecionar a ssh_configchave privada e apropriada . Mas o usuário que está chamando não deve ter permissão para ler ~support-ssh/.ssh/ou seu conteúdo.

O wrapper pode ser tão simples quanto:

#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 permita (um subconjunto de) argumentos de opção. Você pode querer substituir completamente variáveis de ambiente (mas manter os importantes, tais como TERM, LC_*, etc); note que LD_LIBRARY_PATHe LD_PRELOADsão particularmente perigosos.

Um programa de wrapper semelhante pode ser fornecido, scpse necessário.

Uma nota sobre aplicabilidade

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

Considero que a segurança é alcançada por meio de defesas técnicas e não técnicas e que o equilíbrio alcançado aqui ou pelo uso sudoé apropriado para a situação apresentada.

Toby Speight
fonte
Você passa argumentos não verificados para o ssh em execução como outro usuário, veja meu comentário na resposta acima. Ainda consigo ler a chave ... e não contaria com verificações rigorosas de argumentos, o ssh não deve ser executado dessa maneira.
Nkms
@ nkms - eu fiz o wrapper mais restritivo. Pode ser mais aberto, se necessário, mas você está certo em bloquear as coisas, exceto quando necessário, em vez de vice-versa.
perfil completo de Toby Speight
@TobySpeight: sim, parece ser bom. De qualquer maneira, coloquei a maior parte do que disse nos comentários em minha própria resposta.
Peter Cordes
1
Seria melhor usar o sudo do que um invólucro binário. Ao contrário do que você afirma, usar o sudo é muito menos arriscado do que você mesmo. Sudo tem padrões seguros. Você tem certeza de que não esqueceu de remover uma variável de ambiente que influenciaria o ssh?
Gilles 'SO- stop be evil'