---
title: 'Linux 安全、日誌、用戶與群組權限、文件權限'
disqus: kyleAlien
---
Linux 安全、日誌、用戶與群組權限、文件權限
===
## Overview of Content
如有引用該文章請標明 :smile_cat:
Linux 沿用 Unix 文件權限的辦法,允許用會對於目錄、文件(這兩者有些許不同)設置不同的安全訪問,而這些權限又取決於你登入的帳戶
:::success
* 如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/)
本篇文章對應的是 [**Linux 系統管理入門:安全性、用戶管理與權限設定指南**](https://devtechascendancy.com/linux-system-admin_user-file-permissions/)
:::
[TOC]
## Linux 安全性
Linux 的安全核心是 **帳戶**,當你登入不同用戶時,就會有不同的權限;除了用戶以外還需要注意當前帳戶所在的群組,群組也有群組所使用的權限
### 認識 `/etc` 目錄:系統設定檔
* Linux 系統中大部分 **系統設定檔案都存放在 `/etc` 目錄中**,所以系統的程式越多相對的 `/etc` 目錄也就越多;這相對的也會帶來幾個問題…
1. 不容易找到目標應用的設定檔
2. 不易維護(因為應用的設定分離到不同目錄中)
* 目前常見的方式是 **將系統設定檔放置 `/etc` 下的子目錄**(也就是在 `/etc` 目錄下再創建目錄);以下範例,我們看看 systemd 的相關設定檔案放置在 `/etc/systemd` 目錄下
> 
:::info
* 有時設定子目錄會將檔名取為 `/etc/<設定檔>.d`,`.d` 代表的就是目錄
:::
:::warning
* **可設定、不可設定的檔案?**
* `/etc` 目錄下放置的都是 **可制定**(客制)的設定檔
* **`/usr` 目錄下放置的則是不可設定檔**(應用程式的相關細節)
:::
## 系統日誌
系統日誌是系統最重要的部分之一,如果不清楚系統哪裡錯誤,可以查找系統日誌檔來找出錯誤關鍵,而日誌系統的使用會依照 OS 系統版本有所不同
* **系統日誌**(以 Ubuntu 為例)
* 傳統版 `syslogd`
* 新版為 `rsyslogd`:它除了紀錄之外,還可以它載入一個將日誌資訊寫到資料函數庫的模組
:::success
* **`/var/log` 目錄**也是放置日誌的位置嗎?是的!
`/var/log` 目錄中很多檔案不是由系統日誌來維護的(可以是應用的日誌檔),要知道哪些是日誌屬於 `rsyslogd` 的,需要查看設定檔(之後會說明)
:::
### rsyslogd 設定檔:規則 & 擴充
* `rsyslogd` 的基礎設定檔案在 `/etc/rsyslog.conf` 或是在 `/etc/rsyslog.d` 目錄下;
內容包含傳統規則(由選擇符 `selector`、操作 `action` 組成),也包含了 rsyslogd 的擴充規則(規則以 `$` 開頭)
> 
* 接著,我們來看看 rsyslog 的 **傳統規則**(由選擇符 `selector`、操作 `action` 組成)
```shell=
# rsyslog 格式
<selector> <action>
```
* **選擇符** `selector`:選擇符由兩個成分組成,分別是「設備」、「優先級」(可設定多個),`*` 代表萬用符
1. **`.` 前:代表設備**
2. **`.` 後:代表優先級**,由低到高為 `debug`, `info`, `notice`, `err`, `crit`, `alert`, `emerge`… 概念圖如下
> 如果設定為 `none` 則代表不輸出
```mermaid
graph LR
selector --> 設備
selector --> 優先級
優先級 --> debug
優先級 --> info
優先級 --> notice
優先級 --> err...等等
```
* **操作**`action`:不一定是寫日誌,也可以用來發訊息
```shell=
cat /etc/rsyslog.conf
```
> 
上圖資訊對應下表說明
| 元數據 | 選擇符 | 操作 |
| - | - | - |
| `auth, autgpriv.* /var/log/auth.log` | `auth, autgpriv.*` | 寫入日誌到 `/var/log/auth.log` |
| `daemon.* -/var/log/daemon.log` | `daemon.*` | 寫入日誌到 `-/var/log/daemon.log` |
| `*.* -/var/log/syslog` | 所有設備 `*.*` 所有優先級 | `-/var/log/syslog` |
:::info
* 更多 rsyslog 可以查看 `rsyslog.conf(5)`
:::
* **擴充歸則**(規則以 `$` 開頭)可稱為指令
```shell=
cat /etc/rsyslog.conf
```
> 
可從上圖中我們還可以看到,它會設定生成的 Log 檔案的 `FileOwner` 檔案設定為 root,`FileGroup` 為 adm 群組...等等
> 這裡所說的是「Log 紀錄文件」的權限設置
:::info
* 更多的 rsyslogd 設定可以查看 `rsyslogd(5)`
:::
### 使用 logger 寫入:故障排除
* 測試系統日誌最快的方法就是對指定的設備寫入日誌,可以用來查看設備是否正常運作;範例如下
以下範例對 `daemon.debug` 寫入資料
```shell=
# 寫入日誌
logger -p daemon.debug check log... 123
logger -p daemon.debug check log... 456
# 查看日誌 (只看最後兩筆)
sudo cat /var/log/daemon.log | tail -n 2
```
> 
### 核心日誌
* `rsyslogd` 抓取的日誌不僅是系統的各個裝置,也包括系統啟動訊息(`stsytemd`, `Upstart` 訊息),還有系統服務的伺服器... 等等
```mermaid
graph LR
subgraph rsyslogd 日誌
stsytemd日誌
Upstart日誌
系統服務日誌
end
```
* 以前有一個 `klogd` 的守護進程負責為 `syslogd` 擷取核心的日誌訊息,之後也併入了 `rsyslogd` 中
> `dmesg` 命令就是顯示從日誌中獲取的訊息
## Linux User 用戶
在 Linux 系統中,使用者(User)是作業系統中的一個重要概念,用於管理對系統資源的存取權限
使用者可以是一個人或一個程序,每個使用者都有一個唯一的使用者識別碼(UID)和一個或多個使用者群組識別碼(GID)
> GID 下個小節說明
### User & UID 概念
* 進入 Linux 系統的 **用戶都會被分配 ==唯一== ID(UID)**,但我們在登入系統時不會使用 UID 作為帳號登入,我們會使用登入名 (Username) 登入
```java=
// 概念程式
Map<"UserName", "UUID"> // 紀錄 UserName 對應 UID
```
* **Linux「用戶」的特性**:用戶同時代表了權限控制,會有關於到是否可以訪問某種特定進程 or 用戶資源
* **系統用戶**:UID 在 500 以下
> 後台服務都對應了一個系統服務
* **普通用戶**:UID 在 500 以上
### `/etc/passwd` 文件
* Linux 系統使用一個專門的文件(`/etc/passwd`)來匹配用戶名以及 UUID 還有其他重要的訊息,它的對應格式如下
```shell=
## 輸出格式
root:x:0:0:root:/root:/bin/bash
```
對應訊息(每個訊息之間使用 `:` 隔開數據)
| 原數據(從左到右介紹) | 描述 |
| - | - |
| `root` | 用戶名 |
| `x` | 加密過的 Passwd |
| `0` | UID |
| `0` | GID |
| `root` | 用戶描述 (真實姓名) |
| `/root` | 用戶的家目錄 |
| `/bin/bash` | 用戶使用的 Shell |
:::info
* root 用戶 UID、GID 固定是 0
:::
> 
* 原本該文件有保存加密的密碼,但是這個文件是所有用戶都可訪問的,基於安全性 **有關於用戶密碼的部分已經移動到 `/etc/shadow` 文件中** (只有特定應用可以訪問)
:::warning
* `/etc/passwd` 文件是全域文件,盡量不要去手動修改它,否則可能導致某修用戶無法登入
> 可以使用其他 shell 工具去操作帳戶
:::
### `/etc/shadow` 文件
* `/etc/shadow` 文件只有 root 才可以訪問
```shell=
## 查看文件
sudo cat /etc/shadow
```
其中內容會保存每個用戶的使用紀錄、限制,其格式如下
```shell=
## 輸出格式
alien:$y$j9T$MIPKSjvDFVS24HA8OhEOs0$FHW29Tbal1faccdcCYERau3xGHHAP1Z199.zp8KEl98:19409:0:99999:7:::
```
對應訊息(每個訊息之間使用 `:` 隔開數據)
| 原數據(從頭開始) | 描述 |
| - | - |
| alien | 用戶名 |
| \$y\$j9T$MIP...省略 | 加密過的 Passwd |
| 19409 | 上次修改密碼後過幾天 |
| 0 | 多少天後能修改密碼 |
| 99999 | 多少天必須修改密碼 |
| 7 | 密碼過期前幾天提醒用戶 |
| (空) | 密碼過期後幾天禁用用戶 |
| (空) | 用戶被禁用的日期 (ISO8061 天數) |
| (空) | 預留字段 |
:::info
* `/etc/shadow` 文件為密碼儲存提供靈活的方法、函數庫、工具,而之後它還是很快 **被 `PAM` 框架給取代**
PAM 沒有引進新的檔案,而是繼續使用 `/etc/shadow` 檔案,只是 PAM 可以外掛許多身份驗證的插件,並幫我們訪問 `/etc/shadow` 文件
> 這裡用「取代」可能不夠正確… 因為 PAM 可以與 `/etc/shadow` 文件一起使用,但是 PAM 框架的自由度高,導致 PAM 框架的光彩更大,進而掩蓋了 `/etc/shadow` 文件
:::
### 添加用戶:useradd
* 使用 useradd 命令可以快速創建一個用戶 (如果 PATH 沒有這個路徑,那可以在 `/usr/sbin` 目錄下尋找看看)
1. 查看創建用戶時的預設參數 -D
```shell=
## 查看創建用戶時給予的預設值 (-D 是 Default 的意思)
useradd -D
```
> 
依照上圖所示,針對幾個比較少見的設定值說明
| useradd 後返回的資訊 | 說明 |
| - | - |
| `INACTIVE` | 密碼過期後是否禁用 |
| `EXPIRE` | 該用戶的過期時間 |
| `SKEL` | **使否將 `/etc/skel` 目錄下的內容複製到要創建的帳戶底下(包含一些 `.bashrc` ... 檔案)** |
| `CREATE_MAIL_SPOOL` | 是否創建一個接收 mail 的文件 |
:::info
* **`/etc/skel` 目錄**:該目錄下包含了 bash shell 環境的標準啟動文件
> 
:::
2. useradd 預設是「**不會創建一個帳戶目錄**」,如果要創建帳戶目錄(`/home` 目錄下)就可以使用 `-m` 操作
```shell=
sudo useradd -m account_m
## home 目錄下就會有一個 `account_m`
ls -la /home/
## account_m 目錄下的檔案就是從 `/etc/skel 複製出來的檔案`
ls -la /home/account_m
```
> 從下圖中,我們可以看到在 `/home` 目錄下確實創建出了 `account_m` 資料夾
> 
3. `-D` 之後接參數就可以修改創建用戶時的預設值
> 以下修改 Shell 預設值為 `/bin/tsch`
```shell=
## 改變預設 bash shell
useradd -D -s /bin/tsch
```
### 刪除用戶:userdel
* `userdel` 命令可以用來刪除用戶,但是!它默認 **只會刪除 `/etc/passwd` 檔案中的用戶訊息**,其他相關的用呼資料都不會刪除(用戶目錄不會刪除)
如果 **要刪除其他用戶資料則需添加 `-r` 操作**
```shell=
## 查看所有用戶
tail /etc/passwd
## 刪除 `account_no_options` 用戶
userdel -r account_no_options
## 再次查看是否被刪除
tail /etc/passwd
```
> 
### 修改用戶權限、密碼
* 當用戶創建完成後,要修改用戶的設定(`/etc/passwd`)有以下幾種方式,每方式修改的目標也不同
1. `usermod`:可以修改大部分 `/etc/passwd` 中的設定字段,其 options 與 `useradd` 差不多
| usermod options | 功能 |
| -------- | -------- |
| -c | 備注字段 |
| -e | 修改過期日期 |
| -g | 修改默認群組 |
| -l | 修改用戶名(username) |
| -p | 修改用戶密碼 |
| -L | 鎖定帳戶 |
| -U | 解除已鎖定帳戶 |
2. `passwd`(修改自己的密碼) & `chpasswd`(修改其他用戶密碼):
```shell=
echo "Account_m:456" > test.txt
sudo chpasswd < test.txt
```
3. 修改特定用戶訊息 `chsh` (修改 shell)、`chfn`(修改 finger 讀取到的數據)、`chage`(修改帳戶有效日期)
## Linux Group 群組
如果是針對單用戶來說,帳戶 (User) 權限就足以安全的控管權限,而如果需要 **共享某個進程、資源,就不方便使用**;所以 Linux 多了 Group 的控管概念,讓權限拓展到更廣泛的群組,讓同一個群組內的使用者可以共享資料
### Group & GID 概念:主、次要群
* 每個群組都有「**唯一的 GID**」,該 GID 對應了一個唯一的組名 (可以透過群組名找到對應的 GID)
```java=
// 概念程式
Map<"群組名" : "GID"> // 紀錄 用戶名對應的 GID
```
:::info
* 新創建的使用者,沒有指定 Group 會怎樣?
這部分到不用擔心,**Ubuntu 預設會為每個用戶創建各自的群組**
> 假設你創建了 Apple 帳號,它就會幫你創建一個 Apple 群組
```mermaid
graph LR
Shell --> 系統 -.-> |創建帳戶| Apple帳戶
系統 -.-> |創建群組| Apple群組
```
:::
* **群組的差異**:在 Linux 系統中,每個使用者都屬於一個 **主群組(`primary group`)** 和 **次要群組(`secondary group`)**
```mermaid
graph LR
subgraph 使用者
主群組
次要群組
end
```
* **Primary group 是一個使用者帳號的主要群組**:
這個群組會被指定為使用者在建立檔案時的預設群組。當使用者建立檔案時,該檔案的群組權限(`group ownership`)會被設定為使用者的 `primary group`
* **Secondary group 則是其他使用者群組**:
使用者可以隨時加入或退出這些群組,但這些群組並不會影響使用者建立檔案的預設群組。
> 在命令行中,使用 `usermod -g` 來修改使用者的 `primary group`,而使用 `usermod -aG` 來將使用者加入一個 secondary group
### `/etc/group` 文件
* `/etc/group` 文件用來保存 Linux Group 的相關訊息,在這個文件中我們可以看到系統中的全部群組
```shell=
## 輸出格式
root:x:0:
```
對應訊息(每個訊息之間使用 `:` 隔開數據)
| 原數據(從左到右) | 描述 |
| - | - |
| root | 群組名 |
| x | 加密過的 Group Passwd |
| GID | UID |
| (空) | 用戶列表(屬於這個群組的用戶) |
:::info
root Group ID 固定是 0
:::
:::danger
* 請不要直接修改(編輯)這個 `/etc/group` 文件,可以用 Shell 命令來修改;像是可以用 `usermod -aG` 來添加用戶的群組
> 使用指令修改是一種安全操作
```shell=
## 將 alien 用戶添加到 account_m 群組中
usermod -aG account_m alien
## 將 alien 原有的群組移除,將 alien 群組設定為 account_m
usermod -G account_m alien
```
> 
:::
:::success
1. **Group 密碼**:使用 Group 密碼,可以讓非這個 Group 的成員 **暫時** 成為著個組的成員
2. 在 `etc/group` 文件中可能會發現,原本應該出現在群組的成員沒有在列表中,**這是因為創建群組時,默認群組設置 不會出現在該列表中**;
默認群組設置可以用以下指令查看
```shell=
## 查看默認設置
useradd -D
```
> 
:::
### 創建群組:groupadd、添加群組:usermod
* `groupadd` 可以創建一個新群組,但是它並沒有將某個用戶加入該群組的功能,但這個操作可以透過 `usermod -aG` 來補足
```shell=
## 創建 hello_group 群組
sudo groupadd hello_group
tail /etc/group
```
> 
指定用戶並操作用戶的群組,範例如下
```shell=
## 將 alien 用戶指定為 hello_group 群組的成員
sudo usermod -G hello_group alien
cat /etc/group | grep hello
## 將 account_m 用戶指定為 hello_group 群組的成員
sudo usermod -G hello_group account_m
cat /etc/group | grep hello
```
> 從下圖中,我們可以看到用戶 `alien`、`account_m` 都在 `hello_group` 群組中
> 
:::info
* 如果該帳戶已經被登入,並在它登入後才修改群組,那修改後的群組關係必須要 **重新登入後才會作用**
:::
### 修改群組:groupmod
* `usermod -aG` 命令可以用來修改(新增)使用者的群組,但如果要直接修改 `/etc/group` 內容可以用 `groupmod` 命令
> usermod 命令是站在使用者的角度來操作群組,`groupmod` 命令是直接針對群組設定做操作
```shell=
tail -1 /etc/group
## 將新組名 my_group 設定給 hello_group(取代舊群組名)
sudo groupmod -n my_group hello_group
tail -1 /etc/group
```
> 
## 文件、資料夾權限
在 Linux 中每個文件都有所屬的 `Owner`, `Group`
### 文件、資料夾權限符
* 使用 `ls -l` 命令就可以查看到當前目錄下所有的文件,包括其權限
```shell=
ls -l
```
> 
權限符號就是 前面那一個字串(10 碼組成),下表會介紹常見的權限符號,由左到右來介紹這 10 碼
| 碼順序 | 說明 | 補充 |
| - | - | - |
| 0 | 文件類型(用符號區分) | `-` 目錄、連結、`b` 塊設備、`c` 字符設備、`n` 網路設備 |
| 1 | r | 針對 **當前用戶**,文件可讀性 |
| 2 | w | 針對 **當前用戶**,文件可寫性 |
| 3 | x | 針對 **當前用戶**,文件可執行性 |
| 4 | r | 針對 **相同群組的用戶**,文件可讀性 |
| 5 | w | 針對 **相同群組的用戶**,文件可執行性 |
| 6 | x | 針對 **相同群組的用戶**,文件可執行性 |
| 7 | r | 針對 **其他用戶**,文件可讀性 |
| 8 | w | 針對 **其他用戶**,文件可執行性 |
| 9 | x | 針對 **其他用戶**,文件可執行性 |
* 文件的權限是「**八進制**」的算法,如下表(這邊我們只看其中一組 `rwx` 就好,另外兩組是一樣的)
| 權限字符 | 2 進制 | 8 進制 |
| -------- | -------- | -------- |
| -\-\- | 000 | 0 |
| -\-x | 001 | 1 |
| -w- | 010 | 2 |
| -wx | 011 | 3 |
| r-\- | 100 | 4 |
| r-x | 101 | 5 |
| rw- | 110 | 6 |
| rwx | 111 | 7 |
### 默認文件、資料夾權限:umask
* 所謂的默認權限就是你在創建文件、資料夾時系統會默認的權限
:::danger
而其中「文件」、「資料夾」默認的權限並不一樣
:::
* `umask` 命令:文件的默認權限可以透過 `umask` 命令查看;而 **默認權限就是由 666(文件)、777(目錄) 減去 umask 的數值決定**
> 做 AND 掩碼運算
```kotlin=
umask
touch createFile
mkdir createDir
ls -laF
```
> 
:::info
* **umask 預設值**
umask 的預設值是由 PAM (`Pluggable Authentication Modules)` 模組所設定,而不是直接由某個文件設定
PAM 是一種通用的身份驗證架構,它可以讓系統管理員在設定身份驗證機制時更有彈性。在 Ubuntu 22 中,umask 的預設值是由 **`pam_umask` 模組** 所控制
* **更改 umask 數值**
umask 的預設值,可以編輯 `/etc/login.defs` 文件,並修改其中的 UMASK 設定
也可以編輯個別使用者的 `~/.profile` 或 `~/.bashrc` 文件,並在其中加入 umask 命令來設定使用者的 umask 值
:::
### 修改文件、資料夾權限:chmod
* **`chmod` 命令**:可以透過該命令來修改文件、資料夾的權限
1. **直接指定**:一般使用方式就是直接指定 8 進位權限
> 格式:chmod options mode file
```shell=
## 修改 createFile 權限為 777
chmod 777 createFile
```
2. **透過符號**:透過符號來操作檔案、文件權限,以下列出幾個常見的設定選項
> 格式:chmod [ugoa] [+-=] [rxw...]
| 指定目標 | 符號 | 說明 |
| -------- | -------- | -------- |
| 權限作用目標 | u | 當前用戶 |
| | g | Group 用戶 |
| | o | 其他用戶 |
| | a | 全部用戶 |
| 指定權限 | + | 添加權限 |
| | - | 減少權限 |
| | = | 指定權限 |
| 權限 | r | 可讀 |
| | w | 可寫 |
| | x | 可執行 |
| | u | 把權限設定為跟 User 設定相同 |
| | g | 把權限設定為跟 Group 設定相同 |
| | o | 把權限設定為跟 Other 設定相同 |
| | s | 運行時設定的 GID, UID (常用於共享文件) |
### 修改文件、資料夾所屬、群組:chown/chgrp
* **`chgrp` 命令**:該命可以修改文件、資料夾的群組
> 格式:chgrp group file
```shell=
ls -laF createFile
## 改變文件所群組
sudo chgrp MyNewAccount createFile
ls -laF
```
> 
* **`chown` 命令**:該命令可以指定該文件、資料夾的所有者
> 格式:chown options owner[.group] file
:::info
可以使用 `-R` 遞歸設定資料夾內所有的文件
:::
```shell=
ls -laF createFile
## 改變文件所屬
sudo chown MyNewAccount createFile
ls -laF createFile
```
> 
**`chown` 命令也可以只修改文件 Group**
```shell=
sudo groupadd MyNewGroup
ls -laF createFile
## 修改檔案群組
sudo chown .MyNewGroup createFile
ls -laF createFile
```
> 
:::info
* 一次性修改 Owner & Group,只需要在指定 Owner 時在後面加上 `.` 就會連同 Group 一起修改為當前登入用戶的 Group
```shell=
sudo chown alien. createFile
```
> 
:::
### umask 的額外訊息:創建共享文件
* 還記得 `umask` 其實列出了 4 個數字嘛?我們那時並沒有說明第一碼
那第一個碼(數字)就是文件的額外訊息;每個文件、目錄還儲存了 **額外的 3 個額外訊息**
| 儲存訊息 | 說明 | 補充 |
| - | - | - |
| 設定用戶 (SUID) | 當文件被使用時,程序會以 **文件所屬主 (Owner) 的權限運行** | |
| 設定群組 (SGID) | 同上,運行時程序會以 **文件所屬組 (Group) 的權限運行** | **SGID 對於 共享文件 很重要** |
| 黏著位 | 進程結束後,文件還留存在內存中(這就是黏著) | |
使用命令 `chmod` 就可以啟用 `SGID`,**它可以強制讓該目錄下創建的文件都設定為該目錄的所屬群**;其第一碼對應的八進位跟意義如下
| 二進位 | 八進位 | 說明 |
| - | - | - |
| 000 | 0 | 清零 |
| 001 | 1 | 設定黏著位 |
| 010 | 2 | SGID |
| 011 | 3 | SGID + 黏著位 |
| 100 | 4 | SUID |
| 101 | 5 | SUID + 黏著位 |
| 110 | 6 | SUID + SGID |
| 111 | 7 | SUID + SGID + 黏著位 |
* 「**共享文件**」的概念就是 ^1.^ 將文件指定為某一群組 Group,之後,^2.^**在該資料夾底下創建的文件都是指定 Group 的文件**,藉此達到只要是該群組的成員都可以操控該資料夾的內容
創建共享文件的範例如下…
```shell=
## 創建共用資料夾
mkdir share_dir
## 查看該資料夾的詳細資訊
ls -ld share_dir
## 創建共享的群組 share_group
sudo groupadd share_group
## 改變資料夾的群組
sudo chgrp share_dir ./share_dir
## 確認該資料夾是否已改變群組
ls -ld share_dir
## 設置 share_dir 的 SGID
sudo chmod g+s ./share_dir/
## 確認該資料夾是否已改變 SGID 設置
ls -ld share_dir
```
> 設定成功後 `./share_dir/` 資料夾 x 會轉變成 s
>
> 
在分享資料夾下創建文件,就會發現該文件的預設群組就變成 `share_group`
```shell=
## 在共享資料夾創建文件
touch ./share_dir/testFile
## 查看該文件的群組
ls -l ./share_dir/testFile
```
> 
## Appendix & FAQ
:::info
:::
###### tags: `Linux Shell`