访问授权插件
本文档描述了 Docker Engine 中可用的 Docker Engine 插件。要查看由 Docker Engine 管理的插件信息,请参阅 Docker Engine 插件系统。
Docker 开箱即用的授权模型是非黑即白的。任何有权访问 Docker 守护进程的用户都可以运行任何 Docker 客户端命令。对于使用 Docker Engine API 连接守护进程的调用者,情况亦同。如果您需要更细粒度的访问控制,可以创建授权插件(authorization plugins)并将其添加到 Docker 守护进程的配置文件。通过使用授权插件,Docker 管理员可以配置精细的访问策略来管理对 Docker 守护进程的访问。
任何具备相应技能的人都可以开发授权插件。这些最基本的技能包括对 Docker 的了解、对 REST 的理解以及扎实的编程知识。本文档描述了授权插件开发者可用的架构、状态和方法信息。
基本原则
Docker 的 插件架构 允许通过通用 API 加载、卸载和与第三方组件通信,从而扩展 Docker 的功能。访问授权子系统就是利用这一机制构建的。
使用此子系统,您无需重新构建 Docker 守护进程即可添加授权插件。您可以向已安装的 Docker 守护进程添加插件。但是,您需要重启 Docker 守护进程才能添加新插件。
授权插件根据当前的认证上下文和命令上下文,批准或拒绝向 Docker 守护进程的请求。认证上下文包含所有用户详细信息和认证方法。命令上下文包含所有相关的请求数据。
授权插件必须遵循Docker Plugin API中描述的规则。 每个插件必须驻留在“插件发现”部分所述的目录中。
注意
缩写
AuthZ和AuthN分别代表授权和认证。
默认用户授权机制
如果在
Docker 守护进程中启用了 TLS,则默认的用户授权流程会从证书主题名称中提取用户详细信息。
也就是说,User字段设置为客户端证书主题的通用名称(Common Name),而 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值。此值可以是插件的 socket 或指向规格文件的路径。
无需重启守护进程即可加载授权插件。有关详细信息,请参阅
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"
}请求授权
每个插件必须支持两种请求授权消息格式:一种是从守护进程发送到插件,另一种是从插件发送回守护进程。下表详细说明了每条消息中预期的内容。
守护进程 -> 插件
| 名称 | 类型 | 描述 |
|---|---|---|
| 用户 | string | 用户身份识别 |
| 认证方式 | string | 使用的身份验证方法 |
| 请求方法 | 枚举 | HTTP 方法(GET/DELETE/POST) |
| 请求 URI | string | 包含 API 版本的 HTTP 请求 URI(例如,v.1.17/containers/json) |
| 请求头 | map[string]string | 请求头作为键值对(不包含授权头) |
| 请求体 | []byte | 原始请求正文 |
插件 -> 守护进程
| 名称 | 类型 | 描述 |
|---|---|---|
| 允许 | bool | 布尔值,指示请求是被允许还是被拒绝 |
| 消息 | string | 授权消息(如果访问被拒绝,将返回给客户端) |
| 错误 | string | 错误消息(如果插件遇到错误,将返回给客户端。提供的字符串值可能会出现在日志中,因此不应包含机密信息) |
响应授权
该插件必须支持两种授权消息格式:一种从守护进程发送到插件,另一种从插件发送回守护进程。下表详细说明了每条消息中预期的内容。
守护进程 -> 插件
| 名称 | 类型 | 描述 |
|---|---|---|
| 用户 | string | 用户身份识别 |
| 认证方式 | string | 使用的身份验证方法 |
| 请求方法 | string | HTTP 方法(GET/DELETE/POST) |
| 请求 URI | string | 包含 API 版本的 HTTP 请求 URI(例如,v.1.17/containers/json) |
| 请求头 | map[string]string | 请求头作为键值对(不包含授权头) |
| 请求体 | []byte | 原始请求正文 |
| 响应状态码 | int | 来自 Docker 守护进程的返回码 |
| 响应头 | map[string]string | Response headers as key value pairs |
| 响应体 | []byte | 原始 Docker 守护进程响应正文 |
插件 -> 守护进程
| 名称 | 类型 | 描述 |
|---|---|---|
| 允许 | bool | 布尔值,指示响应是被允许还是被拒绝 |
| 消息 | string | 授权消息(如果访问被拒绝,将返回给客户端) |
| 错误 | string | 错误消息(如果插件遇到错误,将返回给客户端。提供的字符串值可能会出现在日志中,因此不应包含机密信息) |