Harbor 认证过程
Harbor以 Docker Registry v2认证为基础,添加上一层权限保护。1.v2 集成了一个安全认证的功能,将安全认证暴露给外部服务,让外部服务去实现2.强制用户每次Docker pull/push请求都要带一个合法的Token,Registry会通过公钥对Token进行解密验证3.如果不包含Token,会被重定向到Token服务获取Token后重新请求
Registry v2 authentication官方文档
Registry v2 生成令牌代码
1.尝试使用registry开始推/拉操作2.如果registry需要进行授权时,registry将会返回401 Unauthorized响应,同时在响应中包含了docker client如何进行认证的信息3.registry client根据返回的信息,向auth server发送请求获取认证token4.auth server将会根据查询的用户信息,生成token令牌,以及当前用户所具有的相关权限信息5.client携带这附有token的请求,重试原始请求6.registry接受了认证的token并且使得client继续操作上述就是完整的授权过程.当用户完成上述过程以后便可以执行相关的pull/push操作。认证信息会每次都带在请求头中。
例:输入docker login,以下为整个登录过程流程图
1.registry 服务怎么知道服务认证地址?registry 服务本身就提供了一个配置文件,可以在启动 registry 服务的配置文件中指定上认证服务地址即可
...
auth:token:realm: token-realmservice: token-serviceissuer: registry-token-issuerrootcertbundle: /root/certs/bundle
...
其中 realm 就可以用来指定一个认证服务的地址
Harbor 后台认证
- authserver
路径:src/core/service/token/token.go
func (h *Handler) Get() {...token, err := tokenCreator.Create(request)...
}路径:src/core/service/token/creator.go
func (g generalCreator) Create(r *http.Request) (*models.Token, error) {...access := GetResourceActions(scopes)...return MakeToken(r.Context(), ctx.GetUsername(), g.service, access)
}路径:src/core/service/token/authutils.go
// MakeToken makes a valid jwt token based on parms.
func MakeToken(ctx context.Context, username, service string, access []*token.ResourceActions) (*models.Token, error) {options, err := tokenpkg.NewOptions(signingMethod, v2.Issuer, privateKey)if err != nil {return nil, err}expiration, err := config.TokenExpiration(ctx)if err != nil {return nil, err}now := time.Now().UTC()claims := &v2.Claims{RegisteredClaims: jwt.RegisteredClaims{Issuer: options.Issuer,Subject: username,Audience: jwt.ClaimStrings([]string{service}),ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(expiration) * time.Minute)),NotBefore: jwt.NewNumericDate(now),IssuedAt: jwt.NewNumericDate(now),ID: utils.GenerateRandomStringWithLen(16),},Access: access,}tok, err := tokenpkg.New(options, claims)if err != nil {return nil, err}// Add kid to token header for compatibility with docker distribution's code// see https://github.com/docker/distribution/blob/release/2.7/registry/auth/token/token.go#L197k, err := libtrust.UnmarshalPrivateKeyPEM(options.PrivateKey)if err != nil {return nil, err}tok.Header["kid"] = k.KeyID()rawToken, err := tok.Raw()if err != nil {return nil, err}return &models.Token{Token: rawToken,ExpiresIn: expiration * 60,IssuedAt: now.Format(time.RFC3339),}, nil
}