Спецификация аутентификации токена

В этом документе описана схема аутентификации реестра Docker v2:

  1. Попытка начать операцию push/pull с реестром.

  2. Если реестру требуется авторизация, он вернёт HTTP-ответ 401 Unauthorized с информацией о том, как пройти аутентификацию.

  3. Клиент реестра отправляет запрос службе авторизации на токен Bearer.

  4. Служба авторизации возвращает непрозрачный токен носителя, представляющий авторизованный доступ клиента.

  5. Клиент повторяет исходный запрос с маркером носителя, встроенным в заголовок авторизации запроса.

  6. Реестр авторизует клиента, проверяя токен носителя и встроенный в него множество утверждений, и начинает сеанс push/pull, как обычно.

Требования

  • Клиенты реестра, которые могут понимать и отвечать на запросы аутентификации токена, возвращаемые сервером ресурсов.

  • Сервер авторизации, способный управлять контролем доступа к своим ресурсам, размещенным любой данной службой (например, репозиториям в реестре Docker).

  • Реестр Docker, способный доверять серверу авторизации для сигнатуре токенов, которые клиенты могут использовать для авторизации, и возможность проверки данных токенов для однократного использования или для использования в течение достаточно короткого периода времени.

Описания конечных точек сервера авторизации

Описываемый сервер предназначен для использования в качестве автономного диспетчера управления доступом для ресурсов, размещенных другими службами, которые хотят аутентифицировать и управлять авторизацией с помощью отдельного диспетчера управления доступом.

Подобный сервис используется официальным реестром Docker для аутентификации клиентов и проверки их авторизации в репозиториях образов Docker.

Начиная с Docker 1.6 клиент реестра в Docker Engine был обновлен для обработки такого рабочего процесса авторизации.

Как пройти аутентификацию

Клиенты реестра V1 сначала обращаются к индексу, чтобы инициировать отправку или получение. В рабочем процессе Registry V2 клиенты должны сначала связаться с реестром. Если серверу реестра требуется аутентификация, он вернёт ответ 401 Unauthorized с заголовком WWW-Authenticate, в котором подробно приведено, как пройти аутентификацию в этом реестре.

Например, скажем, я (имя пользователя jlhawn) пытаюсь отправить образ в репозиторий samalba/my-app. Чтобы реестр разрешил это, мне потребуется доступ push к репозиторию samalba/my-app. Сначала реестр вернёт данный ответ:

HTTP/1.1 401 Unauthorized
Content-Type: application/json
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"

Данный формат задокументирован в Раздел 3 RFC 6750: Структура авторизации OAuth 2.0: Использование токена носителя

Эта проблема указывает, что реестру требуется токен, выданный указанным сервером токенов, и что запрос, который пытается выполняет клиент, должен включать достаточное количество записей доступа в свой множество утверждений. Чтобы ответить на данный вызов, клиенту потребуется сделать запрос GET к URL-адресу https://auth.docker.io/token, используя значения service и scope из заголовка WWW-Authenticate.

Запрос токена

Определяет получение носителя и токена обновления с помощью конечной точки токена.

Параметры запроса

service

Имя службы, на которой размещается ресурс.

offline_token

Следует ли возвращать токен обновления вместе с токеном носителя. Токен обновления может получать дополнительные токены носителя для одного и того же субъекта с разными областями действия. Токен обновления не имеет срока действия и должен считаться полностью непрозрачным для клиента.

client_id

Строка, идентифицирующая клиента. Данный client_id не нужно регистрировать на сервере авторизации, но ему следует присвоить значимое значение, чтобы разрешить аудит ключей, созданных незарегистрированными клиентами. Принятый синтаксис определён в RFC6749 Приложение A.1.

scope

Рассматриваемый ресурс, отформатированный как одна из записей с разделителями-пробелами из параметров scope из заголовка WWW-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

(Необязательно) Стандартное время UTC в формате RFC 3339, когда был выпущен данный токен. Если issued_at пропущен, истечение срока действия начинается с момента завершения обмена маркерами.

refresh_token

(Необязательно) Токен, который можно использовать для получения дополнительных токенов доступа к тому же субъекту с разными областями. Данный токен должен храниться клиентом в безопасности и отправляться только на сервер авторизации, который выпускает токены-носители. Это поле будет установлено только в том случае, если в запросе указан offline_token=true.

Пример

В этом примере клиент отправляет HTTP-запрос GET на следующий URL-адрес:

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"}

Использование токена Bearer

Как только у клиента появится токен, он снова попытается выполняет запрос реестра с токеном, размещенным в заголовке HTTP Authorization следующим образом:

Authorization: Bearer
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw

Это также приведено в Раздел 2.1 RFC 6750: Структура авторизации OAuth 2.0: Использование токена носителя