# Momentry API Key 管理系統設計

| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-21 |
| 文件版本 | V1.2 |

---

## 版本歷史

| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 |
| V1.1 | 2026-03-20 | 新增 Key 類型與管理流程 | Warren | OpenCode |
| V1.2 | 2026-03-21 | 更新 API Key 格式與驗證流程 | Warren | OpenCode |

---

**狀態**: 開發中

---

## 1. 概述

### 1.1 目標

建立安全的 API Key 管理機制，支援：
- 多類型 API Key（系統、用戶、服務）
- 自動過期與輪換
- 異常使用偵測
- 強制更新機制
- 完整審計日誌
- Gitea Token 整合
- n8n API Key 整合

### 1.2 設計原則

| 原則 | 說明 |
|------|------|
| 最小權限 | 每個 Key 僅授予必要權限 |
| 定期輪換 | 自動過期強制更新 |
| 追蹤可審 | 所有操作都有日誌 |
| 分離儲存 | Key 與使用者資料分離 |

---

## 2. API Key 類型

### 2.1 Key 類型矩陣

| 類型 | 前綴 | 用途 | 預設有效期 | 輪換方式 |
|------|------|------|------------|----------|
| `system` | `msys_` | 系統內部服務 | 365 天 | 手動 |
| `user` | `muser_` | 個人用戶 | 90 天 | 自動 |
| `service` | `msvc_` | 服務間通訊 | 180 天 | 自動 |
| `integration` | `mint_` | 第三方整合 | 30 天 | 強制更新 |
| `emergency` | `memg_` | 緊急存取 | 24 小時 | 一次性 |

### 2.2 Key 格式

```
{prefix}{uuid_v4}_{timestamp}_{checksum}
```

**範例：**
```
msys_a1b2c3d4-e5f6-7890-abcd-ef1234567890_1710998400_sha256
```

---

## 3. 資料庫 Schema

### 3.1 api_keys 表

```sql
CREATE TABLE api_keys (
    id              BIGSERIAL PRIMARY KEY,
    key_id         VARCHAR(64) UNIQUE NOT NULL,  -- 公開 Key ID
    key_hash       VARCHAR(128) NOT NULL,       -- SHA256 哈希
    key_prefix     VARCHAR(8) NOT NULL,         -- Key 前綴
    name           VARCHAR(128) NOT NULL,        -- Key 名稱
    key_type       VARCHAR(32) NOT NULL,        -- system/user/service/integration/emergency
    user_id        BIGINT,                      -- 關聯用戶 (nullable for system)
    service_name   VARCHAR(64),                  -- 服務名稱 (for service keys)
    permissions     JSONB NOT NULL DEFAULT '[]', -- 權限列表
    expires_at     TIMESTAMP,                   -- 過期時間
    last_used_at   TIMESTAMP,                   -- 最後使用時間
    last_used_ip   VARCHAR(45),                 -- 最後使用 IP
    usage_count    BIGINT DEFAULT 0,            -- 使用次數
    status         VARCHAR(16) DEFAULT 'active', -- active/suspended/expired/revoked
    rotation_required BOOLEAN DEFAULT FALSE,     -- 強制輪換標記
    rotation_reason VARCHAR(256),               -- 輪換原因
    created_at     TIMESTAMP DEFAULT NOW(),
    updated_at     TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_api_keys_key_id ON api_keys(key_id);
CREATE INDEX idx_api_keys_user_id ON api_keys(user_id);
CREATE INDEX idx_api_keys_type ON api_keys(key_type);
CREATE INDEX idx_api_keys_status ON api_keys(status);
CREATE INDEX idx_api_keys_expires ON api_keys(expires_at);
```

### 3.2 api_key_audit_log 表

```sql
CREATE TABLE api_key_audit_log (
    id              BIGSERIAL PRIMARY KEY,
    key_id         VARCHAR(64) NOT NULL,
    action         VARCHAR(32) NOT NULL,         -- created/used/rotated/revoked/expired/suspended
    actor          VARCHAR(64),                   -- 操作者 (user_id or 'system')
    ip_address     VARCHAR(45),
    user_agent     VARCHAR(512),
    request_path   VARCHAR(256),
    response_code  INTEGER,
    details        JSONB,
    created_at     TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_audit_key_id ON api_key_audit_log(key_id);
CREATE INDEX idx_audit_action ON api_key_audit_log(action);
CREATE INDEX idx_audit_created ON api_key_audit_log(created_at);
```

### 3.3 api_key_rotation_log 表

```sql
CREATE TABLE api_key_rotation_log (
    id                  BIGSERIAL PRIMARY KEY,
    key_id             VARCHAR(64) NOT NULL,
    old_key_id         VARCHAR(64),
    new_key_id         VARCHAR(64),
    rotation_type      VARCHAR(32) NOT NULL,     -- scheduled/manual/forced/emergency
    reason             VARCHAR(256),
    triggered_by       VARCHAR(64),              -- system/user/scheduler
    grace_period_end   TIMESTAMP,               -- 寬限期結束時間
    created_at         TIMESTAMP DEFAULT NOW()
);
```

---

## 4. API Key 狀態機

```
                    ┌──────────────┐
                    │   created    │
                    └──────┬───────┘
                           │
                           ▼
              ┌────────────────────┐
              │      active        │◄─────────────┐
              └─────────┬──────────┘              │
                        │                          │
          ┌─────────────┼─────────────┐            │
          │             │             │            │
          ▼             ▼             ▼            │
    ┌──────────┐ ┌──────────┐ ┌──────────┐     │
    │ suspended │ │ expired  │ │ revoked  │─────┘
    └──────────┘ └──────────┘ └──────────┘
```

### 狀態轉換規則

| 從 | 到 | 觸發條件 |
|----|----|----------|
| created | active | 啟用 Key |
| active | suspended | 異常使用偵測 |
| active | expired | 達到過期時間 |
| active | revoked | 手動撤銷 |
| suspended | active | 解除鎖定 |
| suspended | revoked | 確認異常 |
| expired | active | 重新啟用 |

---

## 5. 異常偵測機制

### 5.1 異常指標

| 指標 | 閾值 | 處置 |
|------|------|------|
| 每分鐘請求數 | > 1000 | 警告 |
| 每小時請求數 | > 10000 | 鎖定 |
| 錯誤率 | > 50% | 警告 |
| 不同 IP 數 | > 5/小時 | 警告 |
| 非工作時間使用 | 深夜請求 | 警告 |
| 異常模式 | 暴力破解 | 鎖定 |

### 5.2 異常處理流程

```
異常偵測
    │
    ▼
┌─────────┐
│  分析   │──→ 排除正常流量
└────┬────┘
     │
     ▼
┌─────────┐
│  評估   │──→ 輕微 → 警告
└────┬────┘
     │
     ▼
┌─────────┐
│  處置   │──→ 嚴重 → 鎖定 + 輪換
└─────────┘
```

---

## 6. 強制更新機制

### 6.1 觸發條件

| 條件 | 嚴重性 | 動作 |
|------|--------|------|
| 疑似洩露 | 高 | 立即停用 + 強制輪換 |
| 異常使用 | 中 | 警告 + 建議輪換 |
| 計劃性維護 | 低 | 通知 + 排程輪換 |
| 政策要求 | 高 | 強制輪換 |
| 過期 | 低 | 停用 + 通知 |

### 6.2 強制輪換流程

```
1. 系統偵測到需要強制更新
         │
         ▼
2. 建立新 Key（保留舊 Key 在寬限期內）
         │
         ▼
3. 發送通知（Email/Slack/Redis PubSub）
         │
         ▼
4. 寬限期開始（預設 24 小時）
         │
         ├── 在寬限期內更新 → 完成輪換
         │
         └── 寬限期結束 → 舊 Key 停用
```

### 6.3 寬限期配置

| Key 類型 | 寬限期 |
|----------|--------|
| system | 72 小時 |
| user | 24 小時 |
| service | 48 小時 |
| integration | 24 小時 |
| emergency | 0 小時 |

---

## 7. CLI 管理命令

### 7.1 命令列表

```bash
# Key 管理
momentry api-key create --name "My Key" --type user --permissions read,write
momentry api-key list --type user
momentry api-key info <key_id>
momentry api-key revoke <key_id> --reason "安全原因"

# 輪換管理
momentry api-key rotate <key_id>           # 正常輪換
momentry api-key force-rotate <key_id>       # 強制輪換
momentry api-key rotation-status <key_id>    # 查看輪換狀態

# 異常管理
momentry api-key suspend <key_id> --reason "異常使用"
momentry api-key unsuspend <key_id>
momentry api-key blacklist <key_id>         # 列入黑名單

# 審計
momentry api-key audit <key_id> --since 7d
momentry api-key stats --type service --period 30d
```

### 7.2 輸出範例

```bash
$ momentry api-key list --type service

┌────────────────────────────────────┬─────────┬──────────────┬────────────────┐
│ Key ID                             │ Name    │ Status       │ Expires        │
├────────────────────────────────────┼─────────┼──────────────┼────────────────┤
│ msvc_a1b2c3d4_1710998400_sha256    │ N8N     │ active       │ 2026-09-21     │
│ msvc_e5f6g7h8_1713600000_sha256   │ OpenCode│ rotation_req  │ 2026-09-21     │
└────────────────────────────────────┴─────────┴──────────────┴────────────────┘

⚠️  1 個 Key 需要輪換
```

---

## 8. 實現計畫

### Phase 1: 核心功能
- [ ] 資料庫 Schema
- [ ] Key 生成與哈希
- [ ] 基本 CRUD API
- [ ] 過期檢查

### Phase 2: 安全機制
- [ ] 異常偵測
- [ ] 自動鎖定
- [ ] 強制輪換
- [ ] 寬限期管理

### Phase 3: 管理工具
- [ ] CLI 命令
- [ ] 審計日誌
- [ ] 統計報表
- [ ] 通知系統

### Phase 4: 自動化
- [ ] 定時輪換排程
- [ ] Prometheus 指標
- [ ] Alertmanager 整合
- [ ] 自動化回應

---

## 9. 安全考量

### 9.1 Key 儲存
- 明文 Key 只顯示一次（創建時）
- 儲存時使用 SHA256 哈希
- 使用 Fernet 對稱加密敏感配置

### 9.2 傳輸安全
- 所有 API 必須使用 HTTPS
- Key 在 Header 中傳輸（X-API-Key）
- 避免 Key 在 URL 中

### 9.3 存取控制
- 只有管理員可創建/撤銷 Key
- 用戶只能管理自己的 Key
- 系統 Key 需要特殊權限

---

## 10. 環境變數配置

```bash
# API Key 管理
MOMENTRY_API_KEY_GRACE_PERIOD=86400          # 寬限期（秒）
MOMENTRY_API_KEY_MAX_PER_USER=5              # 每用戶最大 Key 數
MOMENTRY_API_KEY_ROTATION_DAYS=90            # 自動輪換天數

# 異常偵測
MOMENTRY_API_KEY_RATE_LIMIT=1000             # 每分鐘限制
MOMENTRY_API_KEY_ERROR_THRESHOLD=0.5         # 錯誤率閾值
MOMENTRY_API_KEY_IP_LIMIT=5                 # 每小時 IP 限制

# 通知
MOMENTRY_API_KEY_ALERT_WEBHOOK=             # 異常通知 webhook
```

---

## 11. Gitea API Token 整合

### 11.1 概述

支援透過 API Key 管理系統建立和管理 Gitea Personal Access Tokens，採用「建立時納管」模式。

### 11.2 納管模式

```
使用者提供帳號密碼 → 呼叫 Gitea API 建立 Token → 明文只顯示一次 → 同步儲存至管理系統
```

**特點：**
- Token 明文僅在建立時取得
- 管理系統記錄 Token 元數據（不含明文）
- 支援本地查詢和刪除

### 11.3 資料庫結構

```sql
CREATE TABLE gitea_tokens (
    id SERIAL PRIMARY KEY,
    gitea_token_id BIGINT NOT NULL,      -- Gitea 內部 Token ID
    gitea_user VARCHAR(128) NOT NULL,    -- Gitea 用戶名
    token_name VARCHAR(128) NOT NULL,    -- Token 名稱
    token_last_eight VARCHAR(8) NOT NULL, -- SHA1 最後 8 碼（顯示用）
    scopes JSONB DEFAULT '[]',           -- 權限範圍
    api_key_id VARCHAR(48),              -- 關聯的 API Key ID（可選）
    last_verified TIMESTAMP,             -- 最後驗證時間
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(gitea_user, token_name)
);
```

### 11.4 Token 權限範圍

| 範圍 | 說明 |
|------|------|
| `read:repository` | 讀取倉庫 |
| `write:repository` | 寫入倉庫 |
| `read:issue` | 讀取議題 |
| `write:issue` | 寫入議題 |
| `read:user` | 讀取用戶資訊 |
| `write:write` | 修改用戶資訊 |
| `read:organization` | 讀取組織 |
| `write:organization` | 修改組織 |
| `read:package` | 讀取套件 |
| `write:package` | 發布套件 |
| `read:notification` | 讀取通知 |
| `write:notification` | 修改通知 |
| `read:admin` | 管理員讀取 |
| `write:admin` | 管理員寫入 |

### 11.5 CLI 命令

#### 建立 Token

```bash
# 基本用法
momentry gitea create \
  --username <gitea_user> \
  --password <gitea_password> \
  --token-name <token_name> \
  --scopes "read:repository,write:repository"

# 範例：建立整合用 Token
momentry gitea create \
  --username admin \
  --password "MyPassword123" \
  --token-name "ci-pipeline" \
  --scopes "read:repository,write:repository,read:issue,write:issue"
```

**輸出範例：**
```
✅ Gitea Token created successfully!

┌─────────────────────────────────────────────────────────────────────────────┐
│  ⚠️  IMPORTANT: Save this token now - it will not be shown again!         │
└─────────────────────────────────────────────────────────────────────────────┘

Token ID:   9
Token Name: ci-pipeline
SHA1:       9a4f282e9ba817b430082e6bff2c18e2ae38e480
Last 8:     ae38e480

Authorization Header:
  Authorization: token 9a4f282e9ba817b430082e6bff2c18e2ae38e480
```

#### 列出 Token

```bash
# 列出用戶的所有 Token
momentry gitea list \
  --username <gitea_user> \
  --password <gitea_password>
```

**輸出範例：**
```
📋 Gitea Tokens for user: admin

┌────────────────────────────────────────────────────────────────────────────┐
│ ID       │ Name                 │ Last 8    │ Registered                  │
├────────────────────────────────────────────────────────────────────────────┤
│        9 │ ci-pipeline          │ ae38e480  │ ✓                          │
│        8 │ dev-token            │ 1234abcd  │ -                          │
└────────────────────────────────────────────────────────────────────────────┘

Total: 2 token(s)
```

#### 刪除 Token

```bash
# 刪除指定 Token
momentry gitea delete \
  --username <gitea_user> \
  --password <gitea_password> \
  --token-name <token_name>
```

#### 查詢本地記錄

```bash
# 查詢已納管的 Token 記錄
momentry gitea verify --token-name <token_name>
```

**輸出範例：**
```
📋 Gitea Token: ci-pipeline
  User:         admin
  Token ID:     9
  Last 8:       ae38e480
  Scopes:       ["read:repository","write:repository"]
  Created:      2026-03-21 06:44:55.577586 UTC
  Last Verified: never
```

### 11.6 使用範圍

#### 適用場景

| 場景 | 說明 |
|------|------|
| CI/CD 整合 | 建立專用 Token 用於自動化流程 |
| 服務間通訊 | 建立 Token 供其他服務存取 Gitea API |
| 開發環境 | 為開發者建立短期 Token |
| 監控整合 | 建立只讀 Token 用於監控和報告 |

#### 限制

| 限制 | 說明 |
|------|------|
| 明文 Token | 僅在建立時取得，無法再次查詢 |
| 管理 API | 需要帳號密碼（BasicAuth） |
| Token 驗證 | 只能透過 API 呼叫驗證有效性 |
| 同步刪除 | 本地刪除不會自動同步到 Gitea |

### 11.7 環境變數

```bash
# Gitea 連線設定
GITEA_URL=http://localhost:3000    # Gitea API URL
```

### 11.8 安全考量

| 項目 | 措施 |
|------|------|
| 密碼傳輸 | 僅在 CLI 命令中使用，不儲存 |
| Token 儲存 | 本地僅存元數據，不含明文 |
| 權限最小化 | 建議僅授予必要權限 |
| 定期輪換 | 建議定期更新 Token |

---

## 12. n8n API Key 整合

### 12.1 概述

支援透過 API Key 管理系統建立和管理 n8n API Keys，採用「建立時納管」模式。

### 12.2 納管模式

```
使用者提供現有 n8n API Key → 呼叫 n8n API 建立新 Key → 明文只顯示一次 → 同步儲存至管理系統
```

**特點：**
- 需要一個現有的 n8n API Key 作為管理憑證
- API Key 明文僅在建立時取得
- 管理系統記錄 Key 元數據（不含明文）
- 支援本地查詢和刪除

### 12.3 資料庫結構

```sql
CREATE TABLE n8n_api_keys (
    id SERIAL PRIMARY KEY,
    n8n_key_id VARCHAR(64) UNIQUE NOT NULL,  -- n8n 內部 Key ID
    label VARCHAR(100) NOT NULL,             -- Key 標籤
    api_key_last_eight VARCHAR(8) NOT NULL,  -- API Key 最後 8 碼（顯示用）
    momentry_api_key_id VARCHAR(48),         -- 關聯的 API Key ID（可選）
    expires_at TIMESTAMP WITH TIME ZONE,     -- 過期時間
    last_verified TIMESTAMP WITH TIME ZONE,  -- 最後驗證時間
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
```

### 12.4 認證方式

n8n 使用 JWT-based API Key，透過 `X-N8N-API-KEY` Header 認證：

```bash
curl -H "X-N8N-API-KEY: <your-api-key>" https://n8n.example.com/api/v1/workflows
```

### 12.5 CLI 命令

#### 建立 API Key

```bash
# 基本用法
momentry n8n create \
  --api-key <existing_n8n_api_key> \
  --label <key_label> \
  --expires-in-days <days>

# 範例：建立 CI/CD 用 Key
momentry n8n create \
  --api_key "n8n_api_xxxxxxxxxxxx" \
  --label "ci-pipeline" \
  --expires-in-days 90
```

**輸出範例：**
```
✅ n8n API Key created successfully!

┌─────────────────────────────────────────────────────────────────────────────┐
│  ⚠️  IMPORTANT: Save this API key now - it will not be shown again!       │
└─────────────────────────────────────────────────────────────────────────────┘

Key ID:    abc123-def456
Label:     ci-pipeline
API Key:   eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Usage:
  curl -H 'X-N8N-API-KEY: eyJhbGciOiJIUz...' https://n8n.momentry.ddns.net/api/v1/workflows
```

#### 列出 API Keys

```bash
# 列出所有 API Keys
momentry n8n list --api-key <existing_n8n_api_key>
```

**輸出範例：**
```
📋 n8n API Keys

┌────────────────────────────────────────────────────────────────────────────┐
│ Label                       │ ID                                      │
├────────────────────────────────────────────────────────────────────────────┤
│ ci-pipeline                 │ abc123-def456-789                      │
│ monitoring                  │ xyz789-abc123-456                      │
└────────────────────────────────────────────────────────────────────────────┘

Total: 2 key(s)
```

#### 刪除 API Key

```bash
# 刪除指定 API Key
momentry n8n delete \
  --api-key <existing_n8n_api_key> \
  --label <key_label>
```

#### 查詢本地記錄

```bash
# 查詢已納管的 API Key 記錄
momentry n8n verify --label <key_label>
```

**輸出範例：**
```
📋 n8n API Key: ci-pipeline
  Key ID:        abc123-def456
  Last 8:        ...JVCJ9
  Created:       2026-03-21 06:44:55.577586 UTC
  Expires:       2026-06-19 06:44:55.577586 UTC
  Last Verified: never
```

### 12.6 使用範圍

#### 適用場景

| 場景 | 說明 |
|------|------|
| CI/CD 整合 | 建立專用 Key 用於自動化流程 |
| 監控整合 | 建立只讀 Key 用於監控工作流狀態 |
| 服務間通訊 | 建立 Key 供其他服務呼叫 n8n API |
| 開發環境 | 為開發者建立短期 Key |

#### 限制

| 限制 | 說明 |
|------|------|
| 明文 API Key | 僅在建立時取得，無法再次查詢 |
| 管理憑證 | 需要一個現有的 n8n API Key |
| 本地刪除 | 不會自動同步到 n8n |
| 權限範圍 | 非 Enterprise 版無細粒度權限 |

### 12.7 環境變數

```bash
# n8n 連線設定
N8N_URL=https://n8n.momentry.ddns.net    # n8n API URL
```

### 12.8 安全考量

| 項目 | 措施 |
|------|------|
| 管理 Key | 需妥善保管，作為管理其他 Key 的憑證 |
| API Key 儲存 | 本地僅存元數據，不含明文 |
| 過期機制 | 建議設定過期時間 |
| 定期輪換 | 建議定期更新 Key |

---

## 13. 參考文檔

- PostgreSQL Schema
- Redis Key 設計（ MOMENTRY_CORE_REDIS_KEYS.md）
- 監控系統（MOMENTRY_CORE_MONITORING.md）
- Gitea 安裝指南（INSTALL_GITEA.md）
- n8n API 文件（https://docs.n8n.io/api/authentication/）
