To start, i wanted to store my gnu keys on an secured external USB drive, such that i could lock the original keys in a safe, and they store the private key on an YubiKey 5Ci. First, i needed a USB drive, which i setup as an encrypted filesystem on my mac.

Of note, i'm borrowing a bit from "Dr. Duh" on github, and they have a great guide for the very paranoid  here: https://github.com/drduh/YubiKey-Guide , Additionally the Free Software founding has a great guide here, and they have a bot setup to help you test your setup!

Setup on your usb drive a folder for your GunPGP keys and configuration.

additionally I will setup my bash environment so that all of my configurations will end up on the usb drive and not on my system. Also I'm assuming you have made the folder on usb drive already

$ export GNUPGHOME=$(pwd)

Despite the fact I'm using an encrypted usb drive, we should also ensure the permissions on the folder do not allow anyone else to take a peek while it's mounted.

$ chmod og=,u=rwX $GNUPGHOME
$ chmod og=,u=rwX $GNUPGHOME/*

Setup your gpg.conf, (store this in the $GNUPGHOME folder)

# https://github.com/drduh/config/blob/master/gpg.conf
# https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html
# https://www.gnupg.org/documentation/manuals/gnupg/GPG-Esoteric-Options.html
# Use AES256, 192, or 128 as cipher
personal-cipher-preferences AES256 AES192 AES
# Use SHA512, 384, or 256 as digest
personal-digest-preferences SHA512 SHA384 SHA256
# Use ZLIB, BZIP2, ZIP, or no compression
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
# Default preferences for new keys
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
# SHA512 as digest to sign keys
cert-digest-algo SHA512
# SHA512 as digest for symmetric ops
s2k-digest-algo SHA512
# AES256 as cipher for symmetric ops
s2k-cipher-algo AES256
# UTF-8 support for compatibility
charset utf-8
# Show Unix timestamps
fixed-list-mode
# No comments in signature
no-comments
# No version in signature
no-emit-version
# Long hexidecimal key format
keyid-format 0xlong
# Display UID validity
list-options show-uid-validity
verify-options show-uid-validity
# Display all keys and their fingerprints
with-fingerprint
# Display key origins and updates
#with-key-origin
# Cross-certify subkeys are present and valid
require-cross-certification
# Disable caching of passphrase for symmetrical ops
no-symkey-cache
# Disable putting recipient key IDs into messages
throw-keyids
# Enable smartcard
use-agent
gpg.conf

Generate your Master Key

Be sure to use a strong password, and one you can store in a secure location, as this is NOT RECOVERABLE!

$ gpg --expert --full-generate-key
gpg (GnuPG) 2.2.16; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: keybox '/Volumes/Ogg_Rescue/gnupg/pubring.kbx' created
Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
Your selection? 8

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? E

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Dr. Ogg
Email address: ogg@sr375.com
Comment:
You selected this USER-ID:
    "Dr. Ogg <ogg@sr375.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /Volumes/Ogg_Rescue/gnupg/trustdb.gpg: trustdb created
gpg: key 0x585C80B653416059 marked as ultimately trusted
gpg: directory '/Volumes/Ogg_Rescue/gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/Volumes/Ogg_Rescue/gnupg/openpgp-revocs.d/9A53E6A0DC152759E944D557585C80B653416059.rev'
public and secret key created and signed.

pub   rsa4096/0x585C80B653416059 2019-11-16 [C]
      Key fingerprint = 9A53 E6A0 DC15 2759 E944  D557 585C 80B6 5341 6059
uid                              Dr. Ogg <ogg@sr375.com>

Export you're key id:

$ export KEYID=0x585C80B653416059

Sub Keys (yes, you need them)

Now that we have our master key setup, we can generate sub keys for the year, so we can rotate keys for better security..

I'm going to create 2 different types of keys, one i can use to sign with and one i can encrypt with.

Signing key

$ gpg --expert --edit-key $KEYID
gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Sun Nov 15 12:32:11 2020 PST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
[ultimate] (1). Dr. Ogg <ogg@sr375.com>
gpg> save

Encryption Key

$ gpg --expert --edit-key $KEYID
gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Sun Nov 15 12:33:22 2020 PST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb  rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>
gpg> save

Prepare your Yubikey for use

First we need to see if gpg can talk with your key...

$ gpg --card-status
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240103040006111562730000
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 11156273
Name of cardholder: Dr. Ogg
Language prefs ...: en

you should get something back that looks like that... if not, your configuration or system may require more help than I'm addressing here.

Let's reset the key to factory settings (yes, this will erase the key)

Download and install YubiKey Manager.

$ ykman openpgp reset
WARNING! This will delete all stored OpenPGP keys and data and restore factory settings? [y/N]: y
Resetting OpenPGP data, don't remove your YubiKey...
Success! All data has been cleared and default PINs are set.
PIN:         123456
Reset code:  NOT SET
Admin PIN:   12345678

If there are issues you can find additional help on the official YubiKey support site.

notice after you have reset your Yubikey it the card-status command will no longer show the cardholder name or any other details...

$ gpg --card-status
Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D2760001240103040006111562730000
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 11156273
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified

At this point, we are back at factory defaults, YOU SHOULD SET A NEW PIN on your Yubikey at this point.

$ gpg --card-edit

Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D2760001240103040006111562730000
Version ..........: 3.4

gpg/card> admin
Admin commands are allowed

gpg/card> passwd

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? q
gpg/card> quit

And if you so desire, not required... however you can set the cardholder name.

$ gpg --card-edit

Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: D2760001240103040006111562730000
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 11156273
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> admin
Admin commands are allowed

gpg/card> name
Cardholder's surname: Shufflebottom
Cardholder's given name: Dr. Ogg

Import keys to your Yubikey...

WARNING: the following operation will have a destructive effect on your gpg keys, you should make a backup of your $GNUPGHOME before proceeding..

NOTE: How do you know what key you can use for what purpose? Look for the Usage label on the key list, "C" is a Key Certificate, "S" is used for signing, E is for Encryption, and A is for Authentication.

backup your keys:

$ tar -czvf gpg-backup.tgz $GNUPGHOME

Now that we have a backup we can proceed to import our sub-keys

gpg --edit-key $KEYID
gpg (GnuPG) 2.2.16; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb  rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>

Let's transfer our signing key first:

gpg> key 1

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb* rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb  rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>

Note, when i select key 1, it will add an asterisk "*" next to the key you are selecting.

gpg> keytocard
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 1

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb* rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb  rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>

When you run this command, it will transfer the key, but it will ask for your the key passphrase then it will ask for the pin you have set on the Yubikey.

Type key 1 again to de-select and key 2 to select the next key:

gpg> key 1

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb  rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>

gpg> key 2

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb* rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>

gpg> keytocard
Please select where to store the key:
   (2) Encryption key
Your selection? 2

sec  rsa4096/0x585C80B653416059
     created: 2019-11-16  expires: never       usage: C
     trust: ultimate      validity: ultimate
ssb  rsa4096/0xA5A3330518BEE712
     created: 2019-11-16  expires: 2020-11-15  usage: S
ssb* rsa4096/0x0D4B6E2A567C9EA3
     created: 2019-11-16  expires: 2020-11-15  usage: E
[ultimate] (1). Dr. Ogg <ogg@sr375.com>

then exit and save the gpg program

gpg> save

Let's check to see if our keys have been moved:

$ gpg --list-secret-keys
gnupg/pubring.kbx
-------------------------------------
sec   rsa4096/0x585C80B653416059 2019-11-16 [C]
      Key fingerprint = 9A53 E6A0 DC15 2759 E944  D557 585C 80B6 5341 6059
uid                   [ultimate] Dr. Ogg <ogg@sr375.com>
ssb>  rsa4096/0xA5A3330518BEE712 2019-11-16 [S] [expires: 2020-11-15]
ssb>  rsa4096/0x0D4B6E2A567C9EA3 2019-11-16 [E] [expires: 2020-11-15]

Note: A ">" after these tags(sec,ssb,pub,sub) indicate that the key is stored on a smartcard/Yubikey.

And if your curious on what the tag meanings are:

sec => 'SECret key'
ssb => 'Secret SuBkey'
pub => 'PUBlic key'
sub => 'public SUBkey'

NOTE: after you're done setting up your Yubikey, you should restore the backup so your keys are restored on your USB drive.

After you have restored your backup, you can eject your USB drive, and store it in a secure location!

Setup your workstation...

export KEYID=0x585C80B653416059
export KEYSERVER=keyserver.ubuntu.com
bash <(curl -s https://gist.githubusercontent.com/DoctorOgg/d1b6a25108968b890b959e8bee7ee366/raw/2a53aa970e661fc6f26385deb3b9a7397888c96a/setupgpg.sh)