Skip to content

Commit

Permalink
Add user login event to audit log
Browse files Browse the repository at this point in the history
  Add common event handler
  Register login event
  Update previous audit log event redirect to auditlogext table

Signed-off-by: stonezdj <[email protected]>
  • Loading branch information
stonezdj committed Jan 16, 2025
1 parent 60798a4 commit 1df7492
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 88 deletions.
16 changes: 9 additions & 7 deletions src/controller/event/handler/auditlog/auditlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ package auditlog

import (
"context"
"fmt"

"github.com/goharbor/harbor/src/controller/event"
evtModel "github.com/goharbor/harbor/src/controller/event/model"
"github.com/goharbor/harbor/src/lib/config"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/audit"
am "github.com/goharbor/harbor/src/pkg/audit/model"
"github.com/goharbor/harbor/src/pkg/auditext"
am "github.com/goharbor/harbor/src/pkg/auditext/model"
)

// Handler - audit log handler
Expand All @@ -30,7 +32,7 @@ type Handler struct {

// AuditResolver - interface to resolve to AuditLog
type AuditResolver interface {
ResolveToAuditLog() (*am.AuditLog, error)
ResolveToAuditLog() (*am.AuditLogExt, error)
}

// Name ...
Expand All @@ -40,13 +42,13 @@ func (h *Handler) Name() string {

// Handle ...
func (h *Handler) Handle(ctx context.Context, value interface{}) error {
var auditLog *am.AuditLog
var auditLog *am.AuditLogExt
var addAuditLog bool
switch v := value.(type) {
case *event.PushArtifactEvent, *event.DeleteArtifactEvent,
*event.DeleteRepositoryEvent, *event.CreateProjectEvent, *event.DeleteProjectEvent,
*event.DeleteTagEvent, *event.CreateTagEvent,
*event.CreateRobotEvent, *event.DeleteRobotEvent:
*event.CreateRobotEvent, *event.DeleteRobotEvent, *evtModel.CommonEvent:
addAuditLog = true
case *event.PullArtifactEvent:
addAuditLog = !config.PullAuditLogDisable(ctx)
Expand All @@ -62,8 +64,8 @@ func (h *Handler) Handle(ctx context.Context, value interface{}) error {
return err
}
auditLog = al
if auditLog != nil {
_, err := audit.Mgr.Create(ctx, auditLog)
if auditLog != nil && config.AuditLogEventEnabled(ctx, fmt.Sprintf("%v_%v", auditLog.Operation, auditLog.ResourceType)) {
_, err := auditext.Mgr.Create(ctx, auditLog)
if err != nil {
log.Debugf("add audit log err: %v", err)
}
Expand Down
1 change: 1 addition & 0 deletions src/controller/event/handler/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func init() {
_ = notifier.Subscribe(event.TopicDeleteTag, &auditlog.Handler{})
_ = notifier.Subscribe(event.TopicCreateRobot, &auditlog.Handler{})
_ = notifier.Subscribe(event.TopicDeleteRobot, &auditlog.Handler{})
_ = notifier.Subscribe(event.TopicCommonEvent, &auditlog.Handler{})

// internal
_ = notifier.Subscribe(event.TopicPullArtifact, &internal.ArtifactEventHandler{})
Expand Down
4 changes: 3 additions & 1 deletion src/controller/event/metadata/commonevent/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ type Metadata struct {
IPAddress string
// ResponseLocation response location
ResponseLocation string
// ResourceName
// ResourceName resource name
ResourceName string
// Payload request payload
Payload string
}

// Resolve parse the audit information from CommonEventMetadata
Expand Down
36 changes: 35 additions & 1 deletion src/controller/event/model/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@

package model

import "github.com/goharbor/harbor/src/pkg/retention/policy/rule"
import (
"time"

"github.com/goharbor/harbor/src/pkg/auditext/model"
"github.com/goharbor/harbor/src/pkg/retention/policy/rule"
)

// Replication describes replication infos
type Replication struct {
Expand Down Expand Up @@ -80,3 +85,32 @@ type Scan struct {
// ScanType the scan type
ScanType string `json:"scan_type,omitempty"`
}

// CommonEvent ...
type CommonEvent struct {
Operator string
ProjectID int64
OcurrAt time.Time
Operation string
Payload string
SourceIP string
ResourceType string
ResourceName string
OperationDescription string
OperationResult bool
}

// ResolveToAuditLog ...
func (c *CommonEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: c.ProjectID,
OpTime: c.OcurrAt,
Operation: c.Operation,
Username: c.Operator,
ResourceType: c.ResourceType,
Resource: c.ResourceName,
OperationDescription: c.OperationDescription,
OperationResult: c.OperationResult,
}
return auditLog, nil
}
178 changes: 99 additions & 79 deletions src/controller/event/topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/lib/selector"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/audit/model"
"github.com/goharbor/harbor/src/pkg/auditext/model"
proModels "github.com/goharbor/harbor/src/pkg/project/models"
robotModel "github.com/goharbor/harbor/src/pkg/robot/model"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
Expand Down Expand Up @@ -50,6 +50,7 @@ const (
TopicTagRetention = "TAG_RETENTION"
TopicCreateRobot = "CREATE_ROBOT"
TopicDeleteRobot = "DELETE_ROBOT"
TopicCommonEvent = "COMMON_API"
)

// CreateProjectEvent is the creating project event
Expand All @@ -62,14 +63,16 @@ type CreateProjectEvent struct {
}

// ResolveToAuditLog ...
func (c *CreateProjectEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: c.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "project",
Resource: c.Project}
func (c *CreateProjectEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: c.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "project",
OperationResult: true,
OperationDescription: fmt.Sprintf("create project: %s", c.Project),
Resource: c.Project}
return auditLog, nil
}

Expand All @@ -88,14 +91,16 @@ type DeleteProjectEvent struct {
}

// ResolveToAuditLog ...
func (d *DeleteProjectEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "project",
Resource: d.Project}
func (d *DeleteProjectEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: d.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "project",
OperationResult: true,
OperationDescription: fmt.Sprintf("delete project: %s", d.Project),
Resource: d.Project}
return auditLog, nil
}

Expand All @@ -114,14 +119,16 @@ type DeleteRepositoryEvent struct {
}

// ResolveToAuditLog ...
func (d *DeleteRepositoryEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "repository",
Resource: d.Repository,
func (d *DeleteRepositoryEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: d.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "repository",
OperationResult: true,
OperationDescription: fmt.Sprintf("delete repository: %s", d.Repository),
Resource: d.Repository,
}
return auditLog, nil
}
Expand Down Expand Up @@ -154,13 +161,15 @@ type PushArtifactEvent struct {
}

// ResolveToAuditLog ...
func (p *PushArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: p.Artifact.ProjectID,
OpTime: p.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: p.Operator,
ResourceType: "artifact"}
func (p *PushArtifactEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: p.Artifact.ProjectID,
OpTime: p.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: p.Operator,
OperationResult: true,
OperationDescription: fmt.Sprintf("push artifact: %s@%s", p.Artifact.RepositoryName, p.Artifact.Digest),
ResourceType: "artifact"}

if len(p.Tags) == 0 {
auditLog.Resource = fmt.Sprintf("%s@%s",
Expand All @@ -183,13 +192,15 @@ type PullArtifactEvent struct {
}

// ResolveToAuditLog ...
func (p *PullArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: p.Artifact.ProjectID,
OpTime: p.OccurAt,
Operation: rbac.ActionPull.String(),
Username: p.Operator,
ResourceType: "artifact"}
func (p *PullArtifactEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: p.Artifact.ProjectID,
OpTime: p.OccurAt,
Operation: rbac.ActionPull.String(),
Username: p.Operator,
OperationResult: true,
OperationDescription: fmt.Sprintf("pull artifact: %s@%s", p.Artifact.RepositoryName, p.Artifact.Digest),
ResourceType: "artifact"}

if len(p.Tags) == 0 {
auditLog.Resource = fmt.Sprintf("%s@%s",
Expand Down Expand Up @@ -219,14 +230,16 @@ type DeleteArtifactEvent struct {
}

// ResolveToAuditLog ...
func (d *DeleteArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.Artifact.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "artifact",
Resource: fmt.Sprintf("%s@%s", d.Artifact.RepositoryName, d.Artifact.Digest)}
func (d *DeleteArtifactEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: d.Artifact.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "artifact",
OperationResult: true,
OperationDescription: fmt.Sprintf("delete artifact: %s@%s", d.Artifact.RepositoryName, d.Artifact.Digest),
Resource: fmt.Sprintf("%s@%s", d.Artifact.RepositoryName, d.Artifact.Digest)}
return auditLog, nil
}

Expand All @@ -246,14 +259,16 @@ type CreateTagEvent struct {
}

// ResolveToAuditLog ...
func (c *CreateTagEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: c.AttachedArtifact.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "tag",
Resource: fmt.Sprintf("%s:%s", c.Repository, c.Tag)}
func (c *CreateTagEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: c.AttachedArtifact.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "tag",
OperationResult: true,
OperationDescription: fmt.Sprintf("create tag: %s:%s", c.Repository, c.Tag),
Resource: fmt.Sprintf("%s:%s", c.Repository, c.Tag)}
return auditLog, nil
}

Expand All @@ -275,14 +290,15 @@ type DeleteTagEvent struct {
}

// ResolveToAuditLog ...
func (d *DeleteTagEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: d.AttachedArtifact.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "tag",
Resource: fmt.Sprintf("%s:%s", d.Repository, d.Tag)}
func (d *DeleteTagEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: d.AttachedArtifact.ProjectID,
OpTime: d.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: d.Operator,
ResourceType: "tag",
OperationResult: true,
Resource: fmt.Sprintf("%s:%s", d.Repository, d.Tag)}
return auditLog, nil
}

Expand Down Expand Up @@ -385,14 +401,16 @@ type CreateRobotEvent struct {
}

// ResolveToAuditLog ...
func (c *CreateRobotEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: c.Robot.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "robot",
Resource: c.Robot.Name}
func (c *CreateRobotEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: c.Robot.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionCreate.String(),
Username: c.Operator,
ResourceType: "robot",
OperationResult: true,
OperationDescription: fmt.Sprintf("create robot: %s", c.Robot.Name),
Resource: c.Robot.Name}
return auditLog, nil
}

Expand All @@ -410,14 +428,16 @@ type DeleteRobotEvent struct {
}

// ResolveToAuditLog ...
func (c *DeleteRobotEvent) ResolveToAuditLog() (*model.AuditLog, error) {
auditLog := &model.AuditLog{
ProjectID: c.Robot.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: c.Operator,
ResourceType: "robot",
Resource: c.Robot.Name}
func (c *DeleteRobotEvent) ResolveToAuditLog() (*model.AuditLogExt, error) {
auditLog := &model.AuditLogExt{
ProjectID: c.Robot.ProjectID,
OpTime: c.OccurAt,
Operation: rbac.ActionDelete.String(),
Username: c.Operator,
ResourceType: "robot",
OperationResult: true,
OperationDescription: fmt.Sprintf("delete robot: %s", c.Robot.Name),
Resource: c.Robot.Name}
return auditLog, nil
}

Expand Down
1 change: 1 addition & 0 deletions src/core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import (
_ "github.com/goharbor/harbor/src/pkg/accessory/model/sbom"
_ "github.com/goharbor/harbor/src/pkg/accessory/model/subject"
"github.com/goharbor/harbor/src/pkg/audit"
_ "github.com/goharbor/harbor/src/pkg/auditext/event/login"
dbCfg "github.com/goharbor/harbor/src/pkg/config/db"
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
"github.com/goharbor/harbor/src/pkg/notification"
Expand Down
3 changes: 3 additions & 0 deletions src/lib/config/userconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ func BannerMessage(ctx context.Context) string {

// AuditLogEventEnabled returns the audit log enabled setting for a specific event_type, such as delete_user, create_user
func AuditLogEventEnabled(ctx context.Context, eventType string) bool {
if DefaultMgr() == nil || DefaultMgr().Get(ctx, common.AuditLogEventsDisabled) == nil {
return true
}
disableListStr := DefaultMgr().Get(ctx, common.AuditLogEventsDisabled).GetString()
disableList := strings.Split(disableListStr, ",")
for _, t := range disableList {
Expand Down
Loading

0 comments on commit 1df7492

Please sign in to comment.