存取授權外掛
本文件說明 Docker Engine 中可用的 Docker Engine 外掛程式。若要檢視由 Docker Engine 管理的外掛程式資訊,請參閱 Docker Engine 外掛程式系統。
Docker 現成的授權模型是「全有或全無」。任何有權存取 Docker daemon 的使用者都可以執行任何 Docker 用戶端指令。使用 Docker Engine API 與 daemon 進行通訊的呼叫者也是如此。如果您需要更嚴格的存取控制,可以建立授權外掛程式並將其新增至您的 Docker daemon 設定中。透過使用授權外掛程式,Docker 管理員可以設定細粒度的存取策略,以管理對 Docker daemon 的存取。
任何具備適當技能的人都可以開發授權外掛程式。這些技能最基本的要求是:熟悉 Docker、了解 REST,以及具備紮實的程式設計知識。本文件說明授權外掛程式開發者可用的架構、狀態與方法資訊。
基本原則
Docker 的外掛程式架構透過使用通用 API 來載入、移除並與第三方元件通訊,從而實現對 Docker 的擴充。存取授權子系統就是使用此機制建構的。
使用此子系統,您不需要重新建置 Docker daemon 即可新增授權外掛程式。您可以將外掛程式新增至已安裝的 Docker daemon。新增新外掛程式後,您需要重新啟動 Docker daemon。
授權外掛程式會根據目前的驗證上下文與指令上下文,核准或拒絕發送至 Docker daemon 的請求。驗證上下文包含所有使用者詳細資料與驗證方法。指令上下文則包含所有相關的請求資料。
授權外掛程式必須遵守 Docker 外掛程式 API 中所述的規則。每個外掛程式都必須位於「外掛程式探索」一節中所述的目錄內。
注意縮寫
AuthZ與AuthN分別代表授權 (Authorization) 與驗證 (Authentication)。
預設使用者授權機制
如果在 Docker daemon 中啟用了 TLS,預設的使用者授權流程會從憑證主體名稱中提取使用者詳細資料。也就是說,User 欄位會設定為用戶端憑證主體的通用名稱 (Common Name),而 AuthenticationMethod 欄位會設定為 TLS。
基本架構
您有責任在 Docker daemon 啟動時註冊您的外掛程式。您可以安裝多個外掛程式並將其串聯起來。此鏈條可以排序。發送給 daemon 的每個請求都會按順序通過此鏈條。只有當所有外掛程式都授予資源存取權時,存取才被允許。
當透過 CLI 或 Engine API 向 Docker daemon 發出 HTTP 請求時,驗證子系統會將請求傳遞給已安裝的驗證外掛程式。該請求包含使用者(呼叫者)與指令上下文。外掛程式負責決定是允許還是拒絕該請求。
下方的順序圖描述了允許與拒絕的授權流程。


發送給外掛程式的每個請求都包含經過驗證的使用者、HTTP 標頭以及請求/回應主體。只有使用者名稱與所使用的驗證方法會傳遞給外掛程式。最重要的是,不會傳遞任何使用者憑證或權杖。最後,並非所有請求/回應主體都會發送給授權外掛程式。只有 Content-Type 為 text/* 或 application/json 的請求/回應主體才會被發送。
對於可能劫持 HTTP 連線 (HTTP Upgrade) 的指令(例如 exec),授權外掛程式僅在初始 HTTP 請求時被呼叫。一旦外掛程式核准該指令,授權就不會應用於流程的其餘部分。具體而言,串流資料不會傳遞給授權外掛程式。對於回傳分塊 HTTP 回應的指令(例如 logs 與 events),僅 HTTP 請求會被發送給授權外掛程式。
在請求/回應處理過程中,某些授權流程可能需要對 Docker daemon 執行額外的查詢。為了完成此類流程,外掛程式可以像一般使用者一樣呼叫 daemon API。若要啟用這些額外查詢,外掛程式必須為管理員提供設定適當驗證與安全策略的方法。
Docker 用戶端流程
若要啟用並設定授權外掛程式,外掛程式開發者必須支援本節中詳細說明的 Docker 用戶端互動。
設定 Docker daemon
使用 --authorization-plugin=PLUGIN_ID 格式的專用指令列旗標來啟用授權外掛程式。該旗標會提供 PLUGIN_ID 值。此值可以是外掛程式的 socket 或規格檔案的路徑。授權外掛程式無需重新啟動 daemon 即可載入。請參閱 dockerd 文件以取得更多資訊。
$ dockerd --authorization-plugin=plugin1 --authorization-plugin=plugin2,...
Docker 的授權子系統支援多個 --authorization-plugin 參數。
呼叫授權指令(允許)
$ docker pull centos
<...>
f1b10cd84249: Pull complete
<...>
呼叫未授權指令(拒絕)
$ docker pull centos
<...>
docker: Error response from daemon: authorization denied by plugin PLUGIN_NAME: volumes are not allowed.
來自外掛程式的錯誤
$ docker pull centos
<...>
docker: Error response from daemon: plugin PLUGIN_NAME failed with error: AuthZPlugin.AuthZReq: Cannot connect to the Docker daemon. Is the docker daemon running on this host?.
API 架構與實作
除了 Docker 的標準外掛程式註冊方法外,每個外掛程式都應實作以下兩個方法:
/AuthZPlugin.AuthZReq:此授權請求方法會在 Docker daemon 處理用戶端請求之前被呼叫。/AuthZPlugin.AuthZRes:此授權回應方法會在 Docker daemon 將回應傳回給用戶端之前被呼叫。
/AuthZPlugin.AuthZReq
請求 (Request)
{
"User": "The user identification",
"UserAuthNMethod": "The authentication method used",
"RequestMethod": "The HTTP method",
"RequestURI": "The HTTP request URI",
"RequestBody": "Byte array containing the raw HTTP request body",
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string "
}回應 (Response)
{
"Allow": "Determined whether the user is allowed or not",
"Msg": "The authorization message",
"Err": "The error message if things go wrong"
}/AuthZPlugin.AuthZRes
請求 (Request)
{
"User": "The user identification",
"UserAuthNMethod": "The authentication method used",
"RequestMethod": "The HTTP method",
"RequestURI": "The HTTP request URI",
"RequestBody": "Byte array containing the raw HTTP request body",
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string",
"ResponseBody": "Byte array containing the raw HTTP response body",
"ResponseHeader": "Byte array containing the raw HTTP response header as a map[string][]string",
"ResponseStatusCode":"Response status code"
}回應 (Response)
{
"Allow": "Determined whether the user is allowed or not",
"Msg": "The authorization message",
"Err": "The error message if things go wrong"
}請求授權
每個外掛程式必須支援兩種請求授權訊息格式:一種從 daemon 到外掛程式,另一種從外掛程式到 daemon。下表詳細說明了每條訊息中預期的內容。
Daemon -> 外掛程式
| 名稱 | 類型 | 描述 |
|---|---|---|
| 使用者 | string | 使用者識別 |
| 驗證方法 | string | 所使用的驗證方法 |
| 請求方法 | 列舉 (enum) | HTTP 方法 (GET/DELETE/POST) |
| 請求 URI | string | 包含 API 版本的 HTTP 請求 URI (例如 v.1.17/containers/json) |
| 請求標頭 | map[string]string | 以鍵值對形式呈現的請求標頭(不含授權標頭) |
| 請求主體 | []byte | 原始請求主體 |
外掛程式 -> Daemon
| 名稱 | 類型 | 描述 |
|---|---|---|
| 允許 | 布林值 (bool) | 指示請求是被允許還是拒絕的布林值 |
| 訊息 | string | 授權訊息(若拒絕存取,將傳回給用戶端) |
| 錯誤 | string | 錯誤訊息(若外掛程式遇到錯誤,將傳回給用戶端。提供的字串值可能會出現在記錄中,因此不應包含機密資訊) |
回應授權
外掛程式必須支援兩種授權訊息格式:一種從 daemon 到外掛程式,另一種從外掛程式到 daemon。下表詳細說明了每條訊息中預期的內容。
Daemon -> 外掛程式
| 名稱 | 類型 | 描述 |
|---|---|---|
| 使用者 | string | 使用者識別 |
| 驗證方法 | string | 所使用的驗證方法 |
| 請求方法 | string | HTTP 方法 (GET/DELETE/POST) |
| 請求 URI | string | 包含 API 版本的 HTTP 請求 URI (例如 v.1.17/containers/json) |
| 請求標頭 | map[string]string | 以鍵值對形式呈現的請求標頭(不含授權標頭) |
| 請求主體 | []byte | 原始請求主體 |
| 回應狀態碼 | 整數 (int) | 來自 Docker daemon 的狀態碼 |
| 回應標頭 | map[string]string | 以鍵值對形式呈現的回應標頭 |
| 回應主體 | []byte | 原始 Docker daemon 回應主體 |
外掛程式 -> Daemon
| 名稱 | 類型 | 描述 |
|---|---|---|
| 允許 | 布林值 (bool) | 指示回應是被允許還是拒絕的布林值 |
| 訊息 | string | 授權訊息(若拒絕存取,將傳回給用戶端) |
| 錯誤 | string | 錯誤訊息(若外掛程式遇到錯誤,將傳回給用戶端。提供的字串值可能會出現在記錄中,因此不應包含機密資訊) |