{"id":303,"date":"2009-04-09T23:19:34","date_gmt":"2009-04-09T21:19:34","guid":{"rendered":"http:\/\/glandium.org\/blog\/?p=303"},"modified":"2010-01-27T08:52:24","modified_gmt":"2010-01-27T07:52:24","slug":"ssh-through-jump-hosts","status":"publish","type":"post","link":"https:\/\/glandium.org\/blog\/?p=303","title":{"rendered":"SSH through jump hosts"},"content":{"rendered":"<p>I often need to connect to a server with ssh from another server because I don't have direct access. I even gave a small <a href=\"\/blog\/?p=223\">configuration example<\/a> to use such jump hosts using <code>ProxyCommand<\/code>s.<\/p>\n<p>A while ago, I got fed up to have to add new entries for each host I wanted to join with a jump server, especially when I only need these entries sporadicly, and decided to write a generic configuration. I ended up with this setup:<\/p>\n<blockquote><p><code>Host *%*<br \/>\nProxyCommand ssh $(echo %h | cut -d%% -f1) nc -w1 $(echo %h | cut -d%% -f2) %p<\/code><\/p><\/blockquote>\n<p>The trick here is that you can use subshell expansions in a <code>ProxyCommand<\/code>. So, when I <code>ssh<\/code> to \"host1%host2\", the first subshell expansion returns \"host1\" and the second \"host2\", this setup ends up being the equivalent of :<\/p>\n<blockquote><p><code>Host host1%host2<br \/>\nProxyCommand ssh host1 nc -w1 host2 %p<\/code><\/p><\/blockquote>\n<p>which is quite similar to the setup from my previous post.<\/p>\n<p>Later on, I came up with an even more powerful implementation:<\/p>\n<blockquote><p><code>Host *%*<br \/>\nProxyCommand ssh $(echo %h | awk -F%% '{OFS=\"%%\"; NF--; print $0}') nc $(echo %h | awk -F%% '{print $NF}') %p<\/code><\/p><\/blockquote>\n<p>Here, the first <code>awk<\/code> splits at the % characters and returns all fields except the last one, and the second <code>awk<\/code> returns only the last field. As a consequence, <code>ssh<\/code>ing to \"host1%host2%host3%host4\" will have the first subshell expansion return \"host1%host2%host3\" and the second \"host4\". The setup will then be equivalent to:<\/p>\n<blockquote><p><code>Host host1%host2%host3%host4<br \/>\nProxyCommand ssh host1%host2%host3 nc -w1 host4 %p<\/code><\/p><\/blockquote>\n<p>The ssh in the ProxyCommand will, in turn, trigger the rule again so that the result is that host4 will be contacted from host3, which is contacted from host2 that we contacted from host1.<\/p>\n<p>In the meanwhile, I decided % was not that nice a separator, and switched to using \/, which also allows for a nicer setup with the same recursive effect:<\/p>\n<blockquote><p><code>Host *\/*<br \/>\nProxyCommand ssh $(dirname %h) nc -w1 $(basename %h) %p<\/code><\/p><\/blockquote>\n<p>Finally, since some remote hosts don't have <code>nc<\/code> installed, I usually copy it in my <code>$HOME<\/code> on these servers and changed my setup to:<\/p>\n<blockquote><p><code>Host *\/*<br \/>\nProxyCommand ssh $(dirname %h) PATH=.:\\$PATH nc -w1 $(basename %h) %p<\/code><\/p><\/blockquote>\n<p>The main drawback of this method is that the more jump hosts you use, the more your ssh traffic is encapsulated (recursively) in other ssh traffic. The advantage, though, is that you don't need to forward an agent onto untrusted servers to use ssh key authentication on any of the jump or final servers, nor to forward X11 or tunnel multiple times.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I often need to connect to a server with ssh from another server because I don&#8217;t have direct access. I even gave a small configuration example to use such jump hosts using ProxyCommands. A while ago, I got fed up to have to add new entries for each host I wanted to join with a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[23],"class_list":["post-303","post","type-post","status-publish","format-standard","hentry","category-pdo","tag-en"],"_links":{"self":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=303"}],"version-history":[{"count":7,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/303\/revisions"}],"predecessor-version":[{"id":646,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/303\/revisions\/646"}],"wp:attachment":[{"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/glandium.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}