docs: add Groups and Access Control Policies guide

Explain what Groups are in NetBird, the four places they surface
(policies, setup keys auto_groups, network routes, DNS), and a
concrete segmentation plan for the current mesh:

- servers group: CT100, CT101
- personal group: mbp-13-pro, iphone-15-pro
- Replace default All->All with least-privilege policies
  (personal->servers, servers<->servers)

Includes UI and API workflows, a phased migration plan, rollback
strategy, and how to wire auto_groups into setup keys for future
deployments.
This commit is contained in:
2026-04-18 15:27:23 +08:00
parent aaece30ca6
commit d7a9fb55ec
3 changed files with 271 additions and 1 deletions

View File

@@ -20,6 +20,7 @@
| [stun-port-conflict.md](./stun-port-conflict.md) | STUN 3478 被 Headscale 佔用 → NetBird 改用 3479 的解法 |
| [client-troubleshooting.md](./client-troubleshooting.md) | 客戶端 P2P 失敗、bufferbloat、Force Relay 等坑 |
| [peer-deployment-ops.md](./peer-deployment-ops.md) | 在 LXC 用 Docker 部署客戶端、改名、Mac daemon 重啟 |
| [groups-and-policies.md](./groups-and-policies.md) | Groups 與 Access Control Policies 概念、設計、API 操作 |
| [SUMMARY.md](./SUMMARY.md) | 部署摘要與疑難排解記錄 |
## 快速開始

View File

@@ -101,7 +101,8 @@ reopen fd 8: permission denied
├── setup-keys-and-pat.md ← Setup Keys / PAT 操作與 API 限制繞道
├── stun-port-conflict.md ← STUN 改用 3479 (3478 被 Headscale 佔用)
├── client-troubleshooting.md ← 客戶端 Force Relay / bufferbloat 排錯
── peer-deployment-ops.md ← Docker 部署客戶端、改名、Mac daemon 重啟
── peer-deployment-ops.md ← Docker 部署客戶端、改名、Mac daemon 重啟
└── groups-and-policies.md ← Groups 與 Access Control 設計與操作
```
### 遠端伺服器192.168.42.127:/opt/netbird/

268
groups-and-policies.md Normal file
View File

@@ -0,0 +1,268 @@
# Groups 與 Access Control Policies
NetBird 的存取控管基本單位。本文用目前部署的 4 個 peermbp-13-pro、iphone-15-pro、CT100、CT101為例說明 Groups 怎麼用。
## Groups 是什麼
**Group** 是 peer 的具名集合。NetBird 不直接管「peer A 能不能連 peer B」而是
1. 把 peer 丟進 group
2.**Policy** 定義「group X → group Y 的流量允許/禁止」
這讓存取控管的規模隨服務/角色擴展,而不是隨 peer 數量爆炸。
## Groups 在 NetBird 裡出現的 4 個地方
| 地方 | 用途 |
|------|------|
| **Access Control → Policies** | 決定 group A 能不能連 group B、哪些 port/protocol |
| **Setup Keys 的 `auto_groups`** | 用此 key 註冊的 peer 自動進指定 group |
| **Network Routes** | 哪個 group 能透過某個 peer 走一條路由(例:透過 CT100 當 exit node |
| **DNS / Nameservers** | 哪個 group 套用特定 DNS 設定 |
這四個功能都以 group 當接口,換句話說 — **group 設計對了,整個存取模型就清楚了**
## 預設:`All` group 與 `Default` policy
NetBird 初始化時自動建立:
- **`All`** group — 所有 peer 自動加入
- **`Default`** policy — `All → All`allow all protocols
所以剛部署完,所有 peer 彼此互通(就像你目前的狀態)。這對起步階段方便,但**不符合最小權限原則**。
Dashboard 的 Peers 頁面顯示 `Add Groups` 按鈕代表該 peer **沒有自訂 group**(它仍然自動在 `All` 裡)。
## 何時要自訂 Group
### 典型情境
1. **角色分離**:個人裝置 vs 伺服器,不希望伺服器能主動戳個人裝置
2. **最小權限**iPhone 只需能連特定服務,不需連所有 peer
3. **自動化註冊**:用 setup key 部署新機時自動分類(`ci-runners``edge-nodes` 等)
4. **分享給家人**:一個 group 只給家人裝置policy 限制他們能看到的範圍
5. **Exit Node 授權**:只有特定 group 能把流量導去某 peer
### 本部署的建議分組
以目前 4 個 peer
| Group | 成員 | 用途 |
|-------|------|------|
| `servers` | CT100、CT101 | 家裡 headless 服務 |
| `personal` | mbp-13-pro、iphone-15-pro | Timmy 的個人裝置 |
對應的 Policy
| # | From | To | 目的 |
|---|------|-----|------|
| 1 | `personal` | `servers` | 個人裝置能連伺服器 |
| 2 | `servers` | `servers` | 伺服器彼此互連(例如未來備份、日誌集中) |
| 3 | ~~`All → All` (Default)~~ | — | **刪除或停用** |
刻意**不**建立 `servers → personal` 的 policy伺服器被入侵時攻擊者無法透過 NetBird 橫向移動到個人裝置。
(未來如果有多個使用者,可再拆 `timmy-devices``family-devices` 等。)
## Peer 可以同時屬於多個 group
常見用法:
- `CT100`: in both `servers` and `jump-boxes`(對不同 policy 都有效)
- `CT101`: in both `servers` and `rustdesk`(另一條政策只開 rustdesk port 給某個子集)
Peer group 是集合運算policy 匹配時用 ORpeer 只要在 policy 的 source group 任一個裡就算命中。
## 怎麼建 Group
### 方式 AUI推薦起步
1. Dashboard → **Access Control → Groups****Create Group**
2.**Name**(例 `servers`
3.**Peers** 勾選要加入的 peer
4. **Create**
建完後去 **Access Control → Policies****Peers** 頁面都能再綁定 group。
### 方式 BAPI
```bash
TOKEN=<你的 PAT>
# 先查目前 peer 清單拿 ID
curl -sf -H "Authorization: Token $TOKEN" \
https://netbird.timmy.us.kg/api/peers | jq '.[] | {id, name}'
# 建 servers group同時塞兩個 peer
curl -sf -X POST -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "servers",
"peers": ["<CT100-peer-id>", "<CT101-peer-id>"]
}' \
https://netbird.timmy.us.kg/api/groups | jq
# 建 personal group
curl -sf -X POST -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "personal",
"peers": ["<Mac-peer-id>", "<iPhone-peer-id>"]
}' \
https://netbird.timmy.us.kg/api/groups | jq
```
## 怎麼建 Policy
### 方式 AUI
1. **Access Control → Policies****Add Policy**
2. **Name**:例 `personal-to-servers`
3. **Source Groups**:選 `personal`
4. **Destination Groups**:選 `servers`
5. **Protocol**`All`(或 TCP/UDP/ICMP
6. **Ports**:留空代表全部
7. **Bidirectional**:看需求
- 勾了 → 來回都允許(大多數家用場景這樣方便)
- 不勾 → 只允許 source 主動連 destination
8. **Create**
### 方式 BAPI
```bash
curl -sf -X POST -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "personal-to-servers",
"enabled": true,
"description": "Personal devices can access servers",
"rules": [{
"name": "personal-to-servers",
"enabled": true,
"action": "accept",
"protocol": "all",
"sources": ["<personal-group-id>"],
"destinations": ["<servers-group-id>"],
"bidirectional": false
}]
}' \
https://netbird.timmy.us.kg/api/policies | jq
```
## 刪除預設 `Default` policy
當你建立好新的 `personal-to-servers``servers-to-servers` 等 policy 後,才關掉預設的 `All → All`,不然會暫時中斷連線。
UI**Access Control → Policies → Default** → 右邊三點 → **Delete** 或 toggle **Disabled**
API
```bash
# 先找 policy ID
curl -sf -H "Authorization: Token $TOKEN" \
https://netbird.timmy.us.kg/api/policies | jq '.[] | {id, name, enabled}'
# 停用(較安全,出問題可立刻打開)
curl -sf -X PUT -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '<GET 出來的內容,改 "enabled": false>' \
https://netbird.timmy.us.kg/api/policies/<POLICY_ID>
# 或直接刪除
curl -X DELETE -H "Authorization: Token $TOKEN" \
https://netbird.timmy.us.kg/api/policies/<POLICY_ID>
```
## Setup Key 搭配 `auto_groups`
部署新 peer 時可以**一步到位自動加 group**
```bash
# 建一把 key註冊進來的 peer 自動進 servers group
curl -sf -X POST -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "CT102-whatever",
"type": "one-off",
"expires_in": 86400,
"usage_limit": 1,
"ephemeral": false,
"auto_groups": ["<servers-group-id>"]
}' \
https://netbird.timmy.us.kg/api/setup-keys | jq
```
如此 CT100/CT101 這類部署可以省掉「註冊完再手動加 group」的步驟。
(之前 CT100/CT101 的 setup key 我建的時候 `auto_groups` 是空的 — 未來部署時記得帶上)
## Policy 細節補充
### Port / Protocol 限制
```yaml
# 只允許 SSH (TCP/22) 從 personal 連到 servers
rules:
- protocol: tcp
ports: ["22"]
sources: [<personal-group-id>]
destinations: [<servers-group-id>]
```
### Bidirectional 的真正含義
- `bidirectional: true` — A → B 與 B → A 都允許
- `bidirectional: false` — 只允許 source 端主動 initiate但回應封包 NetBird 會自動放行stateful不用特別設
家用場景建議**預設 `false`**,只在真的需要雙向 initiate 時才開。
### Posture Checks進階
Policy 可綁 Posture Check — 要求 peer 滿足某些條件OS 版本、地理位置、已登入 SSO 等)才能走這條 policy。進階情境可參考 NetBird docs。
## 驗證 Policy 生效
### 方式 A從 peer 端測試
```bash
# 從 Mac ping iPhone (現在可以) → 建立 personal-only policy 後,應該還是可以
ping 100.71.63.111
# 從 CT100 ping Mac (現在可以) → 刪掉 All→All 後,應該不通
ssh root@192.168.42.100 'docker exec netbird netbird status --detail | grep mbp-13-pro -A 3'
```
### 方式 BDashboard → Control Center
視覺化顯示每個 peer 的 policy 連線關係,可以一眼看出誰能連誰。
## 整套搬遷步驟建議
**漸進式,不中斷當前連線**
```
Phase 1: 建 groups
- Create group "servers" with CT100, CT101
- Create group "personal" with Mac, iPhone
Phase 2: 建新 policies先不刪預設
- Policy "personal-to-servers": personal → servers
- Policy "servers-to-servers": servers → servers (bidirectional)
- 此時 All→All 跟新 policy 並存,功能不變
Phase 3: 驗證新 policy 生效
- 關掉 All→All先 disable 不 delete
- 實測Mac→CT100 通、iPhone→CT101 通、CT100→Mac **不通**
Phase 4: 確認無誤
- 刪除 Default policy如果想
- 日後新 peer 記得 setup key 的 auto_groups 要填對
出問題 rollback把 Default policy 重新啟用即可恢復原狀。
```
## 相關檔案與文件
- `setup-keys-and-pat.md` — PAT 與 setup key 建立(建 group 需要 PAT
- `client-troubleshooting.md` — 如果改 policy 後 peer 突然連不到,先查這裡
- `peer-deployment-ops.md` — 新部署 peer 時的 setup key + auto_groups 用法