Pull distribution reference docs from upstream

This commit is contained in:
Misty Stanley-Jones 2016-11-28 13:11:19 -08:00
parent 0060344386
commit 82eb4bc302
12 changed files with 0 additions and 8821 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,10 +0,0 @@
---
description: Docker Registry v2 authentication schema
keywords: registry, on-prem, images, tags, repository, distribution, authentication, advanced
title: Docker Registry v2 authentication
---
See the [Token Authentication Specification](token.md),
[Token Authentication Implementation](jwt.md),
[Token Scope Documentation](scope.md),
[OAuth2 Token Authentication](oauth.md) for more information.

View file

@ -1,327 +0,0 @@
---
description: Describe the reference implementation of the Docker Registry v2 authentication schema
keywords: registry, on-prem, images, tags, repository, distribution, JWT authentication, advanced
title: Docker Registry v2 Bearer token specification
---
This specification covers the `docker/distribution` implementation of the
v2 Registry's authentication schema. Specifically, it describes the JSON
Web Token schema that `docker/distribution` has adopted to implement the
client-opaque Bearer token issued by an authentication service and
understood by the registry.
This document borrows heavily from the [JSON Web Token Draft Spec](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32)
## Getting a Bearer Token
For this example, the client makes an HTTP GET request to the following URL:
```
https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push
```
The token server should first attempt to authenticate the client using any
authentication credentials provided with the request. As of Docker 1.8, the
registry client in the Docker Engine only supports Basic Authentication to
these token servers. If an attempt to authenticate to the token server fails,
the token server should return a `401 Unauthorized` response indicating that
the provided credentials are invalid.
Whether the token server requires authentication is up to the policy of that
access control provider. Some requests may require authentication to determine
access (such as pushing or pulling a private repository) while others may not
(such as pulling from a public repository).
After authenticating the client (which may simply be an anonymous client if
no attempt was made to authenticate), the token server must next query its
access control list to determine whether the client has the requested scope. In
this example request, if I have authenticated as user `jlhawn`, the token
server will determine what access I have to the repository `samalba/my-app`
hosted by the entity `registry.docker.io`.
Once the token server has determined what access the client has to the
resources requested in the `scope` parameter, it will take the intersection of
the set of requested actions on each resource and the set of actions that the
client has in fact been granted. If the client only has a subset of the
requested access **it must not be considered an error** as it is not the
responsibility of the token server to indicate authorization errors as part of
this workflow.
Continuing with the example request, the token server will find that the
client's set of granted access to the repository is `[pull, push]` which when
intersected with the requested access `[pull, push]` yields an equal set. If
the granted access set was found only to be `[pull]` then the intersected set
would only be `[pull]`. If the client has no access to the repository then the
intersected set would be empty, `[]`.
It is this intersected set of access which is placed in the returned token.
The server will now construct a JSON Web Token to sign and return. A JSON Web
Token has 3 main parts:
1. Headers
The header of a JSON Web Token is a standard JOSE header. The "typ" field
will be "JWT" and it will also contain the "alg" which identifies the
signing algorithm used to produce the signature. It also must have a "kid"
field, representing the ID of the key which was used to sign the token.
The "kid" field has to be in a libtrust fingerprint compatible format.
Such a format can be generated by following steps:
1. Take the DER encoded public key which the JWT token was signed against.
2. Create a SHA256 hash out of it and truncate to 240bits.
3. Split the result into 12 base32 encoded groups with `:` as delimiter.
Here is an example JOSE Header for a JSON Web Token (formatted with
whitespace for readability):
```
{
"typ": "JWT",
"alg": "ES256",
"kid": "PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6"
}
```
It specifies that this object is going to be a JSON Web token signed using
the key with the given ID using the Elliptic Curve signature algorithm
using a SHA256 hash.
2. Claim Set
The Claim Set is a JSON struct containing these standard registered claim
name fields:
<dl>
<dt>
<code>iss</code> (Issuer)
</dt>
<dd>
The issuer of the token, typically the fqdn of the authorization
server.
</dd>
<dt>
<code>sub</code> (Subject)
</dt>
<dd>
The subject of the token; the name or id of the client which
requested it. This should be empty (`""`) if the client did not
authenticate.
</dd>
<dt>
<code>aud</code> (Audience)
</dt>
<dd>
The intended audience of the token; the name or id of the service
which will verify the token to authorize the client/subject.
</dd>
<dt>
<code>exp</code> (Expiration)
</dt>
<dd>
The token should only be considered valid up to this specified date
and time.
</dd>
<dt>
<code>nbf</code> (Not Before)
</dt>
<dd>
The token should not be considered valid before this specified date
and time.
</dd>
<dt>
<code>iat</code> (Issued At)
</dt>
<dd>
Specifies the date and time which the Authorization server
generated this token.
</dd>
<dt>
<code>jti</code> (JWT ID)
</dt>
<dd>
A unique identifier for this token. Can be used by the intended
audience to prevent replays of the token.
</dd>
</dl>
The Claim Set will also contain a private claim name unique to this
authorization server specification:
<dl>
<dt>
<code>access</code>
</dt>
<dd>
An array of access entry objects with the following fields:
<dl>
<dt>
<code>type</code>
</dt>
<dd>
The type of resource hosted by the service.
</dd>
<dt>
<code>name</code>
</dt>
<dd>
The name of the resource of the given type hosted by the
service.
</dd>
<dt>
<code>actions</code>
</dt>
<dd>
An array of strings which give the actions authorized on
this resource.
</dd>
</dl>
</dd>
</dl>
Here is an example of such a JWT Claim Set (formatted with whitespace for
readability):
```
{
"iss": "auth.docker.com",
"sub": "jlhawn",
"aud": "registry.docker.com",
"exp": 1415387315,
"nbf": 1415387015,
"iat": 1415387015,
"jti": "tYJCO1c6cnyy7kAn0c7rKPgbV1H1bFws",
"access": [
{
"type": "repository",
"name": "samalba/my-app",
"actions": [
"pull",
"push"
]
}
]
}
```
3. Signature
The authorization server will produce a JOSE header and Claim Set with no
extraneous whitespace, i.e., the JOSE Header from above would be
```
{"typ":"JWT","alg":"ES256","kid":"PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6"}
```
and the Claim Set from above would be
```
{"iss":"auth.docker.com","sub":"jlhawn","aud":"registry.docker.com","exp":1415387315,"nbf":1415387015,"iat":1415387015,"jti":"tYJCO1c6cnyy7kAn0c7rKPgbV1H1bFws","access":[{"type":"repository","name":"samalba/my-app","actions":["push","pull"]}]}
```
The utf-8 representation of this JOSE header and Claim Set are then
url-safe base64 encoded (sans trailing '=' buffer), producing:
```
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0
```
for the JOSE Header and
```
eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0
```
for the Claim Set. These two are concatenated using a '.' character,
yielding the string:
```
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0
```
This is then used as the payload to a the `ES256` signature algorithm
specified in the JOSE header and specified fully in [Section 3.4 of the JSON Web Algorithms (JWA)
draft specification](https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-38#section-3.4)
This example signature will use the following ECDSA key for the server:
```
{
"kty": "EC",
"crv": "P-256",
"kid": "PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6",
"d": "R7OnbfMaD5J2jl7GeE8ESo7CnHSBm_1N2k9IXYFrKJA",
"x": "m7zUpx3b-zmVE5cymSs64POG9QcyEpJaYCD82-549_Q",
"y": "dU3biz8sZ_8GPB-odm8Wxz3lNDr1xcAQQPQaOcr1fmc"
}
```
A resulting signature of the above payload using this key is:
```
QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w
```
Concatenating all of these together with a `.` character gives the
resulting JWT:
```
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w
```
This can now be placed in an HTTP response and returned to the client to use to
authenticate to the audience service:
```
HTTP/1.1 200 OK
Content-Type: application/json
{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w"}
```
## Using the signed token
Once the client has a token, it will try the registry request again with the
token placed in the HTTP `Authorization` header like so:
```
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw
```
This is also described in [Section 2.1 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-2.1)
## Verifying the token
The registry must now verify the token presented by the user by inspecting the
claim set within. The registry will:
- Ensure that the issuer (`iss` claim) is an authority it trusts.
- Ensure that the registry identifies as the audience (`aud` claim).
- Check that the current time is between the `nbf` and `exp` claim times.
- If enforcing single-use tokens, check that the JWT ID (`jti` claim) value has
not been seen before.
- To enforce this, the registry may keep a record of `jti`s it has seen for
up to the `exp` time of the token to prevent token replays.
- Check the `access` claim value and use the identified resources and the list
of actions authorized to determine whether the token grants the required
level of access for the operation the client is attempting to perform.
- Verify that the signature of the token is valid.
If any of these requirements are not met, the registry will return a
`403 Forbidden` response to indicate that the token is invalid.
**Note**: it is only at this point in the workflow that an authorization error
may occur. The token server should *not* return errors when the user does not
have the requested authorization. Instead, the returned token should indicate
whatever of the requested scope the client does have (the intersection of
requested and granted access). If the token does not supply proper
authorization then the registry will return the appropriate error.
At no point in this process should the registry need to call back to the
authorization server. The registry only needs to be supplied with the trusted
public keys to verify the token signatures.

View file

@ -1,183 +0,0 @@
---
description: Specifies the Docker Registry v2 authentication
keywords: registry, on-prem, images, tags, repository, distribution, oauth2, advanced
title: Docker Registry v2 authentication using OAuth2
---
This document describes support for the OAuth2 protocol within the authorization
server. [RFC6749](https://tools.ietf.org/html/rfc6749) should be used as a
reference for the protocol and HTTP endpoints described here.
## Refresh token format
The format of the refresh token is completely opaque to the client and should be
determined by the authorization server. The authorization should ensure the
token is sufficiently long and is responsible for storing any information about
long-lived tokens which may be needed for revoking. Any information stored
inside the token will not be extracted and presented by clients.
## Getting a token
POST /token
#### Headers
Content-Type: application/x-www-form-urlencoded
#### Post parameters
<dl>
<dt>
<code>grant_type</code>
</dt>
<dd>
(REQUIRED) Type of grant used to get token. When getting a refresh token
using credentials this type should be set to "password" and have the
accompanying username and password paramters. Type "authorization_code"
is reserved for future use for authenticating to an authorization server
without having to send credentials directly from the client. When
requesting an access token with a refresh token this should be set to
"refresh_token".
</dd>
<dt>
<code>service</code>
</dt>
<dd>
(REQUIRED) The name of the service which hosts the resource to get
access for. Refresh tokens will only be good for getting tokens for
this service.
</dd>
<dt>
<code>client_id</code>
</dt>
<dd>
(REQUIRED) String identifying the client. This client_id does not need
to be registered with the authorization server but should be set to a
meaningful value in order to allow auditing keys created by unregistered
clients. Accepted syntax is defined in
[RFC6749 Appendix A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1)
</dd>
<dt>
<code>access_type</code>
</dt>
<dd>
(OPTIONAL) Access which is being requested. If "offline" is provided
then a refresh token will be returned. The default is "online" only
returning short lived access token. If the grant type is "refresh_token"
this will only return the same refresh token and not a new one.
</dd>
<dt>
<code>scope</code>
</dt>
<dd>
(OPTIONAL) The resource in question, formatted as one of the space-delimited
entries from the <code>scope</code> parameters from the <code>WWW-Authenticate</code> header
shown above. This query parameter should only be specified once but may
contain multiple scopes using the scope list format defined in the scope
grammar. If multiple <code>scope</code> is provided from
<code>WWW-Authenticate</code> header the scopes should first be
converted to a scope list before requesting the token. The above example
would be specified as: <code>scope=repository:samalba/my-app:push</code>.
When requesting a refresh token the scopes may be empty since the
refresh token will not be limited by this scope, only the provided short
lived access token will have the scope limitation.
</dd>
<dt>
<code>refresh_token</code>
</dt>
<dd>
(OPTIONAL) The refresh token to use for authentication when grant type "refresh_token" is used.
</dd>
<dt>
<code>username</code>
</dt>
<dd>
(OPTIONAL) The username to use for authentication when grant type "password" is used.
</dd>
<dt>
<code>password</code>
</dt>
<dd>
(OPTIONAL) The password to use for authentication when grant type "password" is used.
</dd>
</dl>
#### Response fields
<dl>
<dt>
<code>access_token</code>
</dt>
<dd>
(REQUIRED) An opaque <code>Bearer</code> token that clients should
supply to subsequent requests in the <code>Authorization</code> header.
This token should not be attempted to be parsed or understood by the
client but treated as opaque string.
</dd>
<dt>
<code>scope</code>
</dt>
<dd>
(REQUIRED) The scope granted inside the access token. This may be the
same scope as requested or a subset. This requirement is stronger than
specified in [RFC6749 Section 4.2.2](https://tools.ietf.org/html/rfc6749#section-4.2.2)
by strictly requiring the scope in the return value.
</dd>
<dt>
<code>expires_in</code>
</dt>
<dd>
(REQUIRED) The duration in seconds since the token was issued that it
will remain valid. When omitted, this defaults to 60 seconds. For
compatibility with older clients, a token should never be returned with
less than 60 seconds to live.
</dd>
<dt>
<code>issued_at</code>
</dt>
<dd>
(Optional) The <a href="https://www.ietf.org/rfc/rfc3339.txt">RFC3339</a>-serialized UTC
standard time at which a given token was issued. If <code>issued_at</code> is omitted, the
expiration is from when the token exchange completed.
</dd>
<dt>
<code>refresh_token</code>
</dt>
<dd>
(Optional) Token which can be used to get additional access tokens for
the same subject with different scopes. This token should be kept secure
by the client and only sent to the authorization server which issues
bearer tokens. This field will only be set when `access_type=offline` is
provided in the request.
</dd>
</dl>
#### Example getting refresh token
```
POST /token HTTP/1.1
Host: auth.docker.io
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w&service=hub.docker.io&client_id=dockerengine&access_type=offline
HTTP/1.1 200 OK
Content-Type: application/json
{"refresh_token":"kas9Da81Dfa8","access_token":"eyJhbGciOiJFUzI1NiIsInR5","expires_in":900,"scope":""}
```
#### Example refreshing an Access Token
```
POST /token HTTP/1.1
Host: auth.docker.io
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=kas9Da81Dfa8&service=registry-1.docker.io&client_id=dockerengine&scope=repository:samalba/my-app:pull,push
HTTP/1.1 200 OK
Content-Type: application/json
{"refresh_token":"kas9Da81Dfa8","access_token":"eyJhbGciOiJFUzI1NiIsInR5":"expires_in":900,"scope":"repository:samalba/my-app:pull,repository:samalba/my-app:push"}
```

View file

@ -1,135 +0,0 @@
---
description: Describes the scope and access fields used for registry authorization tokens
keywords: registry, on-prem, images, tags, repository, distribution, advanced, access, scope
title: Docker Registry token scope and access
---
Tokens used by the registry are always restricted what resources they may
be used to access, where those resources may be accessed, and what actions
may be done on those resources. Tokens always have the context of a user which
the token was originally created for. This document describes how these
restrictions are represented and enforced by the authorization server and
resource providers.
## Scope Components
### Subject (Authenticated User)
The subject represents the user for which a token is valid. Any actions
performed using an access token should be considered on behalf of the subject.
This is included in the `sub` field of access token JWT. A refresh token should
be limited to a single subject and only be able to give out access tokens for
that subject.
### Audience (Resource Provider)
The audience represents a resource provider which is intended to be able to
perform the actions specified in the access token. Any resource provider which
does not match the audience should not use that access token. The audience is
included in the `aud` field of the access token JWT. A refresh token should be
limited to a single audience and only be able to give out access tokens for that
audience.
### Resource Type
The resource type represents the type of resource which the resource name is
intended to represent. This type may be specific to a resource provider but must
be understood by the authorization server in order to validate the subject
is authorized for a specific resource.
#### Example Resource Types
- `repository` - represents a single repository within a registry. A
repository may represent many manifest or content blobs, but the resource type
is considered the collections of those items. Actions which may be performed on
a `repository` are `pull` for accessing the collection and `push` for adding to
it.
### Resource Name
The resource name represent the name which identifies a resource for a resource
provider. A resource is identified by this name and the provided resource type.
An example of a resource name would be the name component of an image tag, such
as "samalba/myapp" or "hostname/samalba/myapp".
### Resource Actions
The resource actions define the actions which the access token allows to be
performed on the identified resource. These actions are type specific but will
normally have actions identifying read and write access on the resource. Example
for the `repository` type are `pull` for read access and `push` for write
access.
## Authorization Server Use
Each access token request may include a scope and an audience. The subject is
always derived from the passed in credentials or refresh token. When using
a refresh token the passed in audience must match the audience defined for
the refresh token. The audience (resource provider) is provided using the
`service` field. Multiple resource scopes may be provided using multiple `scope`
fields on the `GET` request. The `POST` request only takes in a single
`scope` field but may use a space to separate a list of multiple resource
scopes.
### Resource Scope Grammar
```
scope := resourcescope [ ' ' resourcescope ]*
resourcescope := resourcetype ":" resourcename ":" action [ ',' action ]*
resourcetype := /[a-z]*/
resourcename := [ hostname '/' ] component [ '/' component ]*
hostname := hostcomponent ['.' hostcomponent]* [':' port-number]
hostcomponent := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
port-number := /[0-9]+/
action := /[a-z]*/
component := alpha-numeric [ separator alpha-numeric ]*
alpha-numeric := /[a-z0-9]+/
separator := /[_.]|__|[-]*/
```
Full reference grammar is defined
[here](https://godoc.org/github.com/docker/distribution/reference). Currently
the scope name grammar is a subset of the reference grammar.
> **NOTE:** that the `resourcename` may contain one `:` due to a possible port
> number in the hostname component of the `resourcename`, so a naive
> implementation that interprets the first three `:`-delimited tokens of a
> `scope` to be the `resourcetype`, `resourcename`, and a list of `action`
> would be insufficient.
## Resource Provider Use
Once a resource provider has verified the authenticity of the scope through
JWT access token verification, the resource provider must ensure that scope
satisfies the request. The resource provider should match the given audience
according to name or URI the resource provider uses to identify itself. Any
denial based on subject is not defined here and is up to resource provider, the
subject is mainly provided for audit logs and any other user-specific rules
which may need to be provided but are not defined by the authorization server.
The resource provider must ensure that ANY resource being accessed as the
result of a request has the appropriate access scope. Both the resource type
and resource name must match the accessed resource and an appropriate action
scope must be included.
When appropriate authorization is not provided either due to lack of scope
or missing token, the resource provider to return a `WWW-AUTHENTICATE` HTTP
header with the `realm` as the authorization server, the `service` as the
expected audience identifying string, and a `scope` field for each required
resource scope to complete the request.
## JWT Access Tokens
Each JWT access token may only have a single subject and audience but multiple
resource scopes. The subject and audience are put into standard JWT fields
`sub` and `aud`. The resource scope is put into the `access` field. The
structure of the access field can be seen in the
[jwt documentation](jwt.md).
## Refresh Tokens
A refresh token must be defined for a single subject and audience. Further
restricting scope to specific type, name, and actions combinations should be
done by fetching an access token using the refresh token. Since the refresh
token is not scoped to specific resources for an audience, extra care should
be taken to only use the refresh token to negotiate new access tokens directly
with the authorization server, and never with a resource provider.

View file

@ -1,250 +0,0 @@
---
description: Specifies the Docker Registry v2 authentication
keywords: registry, on-prem, images, tags, repository, distribution, Bearer authentication, advanced
title: Docker Registry v2 authentication via central service
---
This document outlines the v2 Docker registry authentication scheme:
![v2 registry auth](../../images/v2-registry-auth.png)
1. Attempt to begin a push/pull operation with the registry.
2. If the registry requires authorization it will return a `401 Unauthorized`
HTTP response with information on how to authenticate.
3. The registry client makes a request to the authorization service for a
Bearer token.
4. The authorization service returns an opaque Bearer token representing the
client's authorized access.
5. The client retries the original request with the Bearer token embedded in
the request's Authorization header.
6. The Registry authorizes the client by validating the Bearer token and the
claim set embedded within it and begins the push/pull session as usual.
## Requirements
- Registry clients which can understand and respond to token auth challenges
returned by the resource server.
- An authorization server capable of managing access controls to their
resources hosted by any given service (such as repositories in a Docker
Registry).
- A Docker Registry capable of trusting the authorization server to sign tokens
which clients can use for authorization and the ability to verify these
tokens for single use or for use during a sufficiently short period of time.
## Authorization Server Endpoint Descriptions
The described server is meant to serve as a standalone access control manager
for resources hosted by other services which wish to authenticate and manage
authorizations using a separate access control manager.
A service like this is used by the official Docker Registry to authenticate
clients and verify their authorization to Docker image repositories.
As of Docker 1.6, the registry client within the Docker Engine has been updated
to handle such an authorization workflow.
## How to authenticate
Registry V1 clients first contact the index to initiate a push or pull. Under
the Registry V2 workflow, clients should contact the registry first. If the
registry server requires authentication it will return a `401 Unauthorized`
response with a `WWW-Authenticate` header detailing how to authenticate to this
registry.
For example, say I (username `jlhawn`) am attempting to push an image to the
repository `samalba/my-app`. For the registry to authorize this, I will need
`push` access to the `samalba/my-app` repository. The registry will first
return this response:
```
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"}]}]}
```
Note the HTTP Response Header indicating the auth challenge:
```
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"
```
This format is documented in [Section 3 of RFC 6750: The OAuth 2.0 Authorization
Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-3)
This challenge indicates that the registry requires a token issued by the
specified token server and that the request the client is attempting will
need to include sufficient access entries in its claim set. To respond to this
challenge, the client will need to make a `GET` request to the URL
`https://auth.docker.io/token` using the `service` and `scope` values from the
`WWW-Authenticate` header.
## Requesting a Token
Defines getting a bearer and refresh token using the token endpoint.
#### Query Parameters
<dl>
<dt>
<code>service</code>
</dt>
<dd>
The name of the service which hosts the resource.
</dd>
<dt>
<code>offline_token</code>
</dt>
<dd>
Whether to return a refresh token along with the bearer token. A refresh
token is capable of getting additional bearer tokens for the same
subject with different scopes. The refresh token does not have an
expiration and should be considered completely opaque to the client.
</dd>
<dt>
<code>client_id</code>
</dt>
<dd>
String identifying the client. This client_id does not need
to be registered with the authorization server but should be set to a
meaningful value in order to allow auditing keys created by unregistered
clients. Accepted syntax is defined in
[RFC6749 Appendix A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1).
</dd>
<dt>
<code>scope</code>
</dt>
<dd>
The resource in question, formatted as one of the space-delimited
entries from the <code>scope</code> parameters from the <code>WWW-Authenticate</code> header
shown above. This query parameter should be specified multiple times if
there is more than one <code>scope</code> entry from the <code>WWW-Authenticate</code>
header. The above example would be specified as:
<code>scope=repository:samalba/my-app:push</code>. The scope field may
be empty to request a refresh token without providing any resource
permissions to the returned bearer token.
</dd>
</dl>
#### Token Response Fields
<dl>
<dt>
<code>token</code>
</dt>
<dd>
An opaque <code>Bearer</code> token that clients should supply to subsequent
requests in the <code>Authorization</code> header.
</dd>
<dt>
<code>access_token</code>
</dt>
<dd>
For compatibility with OAuth 2.0, we will also accept <code>token</code> under the name
<code>access_token</code>. At least one of these fields <b>must</b> be specified, but
both may also appear (for compatibility with older clients). When both are specified,
they should be equivalent; if they differ the client's choice is undefined.
</dd>
<dt>
<code>expires_in</code>
</dt>
<dd>
(Optional) The duration in seconds since the token was issued that it
will remain valid. When omitted, this defaults to 60 seconds. For
compatibility with older clients, a token should never be returned with
less than 60 seconds to live.
</dd>
<dt>
<code>issued_at</code>
</dt>
<dd>
(Optional) The <a href="https://www.ietf.org/rfc/rfc3339.txt">RFC3339</a>-serialized UTC
standard time at which a given token was issued. If <code>issued_at</code> is omitted, the
expiration is from when the token exchange completed.
</dd>
<dt>
<code>refresh_token</code>
</dt>
<dd>
(Optional) Token which can be used to get additional access tokens for
the same subject with different scopes. This token should be kept secure
by the client and only sent to the authorization server which issues
bearer tokens. This field will only be set when `offline_token=true` is
provided in the request.
</dd>
</dl>
#### Example
For this example, the client makes an HTTP GET request to the following URL:
```
https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push
```
The token server should first attempt to authenticate the client using any
authentication credentials provided with the request. From Docker 1.11 the
Docker engine supports both Basic Authentication and [OAuth2](oauth.md) for
getting tokens. Docker 1.10 and before, the registry client in the Docker Engine
only supports Basic Authentication. If an attempt to authenticate to the token
server fails, the token server should return a `401 Unauthorized` response
indicating that the provided credentials are invalid.
Whether the token server requires authentication is up to the policy of that
access control provider. Some requests may require authentication to determine
access (such as pushing or pulling a private repository) while others may not
(such as pulling from a public repository).
After authenticating the client (which may simply be an anonymous client if
no attempt was made to authenticate), the token server must next query its
access control list to determine whether the client has the requested scope. In
this example request, if I have authenticated as user `jlhawn`, the token
server will determine what access I have to the repository `samalba/my-app`
hosted by the entity `registry.docker.io`.
Once the token server has determined what access the client has to the
resources requested in the `scope` parameter, it will take the intersection of
the set of requested actions on each resource and the set of actions that the
client has in fact been granted. If the client only has a subset of the
requested access **it must not be considered an error** as it is not the
responsibility of the token server to indicate authorization errors as part of
this workflow.
Continuing with the example request, the token server will find that the
client's set of granted access to the repository is `[pull, push]` which when
intersected with the requested access `[pull, push]` yields an equal set. If
the granted access set was found only to be `[pull]` then the intersected set
would only be `[pull]`. If the client has no access to the repository then the
intersected set would be empty, `[]`.
It is this intersected set of access which is placed in the returned token.
The server then constructs an implementation-specific token with this
intersected set of access, and returns it to the Docker client to use to
authenticate to the audience service (within the indicated window of time):
```
HTTP/1.1 200 OK
Content-Type: application/json
{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w", "expires_in": 3600,"issued_at": "2009-11-10T23:00:00Z"}
```
## Using the Bearer token
Once the client has a token, it will try the registry request again with the
token placed in the HTTP `Authorization` header like so:
```
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw
```
This is also described in [Section 2.1 of RFC 6750: The OAuth 2.0 Authorization
Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-2.1)

View file

@ -1,30 +0,0 @@
---
published: false
---
# Distribution API Implementations
This is a list of known implementations of the Distribution API spec.
## [Docker Distribution Registry](https://github.com/docker/distribution)
Docker distribution is the reference implementation of the distribution API
specification. It aims to fully implement the entire specification.
### Releases
#### 2.0.1 (_in development_)
Implements API 2.0.1
_Known Issues_
- No resumable push support
- Content ranges ignored
- Blob upload status will always return a starting range of 0
#### 2.0.0
Implements API 2.0.0
_Known Issues_
- No resumable push support
- No PATCH implementation for blob upload
- Content ranges ignored

View file

@ -1,10 +0,0 @@
---
description: Explains registry JSON objects
keywords: registry, service, images, repository, json
title: Docker Registry Reference
---
* [HTTP API V2](api.md)
* [Storage Driver](../storage-drivers/index.md)
* [Token Authentication Specification](auth/token.md)
* [Token Authentication Implementation](auth/jwt.md)

View file

@ -1,86 +0,0 @@
---
description: Explains registry JSON objects
keywords: registry, service, images, repository, json
published: false
title: Docker Distribution JSON canonicalization
---
To provide consistent content hashing of JSON objects throughout Docker
Distribution APIs, the specification defines a canonical JSON format. Adopting
such a canonicalization also aids in caching JSON responses.
Note that protocols should not be designed to depend on identical JSON being
generated across different versions or clients. The canonicalization rules are
merely useful for caching and consistency.
## Rules
Compliant JSON should conform to the following rules:
1. All generated JSON should comply with [RFC
7159](http://www.ietf.org/rfc/rfc7159.txt).
2. Resulting "JSON text" shall always be encoded in UTF-8.
3. Unless a canonical key order is defined for a particular schema, object
keys shall always appear in lexically sorted order.
4. All whitespace between tokens should be removed.
5. No "trailing commas" are allowed in object or array definitions.
6. The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e".
Ampersand "&" is escaped to "\u0026".
## Examples
The following is a simple example of a canonicalized JSON string:
```json
{"asdf":1,"qwer":[],"zxcv":[{},true,1000000000,"tyui"]}
```
## Reference
### Other Canonicalizations
The OLPC project specifies [Canonical
JSON](http://wiki.laptop.org/go/Canonical_JSON). While this is used in
[TUF](http://theupdateframework.com/), which may be used with other
distribution-related protocols, this alternative format has been proposed in
case the original source changes. Specifications complying with either this
specification or an alternative should explicitly call out the
canonicalization format. Except for key ordering, this specification is mostly
compatible.
### Go
In Go, the [`encoding/json`](http://golang.org/pkg/encoding/json/) library
will emit canonical JSON by default. Simply using `json.Marshal` will suffice
in most cases:
```go
incoming := map[string]interface{}{
"asdf": 1,
"qwer": []interface{}{},
"zxcv": []interface{}{
map[string]interface{}{},
true,
int(1e9),
"tyui",
},
}
canonical, err := json.Marshal(incoming)
if err != nil {
// ... handle error
}
```
To apply canonical JSON format spacing to an existing serialized JSON buffer, one
can use
[`json.Indent`](http://golang.org/src/encoding/json/indent.go?s=1918:1989#L65)
with the following arguments:
```go
incoming := getBytes()
var canonical bytes.Buffer
if err := json.Indent(&canonical, incoming, "", ""); err != nil {
// ... handle error
}
```

View file

@ -1,161 +0,0 @@
---
description: image manifest for the Registry.
keywords: registry, on-prem, images, tags, repository, distribution, api, advanced, manifest
title: Image manifest V2, schema 1
---
This document outlines the format of of the V2 image manifest. The image
manifest described herein was introduced in the Docker daemon in the [v1.3.0
release](https://github.com/docker/docker/commit/9f482a66ab37ec396ac61ed0c00d59122ac07453).
It is a provisional manifest to provide a compatibility with the [V1 Image
format](https://github.com/docker/docker/blob/master/image/spec/v1.md), as the
requirements are defined for the [V2 Schema 2
image](https://github.com/docker/distribution/pull/62).
Image manifests describe the various constituents of a docker image. Image
manifests can be serialized to JSON format with the following media types:
Manifest Type | Media Type
------------- | -------------
manifest | "application/vnd.docker.distribution.manifest.v1+json"
signed manifest | "application/vnd.docker.distribution.manifest.v1+prettyjws"
*Note that "application/json" will also be accepted for schema 1.*
References:
- [Proposal: JSON Registry API V2.1](https://github.com/docker/docker/issues/9015)
- [Proposal: Provenance step 1 - Transform images for validation and verification](https://github.com/docker/docker/issues/8093)
## *Manifest* Field Descriptions
Manifest provides the base accessible fields for working with V2 image format
in the registry.
- **`name`** *string*
name is the name of the image's repository
- **`tag`** *string*
tag is the tag of the image
- **`architecture`** *string*
architecture is the host architecture on which this image is intended to
run. This is for information purposes and not currently used by the engine
- **`fsLayers`** *array*
fsLayers is a list of filesystem layer blob sums contained in this image.
An fsLayer is a struct consisting of the following fields
- **`blobSum`** *digest.Digest*
blobSum is the digest of the referenced filesystem image layer. A
digest must be a sha256 hash.
- **`history`** *array*
history is a list of unstructured historical data for v1 compatibility. It
contains ID of the image layer and ID of the layer's parent layers.
history is a struct consisting of the following fields
- **`v1Compatibility`** string
V1Compatibility is the raw V1 compatibility information. This will
contain the JSON object describing the V1 of this image.
- **`schemaVersion`** *int*
SchemaVersion is the image manifest schema that this image follows.
>**Note**:the length of `history` must be equal to the length of `fsLayers` and
>entries in each are correlated by index.
## Signed Manifests
Signed manifests provides an envelope for a signed image manifest. A signed
manifest consists of an image manifest along with an additional field
containing the signature of the manifest.
The docker client can verify signed manifests and displays a message to the user.
### Signing Manifests
Image manifests can be signed in two different ways: with a *libtrust* private
key or an x509 certificate chain. When signing with an x509 certificate chain,
the public key of the first element in the chain must be the public key
corresponding with the sign key.
### Signed Manifest Field Description
Signed manifests include an image manifest and a list of signatures generated
by *libtrust*. A signature consists of the following fields:
- **`header`** *[JOSE](http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2)*
A [JSON Web Signature](http://self-issued.info/docs/draft-ietf-jose-json-web-signature.html)
- **`signature`** *string*
A signature for the image manifest, signed by a *libtrust* private key
- **`protected`** *string*
The signed protected header
## Example Manifest
*Example showing the official 'hello-world' image manifest.*
```
{
"name": "hello-world",
"tag": "latest",
"architecture": "amd64",
"fsLayers": [
{
"blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
},
{
"blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
},
{
"blobSum": "sha256:cc8567d70002e957612902a8e985ea129d831ebe04057d88fb644857caa45d11"
},
{
"blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
}
],
"history": [
{
"v1Compatibility": "{\"id\":\"e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0991335f4a11e5c5\",\"parent\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"created\":\"2014-12-31T22:57:59.178729048Z\",\"container\":\"27b45f8fb11795b52e9605b686159729b0d9ca92f76d40fb4f05a62e19c46b4f\",\"container_config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [/hello]\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"docker_version\":\"1.4.1\",\"config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/hello\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
},
{
"v1Compatibility": "{\"id\":\"e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0991335f4a11e5c5\",\"parent\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"created\":\"2014-12-31T22:57:59.178729048Z\",\"container\":\"27b45f8fb11795b52e9605b686159729b0d9ca92f76d40fb4f05a62e19c46b4f\",\"container_config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [/hello]\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"docker_version\":\"1.4.1\",\"config\":{\"Hostname\":\"8ce6509d66e2\",\"Domainname\":\"\",\"User\":\"\",\"Memory\":0,\"MemorySwap\":0,\"CpuShares\":0,\"Cpuset\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/hello\"],\"Image\":\"31cbccb51277105ba3ae35ce33c22b69c9e3f1002e76e4c736a2e8ebff9d7b5d\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":[],\"SecurityOpt\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
},
],
"schemaVersion": 1,
"signatures": [
{
"header": {
"jwk": {
"crv": "P-256",
"kid": "OD6I:6DRK:JXEJ:KBM4:255X:NSAA:MUSF:E4VM:ZI6W:CUN2:L4Z6:LSF4",
"kty": "EC",
"x": "3gAwX48IQ5oaYQAYSxor6rYYc_6yjuLCjtQ9LUakg4A",
"y": "t72ge6kIA1XOjqjVoEOiPPAURltJFBMGDSQvEGVB010"
},
"alg": "ES256"
},
"signature": "XREm0L8WNn27Ga_iE_vRnTxVMhhYY0Zst_FfkKopg6gWSoTOZTuW4rK0fg_IqnKkEKlbD83tD46LKEGi5aIVFg",
"protected": "eyJmb3JtYXRMZW5ndGgiOjY2MjgsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wNC0wOFQxODo1Mjo1OVoifQ"
}
]
}
```

View file

@ -1,292 +0,0 @@
---
description: image manifest for the Registry.
keywords: registry, on-prem, images, tags, repository, distribution, api, advanced, manifest
title: Image manifest V2, schema 2
---
This document outlines the format of of the V2 image manifest, schema version 2.
The original (and provisional) image manifest for V2 (schema 1), was introduced
in the Docker daemon in the [v1.3.0
release](https://github.com/docker/docker/commit/9f482a66ab37ec396ac61ed0c00d59122ac07453)
and is specified in the [schema 1 manifest definition](manifest-v2-1.md)
This second schema version has two primary goals. The first is to allow
multi-architecture images, through a "fat manifest" which references image
manifests for platform-specific versions of an image. The second is to
move the Docker engine towards content-addressable images, by supporting
an image model where the image's configuration can be hashed to generate
an ID for the image.
# Media Types
The following media types are used by the manifest formats described here, and
the resources they reference:
- `application/vnd.docker.distribution.manifest.v1+json`: schema1 (existing manifest format)
- `application/vnd.docker.distribution.manifest.v2+json`: New image manifest format (schemaVersion = 2)
- `application/vnd.docker.distribution.manifest.list.v2+json`: Manifest list, aka "fat manifest"
- `application/vnd.docker.image.rootfs.diff.tar.gzip`: "Layer", as a gzipped tar
- `application/vnd.docker.container.image.v1+json`: Container config JSON
## Manifest List
The manifest list is the "fat manifest" which points to specific image manifests
for one or more platforms. Its use is optional, and relatively few images will
use one of these manifests. A client will distinguish a manifest list from an
image manifest based on the Content-Type returned in the HTTP response.
## *Manifest List* Field Descriptions
- **`schemaVersion`** *int*
This field specifies the image manifest schema version as an integer. This
schema uses the version `2`.
- **`mediaType`** *string*
The MIME type of the manifest list. This should be set to
`application/vnd.docker.distribution.manifest.list.v2+json`.
- **`manifests`** *array*
The manifests field contains a list of manifests for specific platforms.
Fields of an object in the manifests list are:
- **`mediaType`** *string*
The MIME type of the referenced object. This will generally be
`application/vnd.docker.image.manifest.v2+json`, but it could also
be `application/vnd.docker.image.manifest.v1+json` if the manifest
list references a legacy schema-1 manifest.
- **`size`** *int*
The size in bytes of the object. This field exists so that a client
will have an expected size for the content before validating. If the
length of the retrieved content does not match the specified length,
the content should not be trusted.
- **`digest`** *string*
The digest of the content, as defined by the
[Registry V2 HTTP API Specificiation](api.md#digest-parameter).
- **`platform`** *object*
The platform object describes the platform which the image in the
manifest runs on. A full list of valid operating system and architecture
values are listed in the [Go language documentation for `$GOOS` and
`$GOARCH`](https://golang.org/doc/install/source#environment)
- **`architecture`** *string*
The architecture field specifies the CPU architecture, for example
`amd64` or `ppc64le`.
- **`os`** *string*
The os field specifies the operating system, for example
`linux` or `windows`.
- **`os.version`** *string*
The optional os.version field specifies the operating system version,
for example `10.0.10586`.
- **`os.features`** *array*
The optional os.features field specifies an array of strings,
each listing a required OS feature (for example on Windows
`win32k`).
- **`variant`** *string*
The optional variant field specifies a variant of the CPU, for
example `armv6l` to specify a particular CPU variant of the ARM CPU.
- **`features`** *array*
The optional features field specifies an array of strings, each
listing a required CPU feature (for example `sse4` or `aes`).
## Example Manifest List
*Example showing a simple manifest list pointing to image manifests for two platforms:*
```json
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.image.manifest.v2+json",
"size": 7143,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
"platform": {
"architecture": "ppc64le",
"os": "linux",
}
},
{
"mediaType": "application/vnd.docker.image.manifest.v2+json",
"size": 7682,
"digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
"platform": {
"architecture": "amd64",
"os": "linux",
"features": [
"sse4"
]
}
}
]
}
```
# Image Manifest
The image manifest provides a configuration and a set of layers for a container
image. It's the direct replacement for the schema-1 manifest.
## *Image Manifest* Field Descriptions
- **`schemaVersion`** *int*
This field specifies the image manifest schema version as an integer. This
schema uses version `2`.
- **`mediaType`** *string*
The MIME type of the manifest. This should be set to
`application/vnd.docker.distribution.manifest.v2+json`.
- **`config`** *object*
The config field references a configuration object for a container, by
digest. This configuration item is a JSON blob that the runtime uses
to set up the container. This new schema uses a tweaked version
of this configuration to allow image content-addressability on the
daemon side.
Fields of a config object are:
- **`mediaType`** *string*
The MIME type of the referenced object. This should generally be
`application/vnd.docker.container.image.v1+json`.
- **`size`** *int*
The size in bytes of the object. This field exists so that a client
will have an expected size for the content before validating. If the
length of the retrieved content does not match the specified length,
the content should not be trusted.
- **`digest`** *string*
The digest of the content, as defined by the
[Registry V2 HTTP API Specificiation](api.md#digest-parameter).
- **`layers`** *array*
The layer list is ordered starting from the base image (opposite order of schema1).
Fields of an item in the layers list are:
- **`mediaType`** *string*
The MIME type of the referenced object. This should
generally be `application/vnd.docker.image.rootfs.diff.tar.gzip`.
- **`size`** *int*
The size in bytes of the object. This field exists so that a client
will have an expected size for the content before validating. If the
length of the retrieved content does not match the specified length,
the content should not be trusted.
- **`digest`** *string*
The digest of the content, as defined by the
[Registry V2 HTTP API Specificiation](api.md#digest-parameter).
- **`urls`** *array*
For an ordinary layer, this is empty, and the layer contents can be
retrieved directly from the registry. For a layer with *`mediatype`* of
`application/vnd.docker.image.rootfs.foreign.diff.tar.gzip`, this
contains a non-empty list of URLs from which this object can be
downloaded.
## Example Image Manifest
*Example showing an image manifest:*
```json
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 7023,
"digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 32654,
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 16724,
"digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 73109,
"digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
}
],
}
```
# Backward compatibility
The registry will continue to accept uploads of manifests in both the old and
new formats.
When pushing images, clients which support the new manifest format should first
construct a manifest in the new format. If uploading this manifest fails,
presumably because the registry only supports the old format, the client may
fall back to uploading a manifest in the old format.
When pulling images, clients indicate support for this new version of the
manifest format by sending the
`application/vnd.docker.distribution.manifest.v2+json` and
`application/vnd.docker.distribution.manifest.list.v2+json` media types in an
`Accept` header when making a request to the `manifests` endpoint. Updated
clients should check the `Content-Type` header to see whether the manifest
returned from the endpoint is in the old format, or is an image manifest or
manifest list in the new format.
If the manifest being requested uses the new format, and the appropriate media
type is not present in an `Accept` header, the registry will assume that the
client cannot handle the manifest as-is, and rewrite it on the fly into the old
format. If the object that would otherwise be returned is a manifest list, the
registry will look up the appropriate manifest for the amd64 platform and
linux OS, rewrite that manifest into the old format if necessary, and return
the result to the client. If no suitable manifest is found in the manifest
list, the registry will return a 404 error.
One of the challenges in rewriting manifests to the old format is that the old
format involves an image configuration for each layer in the manifest, but the
new format only provides one image configuration. To work around this, the
registry will create synthetic image configurations for all layers except the
top layer. These image configurations will not result in runnable images on
their own, but only serve to fill in the parent chain in a compatible way.
The IDs in these synthetic configurations will be derived from hashes of their
respective blobs. The registry will create these configurations and their IDs
using the same scheme as Docker 1.10 when it creates a legacy manifest to push
to a registry which doesn't support the new format.