Unix/Linux 系統自動化管理: 遠程登錄篇

  Telnet 和 SSH 協議是 Internet 遠程登錄服務的標準協議和主要方式,它們爲用戶提供了在本地機器上完成遠程機器上工作的能力。用戶使用 Telnet 或者 SSH 軟件連接遠程服務器,在 Telnet 或者 SSH 軟件中輸入的命令就會在服務器上運行。Telnet 協議本質上是不安全的,因爲它使用明文傳送數據、用戶賬號和口令,很容易受到中間人***方式的***;而 SSH 協議則是比較可靠、專爲遠程登錄會話和其他網絡服務提供安全性的協議。通過 SSH 可以對所有傳輸的數據進行加密,也能夠防止 DNS 欺騙和 IP 欺騙。本文主要針對 SSH 協議進行闡述,使用的 SSH 軟件是 OpenSSH,它是開放源代碼的免費的 SSH 替代軟件包。

  用戶使用 Telnet 或者 SSH 登錄不同的操作系統,會得到不同的返回信息。用戶可以編寫程序根據運程登錄的返回信息進行判斷和處理,從而實現遠程服務器系統的自動化登錄。本文將先介紹實現遠程自動化登錄用到的技術,再詳細介紹如何實現 Unix/Linux 系統間遠程登錄自動化。 使用 Expect 的自動化登錄

  Expect 的基礎知識

  Expect 是由 Don Libes 基於 Tcl 語言開發的,並被廣泛應用於交互式操作和自動化測試的場景之中,它尤其適用於需要對多臺服務器執行相同操作的環境中,可以大幅度得提高系統管理人員的工作效率。目前,大部分 Unix/Linux 系統安裝有 expect. 萬一系統中沒有,可以從 http://expect.nist.gov/ 下載相應的包安裝。

  Expect 作爲基於 Tcl 的高級語言,增加了一些特殊的語法。傳統意義上的 Expect 是以 Tcl 擴展包的形式出現的,任何 Tcl 語言編寫的應用程序都可以加載 Expect 功能;此外,Expect 已經以模塊的方式移植到了 Perl 和 Python 語言中,因此用戶同樣可以在 Perl 和 Python 腳本中利用 Expect 強大的交互功能。

  Send,expect 和 spwan 是 Expect 語言最基本的命令。其中,send 命令會發送字符串給指定進程(process); expect 命令會等待接受該進程返回的結果並且會根據返回的字符串來決定下一步的操作;而 spwan 命令可以發起一個進程的運行。

  send 命令接收一個字符串做爲參數併發送給指定的進程;從 send “Hello world”

  這行代碼中,send 會送出字符串“Hello world”( 不帶引號 )。如果 Expect 早已經開始與某一個程序進行交互,那麼這個字符串將被髮送給該程序;而在通常情況下,這個字符串會被送到標準輸出設備。

  expect 命令則等待一個響應,通常是來自於 Expect 正在與之交互的進程,或者來自於標準輸入設備;它會等待一個指定的字符串或者滿足給定的正則表達式的任何字符串。我們可以創建一個名爲 response.exp 的文件,來看 Expect 是如何處理的,其內容如下: #!expect – f expect “hi\n” send “hello there\n”

  然後在 shell 下面運行 ”expect response.exp”,它會等待來自標準輸入設備的響應,直到用戶輸入 hi 並回車,它纔會發送”hello there”到標準輸出設備,並回車。然後結束 expect 腳本的運行。但是,如果用戶沒有輸入 hi 並回車,那麼 expect 會繼續等待”hi\n”;輸入其他的字符並不會影響到 expect 的工作。通常情況下,expect 會一直等會輸入,直到最終超時退出。此外, expect 還支持使用正則表達式來預防 expect 匹配到未預想到的輸入數據。 spawn 命令會調用另一個程序。它的第一個參數是要啓動程序的名字;剩餘的參數則會被傳遞給該程序做爲參數。比如 spawn ftp ftp.linux.ibm.com

  命令會衍生出一個 ftp 進程,並且將 ftp.linux.ibm.com 做爲參數傳遞給這個 ftp 進程。

  用戶通過 spawn,send 和 expect 這三個基本命令,就可以編寫一段 Expect 程序來實現自動化工作。

  Expect 腳本實現

  本節將利用基於用戶口令的安全認證方式,並使用 Expect 來實現 SSHD 服務器的自動化登錄過程,並在登錄的會話中實現命令在 SSHD 服務器端的執行。本文使用的具體實驗環境如下:用戶使用的 SSH 客戶端機器:操作系統均爲 RHELS5.3, IP 地址爲 192.168.0.3, Expect 版本爲 version 5.43.0;遠程的 SSHD 服務器:操作系統均爲 RHELS5.3,IP 地址爲 192.168.0.4,用戶名 / 密碼爲 root/123456。

  清單1.登錄 SSHD 服務器的自動化腳本 #!/usr/bin/expect # 設置超時時間爲 60 秒 set timeout 60 # 設置要登錄的主機 IP 地址 set host 192.168.0.4 # 設置以什麼名字的用戶登錄 set name root # 設置用戶名的登錄密碼 set password 123456 #spawn 一個 ssh 登錄進程 spawn ssh $host -l $name # 等待響應,第一次登錄往往會提示是否永久保存 RSA 到本機的 know hosts 列表中;等到回答後,在提示輸出密碼;之後就直接提示輸入密碼 expect { "(yes/no)?" { send "yes\n" expect "assword:" send "$pasword\n" } "assword:" { send "$password\n" } } expect "#" # 下面測試是否登錄到 $host send "uname\n" expect "Linux" send_user "Now you can do some operation on this terminal\n" # 這裏使用了 interact 命令,使執行完程序後,用戶可以在 $host 終端進行交互操作。 Interact

  如果要運行該腳本,可以參考如下的操作,假設 expect 腳本的文件名爲 t1.expect。另外,在運行該腳本之前,需要將 t1.expect 文件設置成可執行的模式 ;

  清單2.運行自動化登錄腳本的操作步驟 [root@redhat ~]chmod a+x t1.expect [root@redhat ~]./t1.expect spawn ssh 192.168.0.4 -l root [email protected]'s password: Last login: Fri Jun 12 15:36:01 2009 from 192.168.0.3 Red Hat Enterprise Linux Server release 5.1 (Tikanga) [root@c96m3h4ms01 ~]# uname Linux Now you can do some operation on this terminal [root@c96m3h4ms01 ~]#

  基於 SSH 交換 Key 自動化登錄

  SSH 證書簡介

  SSH 證書使用一對密鑰 : 私鑰(private key)和公鑰 (public key)。公鑰(public key)對數據進行加密而且只能用於加密,私鑰(private key)只能對所匹配的公鑰(public key)加密過的數據進行解密。私鑰(private key)只保存你獨有的一些祕密信息。SSH 客戶端用其向 SSHD 服務器證明自已的身份。公鑰是公開的,可以隨便將其放入 SSHD 服務器上自已的帳號中 , 在認證時,進行私鑰和公鑰協商,如果匹配,那麼身份就得以證明,認證就成功。

  目前所有的 OpenSSH 版本都應該既能使用 RSA 密鑰又能使用 DSA 密鑰。RSA 密鑰和 DSA 密鑰的生成命令和使用方法相同,本文僅介紹 RSA。

  如果採用 SSH 密鑰認證的方式實現自動化登錄,用戶可以參考下面的章節。

  生成密鑰對

  ssh-keygen 程序生成的 RSA 密鑰的文件名默認爲 id_rsa 和 id_rsa.pub,用戶也可以將其更改爲別的名稱。下面”清單 3. 生成密鑰對”的操作過程將採用系統的默認值。

  清單3. 生成密鑰對 [root@redhat ~]# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): <--- 可以不輸入密碼 Enter same passphrase again: <--- 可以不輸入密碼 Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: 4b:70:20:de:89:92:a9:fe:21:a4:9b:7c:6b:65:ae:e0 root@redhat [root@redhat ~]# ls -al .ssh total 20 drwx------ 2 root root 4096 May 10 02:51 . drwxr-x--- 11 root root 4096 May 10 02:51 .. -rw------- 1 root root 1675 May 10 02:51 id_rsa -rw-r--r-- 1 root root 397 May 10 02:51 id_rsa.pub

  如果 ssh 目錄不存在,程序爲自動創建本地 SSH 目錄 ~/.ssh,並將所生成的密鑰分成兩個文件存儲,私鑰爲 id_rsa,公鑰爲 id_rsa.pub。

  配置自動化登錄

  在配置自動化登錄的過程中,賬戶對應的公鑰需要被添加到 SSHD 服務器端的配置文件。在 3.0 版本的 OPENSSH 中,用戶需要修改的文件爲 authorized_keys,早於 3.0 的版本則使用 authorized_keys2 文件。將在客戶端生成的 id_rsa.pub 文件內容加入到 authorized_keys 或者 authorized_keys2 文件中即可完成配置工作。

  爲安全起見,要確保 $HOME/.ssh 目錄的安全,只有所有者纔有 權寫入。如果遠程用戶的 SSH 配置文件的權限設置不當,服務器可能會拒絕進行認證。

  下面是配置自動化登錄的具體過程,其場景如下:

  Openssh 爲 OpenSSH_4.3p2SSH,將以 root 用戶登錄到 SSHD 服務器(192.168.0.4)上,因此公鑰的內容將存放在 root/.ssh/authorized_keys。

  清單4. 終端操作記錄 [root@redhat ~]# scp /root/.ssh/id_rsa.pub [email protected]:/tmp [root@redhat .ssh]# ssh 192.168.0.4 [email protected]'s password: ****** [root@server ~]# cat /tmp/id_rsa.pub >> /root/.ssh/authorized_keys

  如果用戶在生成 rsa 和 id_rsa.pub 的時候沒有輸入密碼,可以直接使用“ssh [email protected]”登錄,而不用輸入密碼。

  而如果用戶在生成 rsa 和 id_rsa.pub 的時候輸入了密碼,需要進行以下兩步操作: 啓用 ssh-agent 認證代理 ,

  清單5. 終端操作記錄 [root@redhat ~]# ssh-agent $SHELL

  (2) 使用 ssh-add, 裝入私鑰,並輸入生成 rsa 和 id_rsa.pub 時輸入的密碼

  清單6. 終端操作記錄 [root@redhat ~]# ssh-add Enter passphrase for /root/.ssh/id_rsa: Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa) Identity added: /root/.ssh/id_dsa (/root/.ssh/id_dsa) [root@redhat ~]# ssh 192.168.0.4 Last login: Sat May 16 11:37:39 2009 from redhat

  把私鑰保存在內存中,爲認證提供服務,之後以 root 用戶 ssh 登錄時,就不用重複輸入密碼。其生命週期爲 ssh-agent 啓動的那個 shell,當用戶退出該 shell 時,需要重新執行 ssh-agent 和 ssh-add。

  只要密鑰配置好,以後登錄就是自動化了。因此本部分登錄過程不需要用腳本來實現,實現了前期拷貝 SSH key 到遠程服務器,並添加到相應的位置,並測試自動登錄是否成功。 腳本實現配置自動化登錄

  本節的腳本實現基於 SSH key 交換的安全認證方式,並利用 Expect 來實現自動化登錄。本節所實現的腳本可以運行在以下的實驗環境中:用戶使用的 SSH 客戶端機器:操作系統均爲 RHELS5.3, IP 地址爲 192.168.0.3, Expect 版本爲 version 5.43.0;遠程的 SSHD 服務器:操作系統均爲 RHELS5.3,IP 地址爲 192.168.0.4,用戶名 / 密碼爲 root/123456。

  Expect 腳本的內容如下:

  清單7.基於 SSH key 交換的自動化登錄腳本 #!/usr/bin/expect # 判斷輸入的參數是否爲 3 個,如果不爲 3 個,就打印錯誤信息,退出該程序。 if { $argc != 3 } { puts stderr "Usage: test1 host-address username host-password\n" exit 1 } # 設置超時時間爲 60 秒 set timeout 60 # 將命令行輸入的第一個參數作爲將要登錄的 SSHD 服務器 set host [lindex $argv 0] # 第二個參數是用戶名,賦值給 name, 之後用 $name 格式來使用 set name [lindex $argv 1] # 第三個參數是以 $name 登錄 $host 的口令 set password [lindex $argv 2] ##set timeout 60 ##set password "cluster" ##set name “root” ##set host "192.168.0.4" #root 用戶的 rsa key 放在 /root/.ssh 中,其他用戶則放在 /home/$name/.ssh if { $name == "root"} { spawn scp /$name/.ssh/id_rsa.pub $name@$host:/tmp } else { spawn scp /home/$name/.ssh/id_rsa.pub $name@$host:/tmp } # 等待上個命令的響應 expect { "(yes/no)?" { send "yes\n" expect "assword:" send "$pasword\n" } "assword:" { send "$password\n" } } # 輸入密碼後,拷貝成功,出現 100% 字符串,作爲預期響應 expect "100%" # 調用 ssh 以 $name 用戶名登錄到 $host 上 spawn ssh $host – l$name # 期待提示出入密碼的響應 expect "assword:" # 接收密碼 send "$password\n" expect ":~#" # 將剛剛拷貝的 rsa key 添加到用戶的 home 目錄下的 ./ssh/authorized_keys if { $name == "root"} { send "cat /tmp/id_rsa.pub >> /root/.ssh/authorized_keys\n" } else { send "cat /tmp/id_rsa.pub >> /home/$name/.ssh/authorized_keys\n" } expect ":~#" # 操作成功後,退回 SSH 客戶端機器 send "exit\n" expect "#" # 下面將測試能否自動登錄,不用輸入密碼 spawn ssh $host – l$name expect { "Welcome" { send_user "Auto login the server successfully!" } "assword:" { send_user "fa.Unix/Linux 系統自動化管理: 遠程登錄篇 .iled to login the server!" } } send "ls\n" expect ":~#" # 退出 $host send "exit\n" # 程序結束 expect eof

  清單 7 基於 SSH key 交換的自動化登錄腳本註釋掉了主機名,用戶名和密碼,因此用戶在運行腳本時需要手工輸入主機名,用戶名和密碼。一旦 SSH Key 的交換完成,用戶就可以直接運行 “ssh host-address – l username”實現自動化登錄,而不再需要輸入用戶名密碼。 小結 本文做爲 Unix/Linux 系統管理自動化系列中的一篇,主要講述如何利用 Expect 腳本來實現遠程服務器系統的自動化登錄和在遠程系統上執行命令。

  需要讀者注意的是,採用基於用戶口令的安全認證方式時,將用戶名和登錄密碼尤其是 root 用戶的密碼以明文的形式存放在 Expect 腳本中是一種非常不安全的行爲,可能會引起用戶名和密碼的泄露;如果遠端的服務器需要特別安全的防護措施,那麼用戶可以採取利用 SSH key 交換的安全認證方式來實現自動化登錄。這樣既方便了系統管理,同時又能保證系統安全。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章