diff --git a/README.md b/README.md index 0094a40..f5b2b34 100644 --- a/README.md +++ b/README.md @@ -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) | 部署摘要與疑難排解記錄 | ## 快速開始 diff --git a/SUMMARY.md b/SUMMARY.md index 276696a..d2ca1cc 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -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/) diff --git a/groups-and-policies.md b/groups-and-policies.md new file mode 100644 index 0000000..20ad379 --- /dev/null +++ b/groups-and-policies.md @@ -0,0 +1,268 @@ +# Groups 與 Access Control Policies + +NetBird 的存取控管基本單位。本文用目前部署的 4 個 peer(mbp-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 匹配時用 OR:peer 只要在 policy 的 source group 任一個裡就算命中。 + +## 怎麼建 Group + +### 方式 A:UI(推薦起步) + +1. Dashboard → **Access Control → Groups** → **Create Group** +2. 填 **Name**(例 `servers`) +3. 在 **Peers** 勾選要加入的 peer +4. **Create** + +建完後去 **Access Control → Policies** 或 **Peers** 頁面都能再綁定 group。 + +### 方式 B:API + +```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": ["", ""] + }' \ + 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": ["", ""] + }' \ + https://netbird.timmy.us.kg/api/groups | jq +``` + +## 怎麼建 Policy + +### 方式 A:UI + +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** + +### 方式 B:API + +```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": [""], + "destinations": [""], + "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 '' \ + https://netbird.timmy.us.kg/api/policies/ + +# 或直接刪除 +curl -X DELETE -H "Authorization: Token $TOKEN" \ + https://netbird.timmy.us.kg/api/policies/ +``` + +## 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": [""] + }' \ + 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: [] + destinations: [] +``` + +### 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' +``` + +### 方式 B:Dashboard → 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 用法