If you work a lot on linux and use
ssh often, you quickly
realize that typing your password every time you connect to a remote
host gets annoying.
Not only that, it is not the best solution in terms of security either:
- Every time you type a password, a snooper has an extra chance to see it.
- Every host you ssh to with which you use your password, well, has to know
your password. Or a hash of your password. In any case, you probably have typed
your password on that host once or twice in your life
(even if just for passwd, for example).
- If you are victim of a Man In The Middle attack, your password may get
stolen. Sure, you can verify the fingerprint of every host you connect to,
and disable authentication without challenge and response in your ssh config.
But what if there was a way you didn’t have to do that?
This is where key authentication comes into play: instead of using a password
to log in a remote host, you can use a pair of keys, and well,
Using ssh keys
All you have to do is:
generate a pair of keys with
ssh-keygen. This will create two files:
a public key (normally .pub), and a private key.
The private key is normally kept encrypted on disk. After all, it’s well,
supposed to be private.
ssh-keygenwill ask you to insert a password. Note
that this password will be used to
decryptthis file from your local
disk, and never sent to anyone.
And again, as the name suggest, you should never ever disclose your
copy your public key into any system you need to have access to.
You can use
scp, type it manually, or well, use the tool
provided with openssh:
Note that you could even publish your public key online: there is no
(known) way to go from a public key to your private key and to get access
to any of your systems. And if there was a way, well, public key encryption
would be dead, and your bank account likely empty.
and … done! That’s it, really, just try it out:
# Generate and encrypt the key first. $ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/test/.ssh/id_rsa): Created directory '/home/test/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/test/.ssh/id_rsa. Your public key has been saved in /home/test/.ssh/id_rsa.pub. The key fingerprint is: ec:38:bc:94:35:34:55:2b:9a:8d:44:d8:f0:93:09:fb test@joshua The key's randomart image is: +--[ RSA 2048]----+ | o+. ... | | .=.+ . | | . O . . | | = B . | | E . | | . = . | | * . | | . o | | . | +-----------------+ # Copy the public key to my remote server, conveniently called # 'name-of-remote-server'. Note that it will ask you the password # of the remote server. $ ssh-copy-id name-of-remote-server The authenticity of host 'name-of-remote-server (184.108.40.206)' can't be established. ECDSA key fingerprint is 9f:1e:ab:b6:ff:71:88:a9:98:7a:8d:f1:42:7d:8c:20. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys Password: ... # Try now to login into the remote server. SSH will now ask you # for your passphrase, what you used to encrypt your private key on # disk, what you gave to ssh-keygen above. $ ssh name-of-remote-server ... # Let's say you have multiple keys, or you decided to store your key # in a non standard place, and want to provide a specific one for a given # host, you can use the -i option. $ ssh -i /home/test/.ssh/id_rsa name-of-remote-server
So… what are the advantages of using keys? There are many:
- Your passphrase never leaves your local machine. Which generally makes it harder to steal.
- You don’t have a password to remember for each different host. Or…
- … you don’t have the same password for all hosts you connect to
(depending on your password management philosophies).
- If somebody steals your passphrase, there’s not much he can do without
your private key.
- If you fear somebody has seen your passphrase, you can change it easily.
Once. And for all.
- If there is a “man in the middle”, he may be able to hijack your session.
Once (and well, feast on your machine, but that’s another story).
If a “man in the middle” got hold of your password instead, he could
enjoy your machine later, more stealthy, for longer, and may be able
to use your password on other machines.
- They just work. Transparently, most of the times. With
scp, and all their friends.
- You can use an agent to make your life happier and easier.
And if you’re wondering what an agent is, you can go to the next section.
Your agent friend
Ok. So you have read this much of the article, and still we have not solved the
problem of having to type your password every freaking time, have we?
That’s where an agent comes in handy. Think of it as a safe box you have to
start in the background that holds your keys, ready to be used.
You start an
ssh-agent by running something like:
$ eval `ssh-agent`
in your shell. You can then feed it keys, with
$ ssh-add /home/test/.ssh/id_rsa
or, if your key is in the default location, you can just:
ssh-add will ask your passphrase, and store your private key into the
ssh-agent you started earlier.
ssh, and all its friends (including
scp…) will just magically use your agent friend when you try to
ssh somewhere. Convenient, isn’t it?
Assuming you added all the keys you need, you can now
ssh to any host,
as many times as you like, without ever ever having to retype your password.
Not only that, but you can exploit
agent forwarding to jump from one host
to another seamlessly.
Let me give you an example:
- Let’s say you have to connect to a server at your office.
- Let’s say this server is firewalled. In order to
sshthere, you first
gateway. Sounds familiar, doesn’t it?
This means you end up doing:
$ ssh username@my-company-gateway ... Welcome to your company gateway! ... $ ssh username@fancy-server-I-wanted-to-connect-to-to-start-with Password: ...
On this second ssh, what happens? Well, if you type your password, your
cleartext password is visible to the gateway. Yes, it is sent encrypted,
decrypted, and then through the console driver fed to the
If a keylogger was running, your password would be lost.
Worst: we are back to our original problem, we have to type our password
We could, of course, store our private key on the company gateway and run
an agent there. But that would not be a good idea, would it? Remember:
your private key never leaves your private computer, you don’t want
to store it on a remote server.
So, here’s a fancy feature of
ssh-agent: agent forwarding.
On many linux systems, it is enabled by default: but if you pass
ssh command (or the second, or the third, …),
ensure that your agent running on your local machine is usable from the
remote machine as well.
$ ssh -A username@my-company-gateway ... Welcome to your company gateway! ... $ ssh username@fancy-server-I-wanted-to-connect-to-to-start-with ... no password asked! your key is transparently used! ...
ssh here, run from the company gateway, will not ask you
for a password. Instead, it will detect the presence of a remote agent,
and use your private key instead, and ask for no password.
Sounds dangerous? Well, there are some risks associated with it, which
we’ll discuss in another article. But here is the beauty of the agent:
Your private key never leaves your local computer. That’s right.
By design, the agent never ever discloses your private key, it
never ever hands it over to a remote ssh or similar. Instead,
ssh is designed such as when an agent is detected, the information
that needs to be encrypted or verified through the agent is forwarded
to the agent. That’s why it is called
agent forwarding, and
that’s why it is considered a safer option.
Configuring all of this on your machine
So, let’s summarize the steps:
- Generate a set of keys, with
- Install your keys on remote servers, with
- Start an
ssh-agentto use on your machine, with
ssh-addyour key, type your password once.
- Profit! You can now ssh to any host that has your public key
without having to enter a password, and use
forward your agent.
Easy, isn’t it? Where people generally have problems is on how and
where to start the
ssh-agent, and when and how to start
The long running advice has been to start
ssh-agent from your .bashrc,
In today’s world, most distributions (including Debian and derivatives),
just start an
ssh-agent when you first login. So, you really don’t have
anything to do, except run
ssh-add when you need your keys loaded,
and be done with it.
Still many people have snippets to the extent of:
if [ -z "$SSH_AUTH_SOCK" ] ; then eval `ssh-agent` ssh-add fi
.bashrc, which basically says “is there an ssh-agent already running? no? start one, and add my keys”.
This is still very annoying: for each console or each session you login into, you
end up with a new
ssh-agent. Worse: this agent will run forever with your private
keys loaded! Even long after you logged out. Nothing and nobody will ever kill your agent.
So, your three lines of
.bashrc snippet soon becomes 10 lines (to cache agents on disk),
then it breaks the first time you use NFS or any other technology to share your home
directory, and then… more lines to load only some keys, some magic in
kill your agent, and your 4 lines of simple
.bashrc get out of control
I promised myself to talk about the pitfalls of using an agent and common approaches
to solving the most common problems in a dedicated article. My suggestion for now?
ssh-agenttied with your session, and managed by your distro, when
one is available (just try
ssh-addand see if it works!).
ssh-agent, so your private key is kept in the
agent for a limited amount of time. One hour? 5 miutes? you pick. But
at the end of that time, your key is gone.
Use something like ssh-ident, to automatically maintain one or more agents,
and load ssh keys on demand,
so you don’t even have to worry about
For full disclosure, I wrote
ssh-ident. Surprisingly, that still doesn’t prevent
me from liking it.