iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
0

今天來看一下應試目標能力中還沒介紹的幾個項目。

登入帳號管理及權限晉升 (privilege escalation)

應試目標能力中有一點是「管理 Ansible SSH 登入 credential,包含使用非特權 (unprivileged) 的登入帳號」。考慮到安全性,我們一般不會用 root 帳號來進行遠端 SSH 連線,伺服器最好也禁止 root 帳號的 SSH 連線,這可以在 sshd 設定檔進行設定。因此 Ansible 應使用非 root 帳號進行 SSH 連線。一般說來,SSH 連線可以密碼登入,並將密碼記錄在 inventory 檔案中,但必須對密碼進行加密處理。另外一種方式是採用 ssh key 進行登入,我們可以在 inventory 檔案中指定 ssh key 密鑰的位置所在,或者使用 ssh agent 的功能,以代理的方式進行驗證。

而在登入管理節點後,可能會以其他非登入時的身份來執行任務。官方文件中有一節 privilege escalation 旨在說明相關的操作。最常見的狀況是取得 root 權限以進行套件安裝,或啟動服務等工作。

據我所知,一般 Linux 上系統要讓一般使用者取得 root 權限有兩種方法,第一個是直接讓該使用者成為 root,這個可以用 su 來達成,但需要知道 root 的密碼,第二種方法是使用 sudo,使用者在經過授權後,即可在執行命令時加上 sudo,讓此命令以 root 的權限被執行。通常在使用 sudo 時要輸入使用者自己(不是 root)的密碼,但也可以透過設定讓使用者不需輸入自己的密碼即可使用 sudo。因此如果 Ansible 用來登入管理節點的帳號,在該管理節點上沒有 sudo 的權限,應該是無法用 root 權限來執行命令的。文件似乎沒有特別提到登入管理節點的帳號是否應該先在該節點上取得 sudo 權限,有可能是我漏看了,不過以常理來判斷是應該要有 sudo 權限才能以 root 權限執行指令。

在 playbook 中,我們可以針對每一個 task 去指定它要用那個身分執行,常用的參數是:

  • become - 設成 yes 表示允許或打算以其他非登入身份執行此 task
  • become_user - 打算以那個使用者身份來執行 task,預設是 root。文件上說這個設置並不隱含 become 是 yes,因此 become 還是需要設置。

看一下文件中的兩個範例,第一個範例:

- name: Ensure the httpd service is running
  service:
    name: httpd
    state: started
  become: yes

要啟動 httpd 這個服務,一般要 root 權限,因此 become 設成 yes。become_user 不設定,表示是預設值 root。

- name: Run a command as the apache user
  command: somecommand
  become: yes
  become_user: apache

上面這個例子以 apache 的身份來執行指令。

這裡的設置也可以在機器的層次進行,將相關設定置於 inventory 檔案的某一個 group 或 host 中,相對應的設定參數為 ansible_become 和 ansible_become_user。前面有提到要使用 sudo 時,可能會要求輸入密碼,因為密碼是跟著不同主機所設定的,所以密碼的設置放在這裡,參數為 ansible_become_pass。通常不會在設定檔內放入密碼明文,我們會使用 Ansible vault 來進行加密。範例如下:

webserver ansible_user=manager ansible_become=yes

這表示 Ansible 會用 manager 身份登入 webserver 主機,但所有的任務都會以 root 權限執行。

Jinja2 樣板介紹

Jinja2 是一個樣板引擎,讓 Ansible 可以使用動態表示式及存取變數。第一天的範例曾在 template module 中使用過,此外再看一下 filter、test、lookup 這三個較常用,利用 Jinja2 樣板達成的功能。

filter 的作用可以想這是對資料作某種處理,例如以 JSON 、YAML 格式表達,或是讀進 JSON 、YAML 格式字串,或者一個 list 中符合某種樣式才作後續處理等等。然後看一看這些 filter 會發現一大堆神奇的用法,甚至是產生亂數等等。如果要對資料作處理,或是產生資料,可以來這樣看看有沒有能用的 filter。以下是幾個範例:

# 將變數轉為 JSON 或 YAML 格式
{{ some_variable | to_nice_json }}
{{ some_variable | to_nice_yaml }}

# 取得最小值
{{ [3, 4, 2] | max }}

# 聯集 (union)
{{ list1 | union(list2) }}

# 隨機取值
{{ ['a','b','c'] | random }}

# 計算冪次
{{ myvar | pow(2) }}

文件中還有很多範例,請自行參考。

tests 是測試資料並傳回真假 True / False 的方式,通常會搭配前面的 conditional 使用,例如

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True

  - command: /bin/something
    when: result is failed

lookup 是用在查看外部資料,像是讀取某個檔案的內容,而它是發生在 control machine 端,所以是讀不到 remote 端的檔案的。範例如下:

vars:
  motd_value: "{{ lookup('file', '/etc/motd') }}"
tasks:
  - debug:
      msg: "motd value is {{ motd_value }}"

Ansible Vault

Ansible vault 用於將 Ansible 中會用到的機敏資料加密,它可以加密一個檔案,也可以加密字串。因為 Ansible 可以引入外部變數檔案,所以可以將 password 那些資訊放在一個外部檔案用變數方式引入,再將這個檔案以 vault 加密。或者是先利用 vault 先對某個字串加密,直接在需要的地方使用這些加密過後的字串。

先看一下加解密檔案的方式,加密檔案的指令是:

$ ansible-vault encrypt foo.yml bar.yml baz.yml

可以一次加密多個檔案,它會要求輸入一個密碼。請注意在執行 ansible-playbook 時會用到的所有 vault 加密檔案,都必須使用相同的密碼,因為在執行 ansible-playbook 會需要提供一組加密檔案的密碼,這個密碼必須能夠將所有的加密檔案解密。

編輯加密檔案的指令是 ansible-vault edit foo.yml,解密檔案為 ansible-vault decrypt foo.yml,檢視檔案內容為 ansible-vault view foo.yml。

接下來是字串加密的功能,指令為:

$ ansible-vault encrypt_string --vault-id a_password_file 'foobar' --name 'the_secret'

它會加密 foobar 這個字串,並以指派給 the_secret 這個變數的型式輸出於 console。--vault-id 是指加密的密碼,上面的範例中密碼來自檔案,如果要由使用者輸入,可以用 @prompt 取代 a_password_file。範例輸出如下:

the_secret: !vault |
      $ANSIBLE_VAULT;1.1;AES256
      62313365396662343061393464336163383764373764613633653634306231386433626436623361
      6134333665353966363534333632666535333761666131620a663537646436643839616531643561
      63396265333966386166373632626539326166353965363262633030333630313338646335303630
      3438626666666137650a353638643435666633633964366338633066623234616432373231333331
      6564

可以把這個輸出直接使用於定義此變數之處。

最後是執行會使用到 vault 加密檔案或字串的 ansible-playbook 指令:

$ ansible-playbook --vault-id /path/to/my/vault-password-file site.yml

Ansible Role

文件中是這麼描述 Role 的:它是根據已知的文件結構(組織文件的方式),自動載入某些變數檔、task 及 handler 的方法。看了還是不知道 Role 是拿來做什麼的。文件把 Role 這一節放在 Creating Reusable Playbooks 這一節當中,所以應該可以猜想 Role 是 Ansible 中重用 (reuse) Playbook 的方式之一。我覺得可以把它想像成類似 class(類別)的東西,視為一種單元 (entyity) 的表現方式,包含事先定義好的 task,需要的時候就可以直接引用。一個 Role 由一組檔案所定義而成,有點像是 Java 中的 Package,把它們放在和 playbook 同一個目錄的 roles 目錄底下。假設有一個 role 稱作 webservers,則它和 roles 相對應的目錄結構如下:

roles/
   webservers/
     tasks/
     handlers/
     files/
     templates/
     vars/
     defaults/
     meta/

webservers 底下有 7 個目錄,至少要有一個目錄存在。若需要使用該目錄,則該目錄中必須有一個用來記錄所需資訊的 main.yml 檔案,並置放相關的內容。其中 task 和 handler 的用途應該沒有問題,files 和 temlates 放置部署時會用到的檔案和樣本,defaults 是 role 的預設變數,meta 則是 role 的元資料 (meta data)。Role 在 playbook 中的基本用如下:

---
- hosts: webservers
  roles:
     - common
     - webservers

會去尋找 roles 目錄該角色名稱下的七個子目錄,若包含 main.yml 則取用之。role 的設計是為了重用,可以到 Ansible Galaxy 下載安需要的 role 或上傳自己編寫好的 role。要安裝 roles 的方法如下:

$ ansible-galaxy install geerlingguy.apache,v1.0.0    

其他關於 Ansible role 的說明請參照文件。

Dynamic Inventory

當遠端主機建立在某些環境例如雲端供應商時,這些主機可能是動態產主,因此主機資訊無法事先得知,必須透過特定的介面查詢而來。dynamic inventory 即是因應這種狀況而生。設定的方式會因主機資訊來源而有所不同,這裡就先跳過去。我想如果能在實際環境,像是 AWS 中來練習會比較有感覺,看看之後有時間的話再來做。

Ansible Container (Ansible 容器)

Ansible Container 是利用 Ansible Playbook 來創建 Docker 映像檔以及進行容器編配的工具。因為還沒介紹 Docker container,所以這一段就先跳過去了,等以後有機會再來研究。

結語

Ansible 就介紹到這邊,覺得有點虛,雖然寫了很多但好像沒學到什麼,因為 Ansible 文件的內容實在太龐雜了,到後來幾乎都只是挑重點翻譯罷了。此外像之前提到的,很難設計情境可以邊看文件邊實驗,所以對這些設定值不太有感覺。但總之瞭解了 Ansible 的工作原理,以及 playbook 和 inventory 的基礎設置。若鐵人賽結束後有時間再來看看要怎麼樣能夠以更好的方式來學習 Ansible 吧。


上一篇
[Day 13] Ansible (4)
下一篇
[Day 15] Docker (1)
系列文
30 天準備 LPI DevOps Tools Engineer 證照30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言