我想通过SSH在网络(静态以太网)上的多台计算机之间进行通信。为了做到这一点,我需要在每次登录到特定计算机上时都运行ssh-add,我该如何做才能将其设置一次,并且每次我登录或重新启动时都不会要求我输入密码我的机器?
我知道有一种方法可以在bash_profile
文件中添加一些行,但是每次我重新启动/登录到特定计算机时,我仍然需要输入密码。
if [ -z "$SSH_AUTH_SOCK" ] ; then
eval `ssh-agent -s`
ssh-add
fi
我想通过SSH在网络(静态以太网)上的多台计算机之间进行通信。为了做到这一点,我需要在每次登录到特定计算机上时都运行ssh-add,我该如何做才能将其设置一次,并且每次我登录或重新启动时都不会要求我输入密码我的机器?
我知道有一种方法可以在bash_profile
文件中添加一些行,但是每次我重新启动/登录到特定计算机时,我仍然需要输入密码。
if [ -z "$SSH_AUTH_SOCK" ] ; then
eval `ssh-agent -s`
ssh-add
fi
Answers:
这是在安全性和便利性之间进行权衡的典型示例。幸运的是,有很多选择。最合适的解决方案取决于使用方案和所需的安全级别。
带有密码的ssh-key,否 ssh-agent
现在,每次使用密钥进行身份验证时都必须输入密码。从安全角度来看,这是最佳选择,但可用性却最差。这也可能导致按顺序选择了较弱的密码短语,以减轻重复输入密码短语的负担。
带有密码的ssh-key,带有 ssh-agent
添加以下内容~/.bash_profile
将ssh-agent
在登录时自动启动并加载ssh-key:
if [ -z "$SSH_AUTH_SOCK" ] ; then
eval `ssh-agent -s`
ssh-add
fi
现在,必须在每次登录时输入密码。从可用性的角度来看,虽然稍好一点,但它的缺点是ssh-agent
,无论在登录会话期间是否使用密钥,都会提示输入密码短语。每次新登录都会生成一个不同的ssh-agent
实例,即使注销后,该实例仍将使用添加的键在内存中运行,除非明确终止。
要ssh_agent
在注销时终止,请将以下内容添加到~/.bash_logout
if [ -n "$SSH_AUTH_SOCK" ] ; then
eval `/usr/bin/ssh-agent -k`
fi
或以下 ~/.bash_profile
trap 'test -n "$SSH_AUTH_SOCK" && eval `/usr/bin/ssh-agent -k`' 0
ssh-agent
通过在文件系统中固定位置(例如Collin Anderson的answer)中创建与代理的持久通信套接字,可以避免创建多个实例。但是,这是对生成多个代理程序实例的一种改进,除非注销后显式杀死解密的密钥仍保留在内存中。
在台式机上,台式机环境中随附的ssh代理(例如Gnome密钥环SSH代理)可能是一种更好的方法,因为通常可以使它们在首次在登录会话期间使用ssh-key时提示输入密码。将解密的私钥存储在内存中,直到会话结束。
带有密码的ssh-key,带有 ssh-ident
ssh-ident
是可以ssh-agent
代表您进行管理并根据需要加载身份的实用程序。它仅在需要时添加一次密钥,而与需要访问的终端,ssh或登录会话数无关ssh-agent
。它还可以根据所连接的主机或从中调用目录ssh来添加和使用不同的代理和不同的密钥集。当与不同主机一起使用代理转发时,这允许隔离密钥。它还允许在GitHub等网站上使用多个帐户。
要启用ssh-ident
,请安装它,并将以下别名添加到您的~/bash_profile
:
alias ssh='/path/to/ssh-ident'
带有密码的ssh-key,带有 keychain
keychain
是一个小型实用程序,ssh-agent
可以代表您进行管理,并允许ssh-agent
登录会话结束时继续运行。在后续登录时,keychain
将连接到现有ssh-agent
实例。实际上,这意味着必须仅在重新引导后的首次登录期间输入密码。在随后的登录中,将ssh-agent
使用现有实例中的未加密密钥。这对于在cron
没有无密码ssh密钥的作业中允许无密码RSA / DSA身份验证也很有用。
要启用keychain
,请安装它,然后将以下内容添加到~/.bash_profile
:
eval `keychain --agents ssh --eval id_rsa`
从安全角度来看,ssh-ident
和keychain
比糟糕ssh-agent
局限于特定会话的生存情况,但他们提供的便利性高的水平。为了提高的安全性keychain
,有些人在--clear
其~/.bash_profile
钥匙串调用中添加了该选项。通过这样做,必须按上述方式在登录时重新输入密码短语,但是cron
在用户注销后,作业仍将有权访问未加密的密钥。该keychain
wiki页面有更多的信息和示例。
没有密码的ssh-key
从安全角度来看,这是最糟糕的选择,因为私钥在暴露时完全不受保护。但是,这是确保重新启动后无需重新输入密码的唯一方法。
带有密码短语的ssh-key,带有 ssh-agent
,将密码短语传递给 ssh-add
from脚本
例如,虽然ssh-add
从脚本传递密码短语似乎是一个简单的主意,但是echo "passphrase\n" | ssh-add
它看起来ssh-add
不像从不读取密码短语那样直接stdin
,而是/dev/tty
直接打开以供阅读。
这可以被合作周围有expect
,用于自动化交互式应用程序的工具。以下是一个脚本示例,该脚本使用存储在脚本中的密码添加了ssh-key:
#!/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更好。如果要使用此方法,则重要的是要确保expect
包含密码短语的脚本具有适当的权限设置,以使其仅由密钥所有者可读,可写和可运行。
ssh-agent
代码段中的~/.bash_profile
行为,如答案中所述。您可能想看看该keychain
实用程序。有了keychain
你需要重启后第一次登录时输入密码,但后续登录keychain
将连接到现有的ssh-agent
实例与在内存中解密的密钥。除此之外,还可以选择不使用密码生成ssh密钥,但是当然不建议这样做。
ssh-add
从脚本传递到。原因echo "pass\n" | ssh-add
不起作用,ssh-add
是不从读取密码stdin
,而是/dev/tty
直接打开以进行读取。使用名为的实用程序更新了答案,以包括针对此问题的解决方法expect
。
gssapi-with-mic
。通常在较大的网络中使用此方法,但是当然,如果您对此感兴趣,可能值得研究。
将此添加到您的中~/.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-add -l
当代理具有身份时返回退出代码0,否则返回1,因此您可以从最后一个命令中删除grep并使用ssh-add -l > '/dev/null' || ssh-add
与OP的问题没有密切关系,但对其他人可能有用:由于7.2.0 ssh(1)具有一个选项,允许在首次认证时向ssh-agent添加密钥;该选项AddKeysToAgent
,可以设置为yes
,no
,ask
,或confirm
,全系统或您的个人.ssh/config
文件。
.ssh/config
文件的新手:这适用于文件ssh
及其ssh
背后使用的任何东西,例如scp
,并且可以在每个主机的基础上完成。
ssh-agent
缓存各种未锁定的ssh密钥,因此您可以使ssh密钥受密码保护,而不必每次都键入它们。
为了缓存解锁的密钥,显然需要解锁那些密钥。要解锁用密码锁锁定的钥匙,显然需要知道这些密码。
任何不需要人类授权的方法(例如“键入密码”)都将使您的系统不安全;它也会使ssh-agent的整个目的变得毫无意义。
综上所述,您可以简单地使用不受密码保护的ssh-key(Enter在生成密钥时要求输入密码时会命中)。由于没有任何密码,ssh-agent
因此不需要(而不是)缓存密码。
这是一种自动化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
。
echo my_passphrase
是一个很大的安全漏洞。首先,键入密码后,密码将以明文形式显示在所用外壳程序的历史记录文件中。第二个命令行参数在Unix(ps -ef
)上是世界可读的。切勿在命令行参数中输入密码!
ps
输出密码可见问题。无论如何,历史记录文件通常通常只能由拥有用户读取,但是系统上的所有用户都可以读取命令行。
我不建议您在登录时使用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 &
(取决于操作系统)的命令来分叉更多共享相同解锁密钥的终端。/path/to/yourterminal &
==>mintty &
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
我曾经使用过Steampowered提到的脚本,现在我做了下面的脚本,因为它不会留下文件。
zsh
仅在外壳上工作。
#!/bin/sh
AGENT_BIN=`which ssh-agent`
AGENT_ADD_BIN=`which ssh-add`
AGENT_PID=`ps -fe | grep ${AGENT_BIN} | awk -vuser=$USER -vcmd="$AGENT_BIN" '$1==user && $8==cmd{print $2;exit;}'`
if [ -z "$AGENT_BIN" ]; then
echo "no ssh agent found!";
return
fi
if [ "" -eq "$AGENT_PID" ]; then
if read -sq "YN?Do you want to unlock your ssh keys?"; then
echo ""
output=`$AGENT_BIN | sed 's/echo/#echo/g'`
eval $output
$AGENT_ADD_BIN
fi
else
for f in "/proc/"*
do
cmdline=`cat "$f/cmdline"`
if [ "${AGENT_BIN}" -ef "${cmdline}" ]; then
export SSH_AUTH_SOCK=`cat $f/net/unix | grep --binary-file=text -oP '((/[^/]*?)+/ssh-[^/]+/agent\.\d+$)'`
export SSH_AGENT_PID=${f##*/}
break;
fi
done
fi
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
为了添加(可能没有密码)密钥,并确保ssh-add
即使在X下运行,也无论如何都不会提示输入密码:
DISPLAY= ssh-add -k /path/to/key </dev/null &>/dev/null
退出状态指示成功或失败。
如果您将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发生错误。
这是权威脚本。
更新$ 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
我知道的最好方法是使用从以前的工作改编的PAM登录脚本,因为在这个问题上找不到满意的答案。
您的密码短语将使用系统密码和强大的派生功能进行加密存储。登录时,系统密码用于解密密码并将其添加到代理。
https://github.com/capocasa/systemd-user-pam-ssh
与提出的所有其他解决方案相比,优点是它结合了等效于安全性的安全性,相当于在引导时以零努力手动运行ssh-add。它不需要任何额外的工具,并且具有一个默认情况下已在大多数系统(OpenSSL)上安装的额外依赖项。
我在macOS上的设置如下(在.zshrc
或.bash_profile
bash人群中):
# 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_logout
针对bash人士):
if [ -n "$SSH_AUTH_SOCK" ] ; then
eval `/usr/bin/ssh-agent -k`
fi
在macOS Mojave 10.14.5上测试