访问授权插件
本文档描述了Docker Engine中可用的Docker Engine插件。要查看由Docker Engine管理的插件信息,请参阅 Docker Engine插件系统。
Docker的默认授权模型是全有或全无。任何有权访问Docker守护进程的用户都可以运行任何Docker客户端命令。对于使用Docker的Engine API与守护进程通信的调用者也是如此。如果您需要更严格的访问控制,您可以创建授权插件并将其添加到Docker守护进程配置中。使用授权插件,Docker管理员可以配置细粒度的访问策略来管理对Docker守护进程的访问。
任何具备适当技能的人都可以开发一个授权插件。这些技能,最基本的是对Docker的了解,对REST的理解,以及扎实的编程知识。本文档描述了授权插件开发者可用的架构、状态和方法信息。
基本原则
Docker的 插件基础设施 允许 通过使用通用API加载、移除和与第三方组件通信来扩展Docker。访问授权子系统 就是使用这种机制构建的。
使用此子系统,您不需要重建Docker守护进程来添加授权插件。您可以将插件添加到已安装的Docker守护进程中。您确实需要重新启动Docker守护进程以添加新插件。
授权插件根据当前的认证上下文和命令上下文来批准或拒绝Docker守护进程的请求。认证上下文包含所有用户详细信息和认证方法。命令上下文包含所有相关的请求数据。
授权插件必须遵循 Docker 插件 API中描述的规则。 每个插件必须位于 插件发现部分描述的目录中。
注意
缩写
AuthZ和AuthN分别表示授权和认证。
默认用户授权机制
如果在
Docker守护进程中启用了TLS,默认的用户授权流程会从证书主题名称中提取用户详细信息。
也就是说,User字段被设置为客户端证书主题的通用名称,而AuthenticationMethod字段被设置为TLS。
基本架构
您负责在Docker守护进程启动时注册您的插件。您可以安装多个插件并将它们链接在一起。这个链可以是有序的。每个对守护进程的请求都会按顺序通过这个链。只有当所有插件都授予对资源的访问权限时,访问才会被授予。
当通过CLI或Engine API向Docker守护进程发出HTTP请求时,身份验证子系统将请求传递给已安装的身份验证插件。请求包含用户(调用者)和命令上下文。插件负责决定是否允许或拒绝该请求。
下面的序列图描述了允许和拒绝授权流程:


发送到插件的每个请求都包括认证用户、HTTP头信息以及请求/响应体。只有用户名和使用的认证方法会传递给插件。最重要的是,不会传递任何用户凭证或令牌。最后,并非所有的请求/响应体都会发送到授权插件。只有那些Content-Type为text/*或application/json的请求/响应体才会被发送。
对于可能劫持HTTP连接的命令(HTTP Upgrade),例如exec,授权插件仅在初始HTTP请求时被调用。一旦插件批准了该命令,授权将不会应用于流程的其余部分。具体来说,流数据不会传递给授权插件。对于返回分块HTTP响应的命令,例如logs和events,只有HTTP请求会发送给授权插件。
在请求/响应处理过程中,某些授权流程可能需要对Docker守护进程进行额外的查询。为了完成这些流程,插件可以像普通用户一样调用守护进程API。为了启用这些额外的查询,插件必须提供管理员配置适当身份验证和安全策略的手段。
Docker 客户端流程
要启用和配置授权插件,插件开发者必须支持本节中详述的Docker客户端交互。
设置 Docker 守护进程
使用专用的命令行标志启用授权插件,格式为--authorization-plugin=PLUGIN_ID。该标志提供一个PLUGIN_ID值。该值可以是插件的套接字或规范文件的路径。授权插件可以在不重启守护进程的情况下加载。更多信息请参考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守护进程处理客户端请求之前调用。/AuthZPlugin.AuthZRes此授权响应方法在Docker守护进程将响应返回给客户端之前调用。
/AuthZPlugin.AuthZReq
请求
{
"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 "
}响应
{
"Allow": "Determined whether the user is allowed or not",
"Msg": "The authorization message",
"Err": "The error message if things go wrong"
}/AuthZPlugin.AuthZRes
请求:
{
"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"
}响应:
{
"Allow": "Determined whether the user is allowed or not",
"Msg": "The authorization message",
"Err": "The error message if things go wrong"
}请求授权
每个插件必须支持两种请求授权消息格式,一种是从守护进程到插件,然后从插件到守护进程。下表详细说明了每条消息中预期的内容。
守护进程 -> 插件
| Name | Type | Description |
|---|---|---|
| User | string | The user identification |
| Authentication method | string | The authentication method used |
| Request method | enum | The HTTP method (GET/DELETE/POST) |
| Request URI | string | The HTTP request URI including API version (e.g., v.1.17/containers/json) |
| Request headers | map[string]string | Request headers as key value pairs (without the authorization header) |
| Request body | []byte | Raw request body |
插件 -> 守护进程
| Name | Type | Description |
|---|---|---|
| Allow | bool | Boolean value indicating whether the request is allowed or denied |
| Msg | string | Authorization message (will be returned to the client in case the access is denied) |
| Err | string | Error message (will be returned to the client in case the plugin encounter an error. The string value supplied may appear in logs, so should not include confidential information) |
响应授权
插件必须支持两种授权消息格式,一种是从守护进程到插件,另一种是从插件到守护进程。下表详细说明了每条消息中预期的内容。
守护进程 -> 插件
| Name | Type | Description |
|---|---|---|
| User | string | The user identification |
| Authentication method | string | The authentication method used |
| Request method | string | The HTTP method (GET/DELETE/POST) |
| Request URI | string | The HTTP request URI including API version (e.g., v.1.17/containers/json) |
| Request headers | map[string]string | Request headers as key value pairs (without the authorization header) |
| Request body | []byte | Raw request body |
| Response status code | int | Status code from the Docker daemon |
| Response headers | map[string]string | Response headers as key value pairs |
| Response body | []byte | Raw Docker daemon response body |
插件 -> 守护进程
| Name | Type | Description |
|---|---|---|
| Allow | bool | Boolean value indicating whether the response is allowed or denied |
| Msg | string | Authorization message (will be returned to the client in case the access is denied) |
| Err | string | Error message (will be returned to the client in case the plugin encounter an error. The string value supplied may appear in logs, so should not include confidential information) |