Crontab執行指令碼中的ssh命令訪問被拒絕
我們經常會通過crontab來執行定時任務,通常生產環境中在不同主機直接進行登入是通過ssh來連線的。比如我們通過在備份伺服器上設定定時任務,定期通過scp(使用SSH的遠端拷貝命令)來拷貝遠端伺服器的資料到備份伺服器上,這也是我遇到的一個事情。
環境描述:
指令碼與定時任務:
定時任務設定如下:
無論是否執行成功,都把資訊輸出到中
指令碼內容如下:
我這裡僅用ssh命令來測試,實際上這個命令如果可以正常執行的話,你執行scp命令也一樣
#!/bin/bash ssh -v 'ls'
報錯資訊:
下圖是crontab執行定時任務中的指令碼的報錯資訊
你發現TCP連線是成功建立的,然後也在備份伺服器上的~/.ssh/目錄中的known_hosts檔案中找到了host key。這個key是對方主機的公鑰。在/etc/ssh/ssh_config中的
下圖這個意思是說KEY找到了而且匹配,就是說備份伺服器存的對方伺服器的公鑰和對方現在使用的公鑰一致。
最後是嘗試傳送自己使用的公鑰讓對方去驗證,這裡嘗試了幾次,並且更換了幾種驗證方式均宣告失敗,所以最後拒絕訪問。
下圖是單純執行指令碼的輸出資訊:也就是直接在終端中執行指令碼
可以看到驗證是通過的,不過你會發現它使用的是一個叫做id_dsa的公鑰檔案傳送給伺服器,然後對方接受了。可是我這個備份伺服器本地的~/.ssh/目錄中並沒有id_dsa的檔案
我發現跳板機(Linux的跳板機,一般登入IDC的機器都要登入到跳板機,而且其他伺服器也只接受來自跳板機的IP資訊,你就算撥入了VPN,如果不先連線到跳板機,你也是無法登入伺服器的,那可能有人問,我通過跳板機連線到了伺服器,然後從這個伺服器再SSH到另外的伺服器是否可以呢?可以)的~/.ssh/目錄中有id_dsa檔案,於是我就拷貝到我的備份伺服器上,測試後依然失敗。
排查問題:
檢視env
修改指令碼:
修改~/.bashrc檔案,也就是本地變數檔案,在檔案中增加如下內容,這些內容和也就是之前通過env檢視到的
export SSH_CLIENT=" 14567 1314" export SSH_TTY=/dev/pts/2 export SSH_AUTH_SOCK=/tmp/ssh-cvRpw15068/ export SSH_CONNECTION=" 14567 1314"
修改指令碼
#!/bin/bash source $HOME/.bashrc ssh -v 'ls'
驗證:
再次執行就成功了。
總結:
crontab執行指令碼不成功通常都是環境變數導致的,因為crontab執行指令碼屬於非登式shell,針對這種它是不載入/etc/profiel和~/.bash_profile。它的會先載入~/.bashrc,然後載入/etc/bashrc,最後載入/etc//下的變數。所以我在家目錄中的bashrc中設定了和env中一樣的變數,這樣在腳本里面指定就可以了。如果你只是在basrc中寫,而不在指令碼中source初始化檔案也不行。原因我猜測可能是跟crontab自己的環境變數有關,而且在/etc/rond的配置檔案中設定環境變數不生效,不知道為什麼。
所以在crontab執行指令碼,通常的建議是命令寫全路徑,另外還應該設定好環境變數
#!/bin/bash source /etc/profile source $HOME/.bashrc
如果是ssh這種遠端執行,可以使用-i引數指定公鑰。