第1章 ssh命令和SSH服務詳解

基礎服務類系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.htmlhtml


本文對SSH鏈接驗證機制進行了很是詳細的分析,還詳細介紹了ssh客戶端工具的各類功能,相信能讓各位對ssh有個全方位較透徹的瞭解,而不是僅僅只會用它來鏈接遠程主機。linux

另外,本人翻譯了ssh客戶端命令的man文檔,如本文有不理解的地方,能夠參考man文檔手冊:ssh中文手冊算法

SSH系列文章: shell

SSH基礎:SSH和SSH服務windows

SSH轉發代理:ssh-agent用法詳解api

SSH隧道:端口轉發功能詳解安全

1.1 非對稱加密基礎知識

對稱加密:加密和解密使用同樣的算法,只要解密時提供與加密時一致的密碼就能夠完成解密。例如QQ登陸密碼,銀行卡密碼,只要保證密碼正確就能夠。bash

非對稱加密:經過公鑰(public key)和私鑰(private key)來加密、解密。公鑰加密的內容可使用私鑰解密,私鑰加密的內容可使用公鑰解密。通常使用公鑰加密,私鑰解密,但並不是絕對如此,例如CA簽署證書時就是使用本身的私鑰加密。在接下來介紹的SSH服務中,雖然一直建議分發公鑰,但也能夠分發私鑰。服務器

因此,若是A生成了(私鑰A,公鑰A),B生成了(私鑰B,公鑰B),那麼A和B之間的非對稱加密會話情形包括:網絡

(1).A將本身的公鑰A分發給B,B拿着公鑰A將數據進行加密,並將加密的數據發送給A,A將使用本身的私鑰A解密數據。

(2).A將本身的公鑰A分發給B,並使用本身的私鑰A加密數據,而後B使用公鑰A解密數據。

(3).B將本身的公鑰B分發給A,A拿着公鑰B將數據進行加密,並將加密的數據發送給B,B將使用本身的私鑰B解密數據。

(4).B將本身的公鑰B分發給A,並使用本身的私鑰B加密數據,而後A使用公鑰B解密數據。

雖然理論上支持4種情形,但在SSH的身份驗證階段,SSH只支持服務端保留公鑰,客戶端保留私鑰的方式因此方式只有兩種:客戶端生成密鑰對,將公鑰分發給服務端;服務端生成密鑰對,將私鑰分發給客戶端。只不過出於安全性和便利性,通常都是客戶端生成密鑰對並分發公鑰。後文將給出這兩種分發方式的示例。

1.2 SSH概要

(1).SSH是傳輸層和應用層上的安全協議,它只能經過加密鏈接雙方會話的方式來保證鏈接的安全性。當使用ssh鏈接成功後,將創建客戶端和服務端之間的會話,該會話是被加密的,以後客戶端和服務端的通訊都將經過會話傳輸。

(2).SSH服務的守護進程爲sshd,默認監聽在22端口上。

(3).全部ssh客戶端工具,包括ssh命令,scp,sftp,ssh-copy-id等命令都是藉助於ssh鏈接來完成任務的。也就是說它們都鏈接服務端的22端口,只不過鏈接上以後將待執行的相關命令轉換傳送到遠程主機上,由遠程主機執行。

(4).ssh客戶端命令(ssh、scp、sftp等)讀取兩個配置文件:全局配置文件/etc/ssh/ssh_config和用戶配置文件~/.ssh/config。實際上命令行上也能夠傳遞配置選項。它們生效的優先級是:命令行配置選項 > ~/.ssh/config > /etc/ssh/ssh_config。

(5).ssh涉及到兩個驗證:主機驗證和用戶身份驗證。經過主機驗證,再經過該主機上的用戶驗證,就能惟一肯定該用戶的身份。一個主機上能夠有不少用戶,因此每臺主機的驗證只需一次,但主機上每一個用戶都須要單獨進行用戶驗證。

(6).ssh支持多種身份驗證,最經常使用的是密碼驗證機制和公鑰認證機制,其中公鑰認證機制在某些場景實現雙機互信時幾乎是必須的。雖然經常使用上述兩種認證機制,但認證時的順序默認是gssapi-with-mic,hostbased,publickey,keyboard-interactive,password。注意其中的主機認證機制hostbased不是主機驗證,因爲主機認證用的很是少(它所讀取的認證文件爲/etc/hosts.equiv或/etc/shosts.equiv),因此網絡上比較少見到它的相關介紹。總的來講,經過在ssh配置文件(注意不是sshd配置文件)中使用指令PreferredAuthentications改變認證順序不失爲一種驗證的效率提高方式。

(7).ssh客戶端其實有很多很強大的功能,如端口轉發(隧道模式)、代理認證、鏈接共享(鏈接複用)等。

(8).ssh服務端配置文件爲/etc/ssh/sshd_config,注意和客戶端的全局配置文件/etc/ssh/ssh_config區分開來。

(9).很重要卻幾乎被人忽略的一點,ssh登陸時會請求分配一個僞終端。但有些身份認證程序如sudo能夠禁止這種類型的終端分配,致使ssh鏈接失敗。例如使用ssh執行sudo命令時sudo就會驗證是否要分配終端給ssh。

1.3 SSH認證過程分析

假如從客戶端A(172.16.10.5)鏈接到服務端B(172.16.10.6)上,將包括主機驗證和用戶身份驗證兩個過程,以RSA非對稱加密算法爲例。

[root@xuexi ~]# ssh 172.16.10.6

服務端B上首先啓動了sshd服務程序,即開啓了ssh服務,打開了22端口(默認)。

1.3.1 主機驗證過程

當客戶端A要鏈接B時,首先將進行主機驗證過程,即判斷主機B是不是否曾經鏈接過。

判斷的方法是讀取~/.ssh/known_hosts文件和/etc/ssh/known_hosts文件,搜索是否有172.16.10.6的主機信息(主機信息稱爲host key,表示主機身份標識)。若是沒有搜索到對應該地址的host key,則詢問是否保存主機B發送過來的host key,若是搜索到了該地址的host key,則將此host key和主機B發送過來的host key作比對,若是徹底相同,則表示主機A曾經保存過主機B的host key,無需再保存,直接進入下一個過程——身份驗證,若是不徹底相同,則提示是否保存主機B當前使用的host key。

詢問是否保存host key的過程以下所示:

[root@xuexi ~]# ssh 172.16.10.6 
The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.
RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes

或者windows端使用圖形界面ssh客戶端工具時:

在說明身份驗證過程前,先看下known_hosts文件的格式。以~/.ssh/known_hosts爲例。

[root@xuexi ~]# cat ~/.ssh/known_hosts
172.16.10.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz

該文件中,每行一個host key,行首是主機名,它是搜索host key時的索引,主機名後的內容便是host key部分。以此文件爲例,它表示客戶端A曾經試圖鏈接過172.16.10.6這個主機B,並保存了主機B的host key,下次鏈接主機B時,將搜索主機B的host key,並與172.16.10.6傳送過來的host key作比較,若是能匹配上,則表示該host key確實是172.16.10.6當前使用的host key,若是不能匹配上,則表示172.16.10.6修改過host key,或者此文件中的host key被修改過。

那麼主機B當前使用的host key保存在哪呢?在/etc/ssh/ssh_host*文件中,這些文件是服務端(此處即主機B)的sshd服務程序啓動時重建的。以rsa算法爲例,則保存在/etc/ssh/ssh_host_rsa_key和/etc/ssh/ssh_host_rsa_key.pub中,其中公鑰文件/etc/ssh/ssh_host_rsa_key.pub中保存的就是host key。

[root@xuexi ~]# cat /etc/ssh/ssh_host_rsa_key.pub   # 在主機B上查看
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz

發現/etc/ssh/ssh_host_rsa_key.pub文件內容和~/.ssh/known_hosts中該主機的host key部分徹底一致,只不過~/.ssh/known_hosts中除了host key部分還多了一個主機名,這正是搜索主機時的索引。

綜上所述,在主機驗證階段,服務端持有的是私鑰,客戶端保存的是來自於服務端的公鑰。注意,這和身份驗證階段密鑰的持有方是相反的。

實際上,ssh並不是直接比對host key,由於host key太長了,比對效率較低。因此ssh將host key轉換成host key指紋,而後比對兩邊的host key指紋便可。指紋格式以下:

[root@xuexi ~]# ssh 172.16.10.6 
The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.
RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes

host key的指紋可由ssh-kegen計算得出。例如,下面分別是主機A(172.16.10.5)保存的host key指紋,和主機B(172.16.10.6)當前使用的host key的指紋。可見它們是徹底同樣的。

[root@xuexi ~]# ssh-keygen -l -f ~/.ssh/known_hosts
2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf 172.16.10.6 (RSA)

[root@xuexi ~]# ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf   (RSA)

其實ssh還支持host key模糊比較,即將host key轉換爲圖形化的指紋。這樣,圖形結果相差大的很容易就比較出來。之因此說是模糊比較,是由於對於很是近似的圖形化指紋,ssh可能會誤判。圖形化指紋的生成方式以下:只需在上述命令上加一個"-v"選項進入詳細模式便可。

[root@xuexi ~]# ssh-keygen -lv -f ~/.ssh/known_hosts
2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf 172.16.10.6 (RSA)
+--[ RSA 2048]----+
|                 |
|                 |
|           .     |
|          o      |
|        S. . +   |
|      . +++ + .  |
|       B.+.= .   |
|      + B.  +.   |
|       o.+.  oE  |
+-----------------+

更詳細的主機認證過程是:先進行密鑰交換(DH算法)生成session key(rfc文檔中稱之爲shared secret),而後從文件中讀取host key,並用host key對session key進行簽名,而後對簽名後的指紋進行判斷。(In SSH, the key exchange is signed with the host key to provide host authentication.來源:https://tools.ietf.org/html/rfc4419)

過程以下圖:

1.3.2 身份驗證過程

主機驗證經過後,將進入身份驗證階段。SSH支持多種身份驗證機制,它們的驗證順序以下:gssapi-with-mic,hostbased,publickey,keyboard-interactive,password,但常見的是密碼認證機制(password)和公鑰認證機制(public key)。當公鑰認證機制未經過時,再進行密碼認證機制的驗證。這些認證順序能夠經過ssh配置文件(注意,不是sshd的配置文件)中的指令PreferredAuthentications改變。

若是使用公鑰認證機制,客戶端A須要將本身生成的公鑰(~/.ssh/id_rsa.pub)發送到服務端B的~/.ssh/authorized_keys文件中。當進行公鑰認證時,客戶端將告訴服務端要使用哪一個密鑰對,並告訴服務端它已經訪問過密鑰對的私鑰部分~/.ssh/id_rsa(客戶端從本身的私鑰中推導,或者從私鑰同目錄下讀取公鑰,計算公鑰指紋後發送給服務端。因此有些版本的ssh不要求存在公鑰文件,有些版本的ssh則要求私鑰和公鑰同時存在且在同目錄下),而後服務端將檢測密鑰對的公鑰部分,判斷該客戶端是否容許經過認證。若是認證不經過,則進入下一個認證機制,以密碼認證機制爲例。

當使用密碼認證時,將提示輸入要鏈接的遠程用戶的密碼,輸入正確則驗證經過。

1.3.3 驗證經過

當主機驗證和身份驗證都經過後,分兩種狀況:直接登陸或執行ssh命令行中給定某個命令。如:

[root@xuexi ~]# ssh 172.16.10.6 
[root@xuexi ~]# ssh 172.16.10.6  'echo "haha"'

(1).前者ssh命令行不帶任何命令參數,表示使用遠程主機上的某個用戶(此處爲root用戶)登陸到遠程主機172.16.10.6上,因此遠程主機會爲ssh分配一個僞終端,並進入bash環境。

(2).後者ssh命令行帶有命令參數,表示在遠程主機上執行給定的命令【echo "haha"】。ssh命令行上的遠程命令是經過fork ssh-agent獲得的子進程來執行的,當命令執行完畢,子進程消逝,ssh也將退出,創建的會話和鏈接也都將關閉。(之因此要在這裏明確說明遠程命令的執行過程,是爲了說明後文將介紹的ssh實現端口轉發時的注意事項)

實際上,在ssh鏈接成功,登陸或執行命令行中命令以前,能夠指定要在遠程執行的命令,這些命令放在~/.ssh/rc或/etc/ssh/rc文件中,也就是說,ssh鏈接創建以後作的第一件事是在遠程主機上執行這兩個文件中的命令。

1.4 各類文件分佈

以主機A鏈接主機B爲例,主機A爲SSH客戶端,主機B爲SSH服務端。

在服務端即主機B上:

  • /etc/ssh/sshd_config  :ssh服務程序sshd的配置文件。
  • /etc/ssh/ssh_host_*   :服務程序sshd啓動時生成的服務端公鑰和私鑰文件。如ssh_host_rsa_key和ssh_host_rsa_key.pub。
  •                                   :其中.pub文件是主機驗證時的host key,將寫入到客戶端的~/.ssh/known_hosts文件中。
  •                                   :其中私鑰文件嚴格要求權限爲600,若不是則sshd服務可能會拒絕啓動。
  • ~/.ssh/authorized_keys:保存的是基於公鑰認證機制時來自於客戶端的公鑰。在基於公鑰認證機制認證時,服務端將讀取該文件。

在客戶端即主機A上:

  • /etc/ssh/ssh_config    :客戶端的全局配置文件。
  • ~/.ssh/config              :客戶端的用戶配置文件,生效優先級高於全局配置文件。通常該文件默認不存在。該文件對權限有嚴
  •                                   :格要求只對全部者有讀/寫權限,對其餘人徹底拒絕寫權限。
  • ~/.ssh/known_hosts   :保存主機驗證時服務端主機host key的文件。文件內容來源於服務端的ssh_host_rsa_key.pub文件。
  • /etc/ssh/known_hosts:全局host key保存文件。做用等同於~/.ssh/known_hosts。
  • ~/.ssh/id_rsa              :客戶端生成的私鑰。由ssh-keygen生成。該文件嚴格要求權限,當其餘用戶對此文件有可讀權限時,
  •                                   :ssh將直接忽略該文件。
  • ~/.ssh/id_rsa.pub       :私鑰id_rsa的配對公鑰。對權限不敏感。當採用公鑰認證機制時,該文件內容須要複製到服務端的
  •                                   :~/.ssh/authorized_keys文件中。
  • ~/.ssh/rc                     :保存的是命令列表,這些命令在ssh鏈接到遠程主機成功時將第一時間執行,執行完這些命令以後才
  •                                   :開始登錄或執行ssh命令行中的命令。
  • /etc/ssh/rc                  :做用等同於~/.ssh/rc。

1.5 配置文件簡單介紹

分爲服務端配置文件/etc/ssh/sshd_config和客戶端配置文件/etc/ssh/ssh_config(全局)或~/.ssh/config(用戶)。

雖然服務端和客戶端配置文件默認已配置項雖然很是少很是簡單,但它們可配置項很是多。sshd_config完整配置項參見金步國翻譯的sshd_config中文手冊,ssh_config也能夠參考sshd_config的配置,它們大部分配置項所描述的內容是相同的。

1.5.1 sshd_config

簡單介紹下該文件中比較常見的指令。

[root@xuexi ~]# cat /etc/ssh/sshd_config
#Port
22 # 服務端SSH端口,能夠指定多條表示監聽在多個端口上 #ListenAddress 0.0.0.0 # 監聽的IP地址。0.0.0.0表示監聽全部IP Protocol 2 # 使用SSH 2版本 ##################################### # 私鑰保存位置 # ##################################### # HostKey for protocol version 1 #HostKey /etc/ssh/ssh_host_key # SSH 1保存位置/etc/ssh/ssh_host_key # HostKeys for protocol version 2 #HostKey /etc/ssh/ssh_host_rsa_key # SSH 2保存RSA位置/etc/ssh/ssh_host_rsa _key #HostKey /etc/ssh/ssh_host_dsa_key # SSH 2保存DSA位置/etc/ssh/ssh_host_dsa _key ################################### # 雜項配置 # ################################### #PidFile /var/run/sshd.pid # 服務程序sshd的PID的文件路徑 #ServerKeyBits 1024 # 服務器生成的密鑰長度 #SyslogFacility AUTH # 使用哪一個syslog設施記錄ssh日誌。日誌路徑默認爲/var/log/secure #LogLevel INFO # 記錄SSH的日誌級別爲INFO ################################### # 如下項影響認證速度 # ################################### #UseDNS yes # 指定是否將客戶端主機名解析爲IP,以檢查此主機名是否與其IP地址真實對應。默認yes。 # 由此可知該項影響的是主機驗證階段。建議在未配置DNS解析時,將其設置爲no,不然主機驗證階段會很慢 ################################### # 如下是和安全有關的配置 # ################################### #PermitRootLogin yes # 是否容許root用戶登陸 #GSSAPIAuthentication no # 是否開啓GSSAPI身份認證機制,默認爲yes #PubkeyAuthentication yes # 是否開啓基於公鑰認證機制 #AuthorizedKeysFile .ssh/authorized_keys # 基於公鑰認證機制時,來自客戶端的公鑰的存放位置 PasswordAuthentication yes # 是否使用密碼驗證,若是使用密鑰對驗證能夠關了它 #PermitEmptyPasswords no # 是否容許空密碼,若是上面的那項是yes,這裏最好設置no #MaxSessions 10 # 最大客戶端鏈接數量 #LoginGraceTime 2m # 身份驗證階段的超時時間,若在此超時期間內未完成身份驗證將自動斷開 #MaxAuthTries 6 # 指定每一個鏈接最大容許的認證次數。默認值是6。 # 若是失敗認證次數超過該值一半,將被強制斷開,且生成額外日誌消息。 MaxStartups 10 # 最大容許保持多少個未認證的鏈接。默認值10。 ################################### # 如下能夠自行添加到配置文件 # ################################### DenyGroups hellogroup testgroup # 表示hellogroup和testgroup組中的成員不容許使用sshd服務,即拒絕這些用戶鏈接 DenyUsers hello test # 表示用戶hello和test不能使用sshd服務,即拒絕這些用戶鏈接 ################################### # 如下一項和遠程端口轉發有關 # ################################### #GatewayPorts no # 設置爲yes表示sshd容許被遠程主機所設置的本地轉發端口綁定在非環回地址上 # 默認值爲no,表示遠程主機設置的本地轉發端口只能綁定在環回地址上,見後文"遠程端口轉發"

通常來講,如非有特殊需求,只需修改下監聽端口和UseDNS爲no以加快主機驗證階段的速度便可。

配置好後直接重啓啓動sshd服務便可。

[root@xuexi ~]# service sshd restart

1.5.2 ssh_config

須要說明的是,客戶端配置文件有不少配置項和服務端配置項名稱相同,但它們一個是在鏈接時採起的配置(客戶端配置文件),一個是sshd啓動時開關性的設置(服務端配置文件)。例如,兩配置文件都有GSSAPIAuthentication項,在客戶端將其設置爲no,表示鏈接時將直接跳過該身份驗證機制,而在服務端設置爲no則表示sshd啓動時不開啓GSSAPI身份驗證的機制。即便客戶端使用了GSSAPI認證機制,只要服務端沒有開啓,就絕對不可能認證經過。

下面也簡單介紹該文件。

# Host *                              # Host指令是ssh_config中最重要的指令,只有ssh鏈接的目標主機名能匹配此處給定模式時,
                                      # 下面一系列配置項直到出現下一個Host指令纔對這次鏈接生效
#   ForwardAgent no
#   ForwardX11 no
#   RhostsRSAAuthentication no
#   RSAAuthentication yes
#   PasswordAuthentication yes     # 是否啓用基於密碼的身份認證機制
#   HostbasedAuthentication no     # 是否啓用基於主機的身份認證機制
#   GSSAPIAuthentication no        # 是否啓用基於GSSAPI的身份認證機制
#   GSSAPIDelegateCredentials no
#   GSSAPIKeyExchange no
#   GSSAPITrustDNS no
#   BatchMode no                   # 若是設置爲"yes",將禁止passphrase/password詢問。比較適用於在那些不須要詢問提供密
                                   # 碼的腳本或批處理任務任務中。默認爲"no"。
#   CheckHostIP yes
#   AddressFamily any
#   ConnectTimeout 0
#   StrictHostKeyChecking ask        # 設置爲"yes",ssh將從不自動添加host key到~/.ssh/known_hosts文件,
                                     # 且拒絕鏈接那些未知的主機(即未保存host key的主機或host key已改變的主機)。
                                     # 它將強制用戶手動添加host key到~/.ssh/known_hosts中。
                                     # 設置爲ask將詢問是否保存到~/.ssh/known_hosts文件。
                                     # 設置爲no將自動添加到~/.ssh/known_hosts文件。
#   IdentityFile ~/.ssh/identity     # ssh v1版使用的私鑰文件
#   IdentityFile ~/.ssh/id_rsa       # ssh v2使用的rsa算法的私鑰文件
#   IdentityFile ~/.ssh/id_dsa       # ssh v2使用的dsa算法的私鑰文件
#   Port 22                          # 當命令行中不指定端口時,默認鏈接的遠程主機上的端口
#   Protocol 2,1
#   Cipher 3des                      # 指定ssh v1版本中加密會話時使用的加密協議
#   Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc  # 指定ssh v1版本中加密會話時使用的加密協議
#   MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
#   EscapeChar ~
#   Tunnel no
#   TunnelDevice any:any
#   PermitLocalCommand no    # 功能等價於~/.ssh/rc,表示是否容許ssh鏈接成功後在本地執行LocalCommand指令指定的命令。
#   LocalCommand             # 指定鏈接成功後要在本地執行的命令列表,當PermitLocalCommand設置爲no時將自動忽略該配置
                             # %d表本地用戶家目錄,%h表示遠程主機名,%l表示本地主機名,%n表示命令行上提供的主機名,
                             # p%表示遠程ssh端口,r%表示遠程用戶名,u%表示本地用戶名。
#   VisualHostKey no         # 是否開啓主機驗證階段時host key的圖形化指紋
Host *
        GSSAPIAuthentication yes

 

如非有特殊需求,ssh客戶端配置文件通常只需修改下GSSAPIAuthentication的值爲no來改善下用戶驗證的速度便可,另外在有非交互需求時,將StrictHostKeyChecking設置爲no以讓主機自動添加host key。

1.6 ssh命令簡單功能

此處先介紹ssh命令的部分功能,其餘包括端口轉發的在後文相關內容中解釋,關於鏈接複用的選項本文不作解釋。

語法:

ssh [options] [user@]hostname [command]
 
參數說明:
-b bind_address :在本地主機上綁定用於ssh鏈接的地址,當系統有多個ip時才生效。
-E log_file     :將debug日誌寫入到log_file中,而不是默認的標準錯誤輸出stderr。
-F configfile   :指定用戶配置文件,默認爲~/.ssh/config。
-f              :請求ssh在工做在後臺模式。該選項隱含了"-n"選項,因此標準輸入將變爲/dev/null-i identity_file:指定公鑰認證時要讀取的私鑰文件。默認爲~/.ssh/id_rsa。
-l login_name   :指定登陸在遠程機器上的用戶名。也能夠在全局配置文件中設置。
-N              :顯式指明ssh不執行遠程命令。通常用於端口轉發,見後文端口轉發的示例分析。
-n              :將/dev/null做爲標準輸入stdin,能夠防止從標準輸入中讀取內容。ssh在後臺運行時默認該項。
-p port         :指定要鏈接遠程主機上哪一個端口,也可在全局配置文件中指定默認的鏈接端口。
-q              :靜默模式。大多數警告信息將不輸出。
-T              :禁止爲ssh分配僞終端。
-t              :強制分配僞終端,重複使用該選項"-tt"將進一步強制。
-v              :詳細模式,將輸出debug消息,可用於調試。"-vvv"可更詳細。
-V              :顯示版本號並退出。
-o              :指定額外選項,選項很是多。
user@hostname   :指定ssh以遠程主機hostname上的用戶user鏈接到的遠程主機上,若省略user部分,則表示使用本地當前用戶。
                :若是在hostname上不存在user用戶,則鏈接將失敗(將不斷進行身份驗證)。
command         :要在遠程主機上執行的命令。指定該參數時,ssh的行爲將再也不是登陸,而是執行命令,命令執行完畢時ssh鏈接就關閉。

例如,以172.16.10.6主機上的longshuai用戶登陸172.16.10.6。

[root@xuexi ~]# ssh longshuai@172.16.10.6
The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.
ECDSA key fingerprint is 18:d1:28:1b:99:3b:db:20:c7:68:0a:f8:9e:43:e8:b4.
Are you sure you want to continue connecting (yes/no)? yes # 主機驗證
Warning: Permanently added '172.16.10.6' (ECDSA) to the list of known hosts.
longshuai@172.16.10.6's password: # 用戶驗證
Last login: Wed Jul  5 12:27:29 2017 from 172.16.10.6

此時已經登陸到了172.16.10.6主機上。

[longshuai@xuexi ~]$ hostname -I
172.16.10.6

要退出ssh登陸,使用logout命令或exit命令便可返回到原主機環境。

使用ssh還能夠實現主機跳轉,即跳板功能。例如主機B能和A、C通訊,但A、C之間不一樣通訊,即A<-->B<-->C<-x->A的情形。若是要從A登錄到C,則能夠藉助B這個跳板登陸到C。此處一個簡單示例爲:從172.16.10.5登陸到172.16.10.6,再以此爲基礎登陸到172.16.10.3上。

[root@xuexi ~]# ssh 172.16.10.6
The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.
RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts.
Last login: Wed Jul  5 12:36:51 2017 from 172.16.10.6
[root@xuexi ~]# ssh 172.16.10.3
The authenticity of host '172.16.10.3 (172.16.10.3)' can't be established.
ECDSA key fingerprint is 18:d1:28:1b:99:3b:db:20:c7:68:0a:f8:9e:43:e8:b4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.16.10.3' (ECDSA) to the list of known hosts.
root@172.16.10.3's password:
Last login: Thu Jun 29 12:38:56 2017 from 172.16.10.6
[root@xuexi ~]# hostname -I
172.16.10.3 172.16.10.4

一樣,在退出時,也是一層一層退出的。

[root@xuexi ~]# exit
logout
Connection to 172.16.10.3 closed.

[root@xuexi ~]# hostname -I   
172.16.10.6

[root@xuexi ~]# exit
logout
Connection to 172.16.10.6 closed.

注意,因爲在藉助172.16.10.6當跳板鏈接到172.16.10.3,因此172.16.10.3的host key是添加到172.16.10.6上而非172.16.10.5上的。

若是在命令行給出了要執行的命令,默認ssh將工做在前臺,若是同時給定了"-f"選項,則ssh工做在後臺。但儘管是工做在後臺,當遠程執行的命令若是有消息返回時,將隨時可能顯示在本地。當遠程命令執行完畢後,ssh鏈接也將當即關閉。

[root@xuexi ~]# ssh 172.16.10.6 'sleep 5'     # 在前臺睡眠5秒鐘

[root@xuexi ~]# ssh 172.16.10.6 -f 'sleep 5;echo over'   # 在後臺睡眠5秒,睡眠完成後echo一段信息

因爲第二條命令是放在後臺執行的,因此該ssh一創建完成ssh會話就當即返回本地bash環境,但當5秒以後,將在本地忽然顯示"over"。

ssh執行遠程命令默認容許從標準輸入中讀取數據而後傳輸到遠程。可使用"-n"選項,使得標準輸入重定向爲/dev/null。例如:

[root@xuexi ~]# echo haha | ssh 172.16.10.6 'cat'
haha

[root@xuexi ~]# ssh 172.16.10.6 'cat' </etc/fstab  

再看以下兩條命令:

[root@xuexi ~]# tar zc /tmp/* | ssh 172.16.10.6 'cd /tmp;tar xz'

[root@xuexi ~]# ssh 172.16.10.6 'tar cz /tmp' | tar xz

第一條命令將/tmp下文件歸檔壓縮,而後傳送到遠程主機上並被解包;第二條命令將遠程主機上的/tmp目錄歸檔壓縮,並傳輸到本地解包。因此它們實現了拷貝的功能。

不妨再分析下面的命令,該命令改編自ssh-copy-id腳本中的主要命令。若是不知道ssh-copy-id命令是幹什麼的,後文有介紹。

[root@xuexi ~]# cat ~/.ssh/id_rsa.pub | ssh 172.16.10.6 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys"

該命令首先創建ssh鏈接,並在遠程執行"umask 077"臨時修改遠程的umask值,使得遠程建立的目錄權限爲700,而後判斷遠程主機上是否有~/.ssh目錄,若是沒有則建立,最後從標準輸入中讀取本地公鑰文件~/.ssh/id_rsa.pub的內容並將其追加到~/.ssh/authorized_keys文件中。

若是將此命令改成以下命令,使用ssh的"-n"選項,並將追加劇定向改成覆蓋重定向符號。

[root@xuexi ~]# cat ~/.ssh/id_rsa.pub | ssh -n 172.16.10.6 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat > ~/.ssh/authorized_keys"

該命令的結果是清空遠程主機172.16.10.6上的~/.ssh/authorized_keys文件,由於ssh的"-n"選項強行改變了ssh讀取的標準輸入爲/dev/null。

1.7 scp命令及過程分析

scp是基於ssh的遠程拷貝命令,也支持本地拷貝,甚至支持遠程到遠程的拷貝。

scp因爲基於ssh,因此其端口也是使用ssh的端口。其實,scp拷貝的實質是使用ssh鏈接到遠程,並使用該鏈接來傳輸數據。下文有scp執行過程的分析。

另外,scp還很是不佔資源,不會提升多少系統負荷,在這一點上,rsync遠不及它。雖然 rsync比scp會快一點,但rsync是增量拷貝,要判斷每一個文件是否修改過,在小文件衆多的狀況下,判斷次數很是多,致使rsync效率較差,而scp基本不影響系統正常使用。

scp每次都是全量拷貝,在某些狀況下,確定是不及rsync的。

scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]src_file ... [[user@]host2:]dest_file

選項說明:
-1:使用ssh v1版本,這是默認使用協議版本
-2:使用ssh v2版本
-C:拷貝時先壓縮,節省帶寬
-l limit:限制拷貝速度,Kbit/s,1Byte=8bit,因此"-l 800"表示的速率是100K/S
-o ssh_option:指定ssh鏈接時的特殊選項,通常用不上。
-P port:指定目標主機上ssh端口,大寫的字母P,默認是22端口
-p:拷貝時保持源文件的mtime,atime,owner,group,privileges
-r:遞歸拷貝,用於拷貝目錄。注意,scp拷貝遇到連接文件時,會拷貝連接的源文件內容填充到目標文件中(scp的本質就是填充而非拷貝)
-v:輸出詳細信息,能夠用來調試或查看scp的詳細過程,分析scp的機制

src_file是源位置,dest_file是目標位置,即將src_file複製到dest_file,其中src_file能夠指定多個。因爲源位置和目標位置均可以使用本地路徑和遠程路徑,因此scp能實現本地拷貝到遠程、本地拷貝到本地、遠程拷貝到本地、遠程拷貝到另外一個遠程。其中遠程路徑的指定格式爲"user@hostname:/path",能夠省略user,也能夠省略":/path",省略":/path"時表示拷貝到目的用戶的家目錄下。

注意:scp拷貝是強制覆蓋型拷貝,當有重名文件時,不會進行任何詢問。

例如:

(1).本地拷貝到本地:/etc/fstab-->/tmp/a.txt。

[root@xuexi ~]# scp /etc/fstab /tmp/a.txt

(2).本地到遠程:/etc/fstab-->172.16.10.6:/tmp/a.txt。

[root@xuexi ~]# scp /etc/fstab 172.16.10.6:/tmp
fstab                                          100%  805     0.8KB/s   00:00

(3).遠程到本地:172.16.10.6:/etc/fstab-->/tmp/a.txt。

[root@xuexi ~]# scp 172.16.10.6:/etc/fstab /tmp/a.txt
fstab                                          100%  501     0.5KB/s   00:00

(4).遠程路徑1到遠程路徑2:172.16.10.6:/etc/fstab-->/172.16.10.3:/tmp/a.txt。

[root@xuexi ~]# scp 172.16.10.6:/etc/fstab 172.16.10.3:/tmp/a.txt
fstab                                          100%  501     0.5KB/s   00:00   
Connection to 172.16.10.6 closed.

遠程複製到遠程時,可能會由於sudoers的限制不給ssh分配終端,致使沒法輸入yes/密碼或者直接拒絕等而失敗。這時能夠加上一層ssh:

ssh -tt 172.16.10.2 "scp 172.16.10.6:/etc/fstab 172.16.10.3:/tmp/a.txt"

其中172.16.10.2是執行ssh命令所在的主機A,也就是在A主機上使用scp將主機B(10.6)上的文件複製到主機C(10.3)上,這裏的"-tt"表示強制分配僞終端給ssh。

另外,還可使用scp的"-3"選項,改變scp遠程到遠程的默認傳輸模式(默認傳輸模式見下面的機制分析),若是上面的命令失敗的話,也可使用該選項一試。

scp -3 172.16.10.6:/etc/fstab 172.16.10.3:/tmp/a.txt

1.7.1 scp拷貝機制分析

scp的拷貝實質是創建ssh鏈接,而後經過此鏈接來傳輸數據。若是是遠程1拷貝到遠程2,則是將scp命令轉換後發送到遠程1上執行,在遠程1上創建和遠程2的ssh鏈接,並經過此鏈接來傳輸數據。

在遠程複製到遠程的過程當中,例如在本地(172.16.10.5)執行scp命令將A主機(172.16.10.6)上的/tmp/copy.txt複製到B主機(172.16.10.3)上的/tmp目錄下,若是使用-v選項查看調試信息的話,會發現它的步驟相似是這樣的。

# 如下是從結果中提取的過程
# 首先輸出本地要執行的命令
Executing: /usr/bin/ssh -v -x -oClearAllForwardings yes -t -l root 172.16.10.6 scp -v /tmp/copy.txt root@172.16.10.3:/tmp
 
# 從本地鏈接到A主機
debug1: Connecting to 172.16.10.6 [172.16.10.6] port 22.
debug1: Connection established.
 
# 要求驗證本地和A主機之間的鏈接
debug1: Next authentication method: password
root@172.16.10.6's password:
 
# 將scp命令行修改後發送到A主機上
debug1: Sending command: scp -v /tmp/copy.txt root@172.16.10.3:/tmp
 
# 在A主機上執行scp命令
Executing: program /usr/bin/ssh host 172.16.10.3, user root, command scp -v -t /tmp
 
# 驗證A主機和B主機之間的鏈接
debug1: Next authentication method: password
root@172.16.10.3's password:
 
# 從A主機上拷貝源文件到最終的B主機上
debug1: Sending command: scp -v -t /tmp
Sending file modes: C0770 24 copy.txt
Sink: C0770 24 copy.txt
copy.txt                                                           100%   24     0.0KB/s  
 
# 關閉本地主機和A主機的鏈接
Connection to 172.16.10.6 closed.

也就是說,遠程主機A到遠程主機B的複製,其實是將scp命令行從本地傳輸到主機A上,由A本身去執行scp命令。也就是說,本地主機不會和主機B有任何交互行爲,本地主機就像是一個代理執行者同樣,只是幫助傳送scp命令行以及幫助顯示信息。

其實從本地主機和主機A上的~/.ssh/know_hosts文件中能夠看出,本地主機只是添加了主機A的host key,並無添加主機B的host key,而在主機A上則添加了主機B的host key。

 

1.8 基於公鑰認證機制實現雙機互信

在身份驗證階段,因爲默認狀況下基於公鑰認證的機制順序優先於基於密碼認證的機制,因此基於公鑰認證身份,就能夠免輸入密碼,即實現雙機互信(實際上只是單方向的信任)。

基於公鑰認證機制的認證過程在前文已經詳細說明過了,如還不清楚,請跳回上文。

1.8.1 實現步驟

如下是實現基於公鑰認證的實現步驟:

(1).在客戶端使用ssh-keygen生成密鑰對,存放路徑按照配置文件的指示,默認是在~/.ssh/目錄下。

[root@xuexi ~]# ssh-keygen -t rsa    # -t參數指定算法,能夠是rsa或dsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):  # 詢問私鑰保存路徑
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. 

若是不想被詢問,則可使用下面一條命令完成:"-f"指定私鑰文件,"-P"指定passphrase,或者"-N"也同樣。

[root@xuexi ~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''   # 指定加密私鑰文件的密碼爲空密碼,即不加密

[root@xuexi ~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ''   # 同上

查看~/.ssh/目錄下私鑰的權限。私鑰文件有嚴格的權限要求,當私鑰文件的非全部者有可讀權限時,將直接忽略該私鑰文件致使公鑰認證失敗。

[root@xuexi ~]# ls -l ~/.ssh
total 12
-rw------- 1 root root 1671 Jun 29 00:18 id_rsa      # 私鑰權限必須600,屬主爲本身
-rw-r--r-- 1 root root  406 Jun 29 00:18 id_rsa.pub
-rw-r--r-- 1 root root  393 Jun 29 05:56 known_hosts

(2).將上面生成的公鑰使用ssh-copy-id分發(即複製)到遠程待信任主機上。

ssh-copy-id用法很簡單,只需指定待信任主機及目標用戶便可。若是生成的公鑰文件,路徑不是~/.ssh/id_rsa.pub,則使用"-i"選項指定要分發的公鑰。

ssh-copy-id [-i [identity_file]] [user@]machine

例如,將公鑰分發到172.16.10.6上的root用戶家目錄下:

[root@xuexi ~]# ssh-copy-id 172.16.10.6

ssh-copy-id惟一須要注意的是,若是ssh服務端的端口不是22,則須要給ssh-copy-id傳遞端口號,傳遞方式爲 "-p port_num [user@]hostname" (注意加上雙引號),例如"-p 22222 root@172.16.10.6"。之因此要如此傳遞,見下面摘自ssh-copy-id中公鑰分發的命令部分。

{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys && (test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)" || exit 1

其中"{ eval "$GET_ID" ; }"可理解爲待分發的本地公鑰內容,"(test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)"和selinux有關,不用管,因此上述命令簡化爲:

cat ~/.ssh/id_rsa.pub | ssh $1 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys || exit 1

可見,ssh-copy-id的全部參數都是存儲在位置變量$1中傳遞給ssh,因此應該將ssh的端口選項"-p port_num"和user@hostname放在一塊兒傳遞。

經過分析上面的命令,也即知道了ssh-copy-id的做用:在目標主機的指定用戶的家目錄下,檢測是否有~/.ssh目錄,若是沒有,則以700權限建立該目錄,而後將本地的公鑰追加到目標主機指定用戶家目錄下的~/.ssh/authorized_keys文件中。

1.8.2 一鍵shell腳本

就這樣簡單的兩步就實現了基於公鑰的身份認證。固然,不使用ssh-copy-id,也同樣能實現上述過程。更便捷地,能夠寫一個簡單的腳本,簡化上述兩個步驟爲1個步驟。

#!/bin/bash
 
###########################################################
#  description: public key authentication in one step     #
#  author     : 駿馬金龍                                   #
#  blog       : http://www.cnblogs.com/f-ck-need-u/       #
###########################################################
 
privkey="$HOME/.ssh/id_rsa"
publickey="$HOME/.ssh/id_rsa.pub"
 
# Usage help
if [ $# -ne 1 ];then
   echo "Usage:$0 [user@]hostname"
   exit 1
fi
 
# test private/publick key exist or not, and the privilege 600 or not
if [ -f "$privkey" -a -f "$publickey" ];then
   privkey_priv=`stat -c %a $privkey`
   if [ "$privkey_priv" -ne 600 ];then
       echo "The privilege of private key ~/.ssh/id_rsa is not 600, exit now."
       exit 1
   fi
else
   echo "private/public key is not exist, it will create it"
   ssh-keygen -t rsa -f $privkey -N ''
   echo "keys created over, it located on $HOME/.ssh/"
fi
 
ssh-copy-id "-o StrictHostKeyChecking=no $1"
 
if [ $? -eq 0 ];then
   echo -e "\e[31m publickey copy over \e[0m"
else
   echo "ssh can't to the remote host"
   exit 1
fi

該腳本將檢查本地密鑰對~/.ssh/{id_rsa,id_rsa.pub}文件是否存在,還檢查私鑰文件的權限是否爲600。若是缺乏某個文件,將自動新建立密鑰對文件,最後分發公鑰到目標主機。

1.8.3 公鑰認證之——服務端分發私鑰

對於基於公鑰認證的身份驗證機制,除了上面客戶端分發公鑰到服務端的方法,還能夠經過分發服務端私鑰到客戶端來實現。

先理清下公鑰認證的原理:客戶端要鏈接服務端,並告訴服務端要使用那對密鑰對,而後客戶端訪問本身的私鑰,服務端檢測對應的公鑰來決定該公鑰所對應的客戶端是否容許鏈接。因此對於基於公鑰認證的身份驗證,不管是客戶端分發公鑰,仍是服務端分發私鑰,最終客戶端保存的必定是私鑰,服務端保存的必定是公鑰。

那麼服務端分發私鑰實現公鑰認證是如何實現的呢?步驟以下:假如客戶端爲172.16.10.5,服務端爲172.16.10.6。

(1).在服務端使用ssh-keygen生成密鑰對。

[root@xuexi ~]# ssh-keygen -f ~/.ssh/id_rsa -P ''

(2).將上面生成的公鑰追加到本身的authorized_keys文件中。

[root@xuexi ~]# ssh-copy-id 172.16.10.6

(3).將私鑰拷貝到客戶端,且路徑和文件名爲~/.ssh/id_rsa。

[root@xuexi ~]# scp -p ~/.ssh/id_rsa* 172.16.10.5:/root/.ssh/

注意,第三步中也拷貝了公鑰,緣由是客戶端鏈接服務端時會比較本身的公鑰和私鑰是否配對,若是不配對將直接忽略公鑰認證機制,因此會要求輸入密碼。能夠將客戶端的公鑰刪除掉,或者將服務端生成的公鑰覆蓋到客戶端的公鑰上,都能完成公鑰認證。

雖然說,服務端分發私鑰的方式不多用,但經過上面的步驟,想必對ssh基於公鑰認證的身份驗證過程有了更深刻的理解。

1.9 expect實現ssh/scp徹底非交互(批量)

expect工具能夠在程序發出交互式詢問時按條件傳遞所需的字符串,例如詢問yes/no自動傳遞y或yes,詢問密碼時自動傳遞指定的密碼等,這樣就能讓腳本徹底實現非交互。

顯然,ssh等客戶端命令基於密碼認證時老是會詢問密碼,即便是基於公鑰認證,在創建公鑰認證時也要詢問一次密碼。另外,在ssh主機驗證時還會詢問是否保存host key。這一切均可以經過expect自動回答。

關於expect工具,它使用的是tcl語言,雖然說應用在expect上的tcl語言並不是太複雜,但這並不是本文內容,若有興趣,可網上搜索或直接閱讀man文檔。

首先安裝expect工具。

[root@xuexi ~]# yum -y install expect

1.9.1 scp自動應答腳本

如下是scp自動問答的腳本。

[root@xuexi ~]# cat autoscp.exp
#!/usr/bin/expect
########################################################### # description:
scp without interactive # # author : 駿馬金龍 # # blog : http://www.cnblogs.com/f-ck-need-u/ # ########################################################### set timeout 10 set user_hostname [lindex $argv 0] set src_file [lindex $argv 1] set dest_file [lindex $argv 2] set password [lindex $argv 3] spawn scp $src_file $user_hostname:$dest_file expect { "(yes/no)?" { send "yes\n" expect "*assword:" { send "$password\n"} } "*assword:" { send "$password\n" } } expect "100%" expect eof

用法:autoscp.exp [user@]hostname src_file dest_file [password]

該自動回答腳本能夠自動完成主機驗證和密碼認證,即便已是實現公鑰認證的機器也沒問題,由於公鑰認證機制默認優先於密碼認證,且此腳本的password項是可選的,固然,在沒有實現公鑰認證的狀況下,password是必須項,不然expect實現非交互的目的就失去意義了。

如下是幾個示例:

[root@xuexi ~]# ./autoscp.exp 172.16.10.6 /etc/fstab /tmp 123456
spawn scp /etc/fstab 172.16.10.6:/tmp
The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.
RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes          # 主機驗證時詢問是否保存host key,自動回答yes
Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts.
root@172.16.10.6's password:                                        # 密碼認證過程,自動回答指定的密碼"123456"
fstab                                                        100%  805     0.8KB/s   00:00

也能夠指定完成的用戶名和主機名。

[root@xuexi ~]# ./autoscp.exp root@172.16.10.6 /etc/fstab /tmp 123456
spawn scp /etc/fstab root@172.16.10.6:/tmp
root@172.16.10.6's password:         
fstab                                 100%  805     0.8KB/s   00:00

1.9.2 ssh-copy-id自動應答腳本

如下是在創建公鑰認證機制時,ssh-copy-id拷貝公鑰到服務端的自動應答腳本。

[root@xuexi ~]# cat /tmp/autocopy.exp
#!/usr/bin/expect

###########################################################
#  description: scp without interactive                   #
#  author     : 駿馬金龍                                   #
#  blog       : http://www.cnblogs.com/f-ck-need-u/       #
###########################################################

set timeout 10
set user_hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh-copy-id $user_hostname
    expect {
        "(yes/no)?"
        {
            send "yes\n"
            expect "*assword:" { send "$password\n"}
        }
        "*assword:"
        {
            send "$password\n"
        }
    }
expect eof

用法:autocopy.exp [user@]hostname password

如下是一個示例,

[root@xuexi ~]# /tmp/autocopy.exp root@172.16.10.6 123456
spawn ssh-copy-id root@172.16.10.6
The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.
RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes      # 主機認證時,自動應答yes
Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts.
root@172.16.10.6's password:                                    # 密碼認證時自動輸入密碼"123456"
Now try logging into the machine, with "ssh 'root@172.16.10.6'", and check in:
 
  .ssh/authorized_keys
 
to make sure we haven't added extra keys that you weren't expecting.

若是要實現批量非交互,則能夠寫一個shell腳本調用該expect腳本。例如:

[root@xuexi ~]# cat /tmp/sci.sh
#!/bin/bash

###########################################################
#  description: scp without interactive                   #
#  author     : 駿馬金龍                                   #
#  blog       : http://www.cnblogs.com/f-ck-need-u/       #
###########################################################
 
passwd=123456               # 指定要傳遞的密碼爲123456
user_host=`awk '{print $3}' ~/.ssh/id_rsa.pub`   # 此變量用於判斷遠程主機中是否已添加本機信息成功
 
for i in $@  
do
        /tmp/autocopy.exp $i $passwd >&/dev/null
        ssh $i "grep "$user_host" ~/.ssh/authorized_keys" >&/dev/null  # 判斷是否添加本機信息成功
        if [ $? -eq 0 ];then
                echo "$i is ok"
        else
                echo "$i is not ok"
        fi
done

用法:/tmp/sci.sh [user@]hostname

其中hostname部分可使用花括號展開方式枚舉。但有個bug,最好ssh-copy-id的目標不要是腳本所在的本機,可能會強制輸入本機密碼,但批量腳本autocopy.exp則沒有此bug。

例如:

[root@xuexi tmp]# /tmp/sci.sh 172.16.10.3 172.16.10.6
172.16.10.3 is ok
172.16.10.6 is ok
[root@xuexi tmp]# /tmp/sci.sh 172.16.10.{3,6}
172.16.10.3 is ok
172.16.10.6 is ok
[root@xuexi tmp]# /tmp/sci.sh root@172.16.10.3 172.16.10.6
root@172.16.10.3 is ok
172.16.10.6 is ok

1.10 ssh鏈接速度慢的幾個緣由和解決辦法

ssh鏈接包括兩個階段:主機驗證階段和身份驗證階段。這兩個階段均可能致使鏈接速度慢。

具體是哪一個階段的速度慢,徹底能夠經過肉眼看出來:

(1).卡着好久才提示保存host key確定是主機驗證過程慢。

(2).主機驗證完成後卡着好久才提示輸入密碼,確定是身份驗證過程慢。

其中主機驗證過程慢的緣由,多是網絡鏈接慢、DNS解析慢等緣由。網絡鏈接慢,ssh對此毫無辦法,而DNS解析慢,ssh是能夠解決的,解決方法是將ssh服務端的配置文件中UseDNS設置爲no(默認爲yes)。

而身份驗證慢的緣由,則考慮ssh的身份驗證順序:gssapi,host-based,publickey,keyboard-interactive,password。其中gssapi認證順序是比較慢的,因此解決方法一是在ssh客戶端配置文件中將GSSAPI認證機制給關掉,解決方法二是在ssh客戶端配置文件中使用PreferredAuthentications指令修改身份驗證順序。

方法一修改:GSSAPIAuthentication yes

方法二修改:PreferredAuthentications publickey,password,gssapi,host-based,keyboard-interactive

若是感覺不到哪一個階段致使速度變慢,可使用ssh或scp等客戶端工具的"-vvv"選項進行調試,看看是卡在哪一個地方,不過,想看懂"-vvv"的過程,仍是比較考驗耐心的。

1.11 SSH安全隧道(ssh躍牆之術)

本文篇幅太長,這部份內容單獨成篇:SSH隧道:端口轉發功能詳解

1.11.1 ssh隧道(一):本地端口轉發

1.11.2 ssh隧道(二):遠程端口轉發

1.11.3 ssh隧道(三):動態端口轉發(SOCKS代理)

相關文章
相關標籤/搜索