--- version: '3' todo: Collect YUBI_USER_PIN, YUBI_ADMIN_PIN, YUBI_LAST_NAME, YUBI_EMAIL, YUBI_FIRST_NAME, YUBI_TITLE (Principal Software Engineer), YUBI_ALT_NAME, YUBI_ALT_EMAIL, YUBI_ALT_TITLE vars: YUBI_MASTER_EMAIL: no-reply@megabyte.space YUBI_MASTER_NAME: Megabyte Labs env: GNUPGHOME: sh: echo "$HOME/.gnupghome" MASTER_KEY: sh: | if [ -f .yubi-masterkey ]; then cat .yubi-masterkey else LC_ALL=C tr -dc '[:upper:]' < /dev/urandom | fold -w 30 | head -n1 fi tasks: add:identities: env: KEYID: '{{.KEYID}}' YUBI_ALT_EMAIL: sh: jq -r '.YUBI_ALT_EMAIL' .yubi.json YUBI_ALT_NAME: sh: jq -r '.YUBI_ALT_NAME' .yubi.json YUBI_ALT_TITLE: sh: jq -r '.YUBI_ALT_TITLE' .yubi.json YUBI_EMAIL: sh: jq -r '.YUBI_EMAIL' .yubi.json YUBI_FIRST_NAME: sh: jq -r '.YUBI_FIRST_NAME' .yubi.json YUBI_LAST_NAME: sh: jq -r '.YUBI_LAST_NAME' .yubi.json YUBI_TITLE: sh: jq -r '.YUBI_TITLE' .yubi.json cmds: - echo -e "${YUBI_FIRST_NAME} ${YUBI_LAST_NAME}\n${YUBI_EMAIL}\n${YUBI_TITLE}\n" | gpg --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert --edit-key "$KEYID" adduid save - echo -e "${YUBI_ALT_NAME}\n${YUBI_ALT_EMAIL}\n${YUBI_ALT_TITLE}\n" | gpg --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert --edit-key "$KEYID" adduid save card: vars: KEYID: sh: gpg --keyid-format long --list-keys {{.YUBI_MASTER_EMAIL}} | grep "pub rsa" | sed 's/pub rsa4096\///' | sed 's/^\([^ ]*\).*/\1/' env: KEYID: '{{.KEYID}}' YUBI_ADMIN_PIN: sh: jq -r '.YUBI_ADMIN_PIN' .yubi.json YUBI_EMAIL: sh: jq -r '.YUBI_EMAIL' .yubi.json YUBI_FIRST_NAME: sh: jq -r '.YUBI_FIRST_NAME' .yubi.json YUBI_LAST_NAME: sh: jq -r '.YUBI_LAST_NAME' .yubi.json YUBI_USER_PIN: sh: jq -r '.YUBI_USER_PIN' .yubi.json cmds: - cp -rf ~/.gnupg ~/.gnupg.bak - task: card:reset - echo -e "admin\nkdf-setup\n12345678\n" | gpg --command-fd 0 --pinentry-mode loopback --card-edit - echo -e "admin\npasswd\n1\n123456\n${YUBI_USER_PIN}\n${YUBI_USER_PIN}\nq\n" | gpg --command-fd 0 --pinentry-mode loopback --card-edit - echo -e "admin\npasswd\n3\n12345678\n${YUBI_ADMIN_PIN}\n${YUBI_ADMIN_PIN}\nq\n" | gpg --command-fd 0 --pinentry-mode loopback --card-edit - echo -e "admin\nname\n${YUBI_LAST_NAME}\n${YUBI_FIRST_NAME}\n${YUBI_ADMIN_PIN}\nlang\nen\nlogin\n${YUBI_EMAIL}\nquit" | gpg --command-fd 0 --pinentry-mode loopback --card-edit - task: card:keys vars: KEYID: '{{.KEYID}}' # - gpg --delete-secret-key "$KEYID" # - mv ~/.gnupg ~/.gnupg-generated # TODO # - rm -rf ~/.gnupg # - mv ~/.gnupg.bak ~/.gnupg card:keys: env: KEYID: '{{.KEYID}}' YUBI_ADMIN_PIN: sh: jq -r '.YUBI_ADMIN_PIN' .yubi.json cmds: - echo -e "key 1\nkeytocard\n1\n${MASTER_KEY}\n${YUBI_ADMIN_PIN}\n" | gpg --command-fd 0 --pinentry-mode loopback --edit-key "$KEYID" - echo -e "key 2\nkeytocard\n2\n${MASTER_KEY}\n${YUBI_ADMIN_PIN}\n" | gpg --command-fd 0 --pinentry-mode loopback --edit-key "$KEYID" - echo -e "key 3\nkeytocard\n3\n${MASTER_KEY}\n${YUBI_ADMIN_PIN}\n" | gpg --command-fd 0 --pinentry-mode loopback --edit-key "$KEYID" card:reset: cmds: - echo -e "admin\nfactory-reset\ny\nyes\n" | gpg --command-fd 0 --pinentry-mode loopback --card-edit status: - '[ -n "$DONT_RESET_YUBIKEY" ]' check:entropy: vars: ENTROPY_AVAIL: sh: | if [ -f /proc/sys/kernel/random/entropy_avail ]; then cat /proc/sys/kernel/random/entropy_avail fi cmds: - | if [ '{{.ENTROPY_AVAIL}}' -lt '2000' ]; then .config/log error 'The entropy pool value is not high enough. It must be greater than 2000!' && exit 1 fi status: - '[ "{{OS}}" != "linux" ]' export: vars: KEYID: sh: gpg --keyid-format long --list-keys {{.YUBI_MASTER_EMAIL}} | grep "pub rsa" | sed 's/pub rsa4096\///' | sed 's/^\([^ ]*\).*/\1/' cmds: - task: public:export vars: KEYID: '{{.KEYID}}' # - task: revocation:export # vars: # KEYID: '{{.KEYID}}' - task: secrets:export vars: KEYID: '{{.KEYID}}' - task: public:upload vars: KEYID: '{{.KEYID}}' # - task: usb - task: card # - task: usb:unmount generate:authentication: env: KEYID: '{{.KEYID}}' cmds: - echo -e "8\nS\nE\nA\nQ\n4096\n1y\n" | gpg --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert --edit-key "$KEYID" addkey save status: - '[ -n "$YUBIKEY_BACKUP" ]' generate:encryption: env: KEYID: '{{.KEYID}}' cmds: - echo -e "6\n4096\n1y\n" | gpg --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert --edit-key "$KEYID" addkey save status: - '[ -n "$YUBIKEY_BACKUP" ]' generate:master: cmds: - mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME" - mkdir -p "$GNUPGHOME/private-keys-v1.d" - chmod 700 "$GNUPGHOME/private-keys-v1.d" # Original: echo -e "8\nE\nS\nQ\n4096\n0\ny\n{{.YUBI_MASTER_NAME}}\n{{.YUBI_MASTER_EMAIL}}\n\no\n" -- removed \ny for macOS - echo -e "8\nE\nS\nQ\n4096\n0\n{{.YUBI_MASTER_NAME}}\n{{.YUBI_MASTER_EMAIL}}\n\no\n" | gpg --expert --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --full-generate-key status: - '[ -n "$YUBIKEY_BACKUP" ]' generate:signing: env: KEYID: '{{.KEYID}}' cmds: - echo -e "4\n4096\n1y\n" | gpg --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert --edit-key "$KEYID" addkey save status: - '[ -n "$YUBIKEY_BACKUP" ]' generate:subkeys: vars: KEYID: sh: gpg --keyid-format long --list-keys {{.YUBI_MASTER_EMAIL}} | grep "pub rsa" | sed 's/pub rsa4096\///' | sed 's/^\([^ ]*\).*/\1/' cmds: - task: generate:signing vars: KEYID: '{{.KEYID}}' - task: generate:encryption vars: KEYID: '{{.KEYID}}' - task: generate:authentication vars: KEYID: '{{.KEYID}}' - task: add:identities vars: KEYID: '{{.KEYID}}' prepare: desc: Prepares an environment by provisioning all the required software / preliminary steps cmds: - mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME" - echo '{{.MASTER_KEY}}' > .yubi-masterkey - task: prepare:init - task: :install:service:start vars: SERVICE: pcscd - task: check:entropy - task: generate:master - task: generate:subkeys vars: KEYID: sh: gpg --keyid-format long --list-keys {{.YUBI_MASTER_EMAIL}} | grep "pub rsa" | sed 's/pub rsa4096\///' | sed 's/^\([^ ]*\).*/\1/' - task: export - task: :security:ssh:yubikey prepare:init: cmds: - task: prepare:init:continue status: - '[ -n "$YUBIKEY_BACKUP" ]' prepare:init:continue: deps: - :install:requirements:yubikey - :security:gpg:conf - task: :security:gpg:conf vars: CONFIG_DIR_PATH: sh: echo "$GNUPGHOME" - :security:gpg:conf:agent - task: :security:gpg:conf:agent vars: CONFIG_DIR_PATH: sh: echo "$GNUPGHOME" public:export: todo: This differs from guide env: KEYID: '{{.KEYID}}' cmds: - mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME" - gpg --armor --export "$KEYID" > "$GNUPGHOME/gpg-$KEYID-$(date +%F).asc" status: - '[ -n "$YUBIKEY_BACKUP" ]' public:upload: cmds: - gpg --send-key "$KEYID" - gpg --keyserver pgp.mit.edu --send-key "$KEYID" - gpg --keyserver keys.gnupg.net --send-key "$KEYID" - gpg --keyserver hkps://keyserver.ubuntu.com:443 --send-key "$KEYID" status: - | [ "$(echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1)" != "0" ] || [ -n "$YUBIKEY_BACKUP" ] revocation:export: env: KEYID: '{{.KEYID}}' cmds: - mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME" - gpg --output $GNUPGHOME/revoke.asc --gen-revoke "$KEYID" status: - '[ -n "$YUBIKEY_BACKUP" ]' secrets:export: env: KEYID: '{{.KEYID}}' cmds: - mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME" - gpg --armor --export-secret-keys --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert "$KEYID" > $GNUPGHOME/mastersub.key - gpg --armor --export-secret-subkeys --command-fd 0 --pinentry-mode loopback --passphrase "$MASTER_KEY" --expert "$KEYID" > $GNUPGHOME/sub.key status: - '[ -n "$YUBIKEY_BACKUP" ]' secure:delete: env: KEYID: '{{.KEYID}}' cmds: - sudo srm -rf "$GNUPGHOME" || sudo rm -rf "$GNUPGHOME" - gpg --delete-secret-key "$KEYID" stub: summary: | Run this to re-stub the GPG files to point to the current YubiKey. cmds: - gpg-connect-agent "scd serialno" "learn --force" /bye usb: summary: | # Backup Keys (Including Master) to USB and Encrypt This task will partition a USB with two partitions. One partition will be encrypted and contain your GPG keys (including the master key). The other partition will not be encrypted and contain your public key. cmds: - task: usb:create - task: usb:mount - mkdir ~/.gpg-encrypted-storage && cp -rf $GNUPGHOME ~/.gpg-encrypted-storage # TODO /mnt/gpg-encrypted-storage - mkdir ~/.gpg-public && cp $GNUPGHOME/gpg-$KEYID* ~/.gpg-public # TODO /mnt/gpg-public status: - '[ -n "$YUBIKEY_BACKUP" ]' usb:create: deps: - :security:disk:encrypt:create - :security:disk:unencrypted:create usb:mount: deps: - :security:disk:encrypt:mount - :security:disk:unencrypted:mount usb:unmount: deps: - :security:disk:encrypt:unmount - :security:disk:unencrypted:unmount status: - '[ -n "$YUBIKEY_BACKUP" ]' yubikey-agent: deps: - :install:software:yubikey-agent summary: | # Sets Up Resident SSH Key According to [this guide](https://github.com/jamesog/yubikey-ssh), the yubikey-agent package is a simplest, best way of utilizing a YubiKey for SSH by leveraging YubiKey's onboard SSH key generator. By using this method, the private key never leaves the YubiKey which increases security tremendously. See: https://github.com/FiloSottile/yubikey-agent A new method is detailed here: https://www.yubico.com/blog/github-now-supports-ssh-security-keys/ It may be worth migrating to that approach. cmds: - brew services start yubikey-agent - yubikey-agent -setup