1
0
mirror of https://github.com/goharbor/harbor.git synced 2024-12-25 18:18:04 +01:00

Merge pull request from wy65701436/middleware-policy-checker

enable policy checker in response handler
This commit is contained in:
Wang Yan 2019-11-14 18:31:50 +08:00 committed by GitHub
commit 4bec9bbfc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 108 additions and 111 deletions
src/core/middlewares
contenttrust
regtoken
util
vulnerable

View File

@ -21,6 +21,7 @@ import (
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/core/middlewares/util" "github.com/goharbor/harbor/src/core/middlewares/util"
"net/http" "net/http"
"net/http/httptest"
) )
// NotaryEndpoint ... // NotaryEndpoint ...
@ -39,29 +40,15 @@ func New(next http.Handler) http.Handler {
// ServeHTTP ... // ServeHTTP ...
func (cth contentTrustHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (cth contentTrustHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
imgRaw := req.Context().Value(util.ImageInfoCtxKey) doContentTrustCheck, image := validate(req)
if imgRaw == nil || !config.WithNotary() { if !doContentTrustCheck {
cth.next.ServeHTTP(rw, req) cth.next.ServeHTTP(rw, req)
return return
} }
img, _ := req.Context().Value(util.ImageInfoCtxKey).(util.ImageInfo) rec := httptest.NewRecorder()
if img.Digest == "" { cth.next.ServeHTTP(rec, req)
cth.next.ServeHTTP(rw, req) if rec.Result().StatusCode == http.StatusOK {
return match, err := matchNotaryDigest(image)
}
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)
if err != nil { if err != nil {
http.Error(rw, util.MarshalError("PROJECT_POLICY_VIOLATION", "Failed in communication with Notary please check the log"), http.StatusInternalServerError) http.Error(rw, util.MarshalError("PROJECT_POLICY_VIOLATION", "Failed in communication with Notary please check the log"), http.StatusInternalServerError)
return 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) http.Error(rw, util.MarshalError("PROJECT_POLICY_VIOLATION", "The image is not signed in Notary."), http.StatusPreconditionFailed)
return 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) { func matchNotaryDigest(img util.ImageInfo) (bool, error) {

View File

@ -43,7 +43,6 @@ func (r *regTokenHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
r.next.ServeHTTP(rw, req) r.next.ServeHTTP(rw, req)
return return
} }
*req = *(req.WithContext(util.NewDockerPullAuthContext(req.Context(), true)))
rawToken := parts[1] rawToken := parts[1]
opt := pkg_token.DefaultTokenOptions() opt := pkg_token.DefaultTokenOptions()

View File

@ -51,8 +51,6 @@ const (
ImageInfoCtxKey = contextKey("ImageInfo") ImageInfoCtxKey = contextKey("ImageInfo")
// ScannerPullCtxKey the context key for robot account to bypass the pull policy check. // ScannerPullCtxKey the context key for robot account to bypass the pull policy check.
ScannerPullCtxKey = contextKey("ScannerPullCheck") ScannerPullCtxKey = contextKey("ScannerPullCheck")
// DockerPullAuthCtxKey the context key to index whether docker pull request with bearer token
DockerPullAuthCtxKey = contextKey("DockerPullWithBearer")
// TokenUsername ... // TokenUsername ...
// TODO: temp solution, remove after vmware/harbor#2242 is resolved. // TODO: temp solution, remove after vmware/harbor#2242 is resolved.
TokenUsername = "harbor-core" TokenUsername = "harbor-core"
@ -459,17 +457,6 @@ func ScannerPullFromContext(ctx context.Context) (bool, bool) {
return info, ok 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 // NewBlobInfoContext returns context with blob info
func NewBlobInfoContext(ctx context.Context, info *BlobInfo) context.Context { func NewBlobInfoContext(ctx context.Context, info *BlobInfo) context.Context {
return context.WithValue(ctx, blobInfoKey, info) return context.WithValue(ctx, blobInfoKey, info)

View File

@ -17,6 +17,7 @@ package vulnerable
import ( import (
"net/http" "net/http"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/middlewares/util" "github.com/goharbor/harbor/src/core/middlewares/util"
sc "github.com/goharbor/harbor/src/pkg/scan/api/scan" 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" v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
"github.com/goharbor/harbor/src/pkg/scan/vuln" "github.com/goharbor/harbor/src/pkg/scan/vuln"
"github.com/pkg/errors" "github.com/pkg/errors"
"net/http/httptest"
) )
type vulnerableHandler struct { type vulnerableHandler struct {
@ -39,41 +41,20 @@ func New(next http.Handler) http.Handler {
// ServeHTTP ... // ServeHTTP ...
func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
imgRaw := req.Context().Value(util.ImageInfoCtxKey) doVulCheck, img, projectVulnerableSeverity, wl := validate(req)
if imgRaw == nil { if !doVulCheck {
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 {
vh.next.ServeHTTP(rw, req) vh.next.ServeHTTP(rw, req)
return 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 // Invalid project ID
if wl.ProjectID == 0 { if wl.ProjectID == 0 {
err := errors.Errorf("project verification error: project %s", img.ProjectName) err := errors.Errorf("project verification error: project %s", img.ProjectName)
vh.sendError(err, rw) vh.sendError(err, rw)
return return
} }
@ -96,7 +77,6 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
if err != nil { if err != nil {
err = errors.Wrap(err, "middleware: vulnerable handler") err = errors.Wrap(err, "middleware: vulnerable handler")
vh.sendError(err, rw) vh.sendError(err, rw)
return return
} }
@ -105,7 +85,6 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
if !ok { if !ok {
err = errors.Errorf("no scan report existing for the artifact: %s:%s@%s", img.Repository, img.Reference, img.Digest) err = errors.Errorf("no scan report existing for the artifact: %s:%s@%s", img.Repository, img.Reference, img.Digest)
vh.sendError(err, rw) vh.sendError(err, rw)
return return
} }
@ -115,7 +94,6 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
if summary.Severity.Code() >= projectVulnerableSeverity.Code() { 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) 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) vh.sendError(err, rw)
return return
} }
@ -125,8 +103,34 @@ func (vh vulnerableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request)
log.Infof("Vulnerable policy check: scannerPull CVE %s", cve) 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) { func (vh vulnerableHandler) sendError(err error, rw http.ResponseWriter) {