令牌认证规范

预计阅读时间:7分钟

通过中央服务进行Docker Registry v2身份验证

本文档概述了v2 Docker注册表身份验证方案:

v2注册表身份验证

  1. 尝试使用注册表开始推/拉操作。
  2. 如果注册表需要授权,它将返回一个401 Unauthorized HTTP响应,其中包含有关如何进行身份验证的信息。
  3. 注册表客户端向授权服务请求一个Bearer令牌。
  4. 授权服务返回一个不透明的Bearer令牌,代表客户的授权访问。
  5. 客户端使用嵌入在请求的Authorization标头中的Bearer令牌重试原始请求。
  6. 注册表通过验证Bearer令牌和嵌入在其中的声明集来授权客户端,并照常开始推/拉会话。

要求

  • 可以理解并响应资源服务器返回的令牌身份验证质询的注册表客户端。
  • 能够管理对任何给定服务(例如Docker Registry中的存储库)托管的资源的访问控制的授权服务器。
  • Docker注册表能够信任授权服务器对令牌进行签名,客户端可以将其用于授权,并且可以验证这些令牌以供单次使用或在足够短的时间内使用。

授权服务器端点说明

所描述的服务器旨在用作由其他服务托管的资源的独立访问控制管理器,这些服务希望使用单独的访问控制管理器来认证和管理授权。

官方Docker Registry使用此类服务​​来对客户端进行身份验证,并验证其对Docker映像存储库的授权。

从Docker 1.6开始,Docker Engine中的注册表客户端已更新为可处理此类授权工作流程。

如何认证

Registry V1客户端首先联系索引以发起推送或拉动。在Registry V2工作流程下,客户端应首先与注册表联系。如果注册表服务器需要身份验证,它将返回401 Unauthorized 带有WWW-Authenticate标头的响应,其中详细说明了如何对此注册表进行身份验证。

例如,假设我(用户名jlhawn)正在尝试将映像推送到存储库samalba/my-app。为了使注册表授权,我将需要 push访问samalba/my-app存储库。注册表将首先返回以下响应:

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"
Date: Thu, 10 Sep 2015 19:32:31 GMT
Content-Length: 235
Strict-Transport-Security: max-age=31536000

{"errors":[{"code":"UNAUTHORIZED","message":"access to the requested resource is not authorized","detail":[{"Type":"repository","Name":"samalba/my-app","Action":"pull"},{"Type":"repository","Name":"samalba/my-app","Action":"push"}]}]}

请注意指示身份验证挑战的HTTP响应标头:

Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"

此格式记录在RFC 6750的第3节:OAuth 2.0授权框架:承载令牌使用中

该挑战表明注册表需要由指定的令牌服务器发行的令牌,并且客户端尝试的请求将需要在其声明集中包含足够的访问条目。为了应对这一挑战,客户端将需要使用标头中的和值 GET对URLhttps://auth.docker.io/token进行请求 。servicescopeWWW-Authenticate

索取令牌

定义获取使用令牌端点的承载和刷新令牌。

查询参数

service
托管资源的服务的名称。
offline_token
是否与承载令牌一起返回刷新令牌。刷新令牌能够为具有不同范围的同一主题获取其他承载令牌。刷新令牌没有到期时间,应被视为对客户端完全不透明。
client_id
标识客户端的字符串。此client_id不需要在授权服务器上注册,但应设置为有意义的值,以允许审核未注册客户端创建的密钥。可接受的语法在[RFC6749附录A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1)中定义。
scope
有问题的资源,其格式设置为上面显示scopeWWW-Authenticate标题中的参数中以空格分隔的条目之一。如果标头中有多个scope条目,则应多次指定此查询参数WWW-Authenticate。上面的示例将指定为:scope=repository:samalba/my-app:push。作用域字段可以为空,以请求刷新令牌,而无需为返回的承载令牌提供任何资源许可。

令牌响应字段

token
Bearer客户端应向Authorization标头中的后续请求提供的不透明令牌。
access_token
为了与OAuth 2.0兼容,我们还将token在名称下接受access_token必须至少指定这些字段之一,但也可能同时出现(与旧客户端兼容)。当两者都被指定时,它们应该是等效的。如果它们不同,则客户的选择是不确定的。
expires_in
(可选)自颁发令牌以来,保持有效的时间(以秒为单位)。如果省略,则默认为60秒。为了与较旧的客户端兼容,令牌返回的时间不得少于60秒。
issued_at
(可选)发出给定令牌的RFC3339序列化的UTC标准时间。如果issued_at省略,则到期时间为令牌交换完成之时。
refresh_token
(可选)令牌,可用于为具有不同范围的同一主题获取其他访问令牌。该令牌应由客户端保持安全,并仅发送给颁发承载令牌的授权服务器。仅当在请求中提供`offline_token = true`时,才设置此字段。

例子

对于此示例,客户端向以下URL发出HTTP GET请求:

https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push

令牌服务器应该首先尝试使用随请求提供的任何身份验证凭据对客户端进行身份验证。从Docker 1.11开始,Docker引擎同时支持基本身份验证和OAuth2以获取令牌。在Docker 1.10及更低版本中,Docker Engine中的注册表客户端仅支持基本身份验证。如果尝试对令牌服务器进行身份验证失败,则令牌服务器应返回一个401 Unauthorized响应,指示提供的凭据无效。

令牌服务器是否需要身份验证取决于该访问控制提供者的策略。有些请求可能需要身份验证才能确定访问权限(例如,推送或拉出私有存储库),而其他请求则可能不需要身份验证(例如,从公共存储库中拉出)。

在对客户端进行身份验证之后(如果未尝试进行身份验证,则可能只是匿名客户端),令牌服务器必须接下来查询其访问控制列表,以确定该客户端是否具有所请求的范围。在此示例请求中,如果我已通过身份验证为用户jlhawn,则令牌服务器将确定我samalba/my-app 对实体托管的存储库具有什么访问权限registry.docker.io

令牌服务器确定了客户端对scope参数中请求的资源的访问权限后,它将采用对每个资源的请求操作集与实际上已被授予客户端的操作集的交集。如果客户端仅具有请求的访问权限的子集,则不得将其视为错误,因为令牌授权服务器不负责在此工作流中指示授权错误。

继续执行示例请求,令牌服务器将发现客户端对存储库的授予访问权限集是[pull, push]与请求的访问权限相交时[pull, push]产生的一组相等的访问权限。如果仅找到授予的访问集,[pull]则相交的集将仅为[pull]。如果客户端无权访问存储库,则相交的集合将为空[]

正是这个相交的访问集被放置在返回的令牌中。

然后,服务器使用此相交的访问集构造特定于实现的令牌,并将其返回给Docker客户端以用于对受众服务进行身份验证(在指定的时间范围内):

HTTP/1.1 200 OK
Content-Type: application/json

{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w", "expires_in": 3600,"issued_at": "2009-11-10T23:00:00Z"}

使用无记名令牌

客户端获得令牌后,它将使用令牌放在HTTPAuthorization标头中的方式再次尝试注册请求,如下所示:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw

RFC 6750的第2.1节:OAuth 2.0授权框架:承载令牌使用也对此进行了描述。

注册表本地图像标签存储库分发承载认证高级