針對 Linux 使用者的進階管理,同時還有處理一下重要的 ACL 這玩意兒,針對單一用戶、群組所進行的權限設計!
帳號管理是一門大學問,使用者可以回想一下之前玩過的 useradd, userdel, usermod 等指令的功能,同時再回想一下之前的權限概念, 就能夠知道使用者帳號管理的行為有多重要了!這一堂課還會針對同一個檔案給予個別帳號或個別群組的權限功能,啟用的是所謂的 ACL 的概念! 都是非常重要的管理行為!
在管理權限時,操作者可以藉由 id 這個指令查詢使用者所加入的次要群組支援,藉以了解使用者對於某個檔案的權限。 而主要的檔案記錄其實是使用者的 UID 與 GID。
系統記錄使用者 UID 與 GID 的檔案主要在:
針對 UID 的部份,在 CentOS 7.x 以後,系統管理員、系統帳號與一般帳號的 UID 範圍為:
id 範圍 | 該 ID 使用者特性 |
0 (系統管理員) | 當 UID 是 0 時,代表這個帳號是『系統管理員』! |
1~999 (系統帳號) | 保留給系統使用的 ID,其實除了 0 之外,其他的 UID 權限與特性並沒有不一樣。預設 1000
以下的數字讓給系統作為保留帳號只是一個習慣。根據系統帳號的由來,通常這類帳號又約略被區分為兩種:
|
1000~60000 (可登入帳號) | 給一般使用者用的。事實上, Linux 核心支援 32 位元的 UID 記載, 所以目前 linux 核心至少已經可以支援到 4294967295 (2^32-1) 這麼大的 UID 號碼 |
Linux 的帳號資料記錄在 /etc/passwd 當中,這個檔案的內容中,以冒號 (:) 為區隔,共有七個欄位,每個欄位的意義為:
更多的說明可以參考 man 5 passwd 的內容。早期使用者加密過的密碼記錄在 /etc/passwd 第二個欄位,但這個檔案的權限是任何人均可讀取, 因此,有心人士可以查閱到加密過的密碼,再以暴力破解法就可能可以獲取所有人的密碼。因此,密碼欄位已經移動到另一個檔案去, 這就是 /etc/shadow 的由來。 /etc/shadow 以冒號 (:) 分隔成 9 欄位,各欄位功能為 (詳細資料可查詢 man 5 shadow):
使用者的密碼加密機制是可變的,從早期的 md5 到新的 sha512 改善了密碼的資料長度,對於暴力破解法來說, 解密的時間會比較長。至於目前系統的加密機制可使用底下的方式查閱:
[root@localhost authselect]# authselect test sssd -s | grep password password requisite pam_pwquality.so try_first_pass local_users_only password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok password sufficient pam_sss.so use_authtok password required pam_deny.so [root@localhost authselect]# cat /etc/login.defs | grep -i encrypt # Use SHA512 to encrypt password. ENCRYPT_METHOD SHA512
使用者的初始群組 (原生家庭) 記載在 /etc/passwd 檔案的第四個欄位,不過該 GID 對應到人類認識的群組名稱就得到 /etc/group 當中查詢。 這個檔案的內容同樣使用冒號 (:) 分隔成四個欄位,內容為:
這三個檔案中心以 /etc/passwd 為主,連結到 /etc/group 與 /etc/shadow 的示意圖如下:
從上述資料我們可以知道,Linux 的帳號資訊大概都記錄在 /etc/passwd, /etc/shadow, /etc/group 當中,那如果我們要新建帳號時, 系統會怎麼做呢?先測試建置帳號:
[root@localhost ~]# useradd testuser1 [root@localhost ~]# passwd testuser1 Changing password for user testuser1. New password: Retype new password: passwd: all authentication tokens updated successfully.
讓我們觀察一下 testuser 這個帳號的相關資料,先看一下使用者的 UID 與 GID:
[root@localhost ~]# id testuser1 uid=1008(testuser1) gid=1010(testuser1) groups=1010(testuser1) [root@localhost ~]# grep testuser1 /etc/passwd /etc/group /etc/shadow /etc/passwd:testuser1:x:1008:1010::/home/testuser1:/bin/bash /etc/group:testuser1:x:1010: /etc/shadow:testuser1:$6$80dXJbaTImyTNKKd$pS....tgJsFdU1:18393:0:99999:7:::
上述 shadow 的資料可以簡易的使用如下的指令來查詢:
[root@localhost ~]# LANG=C chage -l testuser1
Last password change : May 11, 2020
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
一般來說,新建帳號時,系統會搞定底下的事情:
至於新建使用者時,上述的動作參考資料其實是參考 /etc/default/useradd 檔案而來,該檔案內容如下:
[root@localhost ~]# cat /etc/default/useradd # useradd defaults file GROUP=100 <==若為公開群組,使用 GID 100 的群組名稱 HOME=/home <==預設使用者家目錄位置 INACTIVE=-1 <==密碼是否失效,預設不會失效! EXPIRE= <==帳號是否需要失效 (shadow 第 8 欄位) SHELL=/bin/bash <==預設使用的 shell SKEL=/etc/skel <==預設使用者家目錄的參考依據 CREATE_MAIL_SPOOL=yes <==是否要建立使用者郵件信箱
除了 /etc/default/useradd 之外,其他像是密碼欄位的預設值,則寫入在 /etc/login.defs 這個檔案中,這個檔案的內容如下:
[root@localhost ~]# grep -v '#' /etc/login.defs | grep -v '^$' MAIL_DIR /var/spool/mail <==使用者預設郵件信箱放置目錄 PASS_MAX_DAYS 99999 <==/etc/shadow 內的第 5 欄,多久需變更密碼日數 PASS_MIN_DAYS 0 <==/etc/shadow 內的第 4 欄,多久不可重新設定密碼日數 PASS_MIN_LEN 5 <==密碼最短的字元長度,已被 pam 模組取代,失去效用! PASS_WARN_AGE 7 <==/etc/shadow 內的第 6 欄,過期前會警告的日數 UID_MIN 1000 <==使用者最小的 UID,意即小於 1000 的 UID 為系統保留 UID_MAX 60000 <==使用者能夠用的最大 UID SYS_UID_MIN 201 <==保留給使用者自行設定的系統帳號最小值 UID SYS_UID_MAX 999 <==保留給使用者自行設定的系統帳號最大值 UID GID_MIN 1000 <==使用者自訂群組的最小 GID,小於 1000 為系統保留 GID_MAX 60000 <==使用者自訂群組的最大 GID SYS_GID_MIN 201 <==保留給使用者自行設定的系統帳號最小值 GID SYS_GID_MAX 999 <==保留給使用者自行設定的系統帳號最大值 GID CREATE_HOME yes <==在不加 -M 及 -m 時,是否主動建立使用者家目錄? UMASK 077 <==使用者家目錄建立的 umask ,因此權限會是 700 USERGROUPS_ENAB yes <==使用 userdel 刪除時,是否會刪除初始群組 ENCRYPT_METHOD SHA512 <==密碼加密的機制使用的是 sha512 這一個機制!
一般來說,除非有特殊的需求,例如需要建立的是雲端集中帳號管理,所以需要修改上述的設定檔資料 (/etc/default/useradd, /etc/login.defs),否則盡量使用自訂的手動修改使用者相關參數,不要隨意更動上述的檔案內容。
passwd 就含有很多功能!只是, passwd -S 顯示的訊息比較簡略,有時候我們可以透過另外幾個程式來了解!
若需要刪除帳號,使用 userdel 即可。不過需要加上 -r 的選項較佳!如果忘記加上 -r 的選項時,你應該要這樣做:
[root@localhost ~]# userdel testuser1 [root@localhost ~]# ll -d /home/testuser1 /var/spool/mail/testuser1 drwx------. 3 1008 1010 78 5月 11 15:07 /home/testuser1 -rw-rw----. 1 1008 mail 0 5月 11 15:07 /var/spool/mail/testuser1 [root@localhost ~]# find / -nouser /home/testuser1 /home/testuser1/.mozilla /home/testuser1/.mozilla/extensions /home/testuser1/.mozilla/plugins /home/testuser1/.bash_logout /home/testuser1/.bash_profile /home/testuser1/.bashrc /var/spool/mail/testuser1 [root@localhost ~]# rm -rf /home/testuser1 /var/spool/mail/testuser1
如上所示,系統會有一堆暫存資料需要刪除,因此管理員可能需要使用 rm -rf /home/testuser1 /var/spool/mail/testuser1 來刪除掉這些沒主人的檔案。
我們知道 id 可以找出使用者 UID 與 GID,但是 id 只能接一個參數而已,若需要 /etc/passwd 內所有帳號的 UID 與 GID 列表呢? 除了使用管線命令的 xargs 之外,我們可以使用 shell script 的迴圈控制來處理。Bash shell script 的 for 迴圈基本語法如下:
for 變數名 in 內容1 內容2 內容3 ... do 執行的指令碼 done
變數名稱會在 do..done 當中被取用,然後第一次執行迴圈為『變數名=內容1』,第二次為『變數名=內容2』,以此類推! 依據上面的基本語法,我們可以透過管線命令取出 /etc/passwd 內的第 1 個欄位的帳號資料後,丟進迴圈處理。如下所示:
[root@localhost ~]# mkdir bin; cd bin [root@localhost bin]# vim allid.sh #!/bin/bash # This script will show all users id # VBird 2016/05/03 users=$( cut -d ':' -f 1 /etc/passwd) for username in ${users} do id ${username} done [root@localhost bin]# chmod a+x allid.sh [root@localhost bin]# allid.sh uid=0(root) gid=0(root) groups=0(root) uid=1(bin) gid=1(bin) groups=1(bin) uid=2(daemon) gid=2(daemon) groups=2(daemon) .......
bash shell script 的迴圈控制主要是根據 for ... do ... done 來處理,所以也稱為 for 迴圈。上述的腳本中:
使用者在新建資料時,預設的權限會是如何規範?一般來說,依據帳號的差異而會給予這樣的設定:
這樣的權限設計是考量一般用戶可能會有同群組互相操作『同群組共享目錄』的可能之故。但其實該預設權限是可以修改的, 其主要的設定為 umask 所管理。
[student@localhost ~]$ umask 0002 [root@localhost ~]# umask 0022
分別使用 root 與 student 查閱 umask 時,其輸出的結果並不相同。最簡單的思考方向,umask 為拿掉不想要給予的預設權限。 而四組分數中,第一個為特殊權限分數,不用理會,後續三個分數 (root為022而student為002) 即為一般權限設定的三種身份權限。
如果 linuxuser1 在新建目錄時,希望同群組的用戶可以一同完整操作檔案,但是其他人則沒有任何權限,該如何處理 umask 呢? 簡單的處理流程為:
[root@localhost ~]# su - linuxuser1 [linuxuser1@localhost ~]$ umask 0002 [linuxuser1@localhost ~]$ umask 007 [linuxuser1@localhost ~]$ umask 0007 [linuxuser1@localhost ~]$ mkdir newdir [linuxuser1@localhost ~]$ touch newfile [linuxuser1@localhost ~]$ ll -d new* drwxrwx---. 2 linuxuser1 linuxuser1 6 May 11 16:00 newdir -rw-rw----. 1 linuxuser1 linuxuser1 0 May 11 16:00 newfile
若需要這樣的設定永遠存在,就寫入 ~/.bashrc 當中即可。
解決方案很簡單,因為只是修改未來新用戶的資料而已,因此只要修訂 /etc/skel 即可處理完畢!
[root@localhost ~]# cd /etc/skel [root@localhost skel]# mkdir bin [root@localhost skel]# vim .bashrc # User specific aliases and functions HISTSIZE=10000 HISTFILESIZE=10000 alias cp="cp -i" alias mv="mv -i" alias rm="rm -i" [root@localhost skel]# useradd testuser2 [root@localhost skel]# ll /home/testuser2; tail -n 4 /home/testuser2/.bashrc drwxr-xr-x. 2 testuser2 testuser2 6 5月 11 16:03 bin HISTFILESIZE=10000 alias cp="cp -i" alias mv="mv -i" alias rm="rm -i" [root@localhost skel]# userdel -r testuser2
建置完畢後我們使用 useradd 建立一個名為 testuser2 的帳號來查看一下是否有問題,若沒有問題就可以刪除該帳號了!
這五個帳號需求大致有底下的要求:
上述第一點主要是 shell 改成不可互動的 shell 即可,預設建議使用 /sbin/nologin 較佳。 由於建置帳號的資料太多,因此建議使用 shell script 來處理較佳!
[root@localhost ~]# cd bin [root@localhost bin]# vim mailuser.sh #!/bin/bash # This program will create mail users # VBird 2016/05/03 for user in $(seq 1 5) do username="mailuser${user}" userpass=$(openssl rand -base64 6) useradd -s /sbin/nologin ${username} echo ${userpass} | passwd --stdin ${username} echo "${username} ${userpass}" >> mailuserpw.txt done [root@localhost bin]# sh mailuser.sh [root@localhost bin]# cat mailuserpw.txt mailuser1 M8pk6GEt mailuser2 HznQI88d mailuser3 zKpg4eg/ mailuser4 aakuwjo/ mailuser5 VrJtokaT [root@localhost bin]# grep mailuser /etc/passwd mailuser1:x:1011:1013::/home/mailuser1:/sbin/nologin mailuser2:x:1012:1014::/home/mailuser2:/sbin/nologin mailuser3:x:1013:1015::/home/mailuser3:/sbin/nologin mailuser4:x:1014:1016::/home/mailuser4:/sbin/nologin mailuser5:x:1015:1017::/home/mailuser5:/sbin/nologin
上述即可建立好專門給 mail user 專用的帳號了!而且這些帳號還無法登入系統操作 bash,這樣系統較為安全!
由於軟體的特殊需求,我們需要建立如下的帳號:
其實不難,只要兩個指令即可結束!
[root@localhost ~]# useradd -u 399 -g users sysuser1 [root@localhost ~]# echo centos | passwd --stdin sysuser1 [root@localhost ~]# id sysuser1 uid=399(sysuser1) gid=100(users) groups=100(users)
建議讀者們最終一定要自己檢查看看是否正確才好!所以上述我們使用了 id 這個指令來查詢是否正確!
就是之前談到檔案權限概念時,提到的共享目錄功能囉!
問題不難,讀者應該會想到,之前處理權限資料時,就曾經玩過『共享目錄』的資訊,這裡即是重新複習一次!
[root@localhost ~]# groupadd project [root@localhost ~]# useradd -G project pro1 [root@localhost ~]# useradd -G project pro2 [root@localhost ~]# useradd -G project pro3 [root@localhost ~]# echo password | passwd --stdin pro1 [root@localhost ~]# echo password | passwd --stdin pro2 [root@localhost ~]# echo password | passwd --stdin pro3 [root@localhost ~]# mkdir /srv/projecta [root@localhost ~]# chgrp project /srv/projecta [root@localhost ~]# chmod 2770 /srv/projecta [root@localhost ~]# ll -d /srv/projecta drwxrws---. 2 root project 6 May 3 21:43 /srv/projecta
最終三個用戶都加入 project 這個群組,而這個群組的用戶均可在 /srv/projecta 目錄裡進行任何工作!
由於系統的工作比較複雜,經常有不同的用戶會共同管理一部系統,這在社群的實務運作上經常發現。因為管理系統時需要管理員 (root) 的權限, 本章之前讀者可以透過 su 來切換用戶,但如此一來就得要提供所有的用戶 root 的密碼,對於系統的運作來說,可能會有些許的問題。 例如某位用戶切換成 root 密碼後,不小心改了 root 的密碼,而且自己也忘記了改回來,則未來大家都不知道如何操作系統了。
相對於 su 需要瞭解新切換的使用者密碼 (常常是需要 root 的密碼), sudo 的執行則僅需要自己的密碼即可!甚至可以設定不需要密碼即可執行 sudo ! 由於 sudo 可以讓你以其他用戶的身份執行指令 (通常是使用 root 的身份來執行指令),因此並非所有人都能夠執行 sudo , 而是僅有規範到 /etc/sudoers 內的用戶才能夠執行 sudo 這個指令。
只有信任用戶才能夠操作 sudo 這個指令,因此一開始還是需要使用 root 的權限來管理 sudo 的使用權才行。 雖然 sudo 的設定檔為 /etc/sudoers,不過建議使用 visudo 來編輯較佳,因為 visudo 可以進行設定檔的語法檢驗功能。
[root@localhost ~]# visudo ## Allow root to run any commands anywhere root ALL=(ALL) ALL 使用者帳號 登入者的來源主機=(可切換的身份) 可下達的指令
大約在 100 行附近,讀者會看到上面的 root 開頭那行。由於僅有 root 這一行,亦即一開始僅有 root 可以執行 sudo 的意思。
除了單一個人的設定之外,在 /etc/sudoers 若有底下這一行,亦代表加入 wheel 群組的用戶也能夠操作 sudo 之意。
[root@localhost ~]# visudo ## Allows people in group wheel to run all commands %wheel ALL=(ALL) ALL # 這一行大概在 107 行前後喔!
上面這個練習過程,你可以發現到,讓某個用戶加入 wheel 是一個很可怕的決定!你必需要確認該用戶不會亂用 sudo, 否則,就不應該讓該用戶加入 wheel 群組!這個 sudo 也是網路社共管 server 時,經常使用的技巧!可以避免 root 密碼流落出去而導致的一些資安問題。
如果 10.1 小節最後的一個練習中, /srv/projecta 需要讓 student 這個帳號登入去『查看』資料而已,不能變更現有的權限設定, 此時該如何設計呢?這時就可以考慮 ACL (Access Control List, 存取控制列表) 的使用了!
ACL 是 Access Control List 的縮寫,主要的目的是在提供傳統的 owner,group,others 的 read,write,execute 權限之外的細部權限設定。ACL 可以針對單一使用者,單一檔案或目錄來進行 r,w,x 的權限規範,對於需要特殊權限的使用狀況非常有幫助。
ACL 主要可以針對幾個項目來加以控制:
ACL 必須要配合檔案系統的掛載啟動才能生效,一般均將 acl 參數寫入 /etc/fstab 的第四欄位中。不過由於 ACL 幾乎為目前 Linux 標準支援的檔案系統參數, 因此讀者僅須查詢核心是否啟動 ACL 即可,已無須將 acl 參數寫入掛載設定中。
[root@localhost ~]# dmesg | grep -i acl 506:[ 0.802661] systemd[1]: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy) 566:[ 2.494185] SGI XFS with ACLs, security attributes, no debug enabled 582:[ 4.244339] systemd[1]: systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=legacy)
除了核心已經有支援之外, systemd 也有支援~XFS 檔案系統也預設支援喔!使用 dmesg 就可以明顯的查閱出來。另外, ext4 檔案系統家族,在 CentOS 7 以後的版本 (包含 CentOS 8),預設掛載時也會加上 acl 的參數!
ACL 針對單一用戶的設定練習中,我們以『讓 student 可以讀取 /srv/projecta 』為範本來介紹。
[root@localhost ~]# ll -d /srv/projecta drwxrws---. 2 root project 6 May 11 16:32 /srv/projecta [root@localhost ~]# setfacl -m u:student:rx /srv/projecta [root@localhost ~]# ll -d /srv/projecta drwxrws---+ 2 root project 6 May 11 16:32 /srv/projecta [root@localhost ~]# getfacl /srv/projecta # file: srv/projecta # owner: root # group: project # flags: -s- user::rwx <==預設的擁有者權限 user:student:r-x <==針對 student 的權限 group::rwx <==預設的群組權限 mask::rwx <==預設的 mask 權限 other::---
如上所示,setfacl -m 為設定的指令與選項,而設定的項目則主要有:
至於 getfacl 則是查閱 ACL 設定的指令。輸出結果與上述的設定項目類似,只是當帳號或群組名稱沒有寫的時候,代表為檔案擁有者的帳號與群組之意。 因此就能夠得到上述的結果。
至於 getfacl 輸出的結果中,有個 mask 的項目,10.1.4 所述,umask 為拿掉的權限,在 getfacl 當中,mask 則是可給予的權限之意。 預設 mask 會全部都給予~如果我們將 mask 拿掉只剩下 x 時,會發生的問題如下:
[root@localhost ~]# setfacl -m m::x /srv/projecta [root@localhost ~]# getfacl /srv/projecta # file: srv/projecta # owner: root # group: project # flags: -s- user::rwx user:student:r-x #effective:--x group::rwx #effective:--x mask::--x other::---
由於 mask 的關係,因此 student 這個帳號雖然給予 rx 的權限,但是實際上可以取得的權限則僅有 x 而已 (觀察 effective 的輸出項目)。 此外,如果要取消掉這個設定值時,可以使用如下的方式處理。
[root@localhost ~]# setfacl -m m::rwx /srv/projecta [root@localhost ~]# getfacl /srv/projecta
亦即重新設定進去即可。那如果使用 pro1 這個帳號實際在 /srv/projecta 操作時,會出現的權限狀態情況如下:
[root@localhost ~]# su - pro1 [pro1@localhost ~]$ cd /srv/projecta [pro1@localhost projecta]$ mkdir newdir [pro1@localhost projecta]$ touch newfile [pro1@localhost projecta]$ ll -d new* drwxrwsr-x. 2 pro1 project 6 May 11 20:41 newdir -rw-rw-r--. 1 pro1 project 0 May 11 20:41 newfile
讀者們可以發現在 /srv/projecta 目錄內的新檔案並沒有預設的 ACL 設定值,因此 student 的權限很可能被修改掉而無法保持 rx 的權限設定。此時,我們可以額外指定『預設的 ACL 權限』資訊,如下設定:
[root@localhost ~]# setfacl -m d:u:student:rx /srv/projecta [root@localhost ~]# getfacl /srv/projecta # file: srv/projecta # owner: root # group: project # flags: -s- user::rwx user:student:r-x group::rwx mask::rwx other::--- default:user::rwx default:user:student:r-x default:group::rwx default:mask::rwx default:other::---
若讀者發現設定錯誤,想要將某一條 ACL 的權限設定取消時,例如將 student 的規則取消,則可以使用如下的方式來處理:
[root@localhost ~]# setfacl -x u:student /srv/projecta
取消設定比較單純,不過要注意取消的情況得要使用 -x 這個選項,而非 -m 的選項。此外,由於取消設定是不需要處理權限的, 因此取消時,僅需要處理『 u:帳號 』或『 g:群組 』這樣就好了!那如果要將該檔案的所有 ACL 設定都取消時,可以使用底下的方式:
[root@localhost ~]# setfacl -b /srv/projecta [root@localhost ~]# ll -d /srv/projecta/ drwxrws---. 3 root project 35 May 11 20:41 /srv/projecta/
讀者可以發現到,權限位置最末位的 + 號不見了,因為已經完整的取消的緣故。
作業硬碟一般操作說明:
作業當中,某些部份可能為簡答題~若為簡答題時,請將答案寫入 /home/student/ans.txt 當中,並寫好正確題號,方便老師訂正答案。 請注意,檔名寫錯將無法上傳!
請使用 root 的身份進行如下實做的任務。直接在系統上面操作,操作成功即可,上傳結果的程式會主動找到你的實做結果。 另外,因為題目是有連續性的,請依照順序完成題目,盡量不要跳著做。
作業結果傳輸:請以 root 的身分執行 vbird_book_check_unit 指令上傳作業結果。 正常執行完畢的結果應會出現【XXXXXX_aa:bb:cc:dd:ee:ff_unitNN】字樣。若需要查閱自己上傳資料的時間, 請在作業系統上面使用瀏覽器查詢: http://192.168.251.254 檢查相對應的課程檔案。 相關流程請參考: vbird_book_check_unit