Registry的Token认证
registry的认证方式有三种,本文介绍最常用的token认证机制。
认证流程
我们以docker pull
操作描述一下token认证的流程
1、docker-daemon向registry发起pull操作
2、如果registry开启了认证,则会返回401 Unauthorized
的响应,并且在响应头中携带如何去认证的信息
3、docker-daemon向授权服务(authorization service)发起请求,获取token
4、授权服务返回一个token,该token中携带了权限信息
5、docker-daemon重新向registry发起同样的请求,并且在头部中携带token
6、registry对token进行验证,然后开始正常的pull流程
registry开启token认证
registry要开启token认证,需要在配置文件中添加如下内容,以下四个参数都为必填。
auth:
token:
realm: {token-realm}
service: {token-service}
issuer: {registry-token-issuer}
rootcertbundle: {/root/certs/bundle}
issuer:token签发者的名字,授权服务器签发的token中也有该字段;registry与授权服务的该字段要配置成一致,以便registry验证token是否由目标授权服务签发
以下为本地harbor的registry配置文件中关于token配置的样例:
auth:
token:
realm: http://192.168.1.103:8021/service/token
service: token-service
issuer: registry-token-issuer
rootcertbundle: /etc/registry/root.crt
如何认证
当docker-daemon没有携带任何认证信息向registry发起某个API请求时(对应上图中的步骤1),registry会返回401 Unauthorized
,并且在响应头的参数WWW-Authenticate
中给出如何去获取token的详细信息。
比如,pull镜像的第一步是获取manifest,那么我们没有携带任何认证信息去拉取本地harbor中的library/registry:2.5.0
镜像的manifest文件,会得到如下的响应头(docker-daemon也是请求registry的API,这里我们使用curl模拟下载镜像的API请求):
$ curl -I 192.168.1.103:8021/v2/library/registry/manifests/2.5.0
HTTP/1.1 401 Unauthorized
Server: nginx/1.11.5
Date: Wed, 05 Sep 2018 06:55:23 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 148
Connection: keep-alive
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="http://192.168.1.103:8021/service/token",service="token-service",scope="repository:library/registry:pull"
注意头部中的Www-Authenticate
字段的值,告诉我们应该如何去获取token:
Www-Authenticate: Bearer realm="http://192.168.1.103:8021/service/token",service="token-service",scope="repository:library/registry:pull"
请求Token
QUERY参数
client_id
:(可选)发起请求的客户端的标识,比如docker-daemon发起的请求会将该字段设置为docker
,harbor的复制策略中会将该字段设置为harbor-registry-client
响应BODY字段
token
:授权服务器返回的带有授权信息的token
issued_at
:(可选)token的签发时间,UTC标准时间格式
expires_in
:(可选)token在多少秒以后过期,如果没有说明则默认为60秒
Example
接下来,我们去获取token
$ curl 192.168.1.103:8021/service/token?service=token-service\&scope=repository:library/registry:pull\&client_id=curl
{
"expires_in": 1800,
"issued_at": "2018-09-05T08:34:40Z",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkhNNjY6NkNYUzpaQlBROk1ENVo6QlJZVTpTVE9EOkNCUEs6Uk5ORjpYN0VDOkZMUUw6TFNFMjpLUUtTIn0.eyJpc3MiOiJyZWdpc3RyeS10b2tlbi1pc3N1ZXIiLCJzdWIiOiIiLCJhdWQiOiJ0b2tlbi1zZXJ2aWNlIiwiZXhwIjoxNTM2MTM4MjgwLCJuYmYiOjE1MzYxMzY0ODAsImlhdCI6MTUzNjEzNjQ4MCwianRpIjoiZFpxVkgxVDFjZkhXdnFZTiIsImFjY2VzcyI6W3sidHlwZSI6InJlcG9zaXRvcnkiLCJuYW1lIjoibGlicmFyeS9yZWdpc3RyeSIsImFjdGlvbnMiOlsicHVsbCJdfV19.ilCKa2-oJ9bKQpAo8ntcx1lHpbs0BcWYtbRrvItHAProaDEDpll9EZrzkzg6XR9OOLByFm_oJKKk8Y_wYwQfxYdjvhLbFjCNXzE6MckY8dEcSR5BmYxOK54zAqNVkw24ugUcagGFi7p8Gy0YZqBqf7AP8qCarhuWhKsZ7B4esMQk2xBEn1hh8r_9tb6wnZOkDl7trW0IWbPkqKSaP8ycq8oS9J0T6zaItyTLnERsV_GFJOh6DdfhSYzGwoWUFQH6cmp05ZHXF_-4O6N6d8tosGH9gTsam-ffeVHmWp8da_gpS_R15z3ELR5I2FO0s4gWo1UbTI3yuyV8stSURrCs6GHZSMb2C9_2R2r_Q-uDKmdpoazw2G1DxM3PgfXEwANWEjPJMjD0areUXmjwz_hefSMqYFxLi26TaQinG0th7pNz5m0qroefOy1AGyhRZK-t8rsduZJ9EWQCqtXHrPbTES0FoItJmcMqcJZcvQsrJsBMirtijvGdNn55l44-eDFyrIuExerHzU1dJoSijCtqIYxbdnclLE8HSP-vnBD5TOAJoUUdUfA1N8TvF2QqDjr_LATUOctahrFoWiuDjrFXH-ptmcJJ6lPjo1oCOne3ImKe_mieRR7YCOQLejuCbItIIweuqwBzJU5d33k3Drra0qvbvk-MkO7iBNgpCtfWqD8"
}
{
"iss": "registry-token-issuer",
"sub": "",
"aud": "token-service",
"exp": 1536138280,
"nbf": 1536136480,
"iat": 1536136480,
"jti": "dZqVH1T1cfHWvqYN",
"access": [
{
"type": "repository",
"name": "library/registry",
"actions": [
"pull"
]
}
]
}
从access
字段可以看出,该token对library/registry
这个repository
具有pull
权限。
携带用户信息
在上面获取token的请求中,没有携带任何的用户信息,所以payload的sub
字段为空。但是harbor的授权服务器返回的token还是具有pull权限,这是因为harbor允许匿名用户pull library
中的镜像。不过我们可以携带harbor的admin用户信息去获取token,如下:
$ curl -H "Authorization: Basic YWRtaW46SGFyYm9yMTIzNDU=" 192.168.1.103:8021/service/token?service=token-service\&scope=repository:library/registry:pull\&client_id=curl
其中YWRtaW46SGFyYm9yMTIzNDU=
是admin:Harbor12345
使用base64加密后的字符串:
$ echo -n "admin:Harbor12345" | base64
YWRtaW46SGFyYm9yMTIzNDU=
使用Token
在得到token后,我们就可以在API请求的Header中添加token信息,比如下载镜像的manifest,这次请求就会正常返回了:
curl -H "Authorization: Bearer [token]" 192.168.1.103:8021/v2/library/registry/manifests/2.5.0
扩展知识
说说docker-login
docker login命令的使用方法如下:
docker login -u admin -p Harbor12345 192.168.1.103:8021
当docker login登录成功后,会在当前用户的 ~/.docker/config.json
中出现如下的内容:
{
"auths": {
"192.168.1.103:8021": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
}
}
}
其中字符串YWRtaW46SGFyYm9yMTIzNDU=
是通过base64算法加密得到的字符串。关于base64算法的加密与解密如下:
$ echo -n "admin:Harbor12345" | base64
YWRtaW46SGFyYm9yMTIzNDU=
$ echo -n "YWRtaW46SGFyYm9yMTIzNDU=" | base64 -d
admin:Harbor12345
当docker login成功后,我们再执行docker pull或push操作的时候,docker client便会从当前用户下查找registry的登录信息,并携带给docker daemon,docker-daemon便会在向Authorization Service请求token的API请求头中携带这个字符串。