可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a site as a remote Git repo pulling from Bitbucket.com using an SSH alias. I can manually start the ssh-agent on my server but I have to do this every time I login via SSH.
I manually start the ssh-agent:
eval ssh-agent $SHELL
Then I add the agent:
ssh-add ~/.ssh/bitbucket_id
Then it shows up when I do:
ssh-add -l
And I'm good to go. Is there any way to automate this process so I don't have to do it every time I login? The server is running RedHat 6.2 (Santiago).
回答1:
Please go through this article. You may find this very useful:
http://mah.everybody.org/docs/ssh
Just in case the above link vanishes some day, I am capturing the main piece of the solution below:
This solution from Joseph M. Reagle by way of Daniel Starin:
Add this following to your .bash_profile
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
This version is especially nice since it will see if you've already started ssh-agent and, if it can't find it, will start it up and store the settings so that they'll be usable the next time you start up a shell.
回答2:
On Arch Linux, the following works really great (should work on all systemd-based distros):
Create a systemd user service, by putting the following to ~/.config/systemd/user/ssh-agent.service
:
[Unit]
Description=SSH key agent
[Service]
Type=forking
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStart=/usr/bin/ssh-agent -a $SSH_AUTH_SOCK
[Install]
WantedBy=default.target
Setup shell to have an environment variable for the socket (.bash_profile, .zshrc, ...
):
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
Enable the service, so it'll be started automatically on login, and start it:
systemctl --user enable ssh-agent
systemctl --user start ssh-agent
Add the following configuration setting to your ssh config file ~/.ssh/config
(this works since SSH 7.2):
AddKeysToAgent yes
This will instruct the ssh client to always add the key to a running agent, so there's no need to ssh-add it beforehand.
回答3:
Old question, but I did come across a similar situation. Don't think the above answer fully achieves what is needed. The missing piece is keychain
; install it if it isn't already.
sudo apt-get install keychain
Then add the following line to your ~/.bashrc
eval $(keychain --eval id_rsa)
This will start the ssh-agent
if it isn't running, connect to it if it is, load the ssh-agent
environment variables into your shell, and load your ssh key.
Change id_rsa
to whichever private key in ~/.ssh
you want to load.
Reference
https://unix.stackexchange.com/questions/90853/how-can-i-run-ssh-add-automatically-without-password-prompt
回答4:
The accepted solution have following drawbacks:
- it is complicated to maintain;
- it evaluates storage file which may lead to errors or security breach;
- it starts agent but doesn't stop it which is close equivalent to leaving the key in ignition.
If your keys do not require to type password, I suggest following solution. Add the following to your .bash_profile
very end (edit key list to your needs):
exec ssh-agent $BASH -s 10<&0 << EOF
ssh-add ~/.ssh/your_key1.rsa \
~/.ssh/your_key2.rsa &> /dev/null
exec $BASH <&10-
EOF
It have following advantages:
- much simpler solution;
- agent session ends when bash session ends.
It have possible disadvantages:
- interactive
ssh-add
command will influence only one session, which is in fact an issue only in very untypical circumstances;
- unusable if typing password is required;
- started shell becomes non-login (which doesn't influence anything AFAIK).
Note that several ssh-agent
processes is not a disadvantage, because they don't take more memory or CPU time.
回答5:
Add this to your ~/.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 | grep "The agent has no identities" && ssh-add
This should only prompt for a password the first time you login after each reboot. It will keep reusing the ssh-agent
as long as it stays running.
回答6:
So I used to use the approaches described above, but I kind of prefer the agent to die when my last bash session ends. This is a bit longer than the other solutions, but its my preferred approach. The basic idea is that the first bash session starts the ssh-agent. Then each additional bash session checks for the config file (~/.ssh/.agent_env
). If that is there and there is a session running then source the environment and create a hardlink to the socket file in /tmp
(needs to be on the same filesystem as the original socket file). As bash sessions shut down each deletes its own hardlink. The last session to close will find that the hardlinks have 2 links (the hardlink and the original), removal of the processes own socket and killing of the process will result in 0, leaving a clean environment after the last bash session closes.
# 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
回答7:
Just to add yet another solution :P, I went with a combination of @spheenik and @collin-anderson 's solutions.
# 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
Could be a little more elegant but its simple and readable. This solution:
- ensures
AddKeysToAgent yes
is in your ssh config so keys will be automatically added upon use
- doesn't prompt you to enter any passphrases at login (again, one-time passphrase entering occurs on first use)
- silently starts an ssh-agent if it has not already started one
Comments welcome :)
回答8:
Sorry for being so late:
Users of the fish shell can use this script to do the same thing.
# 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
回答9:
I solved it by adding this to the /etc/profile - system wide (or to user local .profile, or .bash_profile).
# SSH-AGENT
#!/usr/bin/env bash
SERVICE='ssh-agent'
WHOAMI=`who am i |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
This starts a new ssh-agent if not running for user, or re-sets the ssh-agent env parameter if running.
回答10:
Like your answers a lot. It made working from cygwin / linux
hosts a lot easier. I combined start and end functions to make it secure.
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
thanks again