file_access_agent/README.md

265 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# File Access Agent
File Access Agent 是檔案存取代理服務,用來控管 bucket / file space 裡檔案的上傳、下載、metadata 讀取與刪除權限。
本專案已決定使用 C# / ASP.NET Core。目標與授權模型依 `../member_center` 最新文件整理,後續實作會以此為準落地。
## 已確認決策
- 部署模型採 single-tenant instance一個 File Access Agent instance 只服務一個 tenant。
- `tenant_id` 仍是 token 與授權邊界的一部分,但服務端會驗證其必須等於本 instance 的固定 tenant。
- 服務預設為無 DB、stateless access gateway。
- 每個 request 只處理單檔upload/download/metadata/delete不提供結構化查詢。
- 版本管理由上游服務負責;不同版本在 bucket 中視為不同單檔(不同 `object_key` 或等價識別)。
- Agent 可只以 `object_key``file_id` 作為單檔識別,不保存完整 metadata。
## 專案目的
此服務位於業務服務與實際檔案儲存 bucket 之間,負責檔案存取的安全邊界。
核心目的:
- 驗證由 Member Center 簽發的 OAuth2/JWT access token。
-`scope``tenant_id``aud`、檔案識別與 HTTP method 判斷是否允許存取。
- 讓後端服務可以用 S2S token 上傳檔案。
- 讓後端服務在完成自身商業規則檢查後,向 Member Center 取得可給 client 使用的短效下載授權。
- 避免把一般 S2S access token 直接暴露給 client。
- 將 bucket provider 的直接存取權限集中在此服務或其 storage adapter 內。
## Agent 角色定義
File Access Agent 是 access permission gateway不是檔案主資料服務。
負責:
- 驗證 token 與 request 邊界(`tenant_id``scope``aud``method``object_key/file_id`
- 代理單檔 upload/download/metadata/delete
- 呼叫 Member Center delegated token validation endpoint
不負責:
- delegated token 簽發(由 Member Center 負責)
- 商業規則與版本管理(由上游服務負責)
- 結構化查詢、報表或資料分析
- metadata 主資料治理(預設不落地 DB
## 與 Member Center 的關係
Member Center 是 OAuth2/OIDC issuer 與 JWKS 提供者。File Access Agent 不負責會員登入、OAuth client 管理或長效 access token 簽發。
`../member_center` 目前已規劃並落地下列 File Access 相關授權設定:
- audience / resource`file_access_api`
- OAuth client usage`file_api`
- scopes
- `files:upload.write`
- `files:download.read`
- `files:download.delegate`
- `files:metadata.read`
- `files:delete`
最新版 `member_center` 文件已明確把 File Access 納入同一套租戶授權模型:`file_api` client 必須綁定 `tenant_id`upload token 與 delegated download token 也都必須帶 `tenant_id`
File Access Agent 應驗證:
- upload 的 S2S JWT透過 Member Center JWKS 驗 `iss``aud=file_access_api``exp``scope``tenant_id`
- download 的 delegated token以 Member Center validation endpoint 線上驗證
- token 中的 `tenant_id` 是否符合實際 request
- token 中的 `object_key``file_id` 是否符合實際 request
- token 中的 `method` 是否符合實際 request
待確認的檔案邊界 claim
- `user_id`delegated download token 目前由 Member Center 文件定義為必帶,用於對應業務服務已驗過的使用者身分。
- `owner_id` / `subject` / `client_id`:可用於紀錄或限定上傳者。
- `bucket` / `namespace` / `object_prefix`:若 storage 需要多 bucket 或 prefix 隔離,應優先明確化。
- `file_id` / `object_key`:下載 token 必須綁定其中一種檔案識別。
## 預期流程
### Upload: service to File Access Agent
1. 業務服務以 `client_credentials` 向 Member Center 取得 access token。
2. token 需包含 `aud=file_access_api``tenant_id``files:upload.write`
3. 業務服務帶 Bearer token 呼叫 File Access Agent 上傳檔案。
4. File Access Agent 驗 token、`tenant_id` 與檔案邊界後,寫入 bucket / file space。
### Download: service to client to File Access Agent
1. client 向業務服務要求下載檔案。
2. 業務服務自行驗證商業規則與檔案權限。
3. 業務服務以 `files:download.delegate` 呼叫 Member Center `POST /file-access/download-tokens` 取得短效 download token。
4. download token 至少綁定 `tenant_id``user_id``object_key``file_id``method=GET`、短效 `exp`
5. client 帶短效 token 直接向 File Access Agent 下載檔案。
6. File Access Agent 以 `files:download.read` 呼叫 Member Center `POST /file-access/download-tokens/validate`,帶上 token 與實際 GET request 邊界,驗證通過後放行。
責任邊界已確認:
- Member Center簽發 upload 用的 S2S JWT、簽發 delegated short-lived download token、提供 download token validation endpoint。
- File Access Agent驗證 upload JWT、呼叫 validation endpoint 驗 delegated download token、控管實際 bucket / file space 的讀寫。
- 業務服務:先驗商業規則與使用者檔案權限,再向 Member Center 申請 delegated download token。
## 初步 API 邊界
實際路由可在實作時調整,但能力邊界應維持清楚:
- `PUT /files/{object_key}`:上傳檔案,需 `files:upload.write`
- `GET /files/{object_key}`:下載檔案,需 `files:download.read`
- `HEAD /files/{object_key}``GET /files/metadata/{object_key}`:讀 metadata`files:metadata.read`
- `DELETE /files/{object_key}`:刪除檔案,需 `files:delete`
本服務不負責提供 `POST /download-tokens`。該責任已在 Member Center
- `POST /file-access/download-tokens`
- `POST /file-access/download-tokens/validate`
## 非目標
- 不負責會員註冊、登入、OAuth consent 或 OAuth client 管理。
- 不取代 Member Center 的 token issuer 職責。
- 不把 bucket credentials 發給 client。
- 不由 File Access Agent 判斷完整商業規則;業務服務仍需先判斷使用者是否可存取指定檔案。
- 不在語言與 storage provider 尚未決定前鎖死特定 SDK 或框架。
## 上傳命名與重複策略
- Agent 不做複雜命名規則;`object_key` 由介接服務決定。
- 相同 `object_key` 再次上傳時Agent 視為覆蓋overwrite不自動版本化。
- 若要避免檔名重複,介接服務應自行把 `timestamp/uuid/業務主鍵` 放入 `object_key`
- 若要版本管理,介接服務需為每個版本使用不同 `object_key`(例如 `v0001`, `v0002`)。
- 詳細命名建議請見 `docs/API.md` 的 Upload 區段。
## 待決策
- bucket / object storage provider例如 S3、GCS、Cloudflare R2、MinIO 或本機檔案系統。
- 是否需要「可選」持久化token `jti`、審計紀錄或特殊索引(預設不啟用)。
- object key 命名規則與 bucket / namespace / prefix 隔離策略。
- 檔案大小限制、content-type allowlist、病毒掃描與保留期限。
- 是否支援 presigned URL或所有流量都經由 access agent proxy。
## Storage 設定
API 支援兩種 provider
- `Storage:Provider=local`:使用本機檔案系統(`Instance:StorageRoot`
- `Storage:Provider=minio`:使用 MinIOS3 compatible
MinIO 設定(`src/FileAccessAgent.Api/appsettings.json`
- `Minio:Endpoint`:例如 `localhost:9000`
- `Minio:AccessKey`
- `Minio:SecretKey`
- `Minio:BucketName`
- `Minio:UseSsl``true|false`
- `Minio:Region`:可空
## Docker
API Dockerfile 位於 `src/FileAccessAgent.Api/Dockerfile`,建置時請使用 repo root 作為 build context讓 Docker 可以存取 Api、Application、Domain、Infrastructure project references。
建置 image
```bash
docker build -f src/FileAccessAgent.Api/Dockerfile -t file-access-agent-api .
```
啟動 APIcontainer 內 listen `8080`
```bash
docker run --rm -p 8080:8080 \
-e Instance__TenantId=d8107508-e6b9-4630-b982-c7bbb0cb228f \
-e Auth__Issuer=http://host.docker.internal:7850/ \
-e Auth__Audience=file_access_api \
-e Auth__RequireHttpsMetadata=false \
-e MemberCenter__BaseUrl=http://host.docker.internal:7850/ \
file-access-agent-api
```
若使用 local storage建議掛載 volume避免 container 移除後檔案遺失:
```bash
docker run --rm -p 8080:8080 \
-e Storage__Provider=local \
-e Instance__StorageRoot=/app/data/storage \
-v "$(pwd)/data/storage:/app/data/storage" \
file-access-agent-api
```
若使用 MinIO 且 MinIO 也在 Docker network 中,`Minio__Endpoint` 應使用 service/container DNS 名稱,例如 `minio:9000`;不要使用 container 內的 `localhost:9000`
## 實作語言
本專案已決定使用 C# / ASP.NET Core。
### C# / ASP.NET Core
-`member_center` 同語言,跨專案概念與維運一致。
- ASP.NET Core 對大檔串流、middleware、auth policy、DI、設定管理很成熟。
- 編譯期檢查較強,適合安全邊界服務。
- 可直接沿用 `member_center` 的設定、OpenAPI、JWT / OAuth 與部署習慣。
目前實作方向會以 ASP.NET Core Web API 為主,並保留 storage adapter 抽象,避免過早綁死特定 bucket provider。
## 文件維護規則
每次改動功能、流程、API、scope、設定或部署方式時都要同步更新文件。
優先更新順序:
1. `README.md`:專案目的、目前決策、執行方式與重要限制。
2. `docs/`若後續建立更細文件放設計、API、流程、部署、決策紀錄。
3. API 規格:一旦路由與 payload 穩定,補 OpenAPI 或等價規格。
如果程式碼與文件不一致,應先修正 README 或在 README 標示尚未決定,避免讓文件變成過期假設。
目前文件:
- `docs/API.md`File Access Agent API 規格與 Member Center 整合契約
- `docs/openapi.yaml`:本專案 OpenAPI 草案
- `docs/DATA_MODEL.md`:可選持久化擴充(非預設)
## 測試專案
- `src/FileAccessAgent.TestSite`Redirect login 測試站OIDC Authorization Code + PKCE
- 目的:透過 Member Center `web_login` client 登入,取得並顯示 token/claims並直接測試 Agent APIupload / download / head / metadata / delete / health
- 測試站採雙 token 模式:
- `web_login` token只用於身份展示claims / user context
- `file_api` service tokenclient credentials用於呼叫 Agent 與 Member Center delegated token API
最小設定(`src/FileAccessAgent.TestSite/appsettings.json`
- `MemberCenter:Authority`
- `MemberCenter:WebBaseUrl`Member Center Web預設 `http://localhost:5080`,供 redirect logout 使用)
- `MemberCenter:ClientId`web_login
- `MemberCenter:ClientSecret`web_login public client 可留空)
- `MemberCenter:CallbackPath`(需與 Member Center OAuth client redirect URI 一致)
- `MemberCenter:SignedOutCallbackPath`OIDC middleware callback建議保留預設 `/signout-callback-oidc`,不要與 direct logout callback 共用)
- `MemberCenter:Scopes`(建議 `openid email profile`
- `MemberCenter:ServiceClientId`file_api
- `MemberCenter:ServiceClientSecret`file_api
- `MemberCenter:ServiceScopes`(至少 `files:upload.write files:metadata.read files:delete files:download.delegate`
- `FileAccessAgent:BaseUrl`
- `FileAccessAgent:TenantId`
啟動:
- `dotnet run --project src/FileAccessAgent.TestSite/FileAccessAgent.TestSite.csproj`
- 進入首頁後點 `Login`,會導到 Member Center再 redirect 回測試站
- `Logout` 會走 Member Center Web `GET /account/logout?returnUrl=...`,再 callback 回 TestSite `/auth/logout-callback`
- 若 logout 後未回到 TestSite而停在 Member Center需在 Member Center Web 設定:
- `Auth__AllowedLogoutReturnUrlPrefixes=http://localhost:5091/`
- 登入後可在同一頁直接執行 `Upload``Download``Head``Get Metadata``Delete``Health`
- `Upload` 改為檔案挑選上傳;`Object Key` 可選填(留空會自動產生 `demo/uploads/<timestamp>-<filename>`
- 上傳成功後會保留回傳的 `object_key` 供後續 `Metadata/Head/Download/Delete` 直接測試
- 另提供 `Download (Invalid Token)` 測試,故意帶錯 token 驗證 Agent 拒絕邏輯
- `Download` 會先呼叫 Member Center `POST /file-access/download-tokens` 申請 delegated token再帶 token 呼叫 Agent 下載
- `Download File` 走 sample 的直連模式TestSite 僅向 Member Center 取 delegated token接著把 client 轉址到 Agent 下載 URL含短效 `access_token`),下載流量不經 TestSite
## 目前狀態
- 專案目標已依 `../member_center` 文件整理。
- 已確認使用 C# / ASP.NET Core。
- `tenant_id` 與 delegated download token 分工已依最新版 `member_center` 文件校正。
- API 已提供 Dockerfile可用 .NET 8 多階段建置產生 container image。
- 目前目錄中的 .NET skeleton 可作為正式起點,但仍需依最新流程補上 Member Center validation 串接。