SSH 公钥身份验证仅在活动会话之前存在时才有效

Web*_*x10 1 remote-access linux ssh ssh-keys kvm-virtualization

我的 SSH 配置有一个相当奇怪的问题。我在远程访问卡的帮助下设置了我的服务器,并使用 KVM 查看器配置了所有内容。

因此,在通过 KVM 查看器登录服务器时,我仅使用公钥配置了 SSH,并尝试从本地笔记本电脑登录。它工作得很好。

如果我退出 KVM 会话(或在 KVM 会话中与用户一起注销),我将无法再通过 ssh 登录(公钥被拒绝)。SSH 登录仅在用户在某处仍处于登录状态时才有效。

任何提示可能是什么问题?


登录失败的控制台输出(所有个人数据交换):

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 hmac-md5-etm@openssh.com none debug1: kex: client->server aes128-ctr hmac-md5-etm@openssh.com 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).

成功登录的控制台输出(仅在“活动会话”存在时才可能): 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 hmac-md5-etm@openssh.com none debug1: kex: client->server aes128-ctr hmac-md5-etm@openssh.com 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 no-more-sessions@openssh.com debug1: Entering interactive session. debug1: Sending environment. debug1: Sending env LANG = de_DE.UTF-8 Welcome to Ubuntu 14.04.1 LTS

kas*_*erd 5

当用户的主目录被加密时,在挂载主目录之前ecryptfs sshd无法authorized_keys从用户的主目录中读取文件。

登录时sshd将用于pam对用户进行身份验证,pam并将使用用户输入的密码挂载加密的主目录。

如果您想限制sshd为仅允许公钥身份验证,这是有问题的。

但是,您也可以将未加密的authorized_keys文件放在服务器上。这将允许用户使用密钥登录,但由于这不会调用pam,因此不会挂载主目录,并且在不知道密码的情况下挂载主目录也不起作用。

由于未加密的主目录被加密的主目录隐藏,因此将未加密的authorized_keys文件放在首位可能有点棘手。底层文件系统的绑定挂载可以帮助解决这个问题。

例如,如果/home只是根文件系统上的一个目录,则可以执行以下操作:

mkdir /mnt/rootfs
mount --bind / /mnt/rootfs
Run Code Online (Sandbox Code Playgroud)

然后你可以创建 /mnt/rootfs/home/$USER/.ssh/authorized_keys

你可以做的还有更多。由于加密版和未加密版authorized_keys是两个不同的文件,您可以将不同的内容放入其中。例如,未加密的版本可以调用脚本以挂载加密的主目录:

command="/usr/local/bin/ecryptfs-mount-from-ssh" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDM1Ot12ThbTcPOGpfh7AiRqp3P4BMm3DNo4mDg7gDFPwCmM9rKRHTH0fBVSqkSGlXm84q29bckDukg7vfqkbTpbkP3e2YmTkP6p1J2SoX2QMUnBRRgL9It/ZiAfA2I4QzUrcywVvokO1F2DqcRLy5e5wKTUFfvIm6D2QfBmGbnW2Kkpn16hQyLT1ClXjFC1qXUhazePv0cAtWUCUGjRcLr/ipOphS7eOB46cGhYqtbMkKx0t93ZG4f6jM0o32cYy3RqprpZpTmCeG1gDyG+IlSLBYXYggr72iwTKsTZ9pMDTCBQ8Pb7l317TPOcJzTtDxnpgpGE3x4Vu/Ww+zhsIeT kasperd 2014 May 24
Run Code Online (Sandbox Code Playgroud)

重要的部分是command在键之前指定的。这将被调用而不是 shell。但只有在使用此特定公钥时才会发生这种情况,并且仅当用户的主目录未安装时才会发生。

如果用户的主目录已经挂载,则该authorized_keys文件被隐藏并使用加密版本代替。的加密版本authorized_keys没有command,因此不会运行挂载主目录的脚本。

那么,脚本中的内容。这是我的版本:

#!/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
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,authorized_keys文件是不带参数调用的,所以第一个if块被跳过。ecryptfs-mount-private因此,该命令将询问用户的密码。但这不需要sshd启用密码身份验证,因此sshd仅适用于公钥身份验证。

下一个命令将更改为用户的加密主目录(在此之前脚本将在未加密的主目录中运行)。

脚本的最后一部分将运行作为命令参数给出的ssh命令(如果有),或者如果没有给出命令,则运行用户登录 shell。

一个警告是,这不适用于 X11 转发,因为当 cookie 将被存储时,主目录尚不可用。但是在主目录已经挂载时打开的任何其他会话将能够处理 X11 转发。

使用~/.ssh/rc反而可能可能解决X11转发问题。这是我还没有研究过的。

第一个if块有点小技巧,我想出它来允许在不需要密码的情况下挂载用户的主目录。相反,它使用转发ssh-agent来挂载用户的主目录。这部分带有关于没有任何同行评审的免责声明,因此信任密码学ssh-agent-ecryptfs-decryption.py完全由您自己承担风险。

python 脚本如下所示:

#!/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
Run Code Online (Sandbox Code Playgroud)

那么解密是如何工作的呢?首先,脚本提供的参数authorized_keys是任何随机值。生成的 uuiduuidgen可以工作。shell 脚本使用 grep 在authorized_keys文件中查找相关行来提取公钥。

将 base64 编码的公钥以及 uuid 提供给 python 脚本。所使用的公钥正是用户进行身份验证时使用的公钥。python 脚本要求转发代理使用相关公钥对特定消息进行签名(因为签名消息正是ssh-agent可以做的)。然后使用 base64 对签名的一部分进行编码以生成密码。

此密码用于解密ecryptfs包装好的密码文件,但主文件使用用户的登录密码进行加密。这个是用 ssh 密钥生成的密码加密的。