-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from eko/added-audit-logs
Added audit logs
- Loading branch information
Showing
56 changed files
with
1,643 additions
and
454 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package audit | ||
|
||
import ( | ||
"context" | ||
lib_time "time" | ||
|
||
"github.com/eko/authz/backend/configs" | ||
"github.com/eko/authz/backend/internal/entity/manager" | ||
"github.com/eko/authz/backend/internal/entity/repository" | ||
"github.com/eko/authz/backend/internal/helper/time" | ||
"go.uber.org/fx" | ||
"golang.org/x/exp/slog" | ||
) | ||
|
||
type cleaner struct { | ||
logger *slog.Logger | ||
clock time.Clock | ||
statsManager manager.Stats | ||
cleanDelay lib_time.Duration | ||
daysToKeep int | ||
} | ||
|
||
func NewCleaner( | ||
cfg *configs.App, | ||
logger *slog.Logger, | ||
clock time.Clock, | ||
statsManager manager.Stats, | ||
) *cleaner { | ||
return &cleaner{ | ||
logger: logger, | ||
clock: clock, | ||
statsManager: statsManager, | ||
cleanDelay: cfg.StatsCleanDelay, | ||
daysToKeep: cfg.StatsCleanDaysToKeep, | ||
} | ||
} | ||
|
||
func RunCleaner(lc fx.Lifecycle, cleaner *cleaner) { | ||
ticker := lib_time.NewTicker(cleaner.cleanDelay) | ||
|
||
lc.Append(fx.Hook{ | ||
OnStart: func(context.Context) error { | ||
go func() { | ||
for range ticker.C { | ||
cleaner.logger.Info("Stats: cleaning stats older than 30 days") | ||
|
||
if err := cleaner.statsManager.GetRepository().DeleteByFields(map[string]repository.FieldValue{ | ||
"date": { | ||
Operator: "<=", | ||
Value: cleaner.clock.Now().AddDate(0, 0, -cleaner.daysToKeep), | ||
}, | ||
}); err != nil { | ||
cleaner.logger.Error("Stats: unable to clean stats", err) | ||
} | ||
} | ||
}() | ||
|
||
cleaner.logger.Info("Stats: cleaner started") | ||
|
||
return nil | ||
}, | ||
OnStop: func(_ context.Context) error { | ||
ticker.Stop() | ||
|
||
cleaner.logger.Info("Stats: cleaner stopped") | ||
|
||
return nil | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package audit | ||
|
||
import ( | ||
"go.uber.org/fx" | ||
) | ||
|
||
func FxModule() fx.Option { | ||
return fx.Module("audit", | ||
fx.Provide( | ||
NewCleaner, | ||
NewSubscriber, | ||
), | ||
fx.Invoke( | ||
RunCleaner, | ||
RunSubscriber, | ||
), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package audit | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/eko/authz/backend/configs" | ||
"github.com/eko/authz/backend/internal/entity/manager" | ||
"github.com/eko/authz/backend/internal/entity/model" | ||
"github.com/eko/authz/backend/internal/event" | ||
"github.com/eko/authz/backend/internal/helper/spooler" | ||
"go.uber.org/fx" | ||
"golang.org/x/exp/slog" | ||
) | ||
|
||
type subscriber struct { | ||
logger *slog.Logger | ||
dispatcher event.Dispatcher | ||
auditManager manager.Audit | ||
auditFlushDelay time.Duration | ||
} | ||
|
||
func NewSubscriber( | ||
cfg *configs.App, | ||
logger *slog.Logger, | ||
dispatcher event.Dispatcher, | ||
auditManager manager.Audit, | ||
) *subscriber { | ||
return &subscriber{ | ||
logger: logger, | ||
dispatcher: dispatcher, | ||
auditManager: auditManager, | ||
auditFlushDelay: cfg.AuditFlushDelay, | ||
} | ||
} | ||
|
||
func (s *subscriber) subscribeToChecks(lc fx.Lifecycle) { | ||
checkEventChan := s.dispatcher.Subscribe(event.EventTypeCheck) | ||
|
||
lc.Append(fx.Hook{ | ||
OnStart: func(context.Context) error { | ||
go s.handleCheckEvents(checkEventChan) | ||
|
||
s.logger.Info("Audit: subscribed to event dispatchers") | ||
|
||
return nil | ||
}, | ||
OnStop: func(_ context.Context) error { | ||
close(checkEventChan) | ||
|
||
s.logger.Info("Audit: subscription to event dispatcher stopped") | ||
|
||
return nil | ||
}, | ||
}) | ||
} | ||
|
||
func (s *subscriber) handleCheckEvents(eventChan chan *event.Event) { | ||
var spooler = spooler.New(func(values []*event.Event) { | ||
if len(values) == 0 { | ||
return | ||
} | ||
|
||
var audits = []*model.Audit{} | ||
var timestamp int64 | ||
|
||
for _, value := range values { | ||
timestamp = value.Timestamp | ||
|
||
checkEvent, ok := value.Data.(*event.CheckEvent) | ||
if !ok { | ||
continue | ||
} | ||
|
||
audit := &model.Audit{ | ||
Date: time.Unix(timestamp, 0), | ||
Principal: checkEvent.Principal, | ||
ResourceKind: checkEvent.ResourceKind, | ||
ResourceValue: checkEvent.ResourceValue, | ||
Action: checkEvent.Action, | ||
IsAllowed: checkEvent.IsAllowed, | ||
} | ||
|
||
if checkEvent.CompiledPilicy != nil { | ||
audit.PolicyID = checkEvent.CompiledPilicy.PolicyID | ||
} | ||
|
||
audits = append(audits, audit) | ||
} | ||
|
||
if err := s.auditManager.BatchAdd(audits); err != nil { | ||
s.logger.Error("Audit: unable to batch add audit events", err) | ||
} | ||
}, spooler.WithFlushInterval(s.auditFlushDelay)) | ||
|
||
for event := range eventChan { | ||
spooler.Add(event) | ||
} | ||
} | ||
|
||
func RunSubscriber(lc fx.Lifecycle, subscriber *subscriber) { | ||
subscriber.subscribeToChecks(lc) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package audit | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/eko/authz/backend/configs" | ||
"github.com/eko/authz/backend/internal/entity/manager" | ||
"github.com/eko/authz/backend/internal/event" | ||
"github.com/eko/authz/backend/internal/log" | ||
"github.com/golang/mock/gomock" | ||
"github.com/stretchr/testify/assert" | ||
"golang.org/x/exp/slog" | ||
) | ||
|
||
func TestNewSubscriber(t *testing.T) { | ||
// Given | ||
ctrl := gomock.NewController(t) | ||
|
||
cfg := &configs.App{ | ||
AuditFlushDelay: 10 * time.Millisecond, | ||
} | ||
|
||
logger := slog.New(log.NewNopHandler()) | ||
|
||
dispatcher := event.NewMockDispatcher(ctrl) | ||
|
||
auditManager := manager.NewMockAudit(ctrl) | ||
|
||
// When | ||
subscriberInstance := NewSubscriber(cfg, logger, dispatcher, auditManager) | ||
|
||
// Then | ||
assert := assert.New(t) | ||
|
||
assert.IsType(new(subscriber), subscriberInstance) | ||
|
||
assert.Equal(logger, subscriberInstance.logger) | ||
assert.Equal(dispatcher, subscriberInstance.dispatcher) | ||
assert.Equal(auditManager, subscriberInstance.auditManager) | ||
assert.Equal(cfg.AuditFlushDelay, subscriberInstance.auditFlushDelay) | ||
} | ||
|
||
func TestHandleCheckEvents(t *testing.T) { | ||
// Given | ||
ctrl := gomock.NewController(t) | ||
|
||
cfg := &configs.App{ | ||
AuditFlushDelay: 10 * time.Millisecond, | ||
} | ||
|
||
logger := slog.New(log.NewNopHandler()) | ||
|
||
dispatcher := event.NewMockDispatcher(ctrl) | ||
|
||
auditManager := manager.NewMockAudit(ctrl) | ||
auditManager.EXPECT().BatchAdd(gomock.Len(3)).Times(1) | ||
|
||
subscriber := NewSubscriber(cfg, logger, dispatcher, auditManager) | ||
|
||
eventChan := make(chan *event.Event, 1) | ||
|
||
// When - Then | ||
go subscriber.handleCheckEvents(eventChan) | ||
|
||
eventChan <- &event.Event{ | ||
Timestamp: 123456, | ||
Data: &event.CheckEvent{Principal: "user1", ResourceKind: "post", ResourceValue: "1", Action: "edit", IsAllowed: true}, | ||
} | ||
eventChan <- &event.Event{ | ||
Timestamp: 123456, | ||
Data: &event.CheckEvent{Principal: "user1", ResourceKind: "post", ResourceValue: "2", Action: "edit", IsAllowed: false}, | ||
} | ||
eventChan <- &event.Event{ | ||
Timestamp: 123457, | ||
Data: &event.CheckEvent{Principal: "user1", ResourceKind: "post", ResourceValue: "3", Action: "delete", IsAllowed: true}, | ||
} | ||
|
||
close(eventChan) | ||
|
||
// Wait 20ms to ensure the spool is triggered. | ||
<-time.After(20 * time.Millisecond) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.