S_lion's Studio

harbor对接F5的鉴权失败问题

字数统计: 647阅读时长: 2 min
2021/11/23 Share

之前harbor的高可用方案都是通过我们自建VIP与检测机制来做的,此次上线的双活架构下,VIP无法跨网段进行通信,甲方提供F5作为统一入口,由此进行了F5对接harbor的功能性测试。

问题现象

使用docker login harbor时,有时成功,有时失败:

1
2
3
4
5
6
# docker login -u user -p passwd http://xxx.xxx.xxx.xxx:9980
Error response from daemon: login attempt to http://xxx.xxx.xxx.xxx:9980/v2/ failed with status: 401 Unauthorized
# docker login -u user -p passwd http://xxx.xxx.xxx.xxx:9980
Error response from daemon: login attempt to http://xxx.xxx.xxx.xxx:9980/v2/ failed with status: 401 Unauthorized
# docker login -u user -p passwd http://xxx.xxx.xxx.xxx:9980
Login Succeeded

修改docker配置文件中镜像仓库地址为单独的harbor节点再次测试,没有任何问题。

问题分析

接着将docker镜像仓库地址换回F5地址,打开两个终端分别监视两个Harbor节点上的registry的日志。

经过几次测试,发现一个现象:当docker login成功时,都是一个节点上的日志出现更新;而当docker login fail时,会看到两个节点上的registry日志都有变化,这就有些出乎意料了。

查阅harbor官方对docker login的流程解析

  • docker向registry发起请求,由于registry是基于token auth的,因此registry回复应答,告诉docker client去哪个URL去获取token;
  • docker client根据应答中的URL向token service(ui)发起请求,通过user和passwd获取token;如果user和passwd在db中通过了验证,那么token service将用自己的私钥(harbor/common/config/ui/private_key.pem)生成一个token,返回给docker client端;
  • docker client获得token后再向registry发起login请求,registry用自己的证书(harbor/common/config/registry/root.crt)对token进行校验。通过则返回成功,否则返回失败。

从这个原理,可以知道问题就出在docker client多次向Harbor发起请求这个环节:对于每次请求,F5会将域名可能解析为不同IP,因此不同请求可能落到不同的镜像仓库节点上。这样当docker client拿着节点1上token service分配的token去到节点2的registry上鉴权时,就会出现鉴权失败的情况。

解决策略

token service的私钥(harbor/common/config/ui/private_key.pem)和registry的证书(harbor/common/config/registry/root.crt)都是在prepare时生成的,两个节点都独立prepare过,因此两个node上的private_key.pem和root.crt是不同的。所以造成了鉴权失败的问题。统一两个节点的私钥和证书可以解决。

将节点1上的private_key.pem和root.crt复制到节点2上,并重新创建node2上的harbor container。

CATALOG
  1. 1. 问题现象
  2. 2. 问题分析
  3. 3. 解决策略