harbor登录验证_Harbor 源码浅析

时间:2024-10-22 16:45:21

Harbor 是一个CNCF基金会托管的开源的可信的云原生docker registry项目,可以用于存储、签名、扫描镜像内容,Harbor 通过添加一些常用的功能如安全性、身份权限管理等来扩展 docker registry 项目,此外还支持在 registry 之间复制镜像,还提供更加高级的安全功能,如用户管理、访问控制和活动审计等,在新版本中还添加了Helm仓库托管的支持。

本文所有源码基于 Harbor release-1.7.0 版本进行分析。

Harbor最核心的功能就是给 docker registry 添加上一层权限保护的功能,要实现这个功能,就需要我们在使用 docker login、pull、push 等命令的时候进行拦截,先进行一些权限相关的校验,再进行操作,其实这一系列的操作 docker registry v2 就已经为我们提供了支持,v2 集成了一个安全认证的功能,将安全认证暴露给外部服务,让外部服务去实现。

docker registry v2 认证

上面我们说了 docker registry v2 将安全认证暴露给了外部服务使用,那么是怎样暴露的呢?我们在命令行中输入docker login 为例来为大家说明下认证流程:

  • 1. docker client 接收到用户输入的 docker login 命令,将命令转化为调用 engine api 的 RegistryLogin 方法
  • 2. 在 RegistryLogin 方法中通过 http 盗用 registry 服务中的 auth 方法
  • 3. 因为我们这里使用的是 v2 版本的服务,所以会调用 loginV2 方法,在 loginV2 方法中会进行 /v2/ 接口调用,该接口会对请求进行认证
  • 4. 此时的请求中并没有包含 token 信息,认证会失败,返回 401 错误,同时会在 header 中返回去哪里请求认证的服务器地址
  • 5. registry client 端收到上面的返回结果后,便会去返回的认证服务器那里进行认证请求,向认证服务器发送的请求的 header 中包含有加密的用户名和密码
  • 6. 认证服务器从 header 中获取到加密的用户名和密码,这个时候就可以结合实际的认证系统进行认证了,比如从数据库中查询用户认证信息或者对接 ldap 服务进行认证校验
  • 7. 认证成功后,会返回一个 token 信息,client 端会拿着返回的 token 再次向 registry 服务发送请求,这次需要带上得到的 token,请求验证成功,返回状态码就是200了
  • 8. docker client 端接收到返回的200状态码,说明操作成功,在控制台上打印Login Succeeded的信息

至此,整个登录过程完成,整个过程可以用下面的流程图来说明:

要完成上面的登录认证过程有两个关键点需要注意:怎样让 registry 服务知道服务认证地址?我们自己提供的认证服务生成的 token 为什么 registry 就能够识别?

对于第一个问题,比较好解决,registry 服务本身就提供了一个配置文件,可以在启动 registry 服务的配置文件中指定上认证服务地址即可,其中有如下这样的一段配置信息:

......auth: token: realm: token-realm service: token-service issuer: registry-token-issuer rootcertbundle: /root/certs/bundle......

其中 realm 就可以用来指定一个认证服务的地址,下面我们可以看到 Harbor 中该配置的内容

关于 registry 的配置,可以参考官方文档:/registry/configuration/

第二个问题,就是 registry 怎么能够识别我们返回的 token 文件?如果按照 registry 的要求生成一个 token,是不是 registry 就可以识别了?所以我们需要在我们的认证服务器中按照 registry 的要求生成 token,而不是随便乱生成。那么要怎么生成呢?我们可以在 docker registry 的源码中可以看到 token 是如何定义的,文件路径在distribution/registry/token/,从源码中我们可以看到 token 是通过JWT(JSON Web Token)来实现的,所以我们按照要求生成一个 JWT 的 token 就可以了。

Harbor 认证

上面我们已经说明了 docker registry v2 认证的整个流程,Harbor 实际上核心的功能就是提供上面的认证服务的功能。我们在 Harbor 的源码目录中可以查看到 registry 服务的配置文件,路径为:make/common/templates/registry/,其中有两个非常重要的配置信息:

......auth: token: issuer: harbor-token-issuer realm: $public_url/service/token rootcertbundle: /etc/registry/root.crt service: harbor-registry......

一个就是上面我们提到的 ,是用来提供 registry v2 安全认证的外部服务地址,这里默认的配置是$public_url/service/token,其中$public_url就是 Harbor 服务的主域地址,所以安全认证服务就是去请求/service/token这个地址了,由于 Harbor 是基于 beego 这个 web 框架进行开发的,所以我们只需要去查找下/service/token这个路由,就可以找到对应的请求处理方法了。可以很容易在文件src/core/router.go文件中找到改路由:

func initRouters() { ...... ("/service/token