Autenticação de chave pública SSH só funciona se a sessão ativa existir antes

1

Eu tenho um problema bastante estranho com a minha configuração SSH. Eu configurei meu servidor com a ajuda de um Cartão de Acesso Remoto e configurei tudo com um visualizador KVM.

Então, ao estar logado no servidor através do KVM Viewer, eu configurei o SSH com apenas pubkey e tentei fazer o login no meu laptop local. Funcionou bem.

Se eu sair da sessão do KVM (ou sair com o usuário na sessão do KVM), não consigo mais fazer login via ssh (pubkey denied). O login SSH só funciona enquanto o usuário estiver em algum lugar ainda conectado.

Alguma sugestão de qual é o problema?

Saída do console para um login com falha (todos os dados pessoais trocados):

OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011 debug1: Reading configuration data /Users/mylocaluser/.ssh/config debug1: Reading configuration data /etc/ssh_config debug1: /etc/ssh_config line 20: Applying options for * debug1: /etc/ssh_config line 103: Applying options for * debug1: Connecting to 100.100.100.100 [100.100.100.100] port 12345. debug1: Connection established. debug1: identity file /Users/mylocaluser/.ssh/id_rsa type 1 debug1: identity file /Users/mylocaluser/.ssh/id_rsa-cert type -1 debug1: identity file /Users/mylocaluser/.ssh/id_dsa type -1 debug1: identity file /Users/mylocaluser/.ssh/id_dsa-cert type -1 debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_6.2 debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6.1p1 Ubuntu-2ubuntu2 debug1: match: OpenSSH_6.6.1p1 Ubuntu-2ubuntu2 pat OpenSSH* debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: kex: server->client aes128-ctr [email protected] none debug1: kex: client->server aes128-ctr [email protected] none debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP debug1: SSH2_MSG_KEX_DH_GEX_INIT sent debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY debug1: Server host key: RSA ab:12:23:34:45:56:67:78:89:90:12:23:34:45:56:67 debug1: Host '[100.100.100.100]:12345' is known and matches the RSA host key. debug1: Found key in /Users/mylocaluser/.ssh/known_hosts:36 debug1: ssh_rsa_verify: signature correct debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug1: SSH2_MSG_NEWKEYS received debug1: Roaming not allowed by server debug1: SSH2_MSG_SERVICE_REQUEST sent debug1: SSH2_MSG_SERVICE_ACCEPT received debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Offering RSA public key: /Users/mylocaluser/.ssh/id_rsa debug1: Authentications that can continue: publickey debug1: Offering RSA public key: /Users/mylocaluser/.ssh/id_rsa2 debug1: Authentications that can continue: publickey debug1: Trying private key: /Users/mylocaluser/.ssh/id_dsa debug1: No more authentication methods to try. Permission denied (publickey).

Saída do console para um login bem-sucedido (possível somente enquanto "sessão ativa" existir): OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011 debug1: Reading configuration data /Users/mylocaluser/.ssh/config debug1: Reading configuration data /etc/ssh_config debug1: /etc/ssh_config line 20: Applying options for * debug1: /etc/ssh_config line 103: Applying options for * debug1: Connecting to 100.100.100.100 [100.100.100.100] port 12345. debug1: Connection established. debug1: identity file /Users/mylocaluser/.ssh/id_rsa type 1 debug1: identity file /Users/mylocaluser/.ssh/id_rsa-cert type -1 debug1: identity file /Users/mylocaluser/.ssh/id_dsa type -1 debug1: identity file /Users/mylocaluser/.ssh/id_dsa-cert type -1 debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_6.2 debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6.1p1 Ubuntu-2ubuntu2 debug1: match: OpenSSH_6.6.1p1 Ubuntu-2ubuntu2 pat OpenSSH* debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: kex: server->client aes128-ctr [email protected] none debug1: kex: client->server aes128-ctr [email protected] none debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP debug1: SSH2_MSG_KEX_DH_GEX_INIT sent debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY debug1: Server host key: RSA ab:12:23:34:45:56:67:78:89:90:12:23:34:45:56:67 debug1: Host '[100.100.100.100]:12345' is known and matches the RSA host key. debug1: Found key in /Users/mylocaluser/.ssh/known_hosts:36 debug1: ssh_rsa_verify: signature correct debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug1: SSH2_MSG_NEWKEYS received debug1: Roaming not allowed by server debug1: SSH2_MSG_SERVICE_REQUEST sent debug1: SSH2_MSG_SERVICE_ACCEPT received debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Offering RSA public key: /Users/mylocaluser/.ssh/id_rsa debug1: Server accepts key: pkalg ssh-rsa blen 279 debug1: Authentication succeeded (publickey). Authenticated to 100.100.100.100 ([100.100.100.100]:12345). debug1: channel 0: new [client-session] debug1: Requesting [email protected] debug1: Entering interactive session. debug1: Sending environment. debug1: Sending env LANG = de_DE.UTF-8 Welcome to Ubuntu 14.04.1 LTS

    
por Webx10 19.08.2014 / 07:44

3 respostas

5

Quando o diretório pessoal do usuário estiver criptografado com ecryptfs sshd não poderá ler o arquivo authorized_keys do diretório pessoal do usuário antes que o diretório pessoal seja montado.

Durante o login sshd usará pam para autenticar o usuário e pam usará a senha digitada pelo usuário para montar o diretório pessoal criptografado.

Isso é problemático se você quiser restringir sshd para permitir somente a autenticação de chave pública.

No entanto, você também pode colocar um arquivo authorized_keys não criptografado no servidor. Isso permitirá que o usuário faça o login usando uma chave, mas como isso não invoca pam , o diretório inicial não será montado e a montagem do diretório inicial sem conhecer a senha também não funcionará.

Como o diretório inicial não criptografado fica oculto pelo diretório inicial criptografado, colocar o arquivo authorized_keys não criptografado em primeiro lugar pode ser um pouco complicado. Uma montagem de ligação do sistema de arquivos subjacente pode ajudar com isso.

Se, por exemplo, /home for apenas um diretório no sistema de arquivos raiz, você poderá fazer o seguinte:

mkdir /mnt/rootfs
mount --bind / /mnt/rootfs

E então você pode criar /mnt/rootfs/home/$USER/.ssh/authorized_keys

Há mais coisas que você pode fazer. Como a versão criptografada e não criptografada de authorized_keys são dois arquivos diferentes, você pode colocar diferentes conteúdos neles. Por exemplo, a versão não criptografada pode invocar um script para montar o diretório inicial criptografado:

command="/usr/local/bin/ecryptfs-mount-from-ssh" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDM1Ot12ThbTcPOGpfh7AiRqp3P4BMm3DNo4mDg7gDFPwCmM9rKRHTH0fBVSqkSGlXm84q29bckDukg7vfqkbTpbkP3e2YmTkP6p1J2SoX2QMUnBRRgL9It/ZiAfA2I4QzUrcywVvokO1F2DqcRLy5e5wKTUFfvIm6D2QfBmGbnW2Kkpn16hQyLT1ClXjFC1qXUhazePv0cAtWUCUGjRcLr/ipOphS7eOB46cGhYqtbMkKx0t93ZG4f6jM0o32cYy3RqprpZpTmCeG1gDyG+IlSLBYXYggr72iwTKsTZ9pMDTCBQ8Pb7l317TPOcJzTtDxnpgpGE3x4Vu/Ww+zhsIeT kasperd 2014 May 24

A parte importante é o command especificado antes da chave. Isso é invocado em vez do shell. Mas isso acontece somente quando essa chave pública específica é usada e somente se o diretório pessoal do usuário não estiver montado.

Se o diretório pessoal do usuário já estiver montado, esse arquivo authorized_keys ficará oculto e a versão criptografada será usada. A versão criptografada de authorized_keys não tem o command , portanto, o script para montar o diretório inicial não é executado.

Então, o que acontece no script. Aqui está a minha versão:

#!/bin/bash -e

if [ $# = 1 ]
then
    PUBKEY="$(
        grep "$1" "$HOME/.ssh/authorized_keys" |
            sed -e 's/.* ssh-rsa //;s/ .*//')"
    /usr/local/bin/ssh-agent-ecryptfs-decryption.py "$PUBKEY" "$1" |
        ecryptfs-unwrap-passphrase "$HOME/.ecryptfs-ssh-wrapped/$1" - |
        ecryptfs-add-passphrase --fnek
fi
ecryptfs-mount-private
cd "$HOME"

if [ "$SSH_ORIGINAL_COMMAND" != "" ]
then
    exec /bin/bash -c "$SSH_ORIGINAL_COMMAND"
fi

exec /bin/bash -l

No exemplo acima, o arquivo authorized_keys é invocado sem argumentos, portanto, o primeiro bloco if é ignorado. O comando ecryptfs-mount-private solicitará a senha do usuário. Mas isso não exige que sshd tenha a autenticação por senha ativada e, portanto, funcionará somente no sshd com autenticação de chave pública.

O próximo comando será alterado para o diretório inicial criptografado do usuário (até que o script seja executado dentro do diretório inicial não criptografado).

A última parte do script executará o comando fornecido como argumento para o comando ssh , se houver, ou o shell de login do usuário, se nenhum comando tiver sido fornecido.

Uma ressalva é que isso não funciona com o encaminhamento do X11, porque o diretório inicial ainda não está disponível, quando o cookie seria armazenado. Mas qualquer outra sessão aberta enquanto o diretório home já estiver montado, será capaz de lidar com o encaminhamento do X11.

Usar o ~/.ssh/rc poderia resolver o problema de encaminhamento do X11. Isso é algo que eu não olhei ainda.

O primeiro bloco if é um hack, que eu criei para permitir que o diretório pessoal do usuário seja montado sem precisar de senha. Em vez disso, ele usa um ssh-agent encaminhado para montar o diretório pessoal do usuário. Essa parte vem com isenções de responsabilidade sobre não ter tido nenhuma revisão por pares, então confiar na criptografia no ssh-agent-ecryptfs-decryption.py é inteiramente por sua conta e risco.

O script python é assim:

#!/usr/bin/env python

from sys import argv
from os import environ
import socket

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(environ['SSH_AUTH_SOCK'])

def encode_int(v):
    return ('%08x' % v).decode('hex')

def encode_string(s):
    return encode_int(len(s)) + s

def encode_mpint(v):
    h = '%x' % v
    if len(h) & 1: h = '0' + h
    return ('%04x%s' % (len(h) * 4, h)).decode('hex')

key_blob = argv[1].decode('base64')
msg = 'ecryptfs-decrypt ' + argv[2]

s.send(encode_string(chr(13) +
                     encode_string(key_blob) +
                     encode_string(msg) +
                     encode_int(0)))

response = s.recv(1024)

assert response == encode_string(chr(14) + response[5:]), argv[1]

passphrase = response[-48:].encode('base64').replace('\n', '')

print passphrase

Então, como funciona a descriptografia? Primeiro de tudo, o argumento para o script como fornecido por authorized_keys é qualquer valor aleatório. Um uuid gerado com uuidgen poderia funcionar. O script de shell usa o grep para encontrar a linha relevante no arquivo authorized_keys para extrair a chave pública.

A chave pública codificada em base64, bem como o uuid, são fornecidos ao script python. A chave pública usada é exatamente aquela com a qual o usuário se autenticou. O script python solicita ao agente encaminhado uma assinatura em uma mensagem específica usando a chave pública em questão (porque as mensagens de assinatura são exatamente o que o ssh-agent pode fazer). Parte da assinatura é então codificada com base64 para produzir uma senha.

Esta senha é usada para descriptografar um arquivo de senha ecryptfs wrapped, mas o arquivo principal é criptografado usando a senha de login do usuário. Este é criptografado com uma senha gerada a partir da chave ssh.

    
por 20.08.2014 / 18:29
3

Eu fiquei tão inspirado pela ideia de Kasperd ontem que eu fiz isso:

link

Já tentei um pouco e parece funcionar de forma brilhante. Isso torna muito simples adicionar / remover chaves para descriptografia sem senha de pastas domésticas do ecryptfs ao usar o SSH ...

Como o original de kasperd, ele não foi exposto a uma revisão por especialistas - mas como está no github, agora qualquer um pode participar.:)

Você ainda tem que mover suas chaves para fora da sua pasta pessoal, mas com isso você pode pelo menos evitar o login de senha ruim ...

Aproveite!

    
por 22.08.2014 / 14:19
0

Aqui está uma solução simples, mas parece não ser elegante.

Como sua pasta pessoal está criptografada, basta colocar o arquivo authorized_keys em um local não criptografado.

Então você precisa dizer ao ssh onde authorized_keys é. Em /etc/ssh/sshd_config , anexe:

Match User [your_user_name]
AuthorizedKeysFile [new_path_to_authorized_keys]

NOTA: Certifique-se de colocar o Match no final do arquivo. O Match permanece válido até o final do arquivo ou outro Match é atendido.

Agora você pode fazer login via ssh e não precisa fazer o login localmente primeiro. Mas após o login do ssh, você precisa executar:

ecrypts-mount-private

e insira sua senha para montar sua pasta pessoal e, em seguida, cd para sua casa manualmente.

    
por 03.03.2016 / 15:55