我想通过SSH在网络(静态以太网)上的多台计算机之间进行通信。为了做到这一点,我每次登录到特定计算机时都需要运行ssh-add,我该怎么做,以便将其设置一次,并且每次我登录或重新启动时都不会要求我输入密码我的机器吗?

我知道有一种方法可以在bash_profile文件中添加一些行,但是每次我重新启动/登录到特定计算机时,我仍然需要输入密码。 br />
if [ -z "$SSH_AUTH_SOCK" ] ; then
    eval `ssh-agent -s`
    ssh-add
fi


评论

与此问题类似stackoverflow.com/questions/18880024/start-ssh-agent-on-login

stackoverflow.com/a/52671286/217408解决了这个问题,让我通过了来自bitwarden的密码短语

#1 楼

这是安全性和便利性之间折衷的典型示例。幸运的是,有很多选择。最合适的解决方案取决于使用场景和所需的安全级别。

带有密码短语的ssh-key,不需要ssh-agent

现在,每次每次输入密钥时都必须输入密码短语用于身份验证。从安全角度来看,这是最佳选择,但可用性却最差。这也可能会导致按顺序选择较弱的密码短语,以减轻重复输入密码的负担。 to ssh-agent将自动启动~/.bash_profile并在登录时加载ssh密钥:

if [ -z "$SSH_AUTH_SOCK" ] ; then
  eval `ssh-agent -s`
  ssh-add
fi


现在必须在每次登录时输入密码。从可用性的角度来看,虽然稍好一点,但它的缺点是ssh-agent提示输入密码短语,而不管登录会话期间是否使用密钥。每次新登录都会产生一个独特的ssh-agent实例,即使注销后该实例仍会使用添加的键在内存中运行,除非被明确杀死。

要注销ssh-agent时要注销它,请将以下内容添加到ssh_agent

if [ -n "$SSH_AUTH_SOCK" ] ; then
  eval `/usr/bin/ssh-agent -k`
fi


~/.bash_logout的以下内容
trap 'test -n "$SSH_AUTH_SOCK" && eval `/usr/bin/ssh-agent -k`' 0


通过创建与代理的持久通信套接字,可以避免创建多个~/.bash_profile实例在文件系统中的固定位置,例如Collin Anderson的答案。这是对产生多个代理实例的改进,但是,除非显式终止,否则注销后仍保留在内存中的解密密钥。

在台式机上,台式机环境中随附的ssh代理(例如Gnome密钥环SSH代理)可能是一种更好的方法,因为通常可以使它们在首次在登录会话期间使用ssh密钥时提示输入密码,并且将解密的私钥存储在内存中,直到会话结束。
带有密码的ssh-key,带有ssh-agent

ssh-ident是一个实用程序,可以代表您管理ssh-ident,并且必要时加载身份。它仅在需要时添加一次密钥,而与需要访问ssh-agent的终端,ssh或登录会话数无关。它也可以添加和使用不同的代理和不同的密钥集,具体取决于所连接的主机或从中调用目录ssh。当与不同主机一起使用代理转发时,这允许隔离密钥。它还允许在GitHub之类的网站上使用多个帐户。

要启用ssh-agent,请安装它,并将以下别名添加到您的ssh-ident中:

alias ssh='/path/to/ssh-ident'


带密码的ssh-key,带有~/bash_profile

keychain是一个小型实用程序,代表您管理keychain,并且
允许ssh-agent在登录会话结束时保持运行。在后续登录中,ssh-agent将连接到现有的keychain实例。实际上,这意味着必须在重新引导后的首次登录期间输入密码。在随后的登录中,使用来自现有ssh-agent实例的未加密密钥。这对于在ssh-agent作业中允许无密码ssh-key的无密码RSA / DSA身份验证也很有用。

要启用cron,请安装它并在keychain中添加以下内容:

eval `keychain --agents ssh --eval id_rsa`


从安全性的角度来看,~/.bash_profilessh-ident实例比keychain实例受特定会话的生存期限制要差,但是它们提供了高度的便利。为了提高ssh-agent的安全性,有些人在keychain钥匙串调用中添加了--clear选项。通过这样做,必须如上所述在登录时重新输入密码短语,但是在用户注销后,~/.bash_profile作业仍将有权访问未加密的密钥。 cron Wiki页面上提供了更多信息和示例。它是暴露的。但是,这是确保重新启动后无需重新输入密码的唯一方法。 >
虽然将密码从脚本传递给keychain似乎是一个简单的主意,例如ssh-agent并不像ssh-add不会读取ssh-add的密码短语那样直接,而是直接打开echo "passphrase\n" | ssh-add进行读取。

这可以与ssh-add一起解决,stdin是使交互式应用程序自动化的工具。下面是一个脚本示例,该脚本使用存储在脚本中的密码添加了ssh密钥:

#!/usr/bin/expect -f
spawn ssh-add /home/user/.ssh/id_rsa
expect "Enter passphrase for /home/user/.ssh/id_rsa:"
send "passphrase\n";
expect "Identity added: /home/user/.ssh/id_rsa (/home/user/.ssh/id_rsa)"
interact


请注意,由于密码以明文形式存储在脚本中从安全角度来看,这几乎比拥有无密码的ssh-key好。如果要使用此方法,请务必确保包含密码短语的/dev/tty脚本具有适当的权限设置,使其仅由密钥所有者可读,可写和可运行。

评论


好的,但是当我将您的代码放入〜/ .bash_profile时,每次登录时都必须输入密码,我也不希望这样。我根本不关心安全性。回声“ pass \ n” | ssh-add不起作用

–zdun8
2013年9月17日在12:59

@ user1607072是的,这就是〜/ .bash_profile中的ssh-agent代码段的行为,如答案中所述。您可能要看看钥匙串实用程序。使用钥匙串时,您需要在重新引导后的首次登录时输入密码,但是在以后的登录中,钥匙串将连接到现有的ssh-agent实例,且该实例具有内存中的解密密钥。除此之外,还可以选择不使用密码生成ssh密钥,但是当然不建议这样做。

–托马斯·尼曼(Thomas Nyman)
2013年9月17日13:35

@ user1607072虽然我强烈建议一种更安全的方法,但是有一种方法可以将密码短语从脚本传递给ssh-add。回显“ pass \ n”的原因| ssh-add不起作用是因为ssh-add不会从stdin中读取密码,而是直接打开/ dev / tty进行读取。使用名为Expect的实用程序更新了答案,以包括针对此问题的解决方法。

–托马斯·尼曼(Thomas Nyman)
2013年9月17日18:03



@ user1607072对于您的用例而言,这可能有些过头,但是Kerberos与ssh GSSAPI支持结合使用也可以用于无密码的ssh登录。 ssh中相应的身份验证方法称为gssapi-with-mic。通常在较大的网络中使用它,但是当然,如​​果您对此感兴趣,可能值得研究。

–托马斯·尼曼(Thomas Nyman)
2013年9月18日在11:54



@ErickBrown:已经在这里回答了。如果您在systemd登录管理器中禁用了用户徘徊,则SSH Agent单元应在注销时停止。如果启用了用户徘徊,即使关闭了最后一个登录会话,systemd用户实例和SSH代理单元仍保持运行。

–托马斯·尼曼(Thomas Nyman)
18年7月25日在8:00

#2 楼

将此添加到您的~/.bashrc中,然后注销并重新生效。

 if [ ! -S ~/.ssh/ssh_auth_sock ]; then
  eval `ssh-agent`
  ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
ssh-add -l > /dev/null || ssh-add
 


此每次重新启动后,首次登录时仅应提示输入密码。只要它保持运行,它将继续重复使用相同的ssh-agent

评论


非常简洁,这样您就只能运行一个ssh-agent(:@thomasNyman第二种解决方案中的多个代理对我来说似乎有安全隐患...

– drevicko
16年2月10日在11:54

在对各个站点进行研究并阅读了各种解决方案之后,这里的这一点似乎是最清晰,直接的。非常好。 +1

– DrBeco
16年7月18日在0:40

最好这样做:“ alias ssh = ssh-check-agent”,并让check-agent版本执行上述操作。这样:a)您仅获得一个代理,b)仅在需要时获得该代理

– Erik Aronesty
16年7月26日在20:31



我认为-s是默认设置,因此我们已经在这样做了。

–科林·安德森
16-11-22在16:25

请注意,不带参数的ssh-add将添加〜/ .ssh / id_rsa。如果您的私钥在另一个文件中,则可能要传递ssh-add参数。

–马特西亚斯·布劳恩(Matthias Braun)
19年11月1日在13:54

#3 楼

与OP的问题没有密切关系,但对其他人可能有用:由于7.2.0 ssh(1)具有一个选项,允许在首次认证时向ssh-agent添加密钥;该选项是AddKeysToAgent,可以在系统范围内或在您的个人yes文件上设置为noaskconfirm.ssh/config

参考:https://www.openssh.com/txt/release- 7.2

评论


适用于.ssh / config文件的新手:这适用于ssh以及在其后使用ssh的任何内容,例如scp,并且可以在每个主机的基础上完成。

– SEoF
17-09-25在14:32

每次我登录并尝试进行git pull时,它仍然会要求我提供密码。

–火车头病
19年8月7日在10:15

@trainosis问题是您可能没有正在运行的ssh-agent实例将解密后的密钥保存在内存中以备将来使用。使用ssh-agent时,您只需在每个登录会话中输入一次给定密钥的密码。

– esstrada
19年8月13日在20:43

#4 楼

ssh-agent缓存各种未锁定的ssh密钥,因此您可以用密码保护ssh密钥,而不必每次都键入它们。

为了缓存未锁定的密钥,显然需要将那些未锁定的ssh密钥进行解锁。键。要解锁用密码锁锁定的钥匙,显然需要知道这些密码。

任何不需要人类授权的方法(例如“键入密码”)都不会您的系统不安全;综上所述,您可以简单地使用不受密码保护的ssh-key(在输入密码时要求输入密码时按Enter键,世代)。
由于没有任何密码,因此ssh-agent无需再询问您一个密码(或不缓存)。

评论


我同意,只要您的密钥正确地只允许用户使用,与没有许可的密钥相比,ssh-agent几乎没有优势。我喜欢ssh进入登录服务器,然后该服务器具有一堆无永久性密钥,每个密钥只能用于解锁另一台服务器。登录服务器无能为力,因此更难于破解/欺骗等。其他服务器无密码访问,仅是密钥。

– Erik Aronesty
16年7月26日在20:34



#5 楼

这是一种自动化SSH密码的解决方法。



创建一个单行脚本,将您的密码打印到标准输出,例如:

 echo 'echo MY_SSH_PASSWORD' > ~/.print_ssh_password && chmod 700 ~/.print_ssh_password
重要提示:请确保您复制前导空格以防止将密码存储到历史记录中。


并使用以下方法之一。



使用标准输入法:

cat ~/.ssh/id_rsa | SSH_ASKPASS=~/.print_ssh_password ssh-add -



或命名管道法:



创建一个命名管道(您也可以尝试使用流程替换):

mkfifo --mode 0600 ~/.ssh_fifo



通过指定以下内容运行ssh-add用于身份验证的程序:

cat ~/.ssh/id_rsa >~/.ssh_fifo | SSH_ASKPASS=~/.print_ssh_password ssh-add ~/.ssh_fifo



请参阅:man ssh-add以了解有关SSH_ASKPASS的更多信息。




评论


回声my_passphrase是一个很大的安全漏洞。首先,键入密码后,密码将以明文形式显示在所用外壳程序的历史记录文件中。第二个命令行参数在Unix(ps -ef)上是世界可读的。切勿在命令行参数中输入密码!

–天花板
16年8月24日在9:03

@ceving添加额外的前导空格可以解决历史文件的问题。添加了额外的信息。

– Kenorb
16年8月24日在9:25

@kenorb:不能解决更大的问题,即在ps输出中可见的密码。无论如何,历史记录文件通常通常只能由拥有用户读取,但是系统上的所有用户都可以读取命令行。

–托马斯·尼曼(Thomas Nyman)
16-11-23在14:37

#6 楼

我不建议您在登录时使用ssh-add(需要打开ssh-agent)。这是因为您无法控制ssh-agent节的结束时间,并且在不需要在一个登录节中使用密钥文件时会带来安全风险。

我建议编写一个脚本打开ssh-agent的section子外壳,自动添加所有密钥文件,并在需要使用ssh时调用。如果可以采用,请继续阅读。

您将有两种选择:


删除密钥的所有密码短语,如果密钥文件的安全性较弱被偷了。 (因此不建议使用)
对密钥使用相同的密码短语。然后,当您ssh-add keyfile1 keyfile2 ...时,每个部分只需键入一次密码。

在两种情况下,您都可以编写如下脚本文件“ ssh_keys_section.sh”:

#!/bin/bash
# This script run a ssh-agent on a sub-shell and automatically ssh-add all keyfiles at once.
# This agent ends when you type `exit` to close the sub-shell.
exec ssh-agent bash -c "ssh-add /path/to/keyfile1 /path/to/keyfile2 ...; exec bash"


备注:


更改或删除密码的命令:ssh-keygen -p -f keyfile

在子外壳中,您甚至可以通过使用诸如/path/to/yourterminal &(取决于操作系统)之类的命令,分叉更多共享相同解锁密钥的终端机


评论


例如。在Windows上的Cygwin中,/ path / to / yourterminal&==> mintty&

–约翰尼·王(Johnny Wong)
19-3-25在9:50



备注:使用后,请使用ctrl-d关闭会话或退出,就像您已调用嵌套的bash shell并需要将其关闭一样。

–约翰尼·王(Johnny Wong)
19年11月1日在8:44



#7 楼

if [ ! -S ${HOME}/.ssh/ssh_auth_sock ]; then
  eval $(ssh-agent)
  ln -sf "${SSH_AUTH_SOCK}" ${HOME}/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=${HOME}/.ssh/ssh_auth_sock

ssh_keys=$(find -E ~/.ssh -type f -regex '.*(rsa$|pem)')
ssh_agent_keys=$(ssh-add -l | awk '{key=NF-1; print $key}')

for k in "${ssh_keys}"; do
    for l in "${ssh_agent_keys}"; do
        if [[ ! "${k}" = "${l}" ]]; then
            ssh-add "${k}" > /dev/null 2>&1
        fi
    done
done


#8 楼

我以前使用的是Steampowered提到的脚本,现在我做了下面的脚本,因为它不会留下文件。
仅在zsh shell上工作。

评论


“仅在zsh shell上工作”,好吧,但是为什么您的shebang行声明仅要求“ sh”?

–最大
20年9月8日在12:20

#9 楼

SSH_ENV="$HOME/.ssh/environment"

function start_agent {
     echo "Initialising new SSH agent..."
     /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
     echo succeeded
     chmod 600 "${SSH_ENV}"
     . "${SSH_ENV}" > /dev/null
     /usr/bin/ssh-add;
}

# Source SSH settings, if applicable

if [ -f "${SSH_ENV}" ]; then
     . "${SSH_ENV}" > /dev/null
     #ps ${SSH_AGENT_PID} doesn't work under cywgin
     ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
         start_agent;
     }
else
     start_agent;
fi


在此处提供信誉:https://www.cygwin.com/ml/cygwin/2001-06/msg00537.html

此处也认可了该解决方案:http ://mah.everybody.org/docs/ssh

#10 楼

如果您将Seahorse用作密码管理器
...,您可能是; D

要实现您想要的目标的另一种解决方案是,只需将ssh密钥添加到seahorse中即可自动登录时解锁。这样做的主要好处是,通过gdm登录后,即使密钥有密码,也无需输入密钥密码。这需要私钥和公钥。他们还必须遵循海马的命名约定。默认值是可以接受的(私钥使用id_rsa,公钥使用id_rsa.pub ...真的是privatekeyname和privatekeyname.pub都可以)。

将ssh密钥添加到seahorse中,以便在登录时自动解锁;
(在fedora25上,我不确定路径是否在其他发行版上,尽管它可能很相似)

/lib64/seahorse/seahorse-ssh-askpass /path/to/keys/here


对我来说,这是

/lib64/seahorse/seahorse-ssh-askpass ~/.ssh/id_rsa


(在我的案例中,seahorse会自动假定公钥为id_rsa.pub)

执行命令后,seahorse会弹出一个可爱的小gtk密码字段,用于输入私钥的密码。或者如果您生成没有密码的密钥,则将其留空。

如果一切正常,Seahorse不会提示您。您将需要尝试SSH到目标计算机。然后,seahorse会提示您再次以图形方式使用密码解锁密钥(此操作仅会发生一次),但是这次看起来应该有所不同; P(这也是seahorse进行一些seahorse ssh添加魔术的部分) ),并提供在登录时解锁密钥的选项,您必须选中此选项才能实现目标。

由于我没有阅读所有答案,所以建议您撤消每个人告诉你的内容尝试此答案之前,先用ssh-add做。否则可能会导致您的密钥idk发生问题。

#11 楼

SSH的单点登录解决方案可能会导致我进入pam_ssh

根据本文,概念是:


如果您使用多个基于* nix的软件通过ssh的计算机,您可能已经厌倦了每次要访问另一个设备时都要不断输入密码的麻烦。有一种安全的方法可以让您访问ssh可以访问的每台计算机,而无需输入其他密码(原始登录密码除外)。




这实际上很简单,您基本上只需创建一个公钥/私钥对即可向其他计算机进行身份验证,然后让PAM生成代理以在登录后加载密钥,从而提供一个单一登录解决方案来访问您的所有远程计算机。本指南将引导您完成此设置。


我尚未验证它是否可以正常工作。

#12 楼

将此添加到您的~/.bashrc文件中:

ssh-add -L|grep identities > /dev/null && ssh-add /path/to/ssh/private/key


评论


我看不到这与问题的关系,该问题是在后续登录时不提示输入密码。

–克里斯唐(Chris Down)
2014年1月6日13:23



#13 楼

为了添加一个(可能没有密码的)密钥,并确保ssh-add即使在X下运行,无论如何都不会提示输入密码:

DISPLAY= ssh-add -k /path/to/key </dev/null &>/dev/null


退出状态表示成功或失败。

#14 楼

这是权威脚本。

更新$ PASSW,然后将其复制粘贴到您的终端机中

# <sshpass> via typinator
# Updated: 2017-01-18_21h36
#
# apt-get update -y; apt-get install expect -qy

# Pass this value to ssh-add
PASSW="myfancypass123"

# Define a name for this script
THIS_SCRIPT="$(date +%Y-%m-%d_%H-%M-%S-%N)".sh

# Create a fresh directory to work from / Clean up
rm -rf ~/temp; mkdir -p ~/temp; cd ~/temp; ls -la


# Output our bash script file - BEGIN
cat <<< '
#!/bin/bash

set -u     # Stop if an unbound variable is referenced
set -e     # Stop on first error
export HISTIGNORE="expect*";

# Normal CMDs
echo && echo "The process should take about 10 seconds:" && echo
eval "$(ssh-agent -s)"; sleep 0.5;

# Define VAR passed when this bash-script was launched
password="$@"

# Launch the expect magic
expect -c "
    spawn ssh-add /root/.ssh/id_rsa
    expect "?assword:"
    send \"$password\r\"
    expect "?password:"
    send \"$password\r\"
    expect eof"

export HISTIGNORE="";
export password="";
' > $THIS_SCRIPT
# Output our bash script file - END


# Ensure we are in the right path
cd ~/temp; ls -la; sleep 1;

# Run the bash script
chmod +x ./$THIS_SCRIPT; ./$THIS_SCRIPT "$PASSW"; unset password;

# Clean up
rm -rf ~/temp; mkdir -p ~/temp; cd ~/temp; ls -la


#15 楼

我知道的最好方法是使用我从以前的工作改编的PAM登录脚本,因为在此问题中找不到满意的答案。

您的密码将使用系统密码和重推导函数。登录时,系统密码用于解密密码并将其添加到代理。

https://github.com/capocasa/systemd-user-pam-ssh

相较于其他所有解决方案,优点是它结合了等效于安全性的安全性,相当于在引导时手动运行ssh-add,而无需花费任何精力。它不需要任何额外的工具,并且具有一个默认情况下已在大多数系统(OpenSSL)上安装的额外依赖项。

#16 楼

我在macOS上的设置如下(在.zshrc或bash爱好者的.bash_profile中):

# Kill then Load the ssh-agent and set the necessary env variables it outputs
sshRestart() {
    # if all else fails
    # pkill -u $(whoami) ssh-agent;

    if [ -n "$SSH_AUTH_SOCK" ] ; then
        eval `/usr/bin/ssh-agent -k`
    fi
    eval `ssh-agent -s`
    ssh-add ~/.ssh/YOUR_KEY_FILE
    echo "Restarted SSH agent"
}

if [ -z "$SSH_AUTH_SOCK" ] || [[ $SSH_AUTH_SOCK == *"/private/tmp/"* ]] ; then
    eval `ssh-agent -s` > /dev/null 2>&1
    ssh-add ~/.ssh/YOUR_KEY_FILE > /dev/null 2>&1
fi


由于默认值是|| [[ $SSH_AUTH_SOCK == *"/private/tmp/"* ]],因此在macOS上需要/private/tmp/com.apple.launchd.SOMETHINGHERE/Listeners部分。否则@Thomas Nyman综合答案将失败,因为$SSH_AUTH_SOCK始终设置为某项。

然后输入.zlogout(对于bash爱好者则为.bash_logout):

if [ -n "$SSH_AUTH_SOCK" ] ; then
    eval `/usr/bin/ssh-agent -k`
fi


已在macOS Mojave 10.14.5上进行测试