harbor镜像仓库同步401问题解决过程

       项目中出现同步镜像时报401错误,首先想到的就是确认账号是否真的没有权限,然后通过docker login 命令使用该账号登录镜像仓库,也是报了401错误。现象很明确,就是客户端没有访问镜像仓库的权限,那么为啥会出现这种问题呢?

       猜想要么就是该账号确实没权限,要么就是获取到的token在镜像仓库服务端校验的时候失败了。镜像同步是通过访问镜像仓库的原生API进行的,在同步时镜像仓库服务端一样需要token认证来检查客户端是否有权限上传镜像,下面就一一验证这两种情况:

       先说明一下,我们项目中,镜像仓库服务与镜像仓库的token服务器分别部署在不同的机器上。对于第一种情况,验证很简单,换一个管理员账号即可,harbor镜像仓库的管理员账号是有全部镜像操作的权限的,如果管理员账号可以,那说明就是之前绑定的账号确实没权限,如果管理员账号也不行,那就说明是第二种情况了。通过docker login命令使用管理员账号登录镜像仓库,还是报了401错误,说明确实是token验证有问题,而不是账号的问题。那token验证为什么会出错呢?

       先来复习一下客户端访问镜像仓库获取token的原理。

  1. 客户端向镜像仓库发送请求
  2. 镜像仓库发现自己配置了权限认证服务,则返回401状态,并携带获取认证token的服务地址以及客户端访问所需要的权限
  3. 客户端收到镜像仓库的响应后发现要先获取token才能访问镜像仓库,则携带用户名和密码访问获取token的地址
  4. 权限认证服务器校验用户名和密码后,按照客户端需要的权限,返回一个JWT标准的token
  5. 客户端携带获取的token再次访问镜像仓库
  6. 镜像仓库验证客户端携带的token,验证通过则允许访问,验证失败则同第二步一样进行返回

上面第四步提到的JWT标准的token,是一个带有签名内容、签名时间、签名过期时间、签名可以使用的开始时间、签名使用的算法等字段的、通过点分为三部分的一串Base64编码的字符串。回到这次的问题,其实需要考虑的就是签名的这些时间是否正确。通过Base64对token的中间部分进行解码,可以看到签名相关的时间字段,首先就检查签名的过期时间,发现申请的token是一小时后过期,可使用的时间还是很长的,因此排除了签名过期时间短的问题,那剩下的就只能看签名可以使用的开始时间了,也就是JWT签名的nbf字段,查看后发现该字段的秒数转换为当前时间后,比镜像仓库服务的时间服务器时间快了两分钟,即客户端获取到token后,携带该token请求镜像仓库服务时,镜像仓库验证该签名,发现当前系统时间还没到签名的可使用时间,签名还无法使用,因此就返回了401错误。然后去查看镜像仓库token服务器的时间,确实比镜像仓库服务的服务器时间快了两分钟,通过时间同步操作,保证两台服务器时间一致后,重新进行镜像同步,已经可以同步成功了,至此,这个问题完美解决!

总结一下,虽然最终发现还是服务器时间不一致导致的,而且这种问题其实一般在项目部署时都不太容易出现的,毕竟服务器一般都要先做时间同步,保证节点的时间一致,避免很多莫名其妙的问题,但是当出现这种问题时,要知道怎么排查才是最重要的,这个需要事先对镜像仓库的认证过程有一些了解才行,这样才能判断大概问题出现在哪个环节。

 

你可能感兴趣的:(容器,harbor,镜像仓库,JWT,镜像同步,docker)