Skip to main content

Using an ssh-agent, or how to type your ssh password once, safely.

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, ssh-agent.

Using ssh keys

All you have to do is:
  1. 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-keygen will ask you to insert a password. Note that this password will be used to decrypt this file from your local disk, and never sent to anyone. And again, as the name suggest, you should never ever disclose your private key.
  2. copy your public key into any system you need to have access to. You can use rsync, scp, type it manually, or well, use the tool provided with openssh: ssh-copy-id. 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 (144.144.144.144)' 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:
  1. Your passphrase never leaves your local machine. Which generally makes it harder to steal.
  2. You don't have a password to remember for each different host. Or...
  3. ... you don't have the same password for all hosts you connect to (depending on your password management philosophies).
  4. If somebody steals your passphrase, there's not much he can do without your private key.
  5. If you fear somebody has seen your passphrase, you can change it easily. Once. And for all.
  6. 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.
  7. They just work. Transparently, most of the times. With git, rsync, scp, and all their friends.
  8. 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?
Agent Smith from the Matrix saying "No Agent? I'm your friend"
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 like:
$ ssh-add /home/test/.ssh/id_rsa
or, if your key is in the default location, you can just:
$ ssh-add
ssh-add will ask your passphrase, and store your private key into the ssh-agent you started earlier. ssh, and all its friends (including git, rsync, 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 ssh there, you first need to ssh into another 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 ssh process. If a keylogger was running, your password would be lost.
Worst: we are back to our original problem, we have to type our password multiple times!
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 and ssh-agent: agent forwarding.
On many linux systems, it is enabled by default: but if you pass -A to the first ssh command (or the second, or the third, ...), ssh will ensure that your agent running on your local machine is usable from the remote machine as well.
For example:
$ 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! ...
The second 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:
  1. Generate a set of keys, with ssh-keygen.
  2. Install your keys on remote servers, with ssh-copy-id.
  3. Start an ssh-agent to use on your machine, with eval ssh-agent.
  4. ssh-add your key, type your password once.
  5. Profit! You can now ssh to any host that has your public key without having to enter a password, and use ssh -A to 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 ssh-add.
The long running advice has been to start ssh-agent from your .bashrc, and run ssh-add similarly.
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
in their .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 .bash_logout to kill your agent, and your 4 lines of simple .bashrc get out of control

Conclusion

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?
  • Use the ssh-agent tied with your session, and managed by your distro, when one is available (just try ssh-add and see if it works!).
  • Use -t to ssh-add and 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 ssh-add.
For full disclosure, I wrote ssh-ident. Surprisingly, that still doesn't prevent me from liking it.

Comments

Popular posts from this blog

OWASP Top 10 Threats and Mitigations Exam - Single Select

Last updated 4 Aug 11 Course Title: OWASP Top 10 Threats and Mitigation Exam Questions - Single Select 1) Which of the following consequences is most likely to occur due to an injection attack? Spoofing Cross-site request forgery Denial of service   Correct Insecure direct object references 2) Your application is created using a language that does not support a clear distinction between code and data. Which vulnerability is most likely to occur in your application? Injection   Correct Insecure direct object references Failure to restrict URL access Insufficient transport layer protection 3) Which of the following scenarios is most likely to cause an injection attack? Unvalidated input is embedded in an instruction stream.   Correct Unvalidated input can be distinguished from valid instructions. A Web application does not validate a client’s access to a resource. A Web action performs an operation on behalf of the user without checking a shared sec

CKA Simulator Kubernetes 1.22

  https://killer.sh Pre Setup Once you've gained access to your terminal it might be wise to spend ~1 minute to setup your environment. You could set these: alias k = kubectl                         # will already be pre-configured export do = "--dry-run=client -o yaml"     # k get pod x $do export now = "--force --grace-period 0"   # k delete pod x $now Vim To make vim use 2 spaces for a tab edit ~/.vimrc to contain: set tabstop=2 set expandtab set shiftwidth=2 More setup suggestions are in the tips section .     Question 1 | Contexts Task weight: 1%   You have access to multiple clusters from your main terminal through kubectl contexts. Write all those context names into /opt/course/1/contexts . Next write a command to display the current context into /opt/course/1/context_default_kubectl.sh , the command should use kubectl . Finally write a second command doing the same thing into /opt/course/1/context_default_no_kubectl.sh , but without the use of k

标 题: 关于Daniel Guo 律师

发信人: q123452017 (水天一色), 信区: I140 标  题: 关于Daniel Guo 律师 关键字: Daniel Guo 发信站: BBS 未名空间站 (Thu Apr 26 02:11:35 2018, 美东) 这些是lz根据亲身经历在 Immigration版上发的帖以及一些关于Daniel Guo 律师的回 帖,希望大家不要被一些马甲帖广告帖所骗,慎重考虑选择律师。 WG 和Guo两家律师对比 1. fully refund的合约上的区别 wegreened家是case不过只要第二次没有file就可以fully refund。郭家是要两次case 没过才给refund,而且只要第二次pl draft好律师就可以不退任何律师费。 2. 回信速度 wegreened家一般24小时内回信。郭律师是在可以快速回复的时候才回复很快,对于需 要时间回复或者是不愿意给出确切答复的时候就回复的比较慢。 比如:lz问过郭律师他们律所在nsc区域最近eb1a的通过率,大家也知道nsc现在杀手如 云,但是郭律师过了两天只回复说让秘书update最近的case然后去网页上查,但是上面 并没有写明tsc还是nsc。 lz还问过郭律师关于准备ps (他要求的文件)的一些问题,模版上有的东西不是很清 楚,但是他一般就是把模版上的东西再copy一遍发过来。 3. 材料区别 (推荐信) 因为我只收到郭律师写的推荐信,所以可以比下两家推荐信 wegreened家推荐信写的比较长,而且每封推荐信会用不同的语气和风格,会包含lz写 的research summary里面的某个方面 郭家四封推荐信都是一个格式,一种语气,连地址,信的称呼都是一样的,怎么看四封 推荐信都是同一个人写出来的。套路基本都是第一段目的,第二段介绍推荐人,第三段 某篇或几篇文章的abstract,最后结论 4. 前期材料准备 wegreened家要按照他们的模版准备一个十几页的research summary。 郭律师在签约之前说的是只需要准备五页左右的summary,但是在lz签完约收到推荐信 ,郭律师又发来一个很长的ps要lz自己填,而且和pl的格式基本差不多。 总结下来,申请自己上心最重要。但是如果选律师,lz更倾向于wegreened,