歡迎轉載!轉載時請註明出處:http://blog.csdn.net/nfer_zhuang/article/details/42646849linux
我在工做中常常要將一些文件傳輸到另一個服務器上,並且都是Linux的命令行環境,那麼對於我來說scp就是最直接有效的方法了,其餘諸如FTP、SMB以及Winscp這些有界面的文件傳輸工具到反而有些多餘了。算法
使用過scp的都知道須要指定遠端服務器的賬號並手動輸入密碼,那麼如何避免每次都須要輸入密碼這個操做呢?下面就給出兩種方案進行解決。shell
在這裏先介紹兩個概念:SSH公鑰(~/.ssh/id_rsa.pub)和公鑰受權文件(~/.ssh/authorized_keys),這兩個文件的做用具體能夠參考ssh的man手冊:安全
~/.ssh/id_rsa.pub
Contains the public key for authentication. These files are not sensitive and can (but need not) be readable by anyone.
~/.ssh/authorized_keys
Lists the public keys (DSA/ECDSA/RSA) that can be used for logging in as this user. The format of this file is described in the sshd(8) manual page. This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others.ruby
從描述中咱們能夠知道,~/.ssh/id_rsa.pub文件中包含了認證的公鑰信息,並且該文件能夠被任何人讀取;而~/.ssh/authorized_keys文件中則列舉了登陸用戶的公鑰信息(換句話說就是使用這些公鑰信息能夠登陸當前設備),而爲了安全考慮,該文件通常建議只有本用戶能夠有讀寫權限。bash
提到公鑰對應的就會有私鑰,在談這兩個概念以前咱們先了解另一組概念:加密和認證。服務器
上面是從業務概念來上描述了加密和認證的區別,可是從具體技術實現上,認證使用的是加密中的非對稱加密算法來實現鑑權和認證的操做。dom
下面就分別描述一下,採用非對稱算法(即便用公鑰和私鑰)的加密和認證各自的過程。ssh
有兩個用戶Alice和Bob,Alice想把一段數據加密後發送給Bob(注意這裏強調的是數據的安全性),那麼如何保證除了Bob以外的人即便竊取了數據也沒法解密獲得原始的數據?基於公鑰和私鑰的加密能夠完成這個需求,具體流程以下:ide
仍是Alice和Bob,Alice想把一段數據發送給Bob(注意這裏並不強調數據的安全性),當Bob收到數據時如何判斷該數據確實是Alic發送的且傳輸過程當中沒有被篡改?基於公鑰和私鑰的認證能夠完成這個需求,具體流程以下:
瞭解了公鑰/私鑰以及加密/認證這些概念後,咱們就能夠在scp中使用公鑰/私鑰來創建一個信任關係,從而在數據傳輸時完成自動認證而無需輸入密碼。
因此這裏的須要作的就是:
在Linux上使用ssh-keygen工具來生成公私鑰對,在man手冊中關於ssh-keygen工具的說明以下:
ssh-keygen : authentication key generation, management and conversion
-t type
Specifies the type of key to create. The possible values are 'rsa1' for protocol version 1 and 'dsa', 'ecdsa', 'ed25519', or 'rsa' for protocol version 2.
在上面提到了ssh-keygen支持rsa一、dsa、ecdsa、ed25519和rsa這幾種非對稱加密算法,其中最經常使用的就是RSA和DSA,好比使用RSA算法來生成公私鑰對的過程以下:
nfer@nfer-VirtualBox:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/nfer/.ssh/id_rsa):
Created directory '/home/nfer/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/nfer/.ssh/id_rsa.
Your public key has been saved in /home/nfer/.ssh/id_rsa.pub.
The key fingerprint is:
16:77:45:71:31:7c:67:4f:91:09:07:74:4d:30:83:48 nfer@nfer-VirtualBox
The key's randomart image is:
+--[ RSA 2048]----+
| .E..*@XO|
| . ..oBB|
| . . . o+|
| o . .|
| S |
| . |
| |
| |
| |
+-----------------+
nfer@nfer-VirtualBox:~$
將剛纔建立的~/.ssh/id_rsa.pub文件中的內容拷貝添加到B主機上的~/.ssh/authorized_keys文件中(若是沒有則建立一個),這個時候就創建了一條A-->B的信任關係。注意這個信任關係是有方向性的,若是要創建從B-->A的信任關係,則操做步驟和上面的相似,只不過要反過來。
創建好信任關係後,這個時候使用任何ssh相關的工具則都無需輸入遠端的登錄密碼(若是在建立公私鑰對時輸入了密碼,那麼這個時候還須要輸入這個密碼才能使用公私鑰對)。
其實上面的創建信任關係的作法是最方便和安全的作法,可是在有些場景下(好比遠端的authorized_keys是不能隨意更改的),那麼這個時候咱們就能夠藉助sshpass這個第三方工具來完成ssh鏈接時的密碼輸入。先看一下sshpass的man手冊中是如何描述的:
sshpass - noninteractive ssh password provider
從描述上就能夠清晰的瞭解到,sshpass的設計就是爲了使用非交互的場景下輸入ssh鏈接的密碼。
sshpass的使用比較簡單,先看一下幫助文檔:
nfer@nfer-VirtualBox:~$ sshpass
Usage: sshpass [-f|-d|-p|-e] [-hV] command parameters
-f filename Take password to use from file
-d number Use number as file descriptor for getting password
-p password Provide password as argument (security unwise)
-e Password is passed as env-var "SSHPASS"
With no parameters - password will be taken from stdin
-h Show help (this screen)
-V Print version information
At most one of -f, -d, -p or -e should be used
其中-p是直接指定密碼,-f是從文件中讀取密碼。那麼一個使用sshpass的簡單例子就是:
sshpass -p nferzhuang scp a.txt nferzhuang@192.168.1.101:/home/nferzhuang/a.txt
使用sshpass的好處就是方便直接,無需瞭解公私鑰、加密認證等相關知識,簡單易懂;可是使用sshpass最大的壞處就是再使用時會涉及到明文密碼,大大下降了安全性。
expect用於自動化地執行linux環境下的命令行交互任務,例如scp、ssh之類須要用戶手動輸入密碼而後確認的任務。有了這個工具,定義在scp過程當中可能遇到的狀況,而後編寫相應的處理語句,就能夠自動地完成scp操做了。
下面就是一個使用expect來完成scp時無需輸入密碼的腳本:
#!/usr/bin/expect
set timeout 10
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]
spawn scp $src_file $username@$host:$dest_file
expect {
"(yes/no)?"
{
send "yes\n"
expect "*assword:" { send "$password\n"}
}
"*assword:"
{
send "$password\n"
}
}
expect "100%"
expect eof
注意代碼剛開始的第一行,指定了expect的路徑,與shell腳本相同,這一句指定了程序在執行時到哪裏去尋找相應的啓動程序。代碼剛開始還設定了timeout的時間爲10秒,若是在執行scp任務時遇到了代碼中沒有指定的異常,則在等待10秒後該腳本的執行會自動終止。
從以上代碼剛開始的幾行能夠看出,我爲這個腳本設置了5個須要手動輸入的參數,分別爲:目標主機的IP、用戶名、密碼、本地文件路徑、目標主機中的文件路徑。若是將以上腳本保存爲expect_scp文件,則在shell下執行時須要按如下的規範來輸入命令:
./expect_scp 192.168.75.130 root 123456 /root/src_file /root/dest_file以上的命令執行後,將把本地/root目錄下的src_file文件拷貝到用戶名爲root,密碼爲123456的主機192.168.75.130中的/root下,同時還將這個源文件重命名爲dest_file。
使用expect須要瞭解的一點是:用expect速度會比較慢,由於須要等待返回的數據,而後輸入命令執行,沒有ssh密鑰登陸的快速。
注:關於expect部分詳細請參考《shell結合expect寫的批量scp腳本工具》
在本文中提供了三種方法來實現scp的時候無需輸入密碼的需求,從安全性和速度上考慮創建信任關係都是最佳的方法,至於在具體的環境中選擇什麼則由你本身來決定。