{"id":915,"date":"2023-08-21T18:30:34","date_gmt":"2023-08-22T01:30:34","guid":{"rendered":"https:\/\/porkrind.org\/missives\/?p=915"},"modified":"2023-08-21T18:30:34","modified_gmt":"2023-08-22T01:30:34","slug":"ssh_find","status":"publish","type":"post","link":"https:\/\/porkrind.org\/missives\/ssh_find\/","title":{"rendered":"ssh_find"},"content":{"rendered":"<p>I can&#8217;t remember who wrote this first, but my friend and I have been using some version of this shell snippet for years:<\/p>\n<pre><code class=\"language-sh\">ssh_find() {\n    for agent in \"$SSH_AUTH_SOCK\" \/tmp\/ssh-*\/agent.* \/tmp\/com.apple.launchd.*\/Listeners* \/tmp\/keyring-*\/ssh; do\n        SSH_AUTH_SOCK=\"$agent\" ssh-add -l 2&gt;\/dev\/null\n        case \"$?\" in # 0 some keys, 1 no keys, 2 no agent\n            0) export SSH_AUTH_SOCK=\"$agent\"; echo \"Found Keys.\" ; break ;;\n            1) export SSH_AUTH_SOCK=\"$agent\"; echo \"Found Agent.\";  ;; # Keep looking\n        esac\n    done\n}\n<\/code><\/pre>\n<p>This function looks through <code>\/tmp<\/code> for ssh-agent sockets (using various macOS, Linux, openssh naming schemes) and then finds the first one that (a) it has permissions for and (b) have keys unlocked in them (giving precedence to any currently active ones). If it can find some valid agents but none of them have keys then it will use the last one it found.<\/p>\n<p>Later in <code>.bashrc<\/code> I have a section for interactive shells and I call it from there:<\/p>\n<pre><code class=\"language-sh\">#\n# Interactive only stuff:\n#\nif [[ \"$-\" =~ i ]]; then\n    ...snipped...\n\n    # ssh related stuff\n    ssh_find\n\n    if [ x$SSH_AUTH_SOCK == x ]; then\n        exec ssh-agent bash\n    fi\n\n    ...snipped...\nfi\n<\/code><\/pre>\n<p>That looks for an agent and starts one up if there were none running<sup><a href=\"#footnote-1\">1<\/a><\/sup> <sup><a href=\"#footnote-2\">2<\/a><\/sup>.<\/p>\n<h2>How is this actually useful?<\/h2>\n<p>Basically it makes it so ever tab I open in my terminal (or in a tmux) latches on to an existing ssh-agent so that ssh just works from anywhere without ever thinking about it.<\/p>\n<p>It&#8217;s also useful for cron jobs. I have some cron jobs that look like this:<\/p>\n<pre><code>@hourly . $HOME\/.bashrc &amp;&amp; ssh_find &gt; \/dev\/null &amp;&amp; rsync -a something:\/something\/blah \/blah\/blah\n<\/code><\/pre>\n<p>I also have similar ones that do some git operation that needs an ssh key.<\/p>\n<p>It is generally convenient for things that need ssh keys to run, but where you don&#8217;t necessarily want the keys sitting around on the disk in unencrypted form. This lets them sit unencrypted in RAM, which is a little better (but at the expense of needing to ssh-add them manually every reboot).<\/p>\n<hr \/>\n<ol>\n<li><a name=\"footnote-1\"><\/a> This is kinda gross, since <code>exec<\/code> throws out the entire bash progress and starts things over but with a new running ssh-agent (more or less doubling the startup time). This only happens on interactive logins so it&#8217;s not as bad as you might expect. I do it this way instead of <code>eval $(ssh-agent)<\/code> so that if the agent was started by ssh-ing into the machine then it gets killed when the ssh process dies (ie, on logout).<\/li>\n<li><a name=\"footnote-2\"><\/a> This is also racy\u2014picture the case where a gui terminal program starts up and remembers that you had 7 tabs open, so it opens those 7 tabs and starts shells in them in parallel. On my Debian box I have a super complicated and impossible to read fix for this that involves the <code>flock(2)<\/code> command. I hate it and am embarrassed by the whole thing so fixing the race is left as an exercise to the reader. \ud83d\ude42<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>I can&#8217;t remember who wrote this first, but my friend and I have been using some version of this shell snippet for years: ssh_find() { for agent in &#8220;$SSH_AUTH_SOCK&#8221; \/tmp\/ssh-*\/agent.* \/tmp\/com.apple.launchd.*\/Listeners* \/tmp\/keyring-*\/ssh; do SSH_AUTH_SOCK=&#8221;$agent&#8221; ssh-add -l 2&gt;\/dev\/null case &#8220;$?&#8221; in # 0 some keys, 1 no keys, 2 no agent 0) export SSH_AUTH_SOCK=&#8221;$agent&#8221;; echo &#8220;Found &hellip; <a href=\"https:\/\/porkrind.org\/missives\/ssh_find\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">ssh_find<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-915","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/915","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/comments?post=915"}],"version-history":[{"count":8,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/915\/revisions"}],"predecessor-version":[{"id":923,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/posts\/915\/revisions\/923"}],"wp:attachment":[{"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/media?parent=915"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/categories?post=915"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/porkrind.org\/missives\/wp-json\/wp\/v2\/tags?post=915"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}