访问授权插件
本文档描述了 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"
}请求授权
每个插件必须支持两种请求授权消息格式,一种是从守护进程到插件,另一种是从插件到守护进程。下表详细说明了每条消息中预期的内容。
守护进程 -> 插件
| 名称 | 类型 | 描述 |
|---|---|---|
| 用户 | 字符串 | 用户标识 |
| 身份验证方法 | 字符串 | 使用的身份验证方法 |
| 请求方法 | 枚举 | HTTP 方法 (GET/DELETE/POST) |
| 请求 URI | 字符串 | 包含 API 版本的 HTTP 请求 URI(例如,v.1.17/containers/json) |
| 请求头 | map[string]string | 请求头作为键值对(不包含授权头) |
| 请求体 | []byte | 原始请求体 |
插件 -> 守护进程
| 名称 | 类型 | 描述 |
|---|---|---|
| 允许 | 布尔值 | 布尔值,指示请求是否被允许或拒绝 |
| 消息 | 字符串 | 授权消息(如果访问被拒绝,将返回给客户端) |
| 错误 | 字符串 | 错误消息(如果插件遇到错误,将返回给客户端。提供的字符串值可能会出现在日志中,因此不应包含机密信息) |
响应授权
插件必须支持两种授权消息格式,一种是从守护进程到插件,另一种是从插件到守护进程。下表详细说明了每条消息中预期的内容。
守护进程 -> 插件
| 名称 | 类型 | 描述 |
|---|---|---|
| 用户 | 字符串 | 用户标识 |
| 身份验证方法 | 字符串 | 使用的身份验证方法 |
| 请求方法 | 字符串 | HTTP 方法 (GET/DELETE/POST) |
| 请求 URI | 字符串 | 包含 API 版本的 HTTP 请求 URI(例如,v.1.17/containers/json) |
| 请求头 | map[string]string | 请求头作为键值对(不包含授权头) |
| 请求体 | []byte | 原始请求体 |
| 响应状态码 | 整数 | 来自 Docker 守护进程的状态码 |
| 响应头 | map[string]string | 响应头作为键值对 |
| 响应体 | []byte | 原始 Docker 守护进程响应体 |
插件 -> 守护进程
| 名称 | 类型 | 描述 |
|---|---|---|
| 允许 | 布尔值 | 布尔值,指示响应是否被允许或拒绝 |
| 消息 | 字符串 | 授权消息(如果访问被拒绝,将返回给客户端) |
| 错误 | 字符串 | 错误消息(如果插件遇到错误,将返回给客户端。提供的字符串值可能会出现在日志中,因此不应包含机密信息) |