Merge pull request #731 from mstanleyjones/distribution_docs_from_upstream
Pull distribution reference docs from upstream repomaster
						commit
						4a0bf57871
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5478
									
								
								docs/spec/api.md
								
								
								
								
							
							
						
						
									
										5478
									
								
								docs/spec/api.md
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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"} | ||||
| ``` | ||||
|  | @ -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. | ||||
|  | @ -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: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 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) | ||||
|  | @ -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 | ||||
| 
 | ||||
|  | @ -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) | ||||
|  | @ -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 | ||||
| } | ||||
| ``` | ||||
|  | @ -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" | ||||
|       } | ||||
|    ] | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
|  | @ -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. | ||||
		Loading…
	
		Reference in New Issue