354

我有一个站点作为远程 Git 存储库,使用 SSH 别名从 Bitbucket.com 拉取。我可以在我的服务器上手动启动 ssh-agent,但每次通过 SSH 登录时都必须这样做。

我手动启动 ssh-agent:

eval ssh-agent $SHELL

然后我添加代理:

ssh-add ~/.ssh/bitbucket_id

然后当我这样做时它会出现:

ssh-add -l

我可以走了。有没有办法自动化这个过程,所以我每次登录时都不必这样做?服务器正在运行 RedHat 6.2 (Santiago)。

4

12 回答 12

453

请通过这篇文章。您可能会发现这非常有用:

https://web.archive.org/web/20210506080335/https://mah.everybody.org/docs/ssh

以防万一上述链接有一天消失,我将捕获以下解决方案的主要部分:

这个解决方案来自 Joseph M. Reagle,由 Daniel Starin 提供:

将以下内容添加到您的.bash_profile

SSH_ENV="$HOME/.ssh/agent-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

这个版本特别好,因为它会查看你是否已经启动了 ssh-agent,如果找不到它,它会启动它并存储设置,以便下次启动时可以使用它们壳。

于 2013-09-20T10:57:20.927 回答
158

在 Arch Linux 上,以下工作非常好(应该适用于所有基于 systemd 的发行版):

通过将以下内容放入以下内容来创建 systemd 用户服务~/.config/systemd/user/ssh-agent.service

[Unit]
Description=SSH key agent

[Service]
Type=simple
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK

[Install]
WantedBy=default.target

将 shell 设置为具有套接字 ( .bash_profile, .zshrc, ...) 的环境变量:

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"

启用该服务,它会在登录时自动启动,然后启动它:

systemctl --user enable ssh-agent
systemctl --user start ssh-agent

将以下配置设置添加到本地 ssh 配置文件~/.ssh/config(从 SSH 7.2 开始有效):

AddKeysToAgent  yes

这将指示 ssh 客户端始终将密钥添加到正在运行的代理,因此无需事先 ssh-add。

于 2016-08-16T17:25:29.790 回答
126

老问题,但我确实遇到过类似的情况。不要认为上面的答案完全达到了所需要的。缺少的部分是keychain;如果还没有安装它。

sudo apt-get install keychain

然后将以下行添加到您的~/.bashrc

eval $(keychain --eval id_rsa)

如果它没有运行,这将启动,ssh-agent如果它运行,则连接到它,将ssh-agent环境变量加载到您的 shell 中,然后加载您的 ssh 密钥。

更改为您要加载id_rsa的任何私钥。~/.ssh

钥匙串的一些有用选项:

  • -q静音模式
  • --noask不要在启动时询问密码,而是在实际使用 ssh 密钥时按需询问。

参考

https://unix.stackexchange.com/questions/90853/how-can-i-run-ssh-add-automatically-without-password-prompt

于 2014-07-23T04:46:55.837 回答
39

公认的解决方案有以下缺点:

  • 维护复杂;
  • 它评估可能导致错误或安全漏洞的存储文件;
  • 它启动代理但不停止它,这几乎相当于将钥匙留在点火状态。

如果您的密钥不需要输入密码,我建议以下解决方案。将以下内容添加到您的.bash_profile 最后(根据您的需要编辑密钥列表):

exec ssh-agent $BASH -s 10<&0 << EOF
    ssh-add ~/.ssh/your_key1.rsa \
            ~/.ssh/your_key2.rsa &> /dev/null
    exec $BASH <&10-
EOF

它具有以下优点:

  • 更简单的解决方案;
  • 代理会话在 bash 会话结束时结束。

它有可能的缺点:

  • 交互的ssh-add命令只会影响一个会话,这实际上只是在非常不典型的情况下才会出现的问题;
  • 如果需要输入密码则无法使用;
  • 启动的 shell 变为非登录(这不会影响任何 AFAIK)。

请注意,多个ssh-agent进程并不是缺点,因为它们不会占用更多内存或 CPU 时间。

于 2015-04-08T16:44:17.943 回答
39

将此添加到您的~/.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只要它保持运行,它将继续重复使用相同的内容。

于 2016-07-27T17:28:10.720 回答
8

所以我曾经使用上述方法,但我更喜欢代理在我最后一次 bash 会话结束时死掉。这比其他解决方案要长一点,但它是我的首选方法。基本思想是第一个 bash 会话启动 ssh-agent。然后每个额外的 bash 会话都会检查配置文件 ( ~/.ssh/.agent_env)。如果存在并且有一个会话正在运行,则获取环境并创建一个到其中的套接字文件的硬链接/tmp(需要与原始套接字文件位于同一文件系统上)。当 bash 会话关闭时,每个会话都会删除自己的硬链接。上次关闭的会话会发现硬链接有 2 个链接(硬链接和原始),移除进程自己的套接字并杀死进程将导致 0,在最后一个 bash 会话关闭后留下一个干净的环境。

# Start ssh-agent to keep you logged in with keys, use `ssh-add` to log in
agent=`pgrep ssh-agent -u $USER` # get only your agents           
if [[ "$agent" == "" || ! -e ~/.ssh/.agent_env ]]; then
    # if no agents or environment file is missing create a new one
    # remove old agents / environment variable files
    kill $agent running
    rm ~/.ssh/.agent_env 

    # restart
    eval `ssh-agent` 
    echo 'export SSH_AUTH_SOCK'=$SSH_AUTH_SOCK >> ~/.ssh/.agent_env             
    echo 'export SSH_AGENT_PID'=$SSH_AGENT_PID >> ~/.ssh/.agent_env             
fi

# create our own hardlink to the socket (with random name)           
source ~/.ssh/.agent_env                                                    
MYSOCK=/tmp/ssh_agent.${RANDOM}.sock                                        
ln -T $SSH_AUTH_SOCK $MYSOCK                                                
export SSH_AUTH_SOCK=$MYSOCK                                                

end_agent()                                                                     
{
    # if we are the last holder of a hardlink, then kill the agent
    nhard=`ls -l $SSH_AUTH_SOCK | awk '{print $2}'`                             
    if [[ "$nhard" -eq 2 ]]; then                                               
        rm ~/.ssh/.agent_env                                                    
        ssh-agent -k                                                            
    fi                                                                          
    rm $SSH_AUTH_SOCK                                                           
}                                                                               
trap end_agent EXIT                                                             
set +x              
于 2015-09-15T17:46:30.423 回答
8

从许多来源尝试了几种解决方案,但似乎都太麻烦了。最后我找到了最简单的一个:)

如果您还不熟悉zshoh-my-zsh,请安装它。你会喜欢的 :)

然后编辑.zshrc

vim ~/.zshrc

找到plugins部分并更新它以ssh-agent像这样使用:

plugins=(ssh-agent git)

就这样!ssh-agent每次启动 shell 时都会启动并运行

于 2019-10-30T21:37:42.700 回答
7

只是为了添加另一个解决方案:P,我结合了 @spheenik 和 @collin-anderson 的解决方案。

 # Ensure that we have an ssh config with AddKeysToAgent set to true
 if [ ! -f ~/.ssh/config ] || ! cat ~/.ssh/config | grep AddKeysToAgent | grep yes > /dev/null; then
     echo "AddKeysToAgent  yes" >> ~/.ssh/config
 fi
 # Ensure a ssh-agent is running so you only have to enter keys once
 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

可以更优雅一点,但它简单易读。这个解决方案:

  • 确保AddKeysToAgent yes在您的 ssh 配置中,因此密钥将在使用时自动添加
  • 不提示您在登录时输入任何密码(同样,一次性密码在第一次使用时输入)
  • 如果 ssh-agent 尚未启动,则静默启动它

欢迎评论:)

于 2017-10-12T22:06:21.230 回答
4

我通过将其添加到/etc/profile - 系统范围(或用户本地.profile.bash_profile)来解决它:

# SSH-AGENT 
#!/usr/bin/env bash
SERVICE='ssh-agent'
WHOAMI=`whoami |awk '{print $1}'`

if pgrep -u $WHOAMI $SERVICE >/dev/null
then
    echo $SERVICE running.
else
    echo $SERVICE not running.
    echo starting
    ssh-agent > ~/.ssh/agent_env
fi
. ~/.ssh/agent_env

如果当前用户没有运行,这将启动一个新的 ssh-agent,如果正在运行,则重新设置 ssh-agent env 参数。

于 2015-05-29T13:39:54.240 回答
4

fish shell的用户可以使用这个脚本来做同样的事情。

# content has to be in .config/fish/config.fish
# if it does not exist, create the file
setenv SSH_ENV $HOME/.ssh/environment

function start_agent                                                                                                                                                                    
    echo "Initializing new SSH agent ..."
    ssh-agent -c | sed 's/^echo/#echo/' > $SSH_ENV
    echo "succeeded"
    chmod 600 $SSH_ENV 
    . $SSH_ENV > /dev/null
    ssh-add
end

function test_identities                                                                                                                                                                
    ssh-add -l | grep "The agent has no identities" > /dev/null
    if [ $status -eq 0 ]
        ssh-add
        if [ $status -eq 2 ]
            start_agent
        end
    end
end

if [ -n "$SSH_AGENT_PID" ] 
    ps -ef | grep $SSH_AGENT_PID | grep ssh-agent > /dev/null
    if [ $status -eq 0 ]
        test_identities
    end  
else
    if [ -f $SSH_ENV ]
        . $SSH_ENV > /dev/null
    end  
    ps -ef | grep $SSH_AGENT_PID | grep -v grep | grep ssh-agent > /dev/null
    if [ $status -eq 0 ]
        test_identities
    else 
        start_agent
    end  
end
于 2015-09-07T11:54:42.307 回答
2

我非常喜欢你的回答。它使cygwin / linux主机工作变得更加容易。我结合了开始和结束功能以使其安全。

SSH_ENV="$HOME/.ssh/.agent_env"

function start_agent {
    echo "Initialising new SSH agent..."

    eval `/usr/bin/ssh-agent`
    echo 'export SSH_AUTH_SOCK'=$SSH_AUTH_SOCK >> ${SSH_ENV}
    echo 'export SSH_AGENT_PID'=$SSH_AGENT_PID >> ${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

# create our own hardlink to the socket (with random name)
MYSOCK=/tmp/ssh_agent.${RANDOM}.sock
ln -T $SSH_AUTH_SOCK $MYSOCK
export SSH_AUTH_SOCK=$MYSOCK

end_agent()
{
    # if we are the last holder of a hardlink, then kill the agent
    nhard=`ls -l $SSH_AUTH_SOCK | awk '{print $2}'`
    if [[ "$nhard" -eq 2 ]]; then
        rm ${SSH_ENV}
        /usr/bin/ssh-agent -k
    fi
    rm $SSH_AUTH_SOCK
}
trap end_agent EXIT
set +x
于 2015-12-17T10:53:14.663 回答
2

我为此使用了ssh-ident工具。

从它的手册页:

ssh-ident - 启动和使用 ssh-agent 并根据需要加载身份。

于 2019-10-31T08:12:22.593 回答