本文是 Unix/Linux 系統(tǒng)管理自動(dòng)化系列中的一篇,主要講述如何利用腳本來(lái)實(shí)現(xiàn)遠(yuǎn)程服務(wù)器系統(tǒng)的自動(dòng)化登錄和在遠(yuǎn)程系統(tǒng)上執(zhí)行命令。
Telnet 和 SSH 協(xié)議是 Internet 遠(yuǎn)程登錄服務(wù)的標(biāo)準(zhǔn)協(xié)議和主要方式,它們?yōu)橛脩籼峁┝嗽诒镜貦C(jī)器上完成遠(yuǎn)程機(jī)器上工作的能力。用戶使用 Telnet 或者 SSH 軟件連接遠(yuǎn)程服務(wù)器,在 Telnet 或者 SSH 軟件中輸入的命令就會(huì)在服務(wù)器上運(yùn)行。Telnet 協(xié)議本質(zhì)上是不安全的,因?yàn)樗褂妹魑膫魉蛿?shù)據(jù)、用戶賬號(hào)和口令,很容易受到中間人攻擊方式的攻擊;而 SSH 協(xié)議則是比較可靠、專為遠(yuǎn)程登錄會(huì)話和其他網(wǎng)絡(luò)服務(wù)提供安全性的協(xié)議。通過(guò) SSH 可以對(duì)所有傳輸?shù)臄?shù)據(jù)進(jìn)行加密,也能夠防止 DNS 欺騙和 IP 欺騙。本文主要針對(duì) SSH 協(xié)議進(jìn)行闡述,使用的 SSH 軟件是 OpenSSH,它是開(kāi)放源代碼的免費(fèi)的 SSH 替代軟件包。
用戶使用 Telnet 或者 SSH 登錄不同的操作系統(tǒng),會(huì)得到不同的返回信息。用戶可以編寫程序根據(jù)運(yùn)程登錄的返回信息進(jìn)行判斷和處理,從而實(shí)現(xiàn)遠(yuǎn)程服務(wù)器系統(tǒng)的自動(dòng)化登錄。本文將先介紹實(shí)現(xiàn)遠(yuǎn)程自動(dòng)化登錄用到的技術(shù),再詳細(xì)介紹如何實(shí)現(xiàn) Unix/Linux 系統(tǒng)間遠(yuǎn)程登錄自動(dòng)化。
遠(yuǎn)程系統(tǒng)自動(dòng)化登錄機(jī)制簡(jiǎn)介
所謂自動(dòng)化遠(yuǎn)程登錄,是指在用戶不干預(yù)的情況下,不需要手動(dòng)輸入密碼,就能登錄到遠(yuǎn)程系統(tǒng)。目前遠(yuǎn)程登錄工具有兩種安全認(rèn)證方式。
基于用戶口令的安全認(rèn)證
當(dāng)使用登錄賬戶登錄時(shí),根據(jù)提示輸入口令,SSH 就會(huì)用安全密碼認(rèn)證協(xié)議,將加密傳送給 SSHD 服務(wù)器。認(rèn)證成功后,就可以登錄到 SSHD 服務(wù)器。
針對(duì)這種安全認(rèn)證方式,可以讓程序自動(dòng)輸入用戶名和密碼,實(shí)現(xiàn)自動(dòng)化登錄。目前可以用 expect, C 或 Perl 來(lái)實(shí)現(xiàn)。如果采用 C, 需要很熟悉 TCP/IP 協(xié)議,實(shí)現(xiàn)起來(lái)比較復(fù)雜;如果用 expect, 由于 expect 是基于 Tcl 的,需要熟悉 Tcl 語(yǔ)法;如果用 perl 實(shí)現(xiàn),需要采用 perl 的 expect.pm 這個(gè)包。但需要用戶輸入口令,因此這種認(rèn)證方式存在著安全隱患。
基于 SSH key 交換的安全認(rèn)證方式
用戶需要先在 SSH 客戶端為登錄賬戶創(chuàng)建一對(duì)密匙:私鑰(private key)和公鑰 (public key),然后把公鑰傳送到要登錄的 SSHD 服務(wù)器上。當(dāng)用戶使用 SSH 客戶端登錄 SSHD 服務(wù)器時(shí),SSH 客戶端就會(huì)向 SSHD 服務(wù)器發(fā)出用登錄帳戶的密鑰進(jìn)行安全驗(yàn)證的請(qǐng)求;SSHD 服務(wù)器收到請(qǐng)求,先在登錄賬號(hào)的主目錄下尋找對(duì)應(yīng)的公鑰,并與客戶端發(fā)送過(guò)來(lái)的公鑰進(jìn)行對(duì)比;如果兩個(gè)密鑰一致,SSHD 服務(wù)器會(huì)用公鑰加密“質(zhì)詢”(challenge),發(fā)送給 SSH 客戶端;SSH 客戶端收到“質(zhì)詢”之后用客戶端的私鑰解密,再把它發(fā)送給 SSHD 服務(wù)器。這樣就完成了安全認(rèn)證的整個(gè)過(guò)程。
使用基于 SSH key 交換的認(rèn)證方式,用戶只要將在 SSH 客戶端生成的公鑰復(fù)制到遠(yuǎn)程的 SSHD 服務(wù)器。當(dāng)通過(guò) SSH 客戶端登錄 SSHD 服務(wù)器時(shí),用戶不需要輸入密碼,就可以自動(dòng)登錄到遠(yuǎn)程 SSHD 服務(wù)器。這種方式不僅簡(jiǎn)便,而且避免了用戶名和密碼的泄露,比第一種方式要安全。
![]() ![]() |
![]()
|
使用 Expect 的自動(dòng)化登錄
Expect 的基礎(chǔ)知識(shí)
Expect 是由 Don Libes 基于 Tcl 語(yǔ)言開(kāi)發(fā)的,并被廣泛應(yīng)用于交互式操作和自動(dòng)化測(cè)試的場(chǎng)景之中,它尤其適用于需要對(duì)多臺(tái)服務(wù)器執(zhí)行相同操作的環(huán)境中,可以大幅度得提高系統(tǒng)管理人員的工作效率。目前,大部分 Unix/Linux 系統(tǒng)安裝有 expect. 萬(wàn)一系統(tǒng)中沒(méi)有,可以從 http://expect.nist.gov/ 下載相應(yīng)的包安裝。
Expect 作為基于 Tcl 的高級(jí)語(yǔ)言,增加了一些特殊的語(yǔ)法。傳統(tǒng)意義上的 Expect 是以 Tcl 擴(kuò)展包的形式出現(xiàn)的,任何 Tcl 語(yǔ)言編寫的應(yīng)用程序都可以加載 Expect 功能;此外,Expect 已經(jīng)以模塊的方式移植到了 Perl 和 Python 語(yǔ)言中,因此用戶同樣可以在 Perl 和 Python 腳本中利用 Expect 強(qiáng)大的交互功能。
Send,expect 和 spwan 是 Expect 語(yǔ)言最基本的命令。其中,send 命令會(huì)發(fā)送字符串給指定進(jìn)程(process); expect 命令會(huì)等待接受該進(jìn)程返回的結(jié)果并且會(huì)根據(jù)返回的字符串來(lái)決定下一步的操作;而 spwan 命令可以發(fā)起一個(gè)進(jìn)程的運(yùn)行。
send 命令接收一個(gè)字符串做為參數(shù)并發(fā)送給指定的進(jìn)程;從
send “Hello world” |
這行代碼中,send 會(huì)送出字符串“Hello world”( 不帶引號(hào) )。如果 Expect 早已經(jīng)開(kāi)始與某一個(gè)程序進(jìn)行交互,那么這個(gè)字符串將被發(fā)送給該程序;而在通常情況下,這個(gè)字符串會(huì)被送到標(biāo)準(zhǔn)輸出設(shè)備。
expect 命令則等待一個(gè)響應(yīng),通常是來(lái)自于 Expect 正在與之交互的進(jìn)程,或者來(lái)自于標(biāo)準(zhǔn)輸入設(shè)備;它會(huì)等待一個(gè)指定的字符串或者滿足給定的正則表達(dá)式的任何字符串。我們可以創(chuàng)建一個(gè)名為 response.exp 的文件,來(lái)看 Expect 是如何處理的,其內(nèi)容如下:
#!expect – f expect “hi\n” send “hello there\n” |
然后在 shell 下面運(yùn)行 ”
expect response.exp”
,它會(huì)等待來(lái)自標(biāo)準(zhǔn)輸入設(shè)備的響應(yīng),直到用戶輸入 hi 并回車,它才會(huì)發(fā)送”hello there”到標(biāo)準(zhǔn)輸出設(shè)備,并回車。然后結(jié)束 expect 腳本的運(yùn)行。但是,如果用戶沒(méi)有輸入 hi 并回車,那么 expect 會(huì)繼續(xù)等待”hi\n”;輸入其他的字符并不會(huì)影響到 expect 的工作。通常情況下,expect 會(huì)一直等會(huì)輸入,直到最終超時(shí)退出。此外, expect 還支持使用正則表達(dá)式來(lái)預(yù)防 expect 匹配到未預(yù)想到的輸入數(shù)據(jù)。
spawn 命令會(huì)調(diào)用另一個(gè)程序。它的第一個(gè)參數(shù)是要啟動(dòng)程序的名字;剩余的參數(shù)則會(huì)被傳遞給該程序做為參數(shù)。比如
spawn ftp ftp.linux.ibm.com |
命令會(huì)衍生出一個(gè) ftp 進(jìn)程,并且將 ftp.linux.ibm.com 做為參數(shù)傳遞給這個(gè) ftp 進(jìn)程。
用戶通過(guò) spawn,send 和 expect 這三個(gè)基本命令,就可以編寫一段 Expect 程序來(lái)實(shí)現(xiàn)自動(dòng)化工作。
Expect 腳本實(shí)現(xiàn)
本節(jié)將利用基于用戶口令的安全認(rèn)證方式,并使用 Expect 來(lái)實(shí)現(xiàn) SSHD 服務(wù)器的自動(dòng)化登錄過(guò)程,并在登錄的會(huì)話中實(shí)現(xiàn)命令在 SSHD 服務(wù)器端的執(zhí)行。本文使用的具體實(shí)驗(yàn)環(huán)境如下:用戶使用的 SSH 客戶端機(jī)器:操作系統(tǒng)均為 RHELS5.3, IP 地址為 192.168.0.3, Expect 版本為 version 5.43.0;遠(yuǎn)程的 SSHD 服務(wù)器:操作系統(tǒng)均為 RHELS5.3,IP 地址為 192.168.0.4,用戶名 / 密碼為 root/123456。
清單1.登錄 SSHD 服務(wù)器的自動(dòng)化腳本
#!/usr/bin/expect # 設(shè)置超時(shí)時(shí)間為 60 秒 set timeout 60 # 設(shè)置要登錄的主機(jī) IP 地址 set host 192.168.0.4 # 設(shè)置以什么名字的用戶登錄 set name root # 設(shè)置用戶名的登錄密碼 set password 123456 #spawn 一個(gè) ssh 登錄進(jìn)程 spawn ssh $host -l $name # 等待響應(yīng),第一次登錄往往會(huì)提示是否永久保存 RSA 到本機(jī)的 know hosts 列表中;等到回答后,在提示輸出密碼;之后就直接提示輸入密碼 expect { "(yes/no)?" { send "yes\n" expect "assword:" send "$pasword\n" } "assword:" { send "$password\n" } } expect "#" # 下面測(cè)試是否登錄到 $host send "uname\n" expect "Linux" send_user "Now you can do some operation on this terminal\n" # 這里使用了 interact 命令,使執(zhí)行完程序后,用戶可以在 $host 終端進(jìn)行交互操作。 Interact |
如果要運(yùn)行該腳本,可以參考如下的操作,假設(shè) expect 腳本的文件名為 t1.expect。另外,在運(yùn)行該腳本之前,需要將 t1.expect 文件設(shè)置成可執(zhí)行的模式 ;
清單2.運(yùn)行自動(dòng)化登錄腳本的操作步驟
[root@redhat ~]chmod a+x t1.expect [root@redhat ~]./t1.expect spawn ssh 192.168.0.4 -l root root@192.168.0.4'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 自動(dòng)化登錄
SSH 證書簡(jiǎn)介
SSH 證書使用一對(duì)密鑰 : 私鑰(private key)和公鑰 (public key)。公鑰(public key)對(duì)數(shù)據(jù)進(jìn)行加密而且只能用于加密,私鑰(private key)只能對(duì)所匹配的公鑰(public key)加密過(guò)的數(shù)據(jù)進(jìn)行解密。私鑰(private key)只保存你獨(dú)有的一些秘密信息。SSH 客戶端用其向 SSHD 服務(wù)器證明自已的身份。公鑰是公開(kāi)的,可以隨便將其放入 SSHD 服務(wù)器上自已的賬號(hào)中 , 在認(rèn)證時(shí),進(jìn)行私鑰和公鑰協(xié)商,如果匹配,那么身份就得以證明,認(rèn)證就成功。
目前所有的 OpenSSH 版本都應(yīng)該既能使用 RSA 密鑰又能使用 DSA 密鑰。RSA 密鑰和 DSA 密鑰的生成命令和使用方法相同,本文僅介紹 RSA。
如果采用 SSH 密鑰認(rèn)證的方式實(shí)現(xiàn)自動(dòng)化登錄,用戶可以參考下面的章節(jié)。
生成密鑰對(duì)
ssh-keygen 程序生成的 RSA 密鑰的文件名默認(rèn)為 id_rsa 和 id_rsa.pub,用戶也可以將其更改為別的名稱。下面”清單 3. 生成密鑰對(duì)”的操作過(guò)程將采用系統(tǒng)的默認(rèn)值。
清單3. 生成密鑰對(duì)
[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 目錄不存在,程序?yàn)樽詣?dòng)創(chuàng)建本地 SSH 目錄 ~/.ssh,并將所生成的密鑰分成兩個(gè)文件存儲(chǔ),私鑰為 id_rsa,公鑰為 id_rsa.pub。
配置自動(dòng)化登錄
在配置自動(dòng)化登錄的過(guò)程中,賬戶對(duì)應(yīng)的公鑰需要被添加到 SSHD 服務(wù)器端的配置文件。在 3.0 版本的 OPENSSH 中,用戶需要修改的文件為 authorized_keys,早于 3.0 的版本則使用 authorized_keys2 文件。將在客戶端生成的 id_rsa.pub 文件內(nèi)容加入到 authorized_keys 或者 authorized_keys2 文件中即可完成配置工作。
為安全起見(jiàn),要確保 $HOME/.ssh 目錄的安全,只有所有者才有 權(quán)寫入。如果遠(yuǎn)程用戶的 SSH 配置文件的權(quán)限設(shè)置不當(dāng),服務(wù)器可能會(huì)拒絕進(jìn)行認(rèn)證。
下面是配置自動(dòng)化登錄的具體過(guò)程,其場(chǎng)景如下:
Openssh 為 OpenSSH_4.3p2SSH,將以 root 用戶登錄到 SSHD 服務(wù)器(192.168.0.4)上,因此公鑰的內(nèi)容將存放在 root/.ssh/authorized_keys。
清單4. 終端操作記錄
[root@redhat ~]# scp /root/.ssh/id_rsa.pub root@192.168.0.4:/tmp [root@redhat .ssh]# ssh 192.168.0.4 root@192.168.0.4's password: ****** [root@server ~]# cat /tmp/id_rsa.pub >> /root/.ssh/authorized_keys |
如果用戶在生成 rsa 和 id_rsa.pub 的時(shí)候沒(méi)有輸入密碼,可以直接使用“ssh root@192.168.0.4”登錄,而不用輸入密碼。
而如果用戶在生成 rsa 和 id_rsa.pub 的時(shí)候輸入了密碼,需要進(jìn)行以下兩步操作:
清單5. 終端操作記錄
[root@redhat ~]# ssh-agent $SHELL |
(2) 使用 ssh-add, 裝入私鑰,并輸入生成 rsa 和 id_rsa.pub 時(shí)輸入的密碼
清單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 |
把私鑰保存在內(nèi)存中,為認(rèn)證提供服務(wù),之后以 root 用戶 ssh 登錄時(shí),就不用重復(fù)輸入密碼。其生命周期為 ssh-agent 啟動(dòng)的那個(gè) shell,當(dāng)用戶退出該 shell 時(shí),需要重新執(zhí)行 ssh-agent 和 ssh-add。
只要密鑰配置好,以后登錄就是自動(dòng)化了。因此本部分登錄過(guò)程不需要用腳本來(lái)實(shí)現(xiàn),實(shí)現(xiàn)了前期拷貝 SSH key 到遠(yuǎn)程服務(wù)器,并添加到相應(yīng)的位置,并測(cè)試自動(dòng)登錄是否成功。
![]() ![]() |
![]()
|
腳本實(shí)現(xiàn)配置自動(dòng)化登錄
本節(jié)的腳本實(shí)現(xiàn)基于 SSH key 交換的安全認(rèn)證方式,并利用 Expect 來(lái)實(shí)現(xiàn)自動(dòng)化登錄。本節(jié)所實(shí)現(xiàn)的腳本可以運(yùn)行在以下的實(shí)驗(yàn)環(huán)境中:用戶使用的 SSH 客戶端機(jī)器:操作系統(tǒng)均為 RHELS5.3, IP 地址為 192.168.0.3, Expect 版本為 version 5.43.0;遠(yuǎn)程的 SSHD 服務(wù)器:操作系統(tǒng)均為 RHELS5.3,IP 地址為 192.168.0.4,用戶名 / 密碼為 root/123456。
Expect 腳本的內(nèi)容如下:
清單7.基于 SSH key 交換的自動(dòng)化登錄腳本
#!/usr/bin/expect # 判斷輸入的參數(shù)是否為 3 個(gè),如果不為 3 個(gè),就打印錯(cuò)誤信息,退出該程序。 if { $argc != 3 } { puts stderr "Usage: test1 host-address username host-password\n" exit 1 } # 設(shè)置超時(shí)時(shí)間為 60 秒 set timeout 60 # 將命令行輸入的第一個(gè)參數(shù)作為將要登錄的 SSHD 服務(wù)器 set host [lindex $argv 0] # 第二個(gè)參數(shù)是用戶名,賦值給 name, 之后用 $name 格式來(lái)使用 set name [lindex $argv 1] # 第三個(gè)參數(shù)是以 $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 } # 等待上個(gè)命令的響應(yīng) expect { "(yes/no)?" { send "yes\n" expect "assword:" send "$pasword\n" } "assword:" { send "$password\n" } } # 輸入密碼后,拷貝成功,出現(xiàn) 100% 字符串,作為預(yù)期響應(yīng) expect "100%" # 調(diào)用 ssh 以 $name 用戶名登錄到 $host 上 spawn ssh $host – l$name # 期待提示出入密碼的響應(yīng) 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 客戶端機(jī)器 send "exit\n" expect "#" # 下面將測(cè)試能否自動(dòng)登錄,不用輸入密碼 spawn ssh $host – l$name expect { "Welcome" { send_user "Auto login the server successfully!" } "assword:" { send_user "failed to login the server!" } } send "ls\n" expect ":~#" # 退出 $host send "exit\n" # 程序結(jié)束 expect eof |
清單 7 基于 SSH key 交換的自動(dòng)化登錄腳本注釋掉了主機(jī)名,用戶名和密碼,因此用戶在運(yùn)行腳本時(shí)需要手工輸入主機(jī)名,用戶名和密碼。一旦 SSH Key 的交換完成,用戶就可以直接運(yùn)行 “ssh host-address – l username”實(shí)現(xiàn)自動(dòng)化登錄,而不再需要輸入用戶名密碼。
![]() ![]() |
![]()
|
小結(jié)
本文做為 Unix/Linux 系統(tǒng)管理自動(dòng)化系列中的一篇,主要講述如何利用 Expect 腳本來(lái)實(shí)現(xiàn)遠(yuǎn)程服務(wù)器系統(tǒng)的自動(dòng)化登錄和在遠(yuǎn)程系統(tǒng)上執(zhí)行命令。
需要讀者注意的是,采用基于用戶口令的安全認(rèn)證方式時(shí),將用戶名和登錄密碼尤其是 root 用戶的密碼以明文的形式存放在 Expect 腳本中是一種非常不安全的行為,可能會(huì)引起用戶名和密碼的泄露;如果遠(yuǎn)端的服務(wù)器需要特別安全的防護(hù)措施,那么用戶可以采取利用 SSH key 交換的安全認(rèn)證方式來(lái)實(shí)現(xiàn)自動(dòng)化登錄。這樣既方便了系統(tǒng)管理,同時(shí)又能保證系統(tǒng)安全。
聯(lián)系客服