mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-18 22:57:38 +01:00
Merge pull request #9875 from wy65701436/middleware-policy-checker
enable policy checker in response handler
This commit is contained in:
commit
4bec9bbfc6
@ -21,6 +21,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
// NotaryEndpoint ...
|
||||
@ -39,29 +40,15 @@ func New(next http.Handler) http.Handler {
|
||||
|
||||
// ServeHTTP ...
|
||||
func (cth contentTrustHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
imgRaw := req.Context().Value(util.ImageInfoCtxKey)
|
||||
if imgRaw == nil || !config.WithNotary() {
|
||||
doContentTrustCheck, image := validate(req)
|
||||
if !doContentTrustCheck {
|
||||
cth.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
img, _ := req.Context().Value(util.ImageInfoCtxKey).(util.ImageInfo)
|
||||
if img.Digest == "" {
|
||||
cth.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
if pullWithBearer, ok := util.DockerPullAuthFromContext(req.Context()); ok && !pullWithBearer {
|
||||
cth.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
if scannerPull, ok := util.ScannerPullFromContext(req.Context()); ok && scannerPull {
|
||||
cth.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
if !util.GetPolicyChecker().ContentTrustEnabled(img.ProjectName) {
|
||||
cth.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
match, err := matchNotaryDigest(img)
|
||||
rec := httptest.NewRecorder()
|
||||
cth.next.ServeHTTP(rec, req)
|
||||
if rec.Result().StatusCode == http.StatusOK {
|
||||
match, err := matchNotaryDigest(image)
|
||||
if err != nil {
|
||||
http.Error(rw, util.MarshalError("PROJECT_POLICY_VIOLATION", "Failed in communication with Notary please check the log"), http.StatusInternalServerError)
|
||||
return
|
||||
@ -71,7 +58,27 @@ func (cth contentTrustHandler) ServeHTTP(rw http.ResponseWriter, req *http.Reque
|
||||
http.Error(rw, util.MarshalError("PROJECT_POLICY_VIOLATION", "The image is not signed in Notary."), http.StatusPreconditionFailed)
|
||||
return
|
||||
}
|
||||
cth.next.ServeHTTP(rw, req)
|
||||
}
|
||||
util.CopyResp(rec, rw)
|
||||
}
|
||||
|
||||
func validate(req *http.Request) (bool, util.ImageInfo) {
|
||||
var img util.ImageInfo
|
||||
imgRaw := req.Context().Value(util.ImageInfoCtxKey)
|
||||
if imgRaw == nil || !config.WithNotary() {
|
||||
return false, img
|
||||
}
|
||||
img, _ = req.Context().Value(util.ImageInfoCtxKey).(util.ImageInfo)
|
||||
if img.Digest == "" {
|
||||
return false, img
|
||||
}
|
||||
if scannerPull, ok := util.ScannerPullFromContext(req.Context()); ok && scannerPull {
|
||||
return false, img
|
||||
}
|
||||
if !util.GetPolicyChecker().ContentTrustEnabled(img.ProjectName) {
|
||||
return false, img
|
||||
}
|
||||
return true, img
|
||||
}
|
||||
|
||||
func matchNotaryDigest(img util.ImageInfo) (bool, error) {
|
||||
|
@ -43,7 +43,6 @@ func (r *regTokenHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
r.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
*req = *(req.WithContext(util.NewDockerPullAuthContext(req.Context(), true)))
|
||||
|
||||
rawToken := parts[1]
|
||||
opt := pkg_token.DefaultTokenOptions()
|
||||
|
@ -51,8 +51,6 @@ const (
|
||||
ImageInfoCtxKey = contextKey("ImageInfo")
|
||||
// ScannerPullCtxKey the context key for robot account to bypass the pull policy check.
|
||||
ScannerPullCtxKey = contextKey("ScannerPullCheck")
|
||||
// DockerPullAuthCtxKey the context key to index whether docker pull request with bearer token
|
||||
DockerPullAuthCtxKey = contextKey("DockerPullWithBearer")
|
||||
// TokenUsername ...
|
||||
// TODO: temp solution, remove after vmware/harbor#2242 is resolved.
|
||||
TokenUsername = "harbor-core"
|
||||
@ -459,17 +457,6 @@ func ScannerPullFromContext(ctx context.Context) (bool, bool) {
|
||||
return info, ok
|
||||
}
|
||||
|
||||
// NewDockerPullAuthContext returns context with bearer token
|
||||
func NewDockerPullAuthContext(ctx context.Context, withBearer bool) context.Context {
|
||||
return context.WithValue(ctx, DockerPullAuthCtxKey, withBearer)
|
||||
}
|
||||
|
||||
// DockerPullAuthFromContext returns whether the docker pull with bearer
|
||||
func DockerPullAuthFromContext(ctx context.Context) (bool, bool) {
|
||||
info, ok := ctx.Value(DockerPullAuthCtxKey).(bool)
|
||||
return info, ok
|
||||
}
|
||||
|
||||
// NewBlobInfoContext returns context with blob info
|
||||
func NewBlobInfoContext(ctx context.Context, info *BlobInfo) context.Context {
|
||||
return context.WithValue(ctx, blobInfoKey, info)
|
||||
|
@ -17,6 +17,7 @@ package vulnerable
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||
sc "github.com/goharbor/harbor/src/pkg/scan/api/scan"
|
||||
@ -24,6 +25,7 @@ import (
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/vuln"
|
||||
"github.com/pkg/errors"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
type vulnerableHandler struct {
|
||||
@ -39,41 +41,20 @@ func New(next http.Handler) http.Handler {
|
||||
|
||||
// ServeHTTP ...
|
||||
func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
imgRaw := req.Context().Value(util.ImageInfoCtxKey)
|
||||
if imgRaw == nil {
|
||||
vh.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Expected artifact specified?
|
||||
img, ok := imgRaw.(util.ImageInfo)
|
||||
if !ok || len(img.Digest) == 0 {
|
||||
vh.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
if pullWithBearer, ok := util.DockerPullAuthFromContext(req.Context()); ok && !pullWithBearer {
|
||||
vh.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
if scannerPull, ok := util.ScannerPullFromContext(req.Context()); ok && scannerPull {
|
||||
vh.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
// Is vulnerable policy set?
|
||||
projectVulnerableEnabled, projectVulnerableSeverity, wl := util.GetPolicyChecker().VulnerablePolicy(img.ProjectName)
|
||||
if !projectVulnerableEnabled {
|
||||
doVulCheck, img, projectVulnerableSeverity, wl := validate(req)
|
||||
if !doVulCheck {
|
||||
vh.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
vh.next.ServeHTTP(rec, req)
|
||||
// only enable vul policy check the response 200
|
||||
if rec.Result().StatusCode == http.StatusOK {
|
||||
// Invalid project ID
|
||||
if wl.ProjectID == 0 {
|
||||
err := errors.Errorf("project verification error: project %s", img.ProjectName)
|
||||
vh.sendError(err, rw)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -96,7 +77,6 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "middleware: vulnerable handler")
|
||||
vh.sendError(err, rw)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -105,7 +85,6 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||
if !ok {
|
||||
err = errors.Errorf("no scan report existing for the artifact: %s:%s@%s", img.Repository, img.Reference, img.Digest)
|
||||
vh.sendError(err, rw)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -115,7 +94,6 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||
if summary.Severity.Code() >= projectVulnerableSeverity.Code() {
|
||||
err = errors.Errorf("the pulling image severity %q is higher than or equal with the project setting %q, reject the response.", summary.Severity, projectVulnerableSeverity)
|
||||
vh.sendError(err, rw)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -125,8 +103,34 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||
log.Infof("Vulnerable policy check: scannerPull CVE %s", cve)
|
||||
}
|
||||
}
|
||||
}
|
||||
util.CopyResp(rec, rw)
|
||||
}
|
||||
|
||||
vh.next.ServeHTTP(rw, req)
|
||||
func validate(req *http.Request) (bool, util.ImageInfo, vuln.Severity, models.CVEWhitelist) {
|
||||
var vs vuln.Severity
|
||||
var wl models.CVEWhitelist
|
||||
var img util.ImageInfo
|
||||
imgRaw := req.Context().Value(util.ImageInfoCtxKey)
|
||||
if imgRaw == nil {
|
||||
return false, img, vs, wl
|
||||
}
|
||||
|
||||
// Expected artifact specified?
|
||||
img, ok := imgRaw.(util.ImageInfo)
|
||||
if !ok || len(img.Digest) == 0 {
|
||||
return false, img, vs, wl
|
||||
}
|
||||
|
||||
if scannerPull, ok := util.ScannerPullFromContext(req.Context()); ok && scannerPull {
|
||||
return false, img, vs, wl
|
||||
}
|
||||
// Is vulnerable policy set?
|
||||
projectVulnerableEnabled, projectVulnerableSeverity, wl := util.GetPolicyChecker().VulnerablePolicy(img.ProjectName)
|
||||
if !projectVulnerableEnabled {
|
||||
return false, img, vs, wl
|
||||
}
|
||||
return true, img, projectVulnerableSeverity, wl
|
||||
}
|
||||
|
||||
func (vh vulnerableHandler) sendError(err error, rw http.ResponseWriter) {
|
||||
|
Loading…
Reference in New Issue
Block a user