python自動化管理sshy(ssh,ssh-copy-id,ssh-agent)

Python自動化管理sshy介紹

ssh優勢:

  • 安全傳輸文件
  • 登錄
  • 批量執行命令

對於一名剛開始接觸Linux系統管理的工程師來說,他眼裏的系統管理的步驟可能是:使用SSH登錄服務器,修改應用相關的配置文件,執行一些Linux命令,重啓相應的進程,最後退出服務器。如果還有更多的服務器,那麼,就重複上述過程。

上面這一系列步驟是Linux系統管理的基礎知識,是系統管理的基本功。但是,在實際工作中,一般不會手動對
服務器進行操作,而是使用程序進行自動化管理。即使服務器的數量很少,也推薦大家編寫程序進行自動化。相對於手動管理服務器,自動化管理有許多優點。例如:

1)效率高:

自動化操作效率比手動操作效率高。這裏的效率高可以從兩方面來理解:一方面是程序執行的效率比手動操作的效率高;另一方面是指對工程師來說,使用程序可以提高自身的工作效率,減少不必要的時間浪費。即使只有一臺服務器,手動操作雖然可以很快完成,但其操作效率也不能與程序相提並論。如果管理的是服務器集羣,顯然,人工操作非常不現實,不但效率低下.而且枯操乏味,費時費力。程序的好處是一次編寫,多次運行。雖然在編寫程序的時候,花費的時間可能比單次手動操作的時間多,但是,只要程序編寫完成,就可以多次反覆地運行,節省大量時間。

2)不容易犯錯:

俗話說“人無完人”,如果一直使用人工管理的方式管理服務器集羣,那麼,出錯是不可避免的。工程師會有情緒的變化,也會有身體健康狀況等問題,但程序不會。只要程序編寫完成,並且考慮到了相應的異常,程序總是能夠嚴格一致地執行管理操作。

3)享受樂趣:

從事計算機行業有一個天然的好處,那就是不用進行重複性的工作。有任何重複性的工作,找們都可以通過編寫程序消滅掉。消滅重複性的工作,不但節省工作時間,還能夠獲得更多的樂趣和成就感。以管理服務器集羣爲例,看到自己編寫的程序、指揮成百上千的服務器按照既定的需求執行操作,是不是有種指點江山、揮斥方遒的感覺?

這一章將會討論如何使用Python批量管理服務器。首先,我們將會介紹批量管理服務器的基礎知識,即SSH協議;隨後,本章會介紹一個Python編寫的批處理工具;然後將會介紹如何在Python程序中對遠程服務器進行操作;在本章的最後,我們會介紹一個非常強大的系統管理工具,即Fabric,這一部分是本章的重點和難點。

一、使用SSH協議訪問遠程服務器

SSH ( Secure Shell)是一種由IETF的網絡工作小組制定、創建在應用層和傳輸層基礎上的安全協議,爲計算機上的Shell提供安全的傳輸和使用環境。

1、SSH協議

在互聯網早期,通信都是明文的,如rsh、 FTP、POP和Telnet。一旦通信報文被截獲,內容就泄漏無疑。1995年,芬蘭學者Tatu Ylonen設計了SSH協議。將登錄信息全部加密,成爲互聯網安全的一個基本解決方案。這個方案迅速在全世界獲得推廣,目前已經成爲Linux系統的標準配。

SSH只是一種協議,存在多種實現,既有商業實現也有開源實現。目前。在Linux下廣泛使用的是OpenSSH,它是一款應用廣泛的開源軟件。本文即將介紹的paramiko是SSH協議的一種Python實現。

SSH除了提供安全的傳輸和登錄以外,還可以進行批量命令執行,使用非常方便。正是由於SSH簡單好用的特點,本章介紹的幾個工具,以及稍後即將介紹的Ansible,都依賴SSH進行遠程服務器的管理。使用SSH的好處非常明顯,既充分利用了現成的機制,又省去了在遠程服務器安裝代理(Agent)程序。因此,諸多自動化工其都依賴SSH。

2、OpenSSH實現

OpenSSH (OpenBSD Secure Shell)是OpenBSD的一個子項目,是SSH協議的開源實現。在服務端,OpenSSH啓動sshd守護進程,該進程默認監聽22端口。客戶端使用用戶名和密碼連接服務端,連接成功以後,OpenSSH返回給用戶一個Shell,用戶可以使用該Shell在遠程服務器執行命令。

在Debian系統中,OpenSSH的服務端默認讀取/etc/ssh/sshd_config中的配置。在生產環境中,爲了防止******,一般會修改ssh服務的默認端口號,修改ssh服務默認端口號就是在/etc/ssh/sshd_config中完成的。我們也可以通過該配置文件禁止用戶使用密碼進行認證,只能使用密鑰認證。修改完配置文件以後,執行下面的命令重啓OpenSSH的守護進程才能生效:

對於一名剛開始接觸Linux系統管理的工程師來說,他眼裏的系統管理的步驟可能是:使用SSH登錄服務器,修改應用相關的配置文件,執行一些Linux命令,重啓相應的進程,最後退出服務器。如果還有更多的服務器,那麼,就重複上述過程。

上面這一系列步驟是Linux系統管理的基礎知識,是系統管理的基本功。但是,在實際工作中,一般不會手動對
服務器進行操作,而是使用程序進行自動化管理。即使服務器的數量很少,也推薦大家編寫程序進行自動化。相對於手動管理服務器,自動化管理有許多優點。例如:

/etc/init.d/ssh restart

OpenSSH的客戶端是一個名爲ssh可執行程序,我們可以使用ssh命令連接遠程服務器。如下所示:

[root@python ~]# ssh xgp@localhost 
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is bf:c7:de:84:e1:28:f4:d4:7e:41:49:9f:54:dc:e9:83.
Are you sure you want to continue connecting (yes/no)? yes
xgp@localhost's password: 
[xgp@python ~]$ 

如果服務器端不是使用默認的22端口,可以通過SSH命令的-p參數指定建立連接的端口號,格式如下所示:

ssh username@remote_host -p 端口號

我們也可以不進入交互式的Shell,直接使用ssh命令在遠程服務器中執行Linux命令,如下所示:

[root@python ~]# ssh [email protected] 'date'
[email protected]'s password: 
2020年 05月 15日 星期五 15:55:08 CST
s
[root@python ~]#

3、配置ssh的方法:

  • 編輯/etc/ssh/ssh_config
  • 編輯~/.ssh/config

ssh會讀取/etc/ssh/ssh_config文件中的配置。例如,遠程服務器使用的不是默認的22端口號,我們只需要在/etc/ssh/ssh_config進行簡單的配置,就可以在連接遠程服務器時省去指定端口號的參數。除了修/etc/ssh/ssh_config文件以外,更常見的做法是修改用戶home目錄下的~/.ssh/config文件。

查看ssh_config文件

[root@python ~]# find / -name ssh_config          #查看找ssh_config 文件
/etc/ssh/ssh_config
[root@python ~]# cat /etc/ssh/ssh_config | awk #
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:      GNU long options: (standard)
    -f progfile     --file=progfile
    -F fs           --field-separator=fs
    -v var=val      --assign=var=val
Short options:      GNU long options: (extensions)
    -b          --characters-as-bytes
    -c          --traditional
    -C          --copyright
    -d[file]        --dump-variables[=file]
    -e 'program-text'   --source='program-text'
    -E file         --exec=file
    -g          --gen-pot
    -h          --help
    -L [fatal]      --lint[=fatal]
    -n          --non-decimal-data
    -N          --use-lc-numeric
    -O          --optimize
    -p[file]        --profile[=file]
    -P          --posix
    -r          --re-interval
    -S          --sandbox
    -t          --lint-old
    -V          --version

To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
    gawk '{ sum += $1 }; END { print sum }' file
    gawk -F: '{ print $1 }' /etc/passwd

例如,我們經常要使用某一個用戶名、端口號訪問某一臺遠程服務器。爲了省去記住服務器ip的負擔,很多工程師會編寫一個Shell腳本,在腳本中保存用戶名、端口號和ip地址。在下次登錄時,可以省去輸入的煩惱。如下所示:

[root@python ~]# vim /opt/login.sh
#!/usr/bin/bash

ssh [email protected] -p 22

[root@python ~]# useradd test
[root@python ~]# passwd test
更改用戶 test 的密碼 。
新的 密碼:
無效的密碼: 密碼少於 8 個字符
重新輸入新的 密碼:
passwd:所有的身份驗證令牌已經成功更新。
[root@python ~]# sh /opt/login.sh 
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is bf:c7:de:84:e1:28:f4:d4:7e:41:49:9f:54:dc:e9:83.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.
[email protected]'s password: 
[test@python ~]$ 

對於這裏的需求,還有更好的解決方案。命令會讀取~/.ssh/config文件中配置,因此,我們可以在~/.ssh/config文件中提前配置好訪問遠程服務器的信息。如下所示:

[root@python ~]# cp /etc/ssh/ssh_config -p  ~/.ssh/config
[root@python ~]# vim  ~/.ssh/config 

Host python
  ForwardAgent yes
  StrictHostKeyChecking no
  port 22
  User test
  Controlpath ~/.ssh/ssh-%r@%h:%p.sock

Host *
  StrictHostKeyChecking no
  HostName %h
  Port  22
  User  test
  Controlpath ~/.ssh/ssh-%r@%h:%p.sock

配置完成後,直接在命令行執行ssh host2就可以使用用戶名test,以及端口號2092登錄到10.166.224.14中。此外,我們還使用通配符的方式定義了ssh默認用戶名與端口號。假設我們要使用用戶名laoyu、端口號2092訪問10.166.226.153,有了前面的配置以後,可以在命令行直接進行登錄。如下所示:

[root@python ~]# ssh python
Warning: Permanently added 'python,fe80::c64e:c937:2ea8:6676%ens33' (ECDSA) to the list of known hosts.
test@python's password: 
Permission denied, please try again.
test@python's password: 
Last login: Fri May 15 14:34:54 2020 from localhost
[test@python ~]$ 

可以看到,我們只需要在~/.ssh/config文件中進行簡單的配置就能夠有效提高工作效率。

4、使用密鑰登錄遠程服務器

  • ssh使用密碼
  • ssh不使用密碼,使用密鑰

在上面的例子中,我們沒有指定認證的方式,默認使用密碼進行認證。在生產環境中一般不使用密碼認證,一方面是因爲密碼認證沒有密鑰認證安全;另一方面,密碼認證每次登錄時都需要輸入密碼,比較繁瑣。使用密鑰認證,省去了輸入密碼的煩惱。因此,在生產環境中,一般會使用密鑰進行登錄。

密鑰登錄的原理也很簡單,即事先將用戶的公鑰儲存在遠程服務器上(~/.ssh/authorized_keys文件)。使用密鑰登錄時,遠程服務器會向用戶發送一段隨機字符串,SSH使用用戶的私鑰加密字符串後發送給遠程服務器。遠程服務器用事先儲存的公鑰進行解密,如果成功,就證明用戶是可信的,直接允許登錄Shell,不再要求密碼。

OpenSSH除了提供服務端的sshd、客戶端的SSH程序以外,還提供了若干與密鑰認證相關的工其。其中,ssh-keygen是用來生成密鑰對的工具。如下所示:

[root@python ~]# ssh-keygen 

python自動化管理sshy(ssh,ssh-copy-id,ssh-agent)

ssh-keygen執行完以後,用戶的~/.ssh目錄下會存在一個名爲id_ rsa的私鑰文件與一個名爲id_rsa.pub的公鑰文件。

接下來要做的是將公鑰保存到遠程服務器的~/.ssh/authorized_keys文件中。可以使用下面的命令將公鑰保存到遠程服務器的authorized_keys文件中:

[root@python ~]#  ssh [email protected] 'mkdir -p .ssh && cat >>.ssh/authorized_keys' <~/.ssh/id_rsa.pub 
The authenticity of host '192.168.1.80 (192.168.1.80)' can't be established.
ECDSA key fingerprint is SHA256:UbtfIBIs2tGQU1m/SIvSZX72VUQ+r1fH/aIMxVbdobg.
ECDSA key fingerprint is MD5:56:10:49:b1:ae:f6:3c:d3:5e:2d:c5:d9:38:2c:45:e7.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.80' (ECDSA) to the list of known hosts.
[email protected]'s password: 
[root@python ~]# 

上面的命令是使用Shell腳本的方式將公鑰保存到遠程服務器,除此之外,OpenSSH專門提供了一個名爲ssh-copy-id的工具。我們可以使用該工具將公鑰保存到遠程服務器中,這種方式比前面Shell腳本的方式更加方便。如下所示:

[root@python ~]# 
[root@python ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.80
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
[email protected]'s password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '192.168.1.80'"
and check to make sure that only the key(s) you wanted were added.

[root@python ~]# rm -rf  ~/.ssh/config
[root@python ~]# ssh 192.168.1.80
Last login: Fri May 15 15:16:23 2020 from 192.168.1.80
[root@python ~]# 

python自動化管理sshy(ssh,ssh-copy-id,ssh-agent)

配置私鑰認證以後,就可以直接使用私鑰進行登錄。ssh命令會默認讀取~/.ssh/id_rsa這個私鑰文件。如果私鑰文件保存在其他位置,或者是其他名稱,可以使用-t參放指定私鑰文件的地址。如下所示:

ssh [email protected] -p 22 -i ~/私鑰文件所在的位置(含文件名)

使用私鑰登錄時需要注意,私鑰文件與遠程服務器中authorized_keys文件的權限都必須爲600,否則登錄會出錯,這也是工程師使用私鑰登錄時最容易遇到的錯誤。

測試登陸一下

[root@python ~]# vim ~/.ssh/config 

Host python
  ForwardAgent yes
  StrictHostKeyChecking no
  HostName 192.168.1.80
  Port 22
  User test
  Controlpath ~/.ssh/ssh-%r@%h:%p.sock

python自動化管理sshy(ssh,ssh-copy-id,ssh-agent)

[root@python ~]# ssh python
[email protected]'s password: 
Last login: Fri May 15 14:49:17 2020 from fe80::c64e:c937:2ea8:6676%ens33
[test@python ~]$ 

查看公鑰是否一致

[root@python ~]# ssh 192.168.1.80
Last login: Fri May 15 15:16:23 2020 from 192.168.1.80

[root@python ~]# cat ~/.ssh/authorized_keys        #遠程的
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCWLJAYWCpbRPQX8gDbr2mIyXMw/qEKd46u4QhcaDPY7CeGd/buIGsWsuz+DAcnowk095rIwspGGHOdt54s+aeXGXcsRh7Hpuf0Py20Krim+v2LIUQW8vQSJDj1HiQUSnNQNPT3HAm0aqQp8u2EZ0StLYtf/uYSbg6rSzW08mKwhBQkrP0olWb+hD4ak3LxA05OI/WnanGKqtqjLg+4MbgGK96fY53dKvwrdt9NWiuof3pLgTw9fTvPU6CD+cH4LmRg8IVhthlBRhrXPA7oa8gvupTvpMYdNPPUSBsVR2rBcimrUFwdOpzb6T30C7o566noRd3t3nNxkQ/HrKalo9Bn root@python

[root@python ~]# exit
登出
Connection to python closed.

[root@python ~]# cat ~/.ssh/id_rsa.pub              #本地的
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCWLJAYWCpbRPQX8gDbr2mIyXMw/qEKd46u4QhcaDPY7CeGd/buIGsWsuz+DAcnowk095rIwspGGHOdt54s+aeXGXcsRh7Hpuf0Py20Krim+v2LIUQW8vQSJDj1HiQUSnNQNPT3HAm0aqQp8u2EZ0StLYtf/uYSbg6rSzW08mKwhBQkrP0olWb+hD4ak3LxA05OI/WnanGKqtqjLg+4MbgGK96fY53dKvwrdt9NWiuof3pLgTw9fTvPU6CD+cH4LmRg8IVhthlBRhrXPA7oa8gvupTvpMYdNPPUSBsVR2rBcimrUFwdOpzb6T30C7o566noRd3t3nNxkQ/HrKalo9Bn root@python

python自動化管理sshy(ssh,ssh-copy-id,ssh-agent)

二、使用ssh-agent管理私鑰

OpenSSH還提供了一個名爲ssh-agent的程序,該程序可以簡化SSH私鑰的管理操作。ssh-agent是個長時間持續運行的守護進程(daemon),它的唯一目的就是對私鑰進行高速緩存。

使用ssh-agent有以下幾個好處:

(1)如果我們使用了一個加密的私鑰,那麼,使用這個私鑰時將需要輸入密碼才能使用私鑰文件。如果我們使用加密的私鑰並且沒有使用ssh-agent,那麼將不得不在每次使用這個私鑰時都輸入密碼。如果使用ssh-agent管理私鑰,只需要在私鑰加入到ssh-agent的那一刻輸入密碼,在之後的使用中都不用輸入私鑰的密碼;

(2)如果我們有多臺遠程服務器與多個私鑰文件,使用ssh-agent以後,不用在每次登錄服務器時都使用-i參數指定使用哪一個私鑰文件。ssh-agent將會嘗試使用不同的私鑰文件建立連接。直至成功;

(3)使用ssh-agent可以實現私鑰轉發功能。假設現在有三臺服務器,分別是A, B, C。其中,A是我們的控制節點,我們可以在A上直接訪問B,但是我們無法直接訪問C。如果要訪問C,就只能先登最B,再從B登錄C。對於這種情況,是否需要在B中保存用戶的私鑰呢?對於這裏的情況,我們可以使用agent forwarding。使用agent forwarding以後,不用將私鑰保存到B服務器上,只需要在A中保存私鑰,在B和C中保存公鑰,便可在A中訪問B與C這兩臺服務器。爲了使用agent forwarding,我們必須使用ssh-agent管理私鑰。

如果在Windows下使用Xshell進行SSH訪問,要啓動ssh-agent非常簡單,只需要在“連接“-->"SSH“中勾選“使用密碼處理的Xagent (SSH代理)”即可。

(1)先把原先的密鑰刪除並生成新的密鑰

[root@python .ssh]# cd ~/.ssh/
[root@python .ssh]# rm -rf id*
[root@python .ssh]# ssh-keygen 
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.
The key fingerprint is:
dc:57:da:10:e5:1a:8b:15:e3:98:61:d4:02:9f:56:8f root@python
The key's randomart image is:
+--[ RSA 2048]----+
|        .o+.=..  |
|         o.B.B   |
|          *.E +  |
|       . o o O   |
|        S o = .  |
|           .     |
|                 |
|                 |
|                 |
+-----------------+
[root@python .ssh]# ssh-copy-id -i id_rsa.pub 192.168.1.80
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
[email protected]'s password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '192.168.1.80'"
and check to make sure that only the key(s) you wanted were added.

[root@python .ssh]# ssh 192.168.1.80
Enter passphrase for key '/root/.ssh/id_rsa': 
Last login: Fri May 15 15:28:54 2020 from fe80::c64e:c937:2ea8:6676%ens33
[root@python ~]# exit
登出
Connection to 192.168.1.80 closed.

現在登陸需要私鑰

(2)使用ssh-agent保存密鑰

在Linux下,直接執行ssh-agent命令啓動ssh-agent即可。啓動以後,使用ssh-add命令將私鑰添加到ssh-agent中。如下所示:

[root@python ~]# ssh-agent bash
[root@python ~]# ssh-add ~/.ssh/id_rsa
Enter passphrase for /root/.ssh/id_rsa: 
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)
[root@python ~]# 

私鑰添加完成後,可以執行ssh_add -L命令查看哪些私鑰已經被添加到ssh-agent中。如下所示:

[root@python ~]# ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsP4VSOhnnCfidbg7e0OAQFcW5wAgPHld9S8KDTWv3X0/LNilYM3RkXQZ10XQ8Mw34i9rXa3SfqaHk6QYHXjNEUv6PEA/rKWY3kLXH9VUVHry4iwt9kVg9PowfccKLXPi8iWpqS7tk5ZEAnxihBtQattMTC44iz9X6hJDEn1r3r3YplJJGilIR+NaYJrM3ltxUBVuoJ82MfHOomhirc37ihLEwNbqRBMPYC4u1SoXDkagFsh0+HcuE0436yEByFxFw87jPmrjl7bgFsPahQsydrXySXOVdCzQJ8WuzJa1RvKr0xmgCjhZKExUYnMGAN9M79UBAyzZf2vUrwvvpPqWd /root/.ssh/id_rsa

啓動ssh-agent以後,當我們嘗試與遠程服務器建立連接時,ssh客戶端將會嘗試使用存儲在ssh-agent中的私鑰與遠程服務器進行認證。

[root@python ~]# ssh 192.168.1.80
Last login: Fri May 15 15:38:28 2020 from 192.168.1.80
[root@python ~]# exit
登出
Connection to 192.168.1.80 closed.

現在因爲本地保持了私鑰,所以不需要輸入私鑰了

python自動化管理sshy(ssh,ssh-copy-id,ssh-agent)

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