如何在 Mac 上,把 YubiKey 與 GPG、SSH 搭配在一起

這篇是翻譯的技術步驟說明,原創含量很低

Wilson Kao
16 min readFeb 19, 2017

前言

我最近買了一個 YubiKey Nano,最近在探索各種可能的用途。對於有點資安偏執的人如我,YubiKey 提供了可靠的一般雙重認證(U2F authentication, see also FIDO)解決方案,並且受 FacebookGoogleGitHub 所採納。另外,YubiKey 也可以生產出品質夠好的金鑰,保障加密通訊安全 — — 而且,因為可以只把私鑰放在 YubiKey 上的晶片上,所以只有在 YubiKey 插入電腦、並輸入正確的 PIN 碼解鎖之後才能使用解密跟簽署的功能。

(對台灣讀者來說,其實 YubiKey 就是跟自然人憑證是差不多的東西。但 YubiKey 明顯地方便許多:可以直接插進 USB、支援的服務跟介面也比較多,而且不需要以登入實名即可使用。)

在測試用 YubiKey 生產金鑰時,我發現了 GPG and SSH with Yubikey for Mac 這篇詳盡的說明,提供了我很大的幫助。在徵得作者 Richard North 同意之下,我下面會把這篇說明全文翻譯。不過,因為我前頭的操作過程跟 North 不一樣、使用的是 YubiKey Nano 而非 YubiKey Neo(或者因為我現在使用的 macOS 跟 YubiKey 軟體的版本不一樣),因而後頭有些步驟有點小變化,我會在文章中把我的 comment 另外標示成「譯註」,以供讀者參考。另外,為閱讀通順起見,部分文句會加以調整潤飾。

GPG and SSH with Yubikey for Mac, by Richard North

Yubikey Neo [購買連結] 是一款優秀、平價的裝置,支援使用通用二階段認證(U2F authentication)的網路服務,以及 OpenGPG smart card。

本文的目標是,解釋以下功能的設定步驟:

  • 以 GPG 加密並簽署郵件
  • SSH 公鑰認證,例如,應用在伺服器間的連線、git 的原始碼控制,以及 Heroku。

其中,設定 SSH 公鑰認證,讓使用者對存取服務有第二重控制的手段,讓存取服務的過程,不至於因為 SSH 私鑰被竊取、或者電腦被植入鍵盤記錄程式就被破解。因為 GPG 跟 SSH 的私鑰是存在 YubiKey 的晶片上,遠比私鑰存在本地硬碟上還來得安全。

本文是寫給在 Mac 上安裝 Yosemite (OS X 10.10) 與 El Capitan (OS X 10.11) 並且使用 Fish shell 的使用者;並且,假定使用者已經安裝了 Homebrew 跟 brew cask。

原作者註:本文是結合並濃縮了一票我認為有用的設定教學文章,而且我是在跑完這些過程之後一段時間才寫出來的,因此如果有哪邊錯誤、或省略,還請跟我說一聲

譯註一:我使用的是 YubiKey Nano,並且是在 macOS Sierra (10.12.3) 以內建的 bash shell 操作。在操作這些步驟之前,我已經按照 Yubico 官網的指示,把 YubiKey Nano 用 YubiKey PIV Manager 1.4.1 進行初始化設定、把這張跟我的 macOS 帳戶的登入綁定(pair)在一起。整體而言,除了一兩步外,操作步驟還是相同。

譯註二:這篇文章所交代的操作,建議使用者對 macOS 的 terminal 操作有一點點的熟悉(或者至少不害怕去翻 manual)才進行。進行之前,請使用者先安裝最新的 Xcode、Homebrew。如果你跟我一樣是升上 Sierra 之前就已經安裝 Homebrew,很有可能在底下操作中因為系統架構變更,使得安裝軟體會一直出問題。我個人建議就按照這篇的建議,把 Homebrew 用以下的指令砍掉重練(當然,進行任何有風險的操作之前,請先用 Time Machine 為系統做備份):

$ cd brew --prefix
$ sudo rm -rf Cellar
$ brew prune
$ sudo rm -rf Library .git .gitignore bin/brew README.md share/man/man1/brew
$ sudo rm -rf ~/Library/Caches/Homebrew
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

將 Yubikey 準備好

  1. 用以下指令安裝 Yubikey 的管理工具:
$ brew update
$ brew cask update
$ brew cask install yubikey-neo-manager yubikey-personalization-gui
$ brew install yubikey-personalization

譯註三:我個人在第三、第四個指令時,有出現安裝錯誤訊息,要求我手動 overwrite 某些檔案才能建立某些 link。我基本上就比照辦理,之後操作就沒有問題。

2. 將 Yubikey 插入 USB 插座。

3. 將 Yubikey’s 透過以下指令設定為 OpenPGP SmartCard 與 OTP 協同作業模式:

$ ykpersonalize -m82 

4. 安裝 GPGtools(Mac only):

$ brew cask install gpgtools

譯註四:我個人先前已經有在安裝並使用 gpgtools,直接跳過這一步,對結果沒有影響。

5. 在 YubiKey 上根據以下步驟,設定 GPG 專用的 PIN 碼。如果在這一步出現 “card error” 的訊息,請拔出 YubiKey 後再重新插入。

原作者註:如果你輸入原廠預設的 PIN 碼輸錯太多次,YubiKey 會被鎖定。雖說看起來好像可以重設啦,但我個人沒有測試過。

首先,請設定一個調整 YubiKey 設定用的 Admin PIN(出廠預設是 12345678);接下來,設定一個使用者的 user PIN(出廠預設是 123456)

譯註五:如果各位有先用 YubiKey PIV manager 設定過 YubiKey、並且與 macOS Sierra 的登入憑證綁定(pair)過的話,這個步驟會先跳出來要你輸入 user PIN,也就是當初你設定過的 user PIN。然後,整個過程需要重複一次。

$ gpg --card-edit
(中略,是 YubiKey 晶片的資訊)
gpg/card> admin #譯註六:這時候進入 ~gpg/card~ 這個指令環境,admin 這個指令是要把晶片切換到「可以進行更動設定的狀態」;如果想要知道到底有哪些指令,請自己輸入 help
Admin commands are allowed #晶片現在回應說「可以更動設定了」
gpg/card> passwd #譯註七:passwd 這個指令是更換晶片的 PIN 碼,會跑出以下五種選項

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 3
(譯註八:跳出 GUI 視窗要你輸入原廠 Admin PIN 碼,接下來讓你輸入並重複一次你的選項)
PIN changed.

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

Your selection? 1
(譯註九:跳出 GUI 視窗要你輸入原廠 user PIN 碼,接下來讓你輸入並重複一次你的選項)
PIN changed.

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

Your selection? q #譯註十:跳出晶片設定畫面

製作出一組公鑰 / 私鑰配對(public/private keypair)

  1. 接下來的指令,是要在 YubiKey 上生產一組金鑰。我們會設定說「不要在晶片以外的地方留金鑰備份」(譯註十一:也就是說,電腦只有在插入這張 YubiKey 晶片才能正確地使用這組金鑰配對,然後弄丟這張 YubiKey 之後你這組金鑰跟以此加密的資料就掰了),並且設定這組金鑰配對在一年以後過期:
$ gpg --card-edit
gpg/card> admin
gpg/card> generate #譯註十二:這個指令是「生產金鑰配對」的意思
Make off-card backup of encryption key? (Y/n) n #譯註十三:「不要在晶片以外的地方留金鑰配份」
gpg: 3 Admin PIN attempts remaining before card is permanently locked
(輸入 Admin PIN)
(輸入 PIN)
Please specify how long the key should be valid. #譯註十四:選定金鑰的期限,作者這裡使用 1y 就是一年。
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
...
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
#譯註十五:以下是輸入這份金鑰附加的資訊。請依序輸入你的姓名(Real name)、email 地址跟註解(comment)。當然,如果你有隱情的話,輸入假的姓名也是可以啦。
Real name: ...
Email address: ...
Comment: ...
You selected this USER-ID: #譯註十六:這時候底下會請你確認一次資料要不要更動,接下來就會花大約一到兩分鐘生產出金鑰配對了
...

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
gpg: generating new key
gpg: please wait while key is being generated ...
gpg: key generation completed (45 seconds)
gpg: signatures created so far: 0
gpg: signatures created so far: 0
You need a Passphrase to protect your secret key. #譯註十七:不知為何我沒印象我有經歷過要你「輸入一個保護這個密鑰的密碼」的警示。

+++++
..+++++
gpg: signatures created so far: 2
gpg: signatures created so far: 2
gpg: generating new key
gpg: please wait while key is being generated ...
gpg: key generation completed (25 seconds)
gpg: signatures created so far: 4
gpg: signatures created so far: 4
gpg: key <你金鑰的 short ID> marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, classic trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 2048R/<你金鑰的 short ID> <金鑰的生產日期>
Key fingerprint = ...
uid ...
sub 2048R/... ...
sub 2048R/... ...

我把上述的某些資訊馬賽克掉了。但請稍微留意一下 <你的公鑰的 short ID>(在我的例子裡,是 79C56617)

2. 接下來,將這個公鑰存在其他安全的地方,之後要用到它:

$ gpg --armor --export <your public key ID> > ~/my_gpg_public_key.pub

3. 開啟 “GPG Keychain” 這個程式,並且在你的公鑰配對上按右鍵(它應該會以粗體顯示為 sec/pub)。

4. 首先,選擇「生產出一組撤銷憑證(Generate Revoke Certificate…)並存檔在安全的地方。如果你搞丟了你的 YubiKey,你需要用這撤銷憑證,以撤銷掉被你搞定的金鑰。

5. 接下來,請「將這公鑰上傳到 Keyserver」(Send public key to Keyserver)。

設定 GPG Agent

這個步驟讓 GPG Agent 可以驗證你的 SSH Sessions。請編輯 /.gnupg/gpg-agent.conf:

pinentry-program /usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac
enable-ssh-support
write-env-file
use-standard-socket
default-cache-ttl 600
max-cache-ttl 7200
debug-level advanced
log-file /var/log/gpg-agent.log

請注意:

  • pinentry-program 這設定是讓你輸入 GPG user PIN 時,要求跳出一個 Mac 內建的圖形介面

(譯註十八:其實就是大家一直看到的那個輸入密碼的小視窗)

  • enable-ssh-support 就字面上的意思
  • default-cache-ttl 設定你的 PIN 會被暫存 10 分鐘,即 600 秒
  • 若按照預設檔案權限來走,是無法寫入 log 檔、所以也不會產生什麼 log 檔。因此,如果你希望 GPG Agent 把相關訊息記錄下來的話,還需要 Touch 這個檔案: /var/log/gpg-agent.log 並且利用 chown 把權限調整成你的使用者帳號。

接下來,因為我使用 fish shell 作為 ssh 的介面,我必須要把以下這段加入我的 shell 設定,把 GPG Agent 與我的 shell 一同啟動。請將下列指令放進 ~/.config/fish/gnupg.fish

Start or re-use a gpg-agent.

gpgconf --launch gpg-agent

Ensure that GPG Agent is used as the SSH agent
set -e SSH_AUTH_SOCK
set -U -x SSH_AUTH_SOCK ~/.gnupg/S.gpg-agent.ssh

作者註 (2016–04–17): GPG v2.1 中是出了 GPG Agent 自動啟動的功能,這段因此變得簡單許多,相應的指令修改已經更替上去了。

最後,重新啟動你的 shell 讓 GPG Agent 重新載入。

Using GPG for SSH login

在 GPG Agent 執行之下,要使用 YubiKey 進行 SSH 驗證不太需要什麼更多的步驟。不過,我們仍然需要把你的公鑰轉換成 SSH 可以理解的形式:

$ gpgkey2ssh <your public key ID> > ~/my_ssh_public_key.pub

這個步驟會產生出一般 SSH 格式的公鑰。接下來,把 comment 這一節給編輯掉(檔案的最後一段)。

至此,你可以按照一般的作法,把這個 SSH 公鑰散播至:

  • 你需要存取的 server 們上面的 authorized_keys files
  • Github
  • Heroku
  • 其他需要你使用、需要這份 SSH 公鑰的網路服務

如果你成功設定了你的 YubiKey、GPG Agent 並且把你新的公鑰上傳到 GitHub 上,以下步驟應該會顯示出你 GitHub 的使用者名稱(我的是 rnorth,如這裡所示):

$ ssh git@github.com
PTY allocation request failed on channel 0
Hi rnorth! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

Testing GPG for encryption and signing

為了確定你基礎的 GPG 設定可以正確運作,試試看執行下列指令:

$ gpg --sign -a

請輸入 Hello World!,緊接著輸入一個換行鍵與 Ctrl+D。輸出的結果應該與下面的段落看起來有點像:

-----BEGIN PGP MESSAGE----- 
Comment: GPGTools - https://gpgtools.org
owEBQwG8/pANAwAKAaUoZrl5xWYXAcsTYgBV/qIXSGVsbG8gV29ybGQhCokBHAQA AQoABgUCVf6iHAAKCRClKGa5ecVmF+SGB/9oq34MZRkwuUfLD1uyIsyulLfzunVG LJkOaeOTiwO0aeQCcPOe/uSqt5yi5o3a+8L/pBjD7+lwaTYNT4+3Tf4UpbuoDq7L bcgK3ZIbWfqW56OjqdubBMp+hP1Jwgolfc5lZw62LIkUZ/PLf7dJfevSX6PTcxlV UUkIG0xmq/ZIc5ZbyFcCqZ8RaR35LPcTJ3nvsCzF50+HTK15W2+nxspgsorl+uSz JwQHPilsvDyC3PuaMu6+6VvI+xpjor/XcODO/0w6x/vrlXGNluM9/Vc6rgm8vn5E dr34eKaAz48dS/21qK41Oxp2Xx6vf9/culDJzihWlfAtF5Qf2u+6aDKl
=1GQg
-----END PGP MESSAGE-----

還可以試試看的事:

  • 把你的 GPG 公鑰上傳到 keybase.io 上。我手上還有好幾份邀請函,如果有人需要的話。
  • 利用 Mail.app 發一封以 GPG 加密的郵件(GPGtools 自動安裝了 Mail/GPG 的整合外掛)。如果你認為這篇說明有幫助,請試著寄一封 GPG 加密的 email 來跟我說!

指引

我參考以下這些很讚的說明歸納出以上這些步驟:

後記

我按照 Richard North 的指示操作,生產出一組金鑰,公鑰是 4C5DBB03 @ hkp://pgp.mit.edu。結果非常完美:在沒有插卡的狀況下,無法以對應的私鑰將 4C5DBB03 加密的檔案進行解密。

最後,還是要再度感謝 Richard North 慷慨授權我翻譯這篇實用的指引。希望這篇指引能幫助推廣 YubiKey,讓它成為在意資安的朋友們可靠的助手。

--

--

Wilson Kao

因為這世界的樣子將要過去了,我願你們無所掛慮。