访问授权插件

本文档描述了 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 请求时,身份验证子系统会将该请求传递给已安装的身份验证插件。该请求包含用户(调用方)和命令上下文。插件负责决定是否允许或拒绝该请求。

以下序列图展示了允许和拒绝授权的流程:

Authorization Allow flow
Authorization Deny flow

发送到插件的每个请求都包含已认证用户、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)
请求 URIstring包含 API 版本的 HTTP 请求 URI(例如,v.1.17/containers/json)
请求头map[string]string请求头作为键值对(不包含授权头)
请求体[]byte原始请求正文

插件 -> 守护进程

名称类型描述
允许bool布尔值,指示请求是被允许还是被拒绝
消息string授权消息(如果访问被拒绝,将返回给客户端)
错误string错误消息(如果插件遇到错误,将返回给客户端。提供的字符串值可能会出现在日志中,因此不应包含机密信息)

响应授权

该插件必须支持两种授权消息格式:一种从守护进程发送到插件,另一种从插件发送回守护进程。下表详细说明了每条消息中预期的内容。

守护进程 -> 插件

名称类型描述
用户string用户身份识别
认证方式string使用的身份验证方法
请求方法stringHTTP 方法(GET/DELETE/POST)
请求 URIstring包含 API 版本的 HTTP 请求 URI(例如,v.1.17/containers/json)
请求头map[string]string请求头作为键值对(不包含授权头)
请求体[]byte原始请求正文
响应状态码int来自 Docker 守护进程的返回码
响应头map[string]stringResponse headers as key value pairs
响应体[]byte原始 Docker 守护进程响应正文

插件 -> 守护进程

名称类型描述
允许bool布尔值,指示响应是被允许还是被拒绝
消息string授权消息(如果访问被拒绝,将返回给客户端)
错误string错误消息(如果插件遇到错误,将返回给客户端。提供的字符串值可能会出现在日志中,因此不应包含机密信息)