<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Xavier</title>
    <description>The latest articles on DEV Community by Xavier (@tw3n).</description>
    <link>https://dev.to/tw3n</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F6272%2Fe5e6443b-218e-443f-a46a-649032aaeb25.png</url>
      <title>DEV Community: Xavier</title>
      <link>https://dev.to/tw3n</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tw3n"/>
    <language>en</language>
    <item>
      <title>Using YubiKey resident keys for Git and SSH on macOS</title>
      <dc:creator>Xavier</dc:creator>
      <pubDate>Wed, 19 Oct 2022 16:07:01 +0000</pubDate>
      <link>https://dev.to/tw3n/using-yubikey-resident-keys-for-git-and-ssh-on-macos-48j7</link>
      <guid>https://dev.to/tw3n/using-yubikey-resident-keys-for-git-and-ssh-on-macos-48j7</guid>
      <description>&lt;p&gt;I wanted to improve the security of my SSH keys, which are currently only protected by a passphrase. Likewise, I also wanted to ease their migration when I configure a new machine. I used resident keys and a YubiKey to do both.&lt;/p&gt;

&lt;p&gt;Resident keys or discoverable credentials mean that the private key is stored in persistent memory on a FIDO authenticator like a YubiKey. This has two advantages. First, if the authenticator is not connected to the computer, the key cannot be used. Second, if you carry your authenticator with you, you can import the key on any machine that has a compatible version of OpenSSH (8.2 or above).&lt;/p&gt;

&lt;p&gt;Yet, setting this up is more complex than it should be, at least on macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a resident key pair
&lt;/h2&gt;

&lt;p&gt;The OpenSSH bundled with macOS can not generate resident keys, despite being compatible with them. This is due to a compilation flag that disables this option (&lt;code&gt;--disable-security-key&lt;/code&gt;). To work around this, we'll install the latest version of OpenSSH using homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;openssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generating a resident key pair is quite similar to how you're used to generate and use SSH keys. The main difference is that the keys will be stored on the YubiKey (resident). Note that a YubiKey 5 can store up to &lt;strong&gt;25 resident keys&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To store a resident key, the Yubikey must have firmware 5.2.3 or above and a PIN configured.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a terminal window, type the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519-sk &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ssh:personal &lt;span class="nt"&gt;-O&lt;/span&gt; no-touch-required &lt;span class="nt"&gt;-O&lt;/span&gt; resident
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's dive into the different parameters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-t ed25519-sk&lt;/code&gt; is the key type, two options are possible &lt;code&gt;ecdsa-sk&lt;/code&gt; and &lt;code&gt;ed25519-sk&lt;/code&gt; (&lt;code&gt;sk&lt;/code&gt; stands for security key). If you do not know which one to choose, stick with &lt;code&gt;ed25519-sk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-O application=ssh:*&lt;/code&gt; names the key, so you can identify it more easily later, very handy if you generate a few
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3qumra1wamrxh7c9a3g.png" alt="Image description" width="382" height="521"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-O no-touch-required&lt;/code&gt; prevents you from having to touch the YubiKey every time you want to use the key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-O resident&lt;/code&gt; tells OpenSSH to store the key on the YubiKey&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like you would expect, &lt;code&gt;ssh-keygen&lt;/code&gt; created two files on your local machine:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcluoqi8adsuxrmputkfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcluoqi8adsuxrmputkfr.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id_ed25519_sk&lt;/code&gt; is the private key. But, it's a &lt;strong&gt;key handle&lt;/strong&gt; that can only be used with the YubiKey, making it unusable without it. The "real" private key is stored on the YubiKey. Meaning that you'll need to have the YubiKey plugged into your computer to be able to use it. The YubiKey, in this case, acts as a second authentication factor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id_ed25519_sk.pub&lt;/code&gt; is the public key&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Adding your SSH key to the ssh-agent
&lt;/h3&gt;

&lt;p&gt;Even though we've installed the latest version of OpenSSH, the default &lt;code&gt;ssh-agent&lt;/code&gt; bundled with macOS is still running. This agent is not capable of loading resident keys. To tackle this issue, we'll install &lt;a href="https://www.funtoo.org/Funtoo:Keychain" rel="noopener noreferrer"&gt;Funtoo Keychain&lt;/a&gt; to run and manage our own agent from the version of OpenSSH we just installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;keychain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now need to &lt;strong&gt;eval&lt;/strong&gt; Keychain before you can load a resident key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In bash&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;keychain &lt;span class="nt"&gt;--eval&lt;/span&gt; &lt;span class="nt"&gt;--noinherit&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# In fish&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keychain &lt;span class="nt"&gt;--eval&lt;/span&gt; &lt;span class="nt"&gt;--noinherit&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; | psub&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Importing your SSH key on another machine
&lt;/h2&gt;

&lt;p&gt;One of the biggest advantages of resident keys is that they can be imported from a YubiKey. This allows you to securely transfer them from one computer to another. To do this, we have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;ssh-add -K&lt;/code&gt; to load all resident keys from a YubiKey into your &lt;code&gt;ssh-agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;ssh-keygen -K&lt;/code&gt; to download all resident keys from a YubiKey and write them to your current directory. In this scenario, &lt;code&gt;ssh-agent&lt;/code&gt; will be able to load the keys from your disk which is more suitable for permanent use.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshh81bhl9s23izhf7vdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshh81bhl9s23izhf7vdz.png" alt="Image description" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the downloaded key has an &lt;code&gt;_rk_personal&lt;/code&gt; suffix. The &lt;code&gt;rk&lt;/code&gt; part is there to remind you that it's a resident key, and &lt;code&gt;personal&lt;/code&gt; is its name.&lt;/p&gt;

&lt;p&gt;By default, OpenSSH will look for these paths to automatically load private keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/id_dsa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/id_ecdsa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/id_ecdsa_sk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/id_ed25519&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/id_ed25519_sk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/id_rsa&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, &lt;code&gt;_rk_personal&lt;/code&gt; must be removed from the filename for the key to be automatically loaded. If you want to keep this suffix, specify its path in your &lt;code&gt;~/.ssh/config&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Due to the current implementation of resident keys in OpenSSH, the &lt;code&gt;no-touch-required&lt;/code&gt; flag is not restored when importing keys from a YubiKey. This flag will only be available with the &lt;strong&gt;original&lt;/strong&gt; private &lt;strong&gt;key handle&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Git
&lt;/h3&gt;

&lt;p&gt;Like normal ssh keys, resident keys are usable for git operations. Add the public key to your profile of your favorite git service and you're good to go.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At the time of writing, Gitea, GitHub and GitLab do not support &lt;code&gt;no-touch-required&lt;/code&gt;. You'll have to touch the YubiKey for each git operation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  SSH
&lt;/h3&gt;

&lt;p&gt;Using a resident key for SSH is the same as using a regular key. Add the public key to your &lt;code&gt;authorized_keys&lt;/code&gt; and you’re good to go. If the resident key was generated with &lt;code&gt;no-touch-required&lt;/code&gt;, prepend this option to the public key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.ssh/authorized_keys

# Without `no-touch-required` option
sk-ssh-ed25519@openssh.com ...

# With `no-touch-required` option
no-touch-required sk-ssh-ed25519@openssh.com ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/apple-oss-distributions/OpenSSH/pull/1" rel="noopener noreferrer"&gt;macOS: Enable security keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/go-gitea/gitea/issues/18416" rel="noopener noreferrer"&gt;Gitea: Support for &lt;code&gt;no-touch-required&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/community/community/discussions/10593" rel="noopener noreferrer"&gt;GitHub: Support for &lt;code&gt;no-touch-required&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/gitlab-org/gitlab/-/issues/213259" rel="noopener noreferrer"&gt;GitLab: Support for FIDO2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugzilla.mindrot.org/show_bug.cgi?id=3355" rel="noopener noreferrer"&gt;no-touch-required flag not restored from hardware token&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html" rel="noopener noreferrer"&gt;Securing SSH with FIDO2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>macos</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
