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
}