Merge pull request #9571 from steven-zou/fix/support_internal_addr_scanner

support using internal registry addr to perform scan
This commit is contained in:
Steven Zou 2019-10-24 20:52:27 +08:00 committed by GitHub
commit 868851cc51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 89 additions and 18 deletions

View File

@ -10,6 +10,8 @@ CREATE TABLE scanner_registration
access_cred VARCHAR(512) NULL, access_cred VARCHAR(512) NULL,
disabled BOOLEAN NOT NULL DEFAULT FALSE, disabled BOOLEAN NOT NULL DEFAULT FALSE,
is_default BOOLEAN NOT NULL DEFAULT FALSE, is_default BOOLEAN NOT NULL DEFAULT FALSE,
use_internal_addr BOOLEAN NOT NULL DEFAULT FALSE,
immutable BOOLEAN NOT NULL DEFAULT FALSE,
skip_cert_verify BOOLEAN NOT NULL DEFAULT FALSE, skip_cert_verify BOOLEAN NOT NULL DEFAULT FALSE,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP

View File

@ -164,6 +164,12 @@ func (sa *ScannerAPI) Update() {
return return
} }
// Immutable registration is not allowed
if r.Immutable {
sa.SendForbiddenError(errors.Errorf("registration %s is not allowed to update as it is immutable: scanner API: update", r.Name))
return
}
// full dose updated // full dose updated
rr := &scanner.Registration{} rr := &scanner.Registration{}
if err := sa.DecodeJSONReq(rr); err != nil { if err := sa.DecodeJSONReq(rr); err != nil {
@ -207,17 +213,21 @@ func (sa *ScannerAPI) Update() {
// Delete the scanner // Delete the scanner
func (sa *ScannerAPI) Delete() { func (sa *ScannerAPI) Delete() {
uid := sa.GetStringFromPath(":uuid") r := sa.get()
if r == nil {
deleted, err := sa.c.DeleteRegistration(uid) // meet error
if err != nil {
sa.SendInternalServerError(errors.Wrap(err, "scanner API: delete"))
return return
} }
if deleted == nil { // Immutable registration is not allowed
// Not found if r.Immutable {
sa.SendNotFoundError(errors.Errorf("scanner registration: %s", uid)) sa.SendForbiddenError(errors.Errorf("registration %s is not allowed to delete as it is immutable: scanner API: update", r.Name))
return
}
deleted, err := sa.c.DeleteRegistration(r.UUID)
if err != nil {
sa.SendInternalServerError(errors.Wrap(err, "scanner API: delete"))
return return
} }

View File

@ -227,6 +227,7 @@ func (suite *ScannerAPITestSuite) TestScannerAPIDelete() {
URL: "https://a.b.c", URL: "https://a.b.c",
} }
suite.mockC.On("GetRegistration", "uuid").Return(r, nil)
suite.mockC.On("DeleteRegistration", "uuid").Return(r, nil) suite.mockC.On("DeleteRegistration", "uuid").Return(r, nil)
deleted := &scanner.Registration{} deleted := &scanner.Registration{}

View File

@ -19,11 +19,13 @@ import (
"fmt" "fmt"
"time" "time"
tk "github.com/docker/distribution/registry/auth/token"
cj "github.com/goharbor/harbor/src/common/job" cj "github.com/goharbor/harbor/src/common/job"
jm "github.com/goharbor/harbor/src/common/job/models" jm "github.com/goharbor/harbor/src/common/job/models"
"github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/core/service/token"
"github.com/goharbor/harbor/src/jobservice/job" "github.com/goharbor/harbor/src/jobservice/job"
"github.com/goharbor/harbor/src/jobservice/logger" "github.com/goharbor/harbor/src/jobservice/logger"
"github.com/goharbor/harbor/src/pkg/robot" "github.com/goharbor/harbor/src/pkg/robot"
@ -44,6 +46,9 @@ var DefaultController = NewController()
const ( const (
configRegistryEndpoint = "registryEndpoint" configRegistryEndpoint = "registryEndpoint"
configCoreInternalAddr = "coreInternalAddr" configCoreInternalAddr = "coreInternalAddr"
authorizationType = "harbor.scanner-adapter/registry-authorization-type"
authorizationBearer = "Bearer"
authorizationBasic = "Basic"
) )
// uuidGenerator is a func template which is for generating UUID. // uuidGenerator is a func template which is for generating UUID.
@ -190,7 +195,13 @@ func (bc *basicController) Scan(artifact *v1.Artifact) error {
return errors.Wrap(err, "scan controller: scan") return errors.Wrap(err, "scan controller: scan")
} }
jobID, err := bc.launchScanJob(trackID, artifact, r, producesMimes) // Get authorization type
auth := authorizationBasic
if v, ok := meta.Properties[authorizationType]; ok {
auth = v
}
jobID, err := bc.launchScanJob(trackID, artifact, r, producesMimes, auth)
if err != nil { if err != nil {
// Update the status to the concrete error // Update the status to the concrete error
// Change status code to normal error code // Change status code to normal error code
@ -352,8 +363,8 @@ func (bc *basicController) DeleteReports(digests ...string) error {
return bc.manager.DeleteByDigests(digests...) return bc.manager.DeleteByDigests(digests...)
} }
// makeAuthorization creates authorization from a robot account based on the arguments for scanning. // makeBasicAuthorization creates authorization from a robot account based on the arguments for scanning.
func (bc *basicController) makeAuthorization(pid int64, repository string, ttl int64) (string, int64, error) { func (bc *basicController) makeBasicAuthorization(pid int64, repository string, ttl int64) (string, int64, error) {
// Use uuid as name to avoid duplicated entries. // Use uuid as name to avoid duplicated entries.
UUID, err := bc.uuid() UUID, err := bc.uuid()
if err != nil { if err != nil {
@ -389,14 +400,31 @@ func (bc *basicController) makeAuthorization(pid int64, repository string, ttl i
} }
// launchScanJob launches a job to run scan // launchScanJob launches a job to run scan
func (bc *basicController) launchScanJob(trackID string, artifact *v1.Artifact, registration *scanner.Registration, mimes []string) (jobID string, err error) { func (bc *basicController) launchScanJob(trackID string, artifact *v1.Artifact, registration *scanner.Registration, mimes []string, auth string) (jobID string, err error) {
externalURL, err := bc.config(configRegistryEndpoint) var ck string
if registration.UseInternalAddr {
ck = configCoreInternalAddr
} else {
ck = configRegistryEndpoint
}
registryAddr, err := bc.config(ck)
if err != nil { if err != nil {
return "", errors.Wrap(err, "scan controller: launch scan job") return "", errors.Wrap(err, "scan controller: launch scan job")
} }
// Make authorization from a robot account with 30 minutes var (
authorization, rID, err := bc.makeAuthorization(artifact.NamespaceID, artifact.Repository, 1800) authorization string
rID int64 = -1
)
if auth == authorizationBearer {
authorization, err = makeBearerAuthorization(artifact.Repository, fmt.Sprintf("%s:%s", registration.Name, registration.UUID))
} else {
// Make authorization from a robot account with 30 minutes
authorization, rID, err = bc.makeBasicAuthorization(artifact.NamespaceID, artifact.Repository, 1800)
}
if err != nil { if err != nil {
return "", errors.Wrap(err, "scan controller: launch scan job") return "", errors.Wrap(err, "scan controller: launch scan job")
} }
@ -404,7 +432,7 @@ func (bc *basicController) launchScanJob(trackID string, artifact *v1.Artifact,
// Set job parameters // Set job parameters
scanReq := &v1.ScanRequest{ scanReq := &v1.ScanRequest{
Registry: &v1.Registry{ Registry: &v1.Registry{
URL: externalURL, URL: registryAddr,
Authorization: authorization, Authorization: authorization,
}, },
Artifact: artifact, Artifact: artifact,
@ -424,7 +452,9 @@ func (bc *basicController) launchScanJob(trackID string, artifact *v1.Artifact,
params[sca.JobParamRegistration] = rJSON params[sca.JobParamRegistration] = rJSON
params[sca.JobParameterRequest] = sJSON params[sca.JobParameterRequest] = sJSON
params[sca.JobParameterMimes] = mimes params[sca.JobParameterMimes] = mimes
params[sca.JobParameterRobotID] = rID if rID > 0 {
params[sca.JobParameterRobotID] = rID
}
// Launch job // Launch job
callbackURL, err := bc.config(configCoreInternalAddr) callbackURL, err := bc.config(configCoreInternalAddr)
@ -444,3 +474,21 @@ func (bc *basicController) launchScanJob(trackID string, artifact *v1.Artifact,
return bc.jc().SubmitJob(j) return bc.jc().SubmitJob(j)
} }
// makeBearerAuthorization make a authorization with bearer token
func makeBearerAuthorization(repository string, username string) (string, error) {
access := []*tk.ResourceActions{
{
Type: "repository",
Name: repository,
Actions: []string{"pull"},
},
}
accessToken, err := token.MakeToken(username, token.Registry, access)
if err != nil {
return "", errors.Wrap(err, "make bearer authorization")
}
return fmt.Sprintf("Bearer %s", accessToken.Token), nil
}

View File

@ -118,7 +118,11 @@ func (bc *basicController) UpdateRegistration(registration *scanner.Registration
// SetDefaultRegistration ... // SetDefaultRegistration ...
func (bc *basicController) DeleteRegistration(registrationUUID string) (*scanner.Registration, error) { func (bc *basicController) DeleteRegistration(registrationUUID string) (*scanner.Registration, error) {
registration, err := bc.manager.Get(registrationUUID) registration, err := bc.manager.Get(registrationUUID)
if registration == nil && err == nil { if err != nil {
return nil, errors.Wrap(err, "api controller: delete registration")
}
if registration == nil {
// Not found // Not found
return nil, nil return nil, nil
} }

View File

@ -47,6 +47,12 @@ type Registration struct {
// Http connection settings // Http connection settings
SkipCertVerify bool `orm:"column(skip_cert_verify);default(false)" json:"skip_certVerify"` SkipCertVerify bool `orm:"column(skip_cert_verify);default(false)" json:"skip_certVerify"`
// Indicate whether use internal registry addr for the scanner to pull content
UseInternalAddr bool `orm:"column(use_internal_addr);default(false)" json:"use_internal_addr"`
// Indicate if the registration is immutable which is not allowed to remove
Immutable bool `orm:"column(immutable);default(false)" json:"-"`
// Timestamps // Timestamps
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"` CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"` UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`