nova rootwrap 與系統權限管理

前言

修改物理機上的登錄賬號的權限,修改了/etc/sudoers以後,發現nova-compute工作異常了。
日誌中報錯:

2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task File "/usr/lib/python2.7/site-packages/nova/utils.py", line 272, in execute
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task return processutils.execute(*cmd, **kwargs)
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task File "/usr/lib/python2.7/site-packages/oslo_concurrency/processutils.py", line 275, in execute
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task cmd=sanitized_cmd)
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task ProcessExecutionError: Unexpected error while running command.
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task Command: sudo nova-rootwrap /etc/nova/rootwrap.conf chown 162 /var/lib/nova/instances/_base/78eab795858f16749531aa820efa700d1facb279
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task Exit code: 1
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task Stdout: u''
2016-05-17 10:49:00.202 18893 ERROR oslo_service.periodic_task Stderr: u'sudo: sorry, you must have a tty to run sudo\n'

是nova在執行命令行時sudo出錯了。按道理說我只修改了登錄賬號的權限,nova用戶是非登錄賬戶(nologin),並且沒在我修改的涉及範圍之內,不應該受影響纔對。爲了搞清楚這個問題,研究了一下 nova-rootwrap 和 sudoers的相關知識。

rootwrap

rootwrap 主要用來做權限控制。在程序中,非 root 用戶想執行需要 root 權限相關的命令時,用 rootwrap 來控制。openstack 裏很多項目都用到了它,例如 nova、neutron、cinder。

舉個常見的例子,假如在 nova-compute 的代碼中想要執行一個底層的 mv 命令,由於 nova-compute 進程屬於 nova 用戶和用戶組,在代碼中直接調用 mv 可能會由於權限不夠而出錯。那麼要成功地執行mv 有兩種方式: 執行“ sudo mv ..." 和 執行” sudo nova-rootwrap /etc/nova/rootwrap.conf mv ...“ 。第一種方法看似簡單但是沒有安全地被管理。第二種方法經過了 nova-rootwrap,最終還是會調用 mv。nova-rootwrap 會維護一份它允許執行的命令清單,裏面寫了 nova 需要執行哪些命令和執行時需要的權限。我們要執行 mv 命令,nova-rootwrap 會檢查 mv 命令是否在允許執行的清單中,如果允許執行,那麼就以清單中事先寫好的需要的用戶權限執行。這樣一來,如果我們私自改了 nova-compute 代碼,使用 processutils.py 封裝好的函數調用系統命令執行時,如果在 nova-rootwrap 管理的清單中沒有允許這個命令執行,那麼這段代碼就會失敗。這就相當於 nova-rootwrap 做了安全管理,用白名單過濾的方式。

nova-rootwrap 管理的白名單可以稱之爲 filter 。nova-rootwrap 的配置文件是 /etc/nova/rootwrap.conf ,在配置文件中能看到 filters 的存放路徑。

filters_path=/etc/nova/rootwrap.d,/usr/share/nova/rootwrap

過濾規則放到這兩個路徑下 /etc/nova/rootwrap.d 和 /usr/share/nova/rootwrap。例如 nova compute 的規則: /usr/share/nova/rootwrap/compute.filters 。 過濾規則的寫法看一下這個文件就明白了。過濾規則文件是包含在 nova-compute rpm 裏的,安裝好 rpm 包就有了。

根據官方文檔的指示,同時也要求 nova 用戶有權限執行 nova-rootwrap ,在 sudoers 中配置
nova ALL = (root) NOPASSWD: /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf *

openstack 其他項目的 rootwrap 與 nova-rootwrap 類似,配置文件的路徑略有不同。
rootwrap 更詳細的介紹 https://wiki.openstack.org/wiki/Rootwrap

問題分析

回到我們遇到的問題本身,日誌中報錯提示是 執行 cmd 失敗了

Command: sudo nova-rootwrap /etc/nova/rootwrap.conf chown 162 /var/lib/nova/instances/_base/78eab795858f16749531aa820efa700d1facb279

那麼這個命令就是去 chown 虛擬機的鏡像文件,162 是 nova 用戶 id 。檢查 /usr/share/nova/rootwrap/compute.filters 文件,裏面有 chown 命令的規則

chown: CommandFilter, chown, root

並沒有問題。 問題應該不是出在 rootwrap 上。
手動執行命令來模擬 nova 中的調用:
sudo -u nova sudo nova-rootwrap /etc/nova/rootwrap.conf chown 162 /var/lib/nova/instances/_base/78eab795858f16749531aa820efa700d1facb279
前半句 sudo -u nova 是將手動執行的這個命令行在 nova 用戶下執行,後半句 sudo nova-rootwrap ... 和程序中報錯的 cmd 是完全一樣的,要以 root 權限來執行 chown。執行上面的命令後提示要輸入 nova 的密碼(因爲要 sudo 到 root)。此時就發現了疑點,查看 nova 的代碼,出錯的那段代碼中並沒有看到輸入 nova 密碼的邏輯。在一個正常的環境上也執行同樣的指令,成功返回,不需要輸入密碼。 所以問題很可能出現在輸入密碼這個邏輯。

我們的問題的起因是修改 /etc/sudoers 來修改登錄賬號的權限,應該是這個改動導致了 nova 在 sudo 時需要輸入密碼。

sudoers

在修改 /etc/sudoers 時,只是限制了登錄賬號的一些權限,例如使用 ssh 登錄的賬號 mubai ,並沒有修改 nova 賬號相關的功能。二者看似並沒有聯繫。用 man sudoers 可以學習下 sudoers 的功能。

在仔細對比 /etc/sudoers 前後,發現修改時把 #includedir /etc/sudoers.d 這一行當成無用的註釋給刪除了。#include 和 #includedir 是 sudoers 中的固有語法。 sudo 程序在逐行讀取 /etc/sudoers 時,如果遇到 #include 和 #includedir 會暫停執行後面的行,立即跳轉到 include 文件和路徑中的規則,執行完 include 中的規則後再返回原來的斷點繼續往下執行。 上面介紹 rootwrap 時曾提到,官方要求在sudoers 中 配置 nova 的 sudo 規則,規則文件是 /etc/sudoers.d/nova 。 由於修改 /etc/sudoers 文件時誤把 #includedir 當成註釋給刪了,所以 /etc/sudoers.d/nova 規則就不生效了。

正是在 /etc/sudoers.d/nova 中設置了 nova 用戶 sudo 時無需密碼 “nova ALL = (root) NOPASSWD” ,所以如果 /etc/sudoers.d/nova 在執行 sudo 時沒被讀取,就出現了我們遇到的問題。

另外再提幾個 sudoers 的小知識點:
1)sudoers 配置文件的寫法可以參考 man sudoers 中的介紹,裏面很詳細。 我們就是踩到了 #includedir 的坑,以爲 # 開頭的都是註釋。
2)/etc/sudoers.d/ 下面的配置文件是根據命名排序來決定執行順序的,例如 /etc/sudoers.d/neutron 會比 /etc/sudoers.d/nova 先執行
3)sudoers 中如果同一個用戶的規則重複出現,那麼以後出現的爲準,就是後面的會覆蓋前面的,所以在 /etc/sudoers 和 /etc/sudoers.d/ 中的配置如果有衝突,要確認好生效順序。

總結

這個問題的原因是把 /etc/sudoers 中的 “ #includedir /etc/sudoers.d ” 一行誤刪了,導致寫在 /etc/sudoers.d/nova 中的 sudo 規則不會生效,從而 nova 中執行 sudo 的地方都需要輸入密碼而失敗。

在解決這個問題時,涉及到了 rootwrap 和 sudoers 的相關知識點。

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