1. 程式人生 > 實用技巧 >20200811記錄:ansible sudo提權,劇本,變數資訊

20200811記錄:ansible sudo提權,劇本,變數資訊

---------

1 案例1:配置sudo許可權

1.1 問題

本案例要求使用sudo提升普通使用者的許可權,要求如下:

  • 給所有被管理主機建立系統賬戶
  • 賬戶名稱為alice,密碼為123456
  • 修改sudo配置,讓alice可以執行任何管理命令

1.2 方案

sudo(superuser or another do)讓普通使用者可以以超級管理員或其他人的身份執行命令。

sudo基本流程如下:

  1. 管理員需要先授權(修改/etc/sudoers檔案)
  2. 普通使用者以sudo的形式執行命令

修改/etc/sudoers的方法如下:

  1. visudo(帶語法檢查,預設沒有顏色提示)
  2. vim /etc/sudoers(不帶語法檢查,預設有顏色提示)

授權格式如下:

使用者或組 主機列表=(提權身份) [NOPASSWD]:命令列表

注意事項:命令需要寫絕對路徑,對組授權需要在組名稱前面加%。

[root@control ~]# cat  /etc/sudoers         #不要改,下面僅僅是語法格式的示例(例子)
… …
root           ALL=(ALL)       ALL
tom            ALL=(root)      /usr/bin/systemctl
%wheel         ALL=(ALL)       ALL

1.3 步驟

實現此案例需要按照如下步驟進行。

步驟一:配置sudo提權

1)遠端所有被管理主機批量建立系統賬戶,賬戶名稱為alice,密碼為123456。

[root@control ansible]# ansible all -m user -a "name=alice \
password={{'123456' | password_hash('sha512')}}"

2)配置alice賬戶可以提權執行所有命令(control批量授權,node1主機驗證)。

使用lineinfile模組修改遠端被管理端主機的/etc/sudoers檔案,line=後面的內容是需要新增到檔案最後的具體內容。

等於是在/etc/sudoers檔案末尾新增一行:alice ALL=(ALL) NOPASSWD:ALL

[root@control ansible]# ansible all -m lineinfile \
-a "path=/etc/sudoers line='alice  ALL=(ALL) NOPASSWD:ALL'"
[root@control ~]# ssh alice@node1

如何驗證?可以在node1電腦上面使用alice使用者執行sudo重啟服務的命令看看是否成功。

[alice@node1 ~]$ sudo systemctl restart sshd                   #不需要輸入密碼

2 案例2:修改Ansible配置

2.1 問題

沿用練習一,修改ansible配置實現使用普通使用者遠端被控制端主機,具體要求如下:

  • 修改主配置檔案
  • 設定ansible遠端被管理端主機賬戶為alice
  • 設定ansible遠端管理提權的方式為sudo
  • 修改主機清單檔案
  • 修改主機清單配置檔案,新增SSH引數

2.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:配置普通使用者遠端管理其他主機

1)修改主配置檔案,配置檔案檔案的內容可以參考/etc/ansible/ansible.cfg。

[root@control ~]# vim ~/ansible/ansible.cfg
[defaults]
inventory = ~/ansible/inventory
remote_user = alice                #以什麼使用者遠端被管理主機(被管理端主機的使用者名稱)
[privilege_escalation]
become = true                    #alice沒有特權,是否需要切換使用者提升許可權
become_method = sudo                #如何切換使用者(比如用su就可以切換使用者,這裡是sudo)
become_user = root                #切換成什麼使用者(把alice提權為root賬戶)
become_ask_pass = no                #執行sudo命令提權時是否需要輸入密碼

思考:

如果A主機ssh遠端訪問B主機,應該輸入哪個主機的使用者名稱和對應的密碼?

如果張三要去李四家,應該使用誰家的鑰匙,開啟誰家的門?

2)遠端被管理端主機的alice使用者,需要提前配置SSH金鑰。

[root@control ~]# for i in node1  node2  node3  node4  node5
do
  ssh-copy-id    alice@$i
done

驗證效果:

[root@control ~]# ssh alice@node1            #依次遠端所有主機看看是否需要密碼
#注意:是遠端登入node1,應該輸入的是node1電腦上面alice賬戶的密碼,control沒有alice使用者
[root@control ~]# ansible all -m command -a  "who"              #測試效果
[root@control ~]# ansible all -m command -a  "touch /test"     #測試效果

常見報錯(有問題可以參考,沒問題可以忽略):

node1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: alice@node1: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
    "unreachable": true
}
問題分析:
英語詞彙:Failed(失敗),connect(連線),to(到),host(主機),via(通過)
permission(許可權),denied(被拒絕)
Failed to connect to host via ssh alice@node1(通過ssh使用alice遠端連線到主機失敗)
Permission denied(因為無法連線,所以報錯說許可權被拒絕)
解決辦法:手動ssh alice@主機名(如node1),看看是否可以實現免密碼登入。
          Ansible的原理是基於ssh遠端管理,如果無法實現alice免密碼登入,則實驗會失敗!
        如何實現免密碼登入,可以參考案例上面的命令,或者第一階段相關知識。

3)修改inventory主機清單配置檔案(參考即可,不需要操作)。

如果個別主機的賬戶不同,該如何處理呢?

如果有些主機需要使用密碼遠端呢?如果有些主機的SSH埠不是22呢?

[root@control ~]# cat  ~/ansible/inventory
[test]                    
node1           ansible_ssh_port=220                      #自定義遠端SSH埠
[proxy]
node2           ansible_ssh_user=alice                    #自定義遠端連線的賬戶名
[webserver]
node[3:4]       ansible_ssh_pass=密碼                     #自定義遠端連線的密碼
[database]
node5
[cluster:children]                
webserver
database

3 案例3:Playbook應用案例

3.1 問題

沿用練習二,編寫Ansible Playbook劇本,使用Playbook完成自動化操作,具體要求如下:

  • 熟悉Playbook語法格式
  • 編寫Playbook管理系統賬戶
  • 編寫Playbook管理邏輯卷
  • 編寫Playbook管理軟體包

3.2 方案

Ansible ad-hoc可以通過命令列形式遠端管理其他主機,適合執行一些臨時性簡單任務。另外還有一種遠端管理的方式叫Playbook,Ansible Playbook中文名稱叫劇本,它將經常需要執行的任務寫入一個檔案,這個檔案就叫劇本。

  • 劇本中可以包含多個任務
  • 劇本寫後,我們隨時根據劇本,執行相關的任務命令
  • Playbook劇本要求按照YAML格式編寫
  • 適合執行週期性經常執行的複雜任務

YAML是什麼?

  • YAML是一個可讀性高、用來表達資料序列的格式語言
  • YAML:YAML Ain't a Markup Language
  • YAML以資料為中心,重點描述資料的關係和結構

YAML的格式要求如下:

  • "#"代表註釋,一般第一行為三個橫槓(---)
  • 鍵值(key/value)對使用":"表示,陣列使用"-"表示
  • key和value之間使用":"分隔
  • ":"後面必須有空格
  • 一般縮排由兩個或以上空格組成
  • 相同層級的縮排必須對齊,縮排代表層級關係
  • 全文不可以使用tab鍵
  • 區分大小寫
  • 副檔名為yml或者yaml
  • 跨行資料需要使用>或者|,其中|會保留換行符

YAML示例展示:

1)demo1

---
"詩仙": "李白"
或者
"詩仙": 
   "李白"

2)demo2

#陣列的例子
---
- "李白"
- "杜甫"
- "白居易"
- "唐僧"

3)demo3

#使用一行表示陣列的例子
---
"詩人": ["李白","杜甫","白居易"]

4)demo4

#鍵值對和陣列符合例子:
---
"詩人":
  - "李白"
  - "杜甫"
  - "白居易"

5)demo5

1 #複雜案例
2 ---
3 - "詩人":
4     - 唐代:
5          - "李白"
6          - "杜甫"
7     - 宋代:
8          - "蘇軾"
9          - "李清照"

6)demo6

1 #喜歡的電影
2 ---   
3 - 芳華
4 - 戰狼
5 - 霸王別姬

7)demo7

1 #人物描述
2 ---   
3 - 姓名: 李白
4   年齡: 61
5   作品: 蜀道難
6   好友: 汪倫

8)demo8

#跨行文字(計算機理解為一行)
---  
自我介紹:  >
  字太白,號青蓮居士,
  唐代詩人,祖籍隴西郡,
  今甘肅省平涼市

9)demo9

#跨行文字(計算機理解為多行)
---  
自我介紹:  |
  字太白,號青蓮居士,
  唐代詩人,祖籍隴西郡,
  今甘肅省平涼市 

10)demo10

注意-和:後面必須有空格。

 1 #一張發票
 2 --- 
 3 發票編號: 34843
 4 日期: 2028-12-12
 5 商品:
 6   - 商品編號: BL394D
 7     描述: 足球
 8     價格: 100
 9   - 商品編號: BL4438H
10     描述: 棒球
11     價格: 200
12 稅費: 10.00
13 總價: 310.00
14 備註: >
15     本次採購商品均
16     屬於球類運動商品.  

11)demo11

#錯誤日誌
---
時間: 2028-10-01  15:01:42
使用者: ed
錯誤資訊: 
  - 檔案: nginx.conf
    行號: 23
    錯誤編碼: "0x3D5FF1"
  - 檔案: test.php
    行號: 12
    錯誤程式碼: "0xA4C51E"
警告資訊: |
    你有兩個錯誤資訊需要檢視,
    一條是配置檔案錯誤,
    一條是指令碼語法錯誤,
    具體內容參考錯誤資訊. 

Playbook語法格式要求如下:

  • playbook採用YAML格式編寫
  • playbook檔案中由一個或多個play組成
  • 每個play中可以包含:
  • hosts(主機)、tasks(任務)、vars(變數)等元素組成
  • 使用ansible-playbook命令執行playbook劇本

步驟一:測試Playbook語法格式

1)編寫第一個Playbook(劇本)

hosts、tasks、name是關鍵詞(不可修改),ping是模組,呼叫不同模組完成不同任務。

1 [root@control ansible]# vim ~/ansible/test.yml 
2 ---
3 - hosts: all                                #hosts定義要遠端誰?
4   tasks:                                    #tasks定義遠端後要執行的任務有哪些?
5       - name: This is my first playbook      #name後面的具體內容可以任意
6         ping:
7 [root@control ansible]# ansible-playbook ~/ansible/test.yml

執行效果如圖-1所示

2)定義多個主機和任務的劇本

hosts由一個或多個組或主機組成,逗號分隔,tasks由一個或多個任務組成,多個任務按順序執行,執行ansible-playbook命令可以使用-f選項自定義併發量。

 1 [root@control ansible]# vim ~/ansible/test.yml 
 2 - hosts: test,webserver
 3   tasks:
 4       - name: This is my first playbook     #name後面的內容可以任意
 5         ping:
 6       - name: Run a shell command
 7         shell: touch ~/shell.txt
 8 #hosts定義需要遠端哪些被管理主機,hosts是關鍵詞
 9 #tasks定義需要執行哪些任務,tasks是關鍵詞
10 #第一個任務呼叫ping模組,該模組沒有引數
11 #第二個任務呼叫shell模組在被管理主機建立一個空檔案~/shell.txt
12 [root@control ansible]# ansible-playbook ~/ansible/test.yml  -f 5
13 ## 驗證:到node1、node3、node4主機分別執行命令ls /root/shell.txt檢視是否有該檔案

3)多個play的Playbook檔案

 1 [root@control ansible]# vim ~/ansible/test.yml
 2 #第一個play劇目
 3 ---
 4 - hosts: test
 5   tasks:
 6       - name: This is first play
 7         ping:
 8 #第二個play劇目
 9 - hosts: webserver
10   tasks:
11       - name: This is second play
12         ping:

步驟二:Playbook應用案例

1)使用者管理,建立系統賬戶、賬戶屬性、設定密碼(ansible-doc user)。

[root@control ansible]# vim ~/ansible/test_john.yml
---
- hosts: webserver
  tasks:
    - name: Add the user 'johnd' 
      user:
        name: johnd
        uid: 1040
        group: daemon
        password: "{{ '123' | password_hash('sha512') }}"
#hosts定義需要遠端的物件是webserver組,hosts是關鍵詞
#tasks定義需要執行的任務,tasks是關鍵詞
# name是第一個任務的描述資訊,描述資訊可以任意
# user是第一個任務需要呼叫的模組,user下面的縮排內容是給user模組的引數
# name是需要建立的使用者名稱,uid是使用者ID號
# group是使用者屬於哪個基本組
# password是使用者的密碼,密碼是123,密碼經過sha512演算法加密
[root@control ansible]# vim ~/ansible/user_james.yml
---
- hosts: webserver
  tasks:    
    - name:  Add 'james' with a bash shell
      user:
        name: james
        shell: /bin/bash
        groups: bin,adm
        password: "{{ '123' | password_hash('sha512') }}" 
#與上一個案例類似,groups指定使用者屬於哪些附加組.
[root@control ansible]# vim ~/ansible/user_johnd.yml
---
- hosts: webserver
  tasks:
    - name: Remove the user 'johnd'
      user:
        name: johnd
        state: absent
#刪除系統賬戶johnd,state的值設定為absent是刪除使用者

2)使用playbook管理邏輯卷

準備工作:給node2主機再新增一塊磁碟(以下實驗磁碟名稱僅為參考,不要照抄)。

(ansible-doc parted,ansible-doc lvg,ansible-doc lvol)

[root@control ansible]# vim ~/ansible/lvm.yml
---
- hosts: node2                            #遠端node2主機
  tasks:
    - name: Create a new primary partition with a size of 1GiB  #任務的描述資訊
      parted:                                 #呼叫parted模組進行分割槽         
        device: /dev/sdb                     #對/dev/sdb磁碟進行分割槽(磁碟名稱不要照抄)
        label: gpt                          #分割槽表型別為gpt,或msdos
        number: 1                           #分割槽編號(建立第幾個分割槽)
        state: present                     #present是建立分割槽,absent是刪除分割槽
        part_start: 1MiB                   #分割槽的開始位置(預設從最開始位置分割槽)
        part_end: 1GiB                     #分割槽的結束位置(不寫就分到磁碟最後位置)
    - name: Create a volume group on top of /dev/sdb1     #第二個任務的描述資訊
      lvg:                                  #呼叫lvg模組,建立VG卷組
        vg: my_vg                          #要建立的卷組名稱
        pvs: /dev/sdb1                     #使用哪個分割槽建立PV
    - name: Create a logical volume of 512m          #第三個任務的描述資訊
      lvol:                                 #呼叫lvol模組建立LV
        vg: my_vg                          #使用哪個VG建立LV
        lv: my_lv                          #需要建立的LV名稱
        size: 512m                         #要建立的LV大小,可以不指定單位,預設單位m

3)使用playbook管理軟體(ansible-doc yum)

RHEL或CentOS系統中的軟體有組包的概念,使用yum grouplist或者dnf grouplist可以檢視組包的名稱。

[root@control ansible]# vim ~/ansible/package.yml
---
- hosts: webserver                        #需要遠端的主機是誰
  tasks:                                   #定義劇本需要執行的任務
    - name: Install a list of packages  #第一個任務的描述資訊 
      yum:                                 #呼叫yum模組安裝軟體
        name:                              #安裝軟體的名字,它的值有多個,使用陣列-
          - httpd                          #安裝httpd軟體
          - mariadb                        #安裝mariadb軟體
          - mariadb-server                #安裝mariadb-server
    - name: install the 'RPM Development Tools' package group   #第二個任務的描述資訊
      yum:                                  #呼叫yum模組安裝軟體組包
        name: "@RPM Development Tools"        #安裝哪個組包,@是關鍵詞
    - name: update software               #第三個任務的描述資訊
      yum:                                  #呼叫yum模組升級軟體
        name: '*'                           #需要升級哪些軟體
        state: latest                       #latest代表升級軟體
#備註:state的值可以是(present|absent|latest)
#present代表安裝軟體(預設是present);absent代表解除安裝軟體
#latest代表升級軟體

----

4 案例4:Playbook應用案例

4.1 問題

沿用練習三,繼續練習Ansible 特殊模組並掌握自定義變數的方式,具體要求如下:

  • 熟悉setup與debug模組
  • 熟悉各種常見的變數定義方式

步驟一:Ansible特殊模組

1)setup模組

ansible_facts用於採集被管理裝置的系統資訊,所有收集的資訊都被儲存在變數中,每次執行playbook預設第一個任務就是Gathering Facts,使用setup模組可以檢視收集到的facts資訊。

[root@control ansible]# ansible test -m setup
192.168.4.10 | SUCCESS => {
"ansible_facts": {
   "ansible_all_ipv4_addresses": [
… 省略部分內容…

試試自己找出下列變數:

  • ansible_all_ipv4_addresses #IP地址
  • ansible_bios_version #主機板BIOS版本
  • ansible_memtotal_mb #總記憶體
  • ansible_hostname #主機名
  • ansible_fqdn #主機的域名
  • ansible_devices.sda.partitions.sda1.size #某個磁碟分割槽的大小

2)debug模組

debug模組可以顯示變數的值,可以輔助排錯,通過msg可以顯示變數的值,變數需要使用{{}}擴起來。

[root@control ansible]# vim ~/ansible/debug.yml
---
- hosts: test
  tasks:
    - debug:
        msg: "主機名是:{{ ansible_hostname }}"
    - debug:
        msg: "總記憶體大小:{{ ansible_memtotal_mb }}"
#備註呼叫debug模組顯示某些具體的變數值
#debug模組可以顯示變數的值,可以輔助排錯

步驟二:定義變數的方法

Ansible支援十幾種定義變數的方式,這裡我們僅介紹其中一部分變數。

下面是根據優先順序排序的定義方式:

  1. Inventory變數
  2. Host Facts變數
  3. Playbook變數
  4. Playbook提示變數
  5. 變數檔案
  6. 命令列變數

1)Inventory變數(在主機清單配置檔案中定義變數)。

[root@control ansible]# vim ~/ansible/inventory
[test]
node1  iname="nb" 
[proxy]
node2
[webserver]
node[3:4]
[webserver:vars]
iname="dachui"
#備註,在node1主機後面給該主機新增變數iname,值為nb.
#給webserver組定義變數,vars是關鍵詞不可以改變,webserver是上面定義的組
#給這個組定義變數iname="dachui"

下面編寫劇本呼叫剛才的變數:(在劇本中需要呼叫變數是要使用{{}})

[root@control ansible]# vim ~/ansible/inventory_var.yml
---
- hosts: node1,webserver                         #定義需要遠端管理的主機是誰               
  tasks:                                           #劇目要完成哪些任務
    - name: create a user with var.              #劇目中的第一個任務描述資訊
      user:                                        #呼叫user模組建立使用者
        name: "{{ iname }}"                      #需要建立的使用者名稱是iname這個變數
#注意事項:
#在ansible劇本中當呼叫變數時,開始位置就呼叫變數,就需要在{{}}外面加雙引號
#如果是在後面或者中間位置呼叫變數{{}}外面可以不加雙引號
#如:
#  "{{ iname }}"
#  nihao {{ iname }}

2)Host Facts變數(可以直接呼叫ansible收集的系統資訊)

[root@control ansible]# vim ~/ansible/facts_var.yml
---
- hosts: test
  tasks:
    - name: create user.
      user:
        name: "{{ansible_hostname}}"
#定義劇本,遠端所有被管理主機,呼叫user模組,建立使用者
#需要建立的使用者名稱ansible_hostname是一個ansible_facts變數
#驗證: 到node1主機檢視是否有一個與主機名同名的使用者

3)Playbook變數(使用vars關鍵詞可以在playbook內定義變數)。

[root@control ansible]# vim ~/ansible/playbook_var.yml
---
- hosts: test
  vars:                                     #vars是關鍵詞,用來定義變數用的
    iname: heal                            #具體變數名是iname,值是heal
    ipass: '123456'                       #再定義一個變數名是ipass,值是123456
#注意密碼必須是字串,需要引號                           
  tasks:                                   #tasks定義需要執行的任務
    - name: Use variables create user.  #給任務寫個描述資訊   
      user:                                #呼叫user模組建立使用者
        name: "{{ iname }}"               #使用者名稱的是前面定義的變數
        password: "{{ ipass | password_hash('sha512') }}"
#密碼是前面定義好的ipass,管道給password_hash把密碼加密.

4)Playbook提示變數(根據提示輸入變數的值)。

[root@control ansible]# vim ~/ansible/prompt_var.yml
---
- hosts: test
  vars_prompt:                         #vars_prompt是關鍵詞,定義提示變數
    - name: iname                      #通過name定義變數名為iname
      prompt: "請輸入使用者名稱"           #執行劇本時提示資訊
      private: no                      #是否是隱私資料,no代表不是(螢幕可以顯示)                                              
    - name: ipasswd                   #通過name再定義變數,變數名為ipasswd
      prompt: "請輸入密碼"             #執行劇本時提示資訊
      private: yes                     #是否是隱私資料,yes代表是(隱私資料螢幕不顯示)                                              
  tasks:                               #定義劇本需要執行的任務
    - name: Create a user.           #定義第一個任務的描述資訊
      user:                            #呼叫user模組建立使用者,設定使用者密碼
        name: "{{ iname }}"          #使用者名稱是前面建立的變數iname
        password: "{{ ipasswd | password_hash('sha512') }}"
#密碼是前面定義的變數ipasswd,密碼管道給password_hash加密.

5)單獨定義個變數檔案,在playbook中用vars_files呼叫該檔案。

[root@control ansible]# vim ~/ansible/file_var.yml
---
- hosts: test
  vars_files: variables.yml             #當變數比較多時,專門定義一個檔案用來存變數
  tasks:
    - name: create user.
      user:
        name: "{{ iname }}"
        password: "{{ ipass | password_hash('sha512') }}"
#呼叫user模組建立使用者
#使用者名稱是變數檔案variables.yml中定義的變數iname,密碼也是變數檔案中定義的變數
[root@control ansible]# vim  ~/ansible/variables.yml
---
iname: cloud
ipass: '123456'

6)執行ansible-playbook命令時使用-e引數定義變數

[root@control ansible]# vim ~/ansible/command_var.yml
---
- hosts: test
  tasks:
    - name: create user
      user:
        name: "{{ iname }}"
        password: "{{ ipass | password_hash('sha512') }}"
[root@control ansible]# ansible-playbook command_var.yml \
-e iname="beth" -e ipass="123456"

附加思維導圖,如圖-2所示: