docker registry v2认证过程

https://docs.docker.com/registry/spec/images/v2-registry-auth.png

1、尝试从docker regisry中push/pull镜像
2、如果docker registry需要授权,将会返回401 Unauthorized的http响应,并在返回的头信息中提供到哪认证的信息
3、客户端向授权服务请求获取token。
4、认证服务到数据库或ldap中验证用户信息,跟据验证结果生成token
5、docker client携带token令牌再次尝试访问docker registry.
6、docker registry验证用户提交的token,判断是否有有权限进行操作,如果有则进行相应的pull或push。

docker registry 配置文件中的auth

auth:
  silly:
    realm: silly-realm
    service: silly-service
  token:
    realm: token-realm
    service: token-service
    issuer: registry-token-issuer
    rootcertbundle: /root/certs/bundle
  htpasswd:
    realm: basic-realm
    path: /path/to/htpasswd

过程

例如当用户尝试向registry push镜像samalba/my-app时,为了完成当前操作,
用户需要对repository samalba/my-app具有push的权限,registry将会返回401 Unuthorized信息
例如我们执行命令curl -i  https://docker.test/v2/_catalog
1、
HTTP/1.1 401 Unauthorized
Server: nginx
Date: Fri, 11 Aug 2017 02:43:09 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 134
Connection: keep-alive
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="container_registry",scope="registry:catalog:*"
X-Content-Type-Options: nosniff

{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Name":"catalog","Action":"*"}]}]}
2、
Docker Client提供用户输入用户名和密码后向auth server发送请求:
https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push
同时在http head中包含用户相关的登录信息
authorized: Basic YWtaW46cGzc3dvmcQ=
3、
auth server只需要从http head中通过base64获取登录的用户名和密码,并且验证登录信息的合法性,
同时根据业务数据返回用户的实际权限(pull, push)即可.
4、
当docker client获取到token之后,client会将得到的token作为http请求头信息再次尝试访问registry,registry使用公钥解密并验证token内容,并根据token包含的权限信息完成实际的操作

加密

通过公钥私钥加密
auth:
  token:
    realm: https://auth.docker.io/token
    service: Docker registry
    issuer: Auth Service
    rootcertbundle: /certs/auth.crt

token的生成

JWT(Json web token)的构成
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
1、生成jwt的Header信息
{
    "typ": "JWT",
    "alg": "ES256",
    "kid": "PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6"
}

typ: 当使用JWT时,typ固定为“JWT”
alg: 对应私钥文件的加密方式,本示例中即对应auth.key文件的加密方式,可以通过代码读取私钥文件获取
kid: 根据docker提供的规则生成公钥文件的kid,registry会根据同样的算法获取公钥的kid,如果匹配失败则认证失败
2、设置jwt的payload信息
{
    "iss": "Auth Service", //需要注意必须与auth.token.issuer配置保持一致
    "sub": "some id", //根据业务系统的规则自定义生成即可
    "aud": "Docker registry",// 从请求的service参数获取
    "exp": 1415387315, //过期时间
    "nbf": 1415387015, // not before 可选参数
    "iat": 1415387015, // 正式发行时间
    "jti": "tYJCO1c6cnyy7kAn0c7rKPgbV1H1bFws", //随机生成即可
    // access根据请求的scope获取,当然业务系统要判断用户的实际权限并在actions中放回
    "access": [
        {
            "type": "repository",
            "name": "samalba/my-app",
            "actions": [
                "pull",
                "push"
            ]
        }
    ]
}
3、使用私钥进行签名