Skip to content

Commit

Permalink
Merge branch 'v3' into no-nil-credential-store
Browse files Browse the repository at this point in the history
  • Loading branch information
alesstimec authored Jan 10, 2025
2 parents 93a8374 + d4a3f3d commit 096e396
Show file tree
Hide file tree
Showing 21 changed files with 651 additions and 487 deletions.
36 changes: 17 additions & 19 deletions cmd/jimmsrv/service/service.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 Canonical.
// Copyright 2025 Canonical.

// service defines the methods necessary to start a JIMM server
// alongside all the config options that can be supplied to configure JIMM.
Expand Down Expand Up @@ -201,8 +201,7 @@ type Service struct {
jimm *jimm.JIMM
jwkService *jimmjwx.JWKSService

isLeader bool
auditLogCleanupPeriod int
isLeader bool

mux *chi.Mux
cleanups []func() error
Expand Down Expand Up @@ -314,6 +313,17 @@ func NewService(ctx context.Context, p Params) (*Service, error) {
jimmParameters.UUID = uuid.NewString()
}

if p.AuditLogRetentionPeriodInDays != "" {
retentionPeriod, err := strconv.Atoi(p.AuditLogRetentionPeriodInDays)
if err != nil {
return nil, errors.E(op, "failed to parse audit log retention period")
}
if retentionPeriod < 0 {
return nil, errors.E(op, "retention period cannot be less than 0")
}
jimmParameters.AuditLogRetentionDays = retentionPeriod
}

if p.DSN == "" {
return nil, errors.E(op, "missing DSN")
}
Expand Down Expand Up @@ -486,16 +496,6 @@ func NewService(ctx context.Context, p Params) (*Service, error) {
jimmhttp.NewHTTPProxyHandler(s.jimm),
)

if p.AuditLogRetentionPeriodInDays != "" {
var err error
s.auditLogCleanupPeriod, err = strconv.Atoi(p.AuditLogRetentionPeriodInDays)
if err != nil {
return nil, errors.E(op, "failed to parse audit log retention period")
}
if s.auditLogCleanupPeriod < 0 {
return nil, errors.E(op, "retention period cannot be less than 0")
}
}
s.isLeader = p.IsLeader

return s, nil
Expand All @@ -505,12 +505,10 @@ func (s *Service) StartServices(ctx context.Context, svc *service.Service) {
// on the leader unit we start additional routines
if s.isLeader {
// audit log cleanup routine
if s.auditLogCleanupPeriod != 0 {
svc.Go(func() error {
jimm.NewAuditLogCleanupService(s.jimm.Database, s.auditLogCleanupPeriod).Start(ctx)
return nil
})
}
svc.Go(func() error {
s.jimm.AuditLogManager().StartCleanup(ctx)
return nil
})

// the JWKS rotator
svc.Go(func() error {
Expand Down
201 changes: 0 additions & 201 deletions internal/jimm/audit_log.go

This file was deleted.

110 changes: 110 additions & 0 deletions internal/jimm/auditlog/auditlog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2025 Canonical.

// The auditlog package provides business logic for handling audit log related methods.
package auditlog

import (
"context"
"strings"
"time"

"github.com/juju/names/v5"
"github.com/juju/zaputil/zapctx"
"go.uber.org/zap"

"github.com/canonical/jimm/v3/internal/db"
"github.com/canonical/jimm/v3/internal/dbmodel"
"github.com/canonical/jimm/v3/internal/errors"
"github.com/canonical/jimm/v3/internal/openfga"
ofganames "github.com/canonical/jimm/v3/internal/openfga/names"
)

// auditLogManager provides a means to manage audit logs within JIMM.
type auditLogManager struct {
store *db.Database
authSvc *openfga.OFGAClient
jimmTag names.ControllerTag
retentionPeriodInDays int
}

// NewAuditLogManager returns a new auditLog manager that provides audit Log
// creation, and removal.
func NewAuditLogManager(store *db.Database, authSvc *openfga.OFGAClient, jimmTag names.ControllerTag, retentionDays int) (*auditLogManager, error) {
if store == nil {
return nil, errors.E("auditlog store cannot be nil")
}
if authSvc == nil {
return nil, errors.E("auditlog authorisation service cannot be nil")
}
if jimmTag.String() == "" {
return nil, errors.E("auditlog jimm tag cannot be empty")
}
return &auditLogManager{store, authSvc, jimmTag, retentionDays}, nil
}

// addAuditLogEntry causes an entry to be added the the audit log.
func (j *auditLogManager) AddAuditLogEntry(ale *dbmodel.AuditLogEntry) {
ctx := context.Background()
redactSensitiveParams(ale)
if err := j.store.AddAuditLogEntry(ctx, ale); err != nil {
zapctx.Error(ctx, "cannot store audit log entry", zap.Error(err), zap.Any("entry", *ale))
}
}

var sensitiveMethods = map[string]struct{}{
"login": {},
"logindevice": {},
"getdevicesessiontoken": {},
"loginwithsessiontoken": {},
"addcredentials": {},
"updatecredentials": {}}
var redactJSON = dbmodel.JSON(`{"params":"redacted"}`)

func redactSensitiveParams(ale *dbmodel.AuditLogEntry) {
if ale.Params == nil {
return
}
method := strings.ToLower(ale.FacadeMethod)
if _, ok := sensitiveMethods[method]; ok {
newRedactMessage := make(dbmodel.JSON, len(redactJSON))
copy(newRedactMessage, redactJSON)
ale.Params = newRedactMessage
}
}

// FindAuditEvents returns audit events matching the given filter.
func (j *auditLogManager) FindAuditEvents(ctx context.Context, user *openfga.User, filter db.AuditLogFilter) ([]dbmodel.AuditLogEntry, error) {
const op = errors.Op("jimm.FindAuditEvents")

access := user.GetAuditLogViewerAccess(ctx, j.jimmTag)
if access != ofganames.AuditLogViewerRelation {
return nil, errors.E(op, errors.CodeUnauthorized, "unauthorized")
}

var entries []dbmodel.AuditLogEntry
err := j.store.ForEachAuditLogEntry(ctx, filter, func(entry *dbmodel.AuditLogEntry) error {
entries = append(entries, *entry)
return nil
})
if err != nil {
return nil, errors.E(op, err)
}

return entries, nil
}

// PurgeLogs removes all audit logs before the given timestamp. Only JIMM
// administrators can perform this operation. The number of logs purged is
// returned.
func (j *auditLogManager) PurgeLogs(ctx context.Context, user *openfga.User, before time.Time) (int64, error) {
op := errors.Op("jimm.PurgeLogs")
if !user.JimmAdmin {
return 0, errors.E(op, errors.CodeUnauthorized, "unauthorized")
}
count, err := j.store.DeleteAuditLogsBefore(ctx, before)
if err != nil {
zapctx.Error(ctx, "failed to purge logs", zap.Error(err))
return 0, errors.E(op, "failed to purge logs", err)
}
return count, nil
}
Loading

0 comments on commit 096e396

Please sign in to comment.