SSH Agent Forward

少年バット

最近對於 blog 的另外一個改動就是檔案權限的修改,我用的 Blog 系統是 MovableType,它的其中一個特色就是會產生好靜態的檔案,而這些檔案其實我都有丟上 Github 和 Bitbucket 備份,以前我基本上都用 root 來做這些事情,所以沒有權限問題,不過這次重灌後想順便把這問題處理一下,所以做了一番研究,首先在 ArchLinux 上,預設給 HTTP 等相關服務例如 nginx、php 等用的帳號是 http,所以我希望讓這些檔案的 owner 就是 http,一來可以確保所有的網路服務需要這些檔案時,都可以正確的存取,因為我嘗試過用 group 來設定權限共有,不過結果不太順利;二來 MovableType 產生的檔案 owner 也都是 http,可以保持一致性,也不用常常在那邊改檔案的 owner。

不過 http 這個帳號是沒有 shell 的,也就是不可以用這個帳號登入,當然會這樣預設也是安全性的考量,我並不想改掉他,所以第一個遇到的問題就是,我要怎樣用 http 帳號來執行指令,像是git commit之類的,研究一陣子之後,發現可以用sudo來辦到:

sudo -u http -s /bin/sh -c "git commit"

其中-u是設定要換到那個帳號,-s就是關鍵的指定 shell 了,最後的-c則是要執行的指令,如果加上這個設定則不會真的換過去該帳號,而是只是用該帳號執行一次指令而已,解決第一個問題後,馬上來的就是第二個問題了,要git push時,要怎麼使用有權限的 ssh private key,最簡單的方法就是丟到 http 帳號的 home 目錄下,不過我覺得這不太安全,所以想著要用其他方法來把 key 傳過去,當然把其他帳號的 key 的檔案權限調寬鬆並不可行,權限不對的 key 會無法使用,找到唯一比較接近的設計就是 SSH Agent Forward 了,可以把本機的 ssh key pair 帶上遠端主機,然後就可以從遠端主機利用這個帶上去的 key 連線到其他地方,使用方法很簡單,只要在連上遠端主機的時候,多加一個-A的參數就可以了:

ssh -A user@othree.net

或是修改.ssh/config的設定:

Host othree
  HostName othree.net
  ForwardAgent yes

不過可能會需要先把 key 加進去可以 forward 的清單中:

ssh-add

然後連上遠端主機之後,遠端的 login session 就會多一個環境變數$SSH_AUTH_SOCK,印出來看內容會像是:

/tmp/ssh-7UJdnvSdy0/agent.18493

實際上是個檔案路徑,指到一個 unix socket 檔案,理論上 ssh 在連線時會去這邊找 key pair 然後用來做認證,不過我看ssh -vvv的時候是沒有相關訊息出現,連線是可以正確建立就是,透過 agent forward,的機制,我就可以達成某種程度的 key 共用,不過在遠端主機上要使用的帳號是個沒有 shell 也沒有密碼可以登入的帳號,這就成了另外一個問題,遠端能拿到 key 的帳號不是我要用的帳號,所以第三個問題就是我要如何讓這個 key 能夠轉移到 http 帳號下可用的狀態。

這個問題的解決方法是在 StackOverflow 上找到的,用的其實是 ACL 這套比較新的檔案權限管理機制,指令大致如下,先把 unix socket 的檔案權限用 ACL 開給 http 帳號:

setfacl -m u:http:rw $SSH_AUTH_SOCK
setfacl -m u:http:x $(dirname $SSH_AUTH_SOCK)

然後 sudo 時把$SSH_AUTH_SOCK帶過去:

sudo -u http env SSH_AUTH_SOCK=$SSH_AUTH_SOCK

因為 http 帳號沒有 shell,所以實際上指令會變成:

sudo -u http -s /bin/sh -c "env SSH_AUTH_SOCK=$SSH_AUTH_SOCK git pull"

不過這樣執行起來有點麻煩,其實 sudo 可以設定要帶哪些環境變數過去,所以可以去修改/etc/sudoers加上一行:

Defaults    env_keep+=SSH_AUTH_SOCK

然後在遠端 user 帳號下的~/.ssh/rc檔案裡面加上 facl 那兩行指令(尚未確認可行性),加上本機端設定好自動 ForwardAgent,整個流程中比較麻煩一點的就只有 sudo 那行指令而已:

sudo -u http -s /bin/sh

就結果而言,這個作法的安全性反而比我本來的預期更進一步,因為我的 ssh key 就不用放上遠端主機,只要在本機端有一份就好了。