2014年8月21日 星期四

定期排程異地備份不需要密碼, 就交給 ssh 的信任機制與身份識別吧!

ssh 的公鑰/私鑰/密碼 ssh 的身份管理 (identity management) 機制讓你可以:

  1. 用同一個身份、 同一個密碼登入許多 「位於不同機器的不同帳號」。
  2. 不同的人可以用各自不同的身份/密碼登入共用同一個帳號。
  3. 免密碼登入, 方便 定期/排程遠端備份 之類需要無人看管自動登入的工作。

特別是 「無人看管自動登入」 這項工作, 搜尋 「ssh 免密碼」 可以找到很多指令實作好文 -- 例如 「[超易] 兩行指令搞定 Linux SSH登入免密碼」。 另外, 也推薦 「關閉sshd的登入密碼認證」 及那篇文章最後面的幾個連結。 但這篇主要不是要教你如何下指令, 而是要解釋 ssh 的身份管理概念。

ssh 採用 非對稱式加解密 ( sozi 簡報版) 的機制。 可以這樣比喻: 一對金鑰就像拆成兩塊的圖案, 必須把兩枝成對的金鑰合在一起才能看到完整圖像、 解開謎題。 公鑰沒有機密性, 給任何人看到都沒關係; 私鑰則應被持有者當成秘密保護好。 更進一步, 產生金鑰時可以選擇用密碼保護, 這就像是把拼圖拆成三塊一樣, 可以提高解謎的困難度 -- 就算私鑰外洩, 只要密碼沒有跟著外洩, 他人還是無法輕易地拼湊出完整的圖案。 用 ssh-keygen 指令產生金鑰的過程當中, 被問到 Enter passphrase 的時候, 如果選擇直接按 Enter 略過密碼設定, 那就像是拆成兩塊的拼圖; 如果選擇輸入密碼, 那就像是拆成三塊的拼圖。 (註: ssh-keygen 還有一個 -C 選項可以設定 (給人看的) 文字註解, 好用!) 以下為了簡單起見, 插圖中的金鑰只拆成兩塊; 實際上每一組金鑰都可以是兩塊或三塊。 總之, 可以把公鑰想像成鎖頭; 把 [私鑰+密碼] 想像成一把實體的鑰匙。

ssh 的公鑰/私鑰/密碼 用 ssh-keygen 指令產生金鑰時, 原則上金鑰都存放在 ~/.ssh/ 目錄底下; 你可以自己選擇不同的檔案名稱。 產生完畢後, 用 ls -l 查看其權限, 會看到 「副檔名為 .pub」 那一個是全世界可讀的, 也就是公鑰; 沒有副檔名的那一個是私鑰, 權限設定應為只有自己可以讀寫。 這一對檔案的名稱就代表了一個身份。 (identity) 每個人可以用 ssh-keygen 產生好幾對金鑰、 持有好幾個身份。 比方說, 如果我的 ~/.ssh 底下有 id_eagle.pub id_eagle id_rabbit.pub id_rabbit 四個檔案, 那就表示我有兩個身份 (id_eagle 跟 id_rabbit), 可以分別拿來保護不同的 ssh 遠端登入帳號。

相對地, 在伺服器那端, 同樣在 ~/.ssh 目錄底下, 有一個特殊檔案 authorized_keys 記錄著該伺服器所信任的所有身份 (的公鑰)。 比方說, 我在 abc.org 這部主機上面有一個 ssh 帳號名為 mammal。 如果我把 id_rabbit.pub (只貼公鑰就好!) 的內容添加到 abc.org 的 ~/mammal/.ssh/authorized_keys 檔案裡面去, 那就表示 mammal 帳號信任 「握有 id_rabbit 這對金鑰的人士」。 所以日後我可以從我 (含有私鑰 id_rabbit 的) 那部筆電這樣連線: ssh -i ~/.ssh/id_rabbit mammal@abc.org 這裡的 -i ... 就是指定要以 id_rabbit 的身份登入。 此時我需要輸入密碼就不再是 「mammal 帳號 的 linux 密碼」, 而是搭配 id_rabbit 的密碼。

如果我握有很多 linux 帳號 (可能分佈在很多部不相關的主機上面), 而且 id_rabbit.pub 這把公鑰的內容都出現在每個帳號的 ~/.ssh/authorized_keys 裡面, 那麼即使這些帳號的 ip/名稱/密碼都不相同, 我也都可以用同一個密碼 (id_rabbit 的密碼) 登入。

改用這種方式取代原先的 linux 密碼登入還有一個好處: 你可以用 ssh-agent 幫你記住密碼, 每次本地機開機之後只需要叫出 ssh-add 打一次密碼, ssh-agent 就會把它記在記憶體內。 從此以後凡是遇到遠端機器向你要 id_rabbit 密碼的場合, ssh-agent 就自動幫你餵密碼給對方吃, 省去打密碼的麻煩。 當然, 如果你從本地機登出或本地機關機, 就要再重新 ssh-add 一次。

更有趣的是: 我跟幾位朋友可以 共用同一個帳號 (mammal@abc.org) 而不需要知道彼此的密碼。 假設我的朋友 steven 在他的筆電上握有一對金鑰 ~/.ssh/id_elephant.pub 與 ~/.ssh/id_elephant 。 他可以把 id_elephant.pub 的內容寄給我, 我把它新增到 mammal 帳號的 ~/.ssh/authorized_keys 檔案後面去。 (每個身份很長一列, 中間不可穿插換列!) 從此以後 steven 就可以從他的筆記電腦上這樣連線: ssh -i ~/.ssh/id_elephant mammal@abc.org 當然, 他所打的密碼就是當初 他在他的筆電上 產生 id_elephant 那對金鑰時所設定的那組密碼。 可以這樣想像: ~/.ssh/authorized_keys 像是這棟房子 (這個帳號) 的一道很特殊的門。 你可以把好幾位信任好友的鎖頭通通都嵌在這扇門上面。 只要能開啟任何一個鎖頭, 這扇門就會打開。 也就是說每位信任好友可以用各自的鑰匙透過這扇門進出這棟房子。

貴哥會認真研究 ssh, 主要是最近為了定期異地備份網站, 需要設定一個帳號 定期自動登入 另一部機器的帳號去抓備份資料。 在伺服器本機定期執行的工作, 可以交給 crontab, 這個沒問題。 有問題的是: 想定期用 scp 或 rsync 從遠端主機抓檔案, 會被問密碼呀! 如果必須配合 crontab 的設定, 每天半夜三點半起床敲密碼 ... (那我還要 crontab 幹嘛? 摔鍵盤!) 網路上查到的解決方案, 主要是採用 ssh-agent 搭配 screen 或 ssh-agent 搭配 keychain 自動餵密碼。

不過既然我們已經了解 ssh 的身份管理機制, 其實有更簡單的方法: 乾脆根本就不要設密碼 -- 也就是 「超易!」 一文所推薦的做法。 比方說我自己平常使用的身份是 id_rabbit, 這當然要用密碼, 多一層保護; 至於 id_eagle 的身份, 則是要專門拿來備份用的身份, 所以沒有設密碼。 然後:

  1. 進入我所管理的每一部主機上 (以下稱其中一部為 xyz.com 好了), 用 crontab 把資料備份到本機的 /backup 目錄底下, 並且用 chown 把它的所有權交給一個權限很小的 (非 root) 使用者, 比方說叫做 librarian 好了。
  2. 把 id_remote_backup.pub (公鑰!) 的內容貼到 xyz.com 的 ~librarian/.ssh/authorized_keys 裡面。
  3. 把 id_eagle.pub 跟 id_eagle 都 copy 到 mover@hollow.planet 這個 「專司遠端備份」 的機器與帳號, 放在 ~mover/.ssh 底下。
  4. 確認 hollow.planet 跟 xyz.com 這兩部機器上都有安裝 rsync 套件。
  5. 在 mover@hollow.planet 的帳號底下, 用 crontab -e 叫出編輯排程的畫面, 並加入以下:
    41 3 * * * rsync -a -e "ssh -i $HOME/.ssh/id_eagle" librarian@xyz.com:/backup $HOME/backup/xyz.com
    

上句意謂著: 「每天 3:41 分, 用 rsync 把 xyz.com 的 backup 資料夾底下的所有東西同步到 (mover@hollow.planet) 家目錄底下的 backup/xyz.com 子目錄。 連線時採用 ssh 方式及 id_eagle 的身份 (所以不需要密碼)。」 (參考連結: 「rsync 連線時如何指定 ssh 身份?」; 關於 crontab, 請搜尋 「crontab 排程」) 看! 不需要 ssh-agent、 不需要 keygen、 不影響我其他帳號的安全性、 不需要敲密碼就可以自動備份。

如果你希望更嚴謹一些, 例如只允許某身份從某部主機登入、 只准執行某些動作, 那麼可以在 ~/.ssh/authorized_keys 裡面加上 from="...",command="..." 。 詳見 這篇。 以 rsync 備份來說, 就要參考 這篇

如果你有好幾組經常登入的 ssh 帳號, 但是每組帳號都有很囉嗦而且不太一致的設定 (用戶名、 port、 登入身份、 ...) 導致你的每個 ssh 指令都很長, 那麼一定要看一下 這一篇, 把複雜的設定寫入 ~/.ssh/config 之後, 以後每次下 ssh 指令就會變得很簡單。

沒有留言:

張貼留言