Linux普通使用者無法使用sudo處理及sudoers設定
Linux下我們經常使用的SSH遠端連線到系統進行操作,而為了安全,一般使用的是非root使用者連線,只有在必要的時候,我們才會使用sudo切換到root帳戶下進行操作,以保證系統儘可能的安全和不被損壞。然而,在有的時候我們通過普通使用者SSH連線到Linux的時候,使用sudo來執行身份切換的時候,系統會報錯(以下是CentOS6.4下的報錯):
對不起,使用者 yourusername 不能在 CentOS 上執行 sudo。或者
Sorry,user yourusername may not run sudo on CentOS這種情況下,為了讓我們的使用者能夠正常的使用sudo,需要通過修改/etc/sudoers檔案。
#新增下面一行到:/etc/sudoers,即可讓該使用者使用sudoyourusername ALL=(ALL) ALL這種修改是將所有的許可權都賦值給了yourusername,為了sudo這個命令,就這麼ALL幾下,似乎有點不負責任啊,有木有?
sudoers檔案預設是隻讀的,因此不能直接修改。網上很多方法是使用chmod來修改sudoers的許可權後再通過編輯器(vi/vim etc.)來修改sudoers內容,之後再將sudoers檔案的許可權恢復,來達到修改sudoers的目的。這種方法確實能夠修改sudoers,但是卻沒有辦法保證sudoers檔案的正確性,如果修改出現錯誤,將導致sudoers(sudo)不能正常的工作。更正確的做法是直接使用sudoers的專用編輯器:visudo來編輯sudoers檔案。
# visudo## visudo預設的編輯器是vi,如果你需要修改你的預設編輯器,可以通過新增EDITOR="" 來修改。# EDITOR="/usr/bin/vim -p -X" visudo## 如果要永久改變預設編輯器,只要將EDITOR設定為環境變數# export EDITOR="/usr/bin/vim -p -X"使用visudo來編輯sudoers的好處是:當我們完成sudoers的編輯時,系統會自動檢測我們sudoers的格式是否正確,從而保證sudoers檔案的正確性。
其實,sudoers檔案是非常簡單的,其內容只包含兩種,第一種是別名(Aliases,基本變數定義),第二種是使用者規範描述(user specifications,指定某使用者可以執行的內容)。而這兩種內容都是通過擴充套件巴科斯正規化(EBNF)1來進行定義。一旦定義了別名,在使用者說明中,就可以使用別名來簡化給使用者定義執行內容。如果同一個使用者在sudoers檔案中能夠找到多條說明,那麼將使用找到的最後一條。
sudoers的別名包含四種:User_Alias,Runas_Alias,Host_Alias和Cmnd_Alias。
User_Alias是使用者別名,這個和系統中的group有點類似。通過使用者別名,在sudoers中,可以將一個或者多個使用者用別名來替代。
## 定義一個使用者別名User_Alias OPERATORS = operator1,operator2,remote_admin注意:
1. 等號後面的都是系統中的使用者名稱,使用者ID,組,組id等組成,多個用逗號分隔,具體資訊可參看文後參考內容sudoers2
2. 別名只能是大寫字母開頭的,並由大寫字母,下劃線和數字組成的字串
Runas_Alias和User_Alias類似,但不同的是Runas_Alias指明的是使用者將要執行命令的身份。Runas_Alias可以包含Runas_Alias別名(User_Alias是包含User_Alias別名)。
同時要注意的是,上面兩個別名在匹配的時候使用的是字串匹配法則,也就是說,當兩個不同使用者名稱的使用者,即使使用了同一個使用者ID,在實際情況下,也會被認為是不同的。要避免這種情況,可以考慮使用使用者的ID來替代使用者名稱。如:
Runas_Alias ROOT = #0## 所有的使用者ID為0的,統歸為ROOT別名Host_Alias是主機別名,指定規則適用的主機列表。
Host_Alias SERVERS = 192.168.0.1, 192.168.0.2, server1注意:
1. Host_Alias中,只能使用真實的地址,這就意味著127.0.0.1這種地址是永遠不會被匹配到的。而localhost要只有在真有主機的主機名為localhost的時候才能被匹配。
2. 如果IP地址沒有給定掩碼,sudo自動會搜尋本地網絡卡上對應匹配的掩碼地址來作為預設的網路掩碼。
Cmnd_Alias是命令別名,指定使用者能夠執行的某一類命令的列表。可包含一個,或多個命令(帶引數),目錄,或者其他的命令別名。
Cmnd_Alias SHUTDOWN_CMDS = /sbin/poweroff, /sbin/reboot, /sbin/halt##所有的關機命令Cmnd_Alias ADMIN_CMDS = /usr/sbin/passwd, /usr/sbin/useradd, /usr/sbin/userdel, /usr/sbin/usermod, /usr/sbin/visudo## 所有的使用者管理命令注意:
1. 命令列表中如果包含目錄(以/結束),那麼該目錄下(不含子目錄)的所有可執行檔案都被賦予了執行許可權,這和使用萬用字元*類似;
2. 命令列表中務必使用全路徑名,如果不使用完全限定名,將意味著惡意使用者可以建立同名檔案並在切換後的使用者下執行,這將給系統帶來未知的安全風險;
3. 當命令列表中的命令需要帶引數的時候,如果出現特殊字元(',',':','=','/'),將需要使用反斜杆('/')進行轉義。
通過上面四種別名,我們能夠定義出特定的使用者,主機和命令列表,在實際執行中,我們如果要對這些特定的列表的某些執行時配置項3進行修改,我們可以通過Default來完成。
Default對於前面四種別名的限制格式各有不同,定義如下:
## EBNFDefault_Entry ::= ('Defaults' |'Default' '@' Host_List |'Default' ':' User_List | 'Default' '!' Cmnd_List | 'Default' '>' Runas_List ) Parameter_ListParameter_List ::= (Parameter '=' Value |Parameter '+=' Value |Parameter '-=' Value |'!'* Parameter)[ , Parameter_List]定義中 *_List可以是別名也可以是特定的具體資訊(如:使用者名稱)。
別名之後,就是具體的使用者規範描述(User Specification)了。
User Specification表述的主要意義就是:哪些使用者在哪些環境裡可以作為哪些使用者來執行哪些程式。用EBNF來表示這個定義如下:
User_Spec ::= User_List Host_List '=' (Cmnd_Spec | Cmnd_Spec ',' Cmnd_Spec_List) /(':' Host_List '=' Cmnd_Spec_List)*Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Solaris_Priv_Spec? Tag_Spec* Cmnd Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' SELinux_Spec ::= ('ROLE=role' | 'TYPE=type') Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset') Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' |'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' |'LOG_OUTPUT:' | 'NOLOG_OUTPUT:')看起來很複雜,來個栗子也許會好很多:
## 在SERVERS環境中OPERATORS可以以ROOT角色執行SHUTDOWN_CMDSOPERATORS SERVERS = (ROOT) SHUTDOWN_CMDS## 在所有的環境中yourusername都可以切換到所有賬戶下執行所有的命令yourusername ALL = (ALL) ALL## yourusername使用者在SERVERS上面執行關機操作yourusername SERVERS = /sbin/halt, /sbin/poweroff## 以root來執行關機操作,但以operator來執行kill命令yourusername SERVERS = (root) SHUTDOWN_CMDS, (operator) /bin/kill## sudo -u來選擇使用者## 僅以operator組來執行kill命令yourusername SERVERS = (:operator) /bin/kill## 注意,在sudo的時候需要使用-g配合,但kill還是由yourusername執行## 無需使用密碼(不用校驗operator身份),即可以operator身份來執行kill命令yourusername SERVERS = (operator) NOPASSWD: /bin/kill至於SELinux_Spec和Solaris_Priv_Spec一般不會用到,SELinux_Spec是在支援SELinux的系統中有效,而Solaris_Priv_Spce則是針對Solaris系統的配置。Tag_Spec相對前兩個在Linux系統來說就實用的多,Tag_Spec共有10個可選tag引數,可以分成5組,每組由互斥的兩個tag引數構成,分別是:NOPASSWD和PASSWD,NOEXEC和EXEC,SETENV和NOSETENV,LOG_INPUT和NOLOG_INPUT,LOG_OUTPUT和NOLOG_OUTPUT。不同組別的tag引數可以同時使用,在使用Tag_Spec之後,如果沒有使用相反的tag引數覆蓋,則同行後面的命令將會繼承tag引數設定。下面是5組tag的說明:
Tag引數 | 作用描述 |
NOPASSWD,PASSWD | 標識是否需要身份驗證 |
NOEXEC,EXEC | 是否限制程式進一步執行命令(動態連結有效) |
SETENV,NOSETENV | 標誌如何處理環境變數,建議不用SETENV(預設是NOSETENV),SETENV會禁用通過命令列傳遞的env_reset引數 |
LOG_INPUT,NOLOG_INPUT | 輸入日誌開啟標誌,LOG_INPUT開啟後,所有輸入資訊都會被記錄,如密碼這類敏感資訊同樣會以明文形式記錄下來 |
LOG_OUTPUT,NOLOG_OUTPUT | 輸出日誌標誌,開啟後,所有的輸出都會被儲存在檔案中 |
到此為止,sudoers檔案的主體就已經完成了,根據這些東西,你就可以順利修改sudoers了。
高階部分:
1. 可以通過#includedir,#include兩中方式將其他的sudoers檔案包含進來;
2. 要註釋,用#,當然,第一點中的這個和#後面跟數字的要小心(猜猜看,是神碼?);
3. 在編輯中,為了簡便,你可以在主機列表,路徑名稱和命令列表中使用萬用字元(不是正則),萬用字元:*(匹配0或多個),?(匹配單個字元),[...](匹配範圍內的任一字元),[!...](說了不是正則了,匹配任一不在指定範圍內的字元),/x(轉義特殊字元,如:*,?, [, ])。例外:""雙引號在命令列引數中表示的是命令不允許帶任何引數;傳遞給sudoedit內建命令的命令列引數必須包含路徑名稱,因此斜杆(/)不會被萬用字元匹配;
4. 在Alias,Defaulsts,User Specification中設定值的時候可以使用感嘆號(!),表示取非(排除),當然,如果你覺得多幾個感嘆號能加強效果也是可以的,記住單數表示取反,偶數是雙重否定,直接抵消作用即可。同時也要注意,這個感嘆號有時候會失效,會帶來一些安全風險;
5. 上一點的一點特例:
## 可Runas除了root之外的所有使用者User_Alias SPECIALUSERS = ALL,!root## 這個的作用不同於上面這行規則,sudo匹配的時候是不匹配root## 同時也不會匹配任何其他使用者User_Alias SPECIALUSERS = !root6. 規則太長,一行寫不下?試試行尾加上反斜杆(/),然後換到第二行繼續寫。
7. MitchellChu本身也是菜鳥一枚,共勉! (這個最高階:P)
最後迴歸開篇第一個問題,你覺得這種配置有問題麼?
參考:
1. 擴充套件巴科斯正規化(EBNF):Extended Backus-Naur Form,Backus-Naur Form,巴科斯正規化,擴充套件巴科斯正規化
2. sudoers:Sudoers Manual
3. Sudoers的Default可配置引數請參看2中Sudoers Manual中的SUDOERS OPTIONS
4.其他一些參考:Archlinux SUDO,Ubuntu Sudoers,sudo.ws SUDO manual