diff --git a/internal/backend/runtime/omni/audit/audit.go b/internal/backend/runtime/omni/audit/audit.go new file mode 100644 index 00000000..a7de4b09 --- /dev/null +++ b/internal/backend/runtime/omni/audit/audit.go @@ -0,0 +1,21 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +// Package audit provides a state wrapper that logs audit events. +package audit + +import ( + "github.com/siderolabs/omni/internal/pkg/auth/role" +) + +// Data contains the audit data. +type Data struct { + UserAgent string `json:"user_agent,omitempty"` + IPAddress string `json:"ip_address,omitempty"` + UserID string `json:"user_id,omitempty"` + Identity string `json:"identity,omitempty"` + Role role.Role `json:"role,omitempty"` + Email string `json:"email,omitempty"` +} diff --git a/internal/backend/runtime/omni/audit/export_test.go b/internal/backend/runtime/omni/audit/export_test.go new file mode 100644 index 00000000..edf8f794 --- /dev/null +++ b/internal/backend/runtime/omni/audit/export_test.go @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +package audit + +import "time" + +func (l *LogFile) DumpAt(data any, at time.Time) error { + return l.dumpAt(data, at) +} diff --git a/internal/backend/runtime/omni/audit/log_file.go b/internal/backend/runtime/omni/audit/log_file.go new file mode 100644 index 00000000..4f94f9b7 --- /dev/null +++ b/internal/backend/runtime/omni/audit/log_file.go @@ -0,0 +1,106 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +package audit + +import ( + "bytes" + "encoding/json" + "os" + "path/filepath" + "sync" + "time" + + "github.com/siderolabs/gen/pair/ordered" + + "github.com/siderolabs/omni/internal/pkg/pool" +) + +// LogFile is a rotating log file. +// +//nolint:govet +type LogFile struct { + dir string + + mu sync.Mutex + f *os.File + lastWrite time.Time + + pool pool.Pool[bytes.Buffer] +} + +// NewLogFile creates a new rotating log file. +func NewLogFile(dir string) *LogFile { + return &LogFile{ + dir: dir, + pool: pool.Pool[bytes.Buffer]{ + New: func() *bytes.Buffer { + return &bytes.Buffer{} + }, + }, + } +} + +// Dump writes data to the log file, creating new one on demand. +func (l *LogFile) Dump(data any) error { + return l.dumpAt(data, time.Time{}) +} + +func (l *LogFile) dumpAt(data any, at time.Time) error { + b := l.pool.Get() + defer func() { b.Reset(); l.pool.Put(b) }() + + err := json.NewEncoder(b).Encode(data) + if err != nil { + return err + } + + l.mu.Lock() + defer l.mu.Unlock() + + if at.IsZero() { + at = time.Now() + } + + f, err := l.openFile(at) + if err != nil { + return err + } + + _, err = b.WriteTo(f) + if err != nil { + return err + } + + l.lastWrite = at + + return nil +} + +// openFile opens a file for the given date. It returns the file is date for at matches +// the last write date. Otherwise, it opens a new file. +func (l *LogFile) openFile(at time.Time) (*os.File, error) { + if l.f != nil && ordered.MakeTriple(at.Date()).Compare(ordered.MakeTriple(l.lastWrite.Date())) <= 0 { + return l.f, nil + } + + if l.f != nil { + // Ignore the error, we can't do anything about it anyway + l.f.Close() //nolint:errcheck + + l.f = nil + } + + logPath := filepath.Join(l.dir, at.Format("2006-01-02")) + ".jsonlog" + + f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) + if err != nil { + return nil, err + } + + l.f = f + + return f, nil +} diff --git a/internal/backend/runtime/omni/audit/log_file_test.go b/internal/backend/runtime/omni/audit/log_file_test.go new file mode 100644 index 00000000..493e4da9 --- /dev/null +++ b/internal/backend/runtime/omni/audit/log_file_test.go @@ -0,0 +1,163 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +package audit_test + +import ( + "embed" + "fmt" + "io/fs" + "os" + "path/filepath" + "slices" + "strings" + "testing" + "time" + + "github.com/siderolabs/gen/xtesting/must" + "github.com/stretchr/testify/require" + + "github.com/siderolabs/omni/internal/backend/runtime/omni/audit" +) + +//go:embed testdata/currentday +var currentDay embed.FS + +func TestLogFile_CurrentDay(t *testing.T) { + dir := must.Value(os.MkdirTemp("", "log_file_test"))(t) + + t.Cleanup(func() { os.RemoveAll(dir) }) //nolint:errcheck + + entries := []entry{ + {shift: time.Second, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: "10.10.0.1", Email: "random_email1@example.com"}}, + {shift: time.Minute, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: "10.10.0.2", Email: "random_email2@example.com"}}, + {shift: 30 * time.Minute, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: "10.10.0.3", Email: "random_email3@example.com"}}, + } + + start := time.Date(2012, 1, 1, 23, 0, 0, 0, time.Local) + now := start + file := audit.NewLogFile(dir) + + for _, e := range entries { + now = now.Add(e.shift) + + require.NoError(t, file.DumpAt(e.data, now)) + } + + checkFiles(t, basicLoader(dir), fsSub(t, currentDay, "currentday")) +} + +//go:embed testdata/nextday +var nextDay embed.FS + +func TestLogFile_CurrentAndNewDay(t *testing.T) { + dir := must.Value(os.MkdirTemp("", "log_file_test"))(t) + + t.Cleanup(func() { os.RemoveAll(dir) }) //nolint:errcheck + + entries := []entry{ + {shift: 0, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: "10.10.0.1", Email: "random_email1@example.com"}}, + {shift: 55 * time.Minute, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: "10.10.0.2", Email: "random_email2@example.com"}}, + {shift: 5 * time.Minute, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: "10.10.0.3", Email: "random_email3@example.com"}}, + } + + start := time.Date(2012, 1, 1, 23, 0, 0, 0, time.Local) + now := start + file := audit.NewLogFile(dir) + + for _, e := range entries { + now = now.Add(e.shift) + + require.NoError(t, file.DumpAt(e.data, now)) + } + + checkFiles(t, basicLoader(dir), fsSub(t, nextDay, "nextday")) +} + +//go:embed testdata/concurrent +var concurrent embed.FS + +func TestLogFile_CurrentDayConcurrent(t *testing.T) { + dir := must.Value(os.MkdirTemp("", "log_file_test"))(t) + + t.Cleanup(func() { os.RemoveAll(dir) }) //nolint:errcheck + + entries := make([]entry, 0, 250) + + for i := range 250 { + address := fmt.Sprintf("10.10.0.%d", i+1) + email := fmt.Sprintf("random_email_%d@example.com", i+1) + + entries = append(entries, entry{shift: time.Second, data: audit.Data{UserAgent: "Mozilla/5.0", IPAddress: address, Email: email}}) + } + + start := time.Date(2012, 1, 1, 23, 0, 0, 0, time.Local) + now := start + file := audit.NewLogFile(dir) + + t.Run("concurrent", func(t *testing.T) { + for _, e := range entries { + now = now.Add(e.shift) + nowCopy := now + + t.Run("", func(t *testing.T) { + t.Parallel() + + require.NoError(t, file.DumpAt(e.data, nowCopy)) + }) + } + }) + + checkFiles(t, sortedLoader(basicLoader(dir)), fsSub(t, concurrent, "concurrent")) +} + +//nolint:govet +type entry struct { + shift time.Duration + data audit.Data +} + +type subFS interface { + fs.ReadFileFS + fs.ReadDirFS +} + +func checkFiles(t *testing.T, loader fileLoader, expectedFS subFS) { + expectedFiles := must.Value(expectedFS.ReadDir("."))(t) + + for _, expectedFile := range expectedFiles { + if expectedFile.IsDir() { + t.Fatal("unexpected directory", expectedFile.Name()) + } + + expectedData := string(must.Value(expectedFS.ReadFile(expectedFile.Name()))(t)) + actualData := loader(t, expectedFile.Name()) + + require.Equal(t, expectedData, actualData, "file %s", expectedFile.Name()) + } +} + +func fsSub(t *testing.T, subFs subFS, folder string) subFS { + return must.Value(fs.Sub(subFs, filepath.Join("testdata", folder)))(t).(subFS) //nolint:forcetypeassert +} + +type fileLoader func(t *testing.T, filename string) string + +func basicLoader(dir string) func(t *testing.T, filename string) string { + return func(t *testing.T, filename string) string { + return string(must.Value(os.ReadFile(filepath.Join(dir, filename)))(t)) + } +} + +func sortedLoader(loader fileLoader) fileLoader { + return func(t *testing.T, filename string) string { + data := strings.TrimRight(loader(t, filename), "\n") + slc := strings.Split(data, "\n") + + slices.Sort(slc) + + return strings.Join(slc, "\n") + "\n" + } +} diff --git a/internal/backend/runtime/omni/audit/testdata/concurrent/2012-01-01.jsonlog b/internal/backend/runtime/omni/audit/testdata/concurrent/2012-01-01.jsonlog new file mode 100644 index 00000000..fcf365b1 --- /dev/null +++ b/internal/backend/runtime/omni/audit/testdata/concurrent/2012-01-01.jsonlog @@ -0,0 +1,250 @@ +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.1","email":"random_email_1@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.10","email":"random_email_10@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.100","email":"random_email_100@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.101","email":"random_email_101@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.102","email":"random_email_102@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.103","email":"random_email_103@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.104","email":"random_email_104@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.105","email":"random_email_105@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.106","email":"random_email_106@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.107","email":"random_email_107@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.108","email":"random_email_108@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.109","email":"random_email_109@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.11","email":"random_email_11@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.110","email":"random_email_110@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.111","email":"random_email_111@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.112","email":"random_email_112@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.113","email":"random_email_113@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.114","email":"random_email_114@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.115","email":"random_email_115@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.116","email":"random_email_116@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.117","email":"random_email_117@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.118","email":"random_email_118@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.119","email":"random_email_119@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.12","email":"random_email_12@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.120","email":"random_email_120@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.121","email":"random_email_121@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.122","email":"random_email_122@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.123","email":"random_email_123@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.124","email":"random_email_124@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.125","email":"random_email_125@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.126","email":"random_email_126@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.127","email":"random_email_127@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.128","email":"random_email_128@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.129","email":"random_email_129@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.13","email":"random_email_13@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.130","email":"random_email_130@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.131","email":"random_email_131@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.132","email":"random_email_132@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.133","email":"random_email_133@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.134","email":"random_email_134@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.135","email":"random_email_135@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.136","email":"random_email_136@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.137","email":"random_email_137@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.138","email":"random_email_138@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.139","email":"random_email_139@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.14","email":"random_email_14@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.140","email":"random_email_140@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.141","email":"random_email_141@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.142","email":"random_email_142@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.143","email":"random_email_143@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.144","email":"random_email_144@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.145","email":"random_email_145@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.146","email":"random_email_146@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.147","email":"random_email_147@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.148","email":"random_email_148@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.149","email":"random_email_149@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.15","email":"random_email_15@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.150","email":"random_email_150@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.151","email":"random_email_151@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.152","email":"random_email_152@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.153","email":"random_email_153@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.154","email":"random_email_154@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.155","email":"random_email_155@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.156","email":"random_email_156@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.157","email":"random_email_157@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.158","email":"random_email_158@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.159","email":"random_email_159@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.16","email":"random_email_16@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.160","email":"random_email_160@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.161","email":"random_email_161@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.162","email":"random_email_162@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.163","email":"random_email_163@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.164","email":"random_email_164@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.165","email":"random_email_165@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.166","email":"random_email_166@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.167","email":"random_email_167@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.168","email":"random_email_168@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.169","email":"random_email_169@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.17","email":"random_email_17@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.170","email":"random_email_170@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.171","email":"random_email_171@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.172","email":"random_email_172@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.173","email":"random_email_173@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.174","email":"random_email_174@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.175","email":"random_email_175@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.176","email":"random_email_176@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.177","email":"random_email_177@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.178","email":"random_email_178@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.179","email":"random_email_179@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.18","email":"random_email_18@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.180","email":"random_email_180@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.181","email":"random_email_181@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.182","email":"random_email_182@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.183","email":"random_email_183@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.184","email":"random_email_184@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.185","email":"random_email_185@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.186","email":"random_email_186@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.187","email":"random_email_187@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.188","email":"random_email_188@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.189","email":"random_email_189@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.19","email":"random_email_19@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.190","email":"random_email_190@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.191","email":"random_email_191@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.192","email":"random_email_192@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.193","email":"random_email_193@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.194","email":"random_email_194@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.195","email":"random_email_195@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.196","email":"random_email_196@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.197","email":"random_email_197@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.198","email":"random_email_198@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.199","email":"random_email_199@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.2","email":"random_email_2@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.20","email":"random_email_20@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.200","email":"random_email_200@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.201","email":"random_email_201@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.202","email":"random_email_202@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.203","email":"random_email_203@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.204","email":"random_email_204@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.205","email":"random_email_205@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.206","email":"random_email_206@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.207","email":"random_email_207@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.208","email":"random_email_208@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.209","email":"random_email_209@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.21","email":"random_email_21@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.210","email":"random_email_210@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.211","email":"random_email_211@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.212","email":"random_email_212@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.213","email":"random_email_213@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.214","email":"random_email_214@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.215","email":"random_email_215@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.216","email":"random_email_216@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.217","email":"random_email_217@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.218","email":"random_email_218@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.219","email":"random_email_219@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.22","email":"random_email_22@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.220","email":"random_email_220@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.221","email":"random_email_221@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.222","email":"random_email_222@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.223","email":"random_email_223@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.224","email":"random_email_224@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.225","email":"random_email_225@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.226","email":"random_email_226@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.227","email":"random_email_227@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.228","email":"random_email_228@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.229","email":"random_email_229@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.23","email":"random_email_23@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.230","email":"random_email_230@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.231","email":"random_email_231@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.232","email":"random_email_232@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.233","email":"random_email_233@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.234","email":"random_email_234@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.235","email":"random_email_235@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.236","email":"random_email_236@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.237","email":"random_email_237@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.238","email":"random_email_238@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.239","email":"random_email_239@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.24","email":"random_email_24@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.240","email":"random_email_240@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.241","email":"random_email_241@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.242","email":"random_email_242@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.243","email":"random_email_243@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.244","email":"random_email_244@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.245","email":"random_email_245@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.246","email":"random_email_246@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.247","email":"random_email_247@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.248","email":"random_email_248@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.249","email":"random_email_249@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.25","email":"random_email_25@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.250","email":"random_email_250@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.26","email":"random_email_26@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.27","email":"random_email_27@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.28","email":"random_email_28@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.29","email":"random_email_29@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.3","email":"random_email_3@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.30","email":"random_email_30@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.31","email":"random_email_31@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.32","email":"random_email_32@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.33","email":"random_email_33@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.34","email":"random_email_34@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.35","email":"random_email_35@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.36","email":"random_email_36@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.37","email":"random_email_37@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.38","email":"random_email_38@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.39","email":"random_email_39@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.4","email":"random_email_4@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.40","email":"random_email_40@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.41","email":"random_email_41@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.42","email":"random_email_42@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.43","email":"random_email_43@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.44","email":"random_email_44@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.45","email":"random_email_45@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.46","email":"random_email_46@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.47","email":"random_email_47@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.48","email":"random_email_48@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.49","email":"random_email_49@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.5","email":"random_email_5@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.50","email":"random_email_50@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.51","email":"random_email_51@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.52","email":"random_email_52@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.53","email":"random_email_53@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.54","email":"random_email_54@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.55","email":"random_email_55@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.56","email":"random_email_56@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.57","email":"random_email_57@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.58","email":"random_email_58@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.59","email":"random_email_59@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.6","email":"random_email_6@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.60","email":"random_email_60@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.61","email":"random_email_61@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.62","email":"random_email_62@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.63","email":"random_email_63@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.64","email":"random_email_64@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.65","email":"random_email_65@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.66","email":"random_email_66@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.67","email":"random_email_67@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.68","email":"random_email_68@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.69","email":"random_email_69@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.7","email":"random_email_7@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.70","email":"random_email_70@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.71","email":"random_email_71@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.72","email":"random_email_72@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.73","email":"random_email_73@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.74","email":"random_email_74@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.75","email":"random_email_75@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.76","email":"random_email_76@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.77","email":"random_email_77@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.78","email":"random_email_78@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.79","email":"random_email_79@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.8","email":"random_email_8@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.80","email":"random_email_80@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.81","email":"random_email_81@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.82","email":"random_email_82@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.83","email":"random_email_83@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.84","email":"random_email_84@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.85","email":"random_email_85@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.86","email":"random_email_86@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.87","email":"random_email_87@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.88","email":"random_email_88@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.89","email":"random_email_89@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.9","email":"random_email_9@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.90","email":"random_email_90@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.91","email":"random_email_91@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.92","email":"random_email_92@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.93","email":"random_email_93@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.94","email":"random_email_94@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.95","email":"random_email_95@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.96","email":"random_email_96@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.97","email":"random_email_97@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.98","email":"random_email_98@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.99","email":"random_email_99@example.com"} diff --git a/internal/backend/runtime/omni/audit/testdata/currentday/2012-01-01.jsonlog b/internal/backend/runtime/omni/audit/testdata/currentday/2012-01-01.jsonlog new file mode 100644 index 00000000..61cf3408 --- /dev/null +++ b/internal/backend/runtime/omni/audit/testdata/currentday/2012-01-01.jsonlog @@ -0,0 +1,3 @@ +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.1","email":"random_email1@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.2","email":"random_email2@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.3","email":"random_email3@example.com"} diff --git a/internal/backend/runtime/omni/audit/testdata/nextday/2012-01-01.jsonlog b/internal/backend/runtime/omni/audit/testdata/nextday/2012-01-01.jsonlog new file mode 100644 index 00000000..c67503c7 --- /dev/null +++ b/internal/backend/runtime/omni/audit/testdata/nextday/2012-01-01.jsonlog @@ -0,0 +1,2 @@ +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.1","email":"random_email1@example.com"} +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.2","email":"random_email2@example.com"} diff --git a/internal/backend/runtime/omni/audit/testdata/nextday/2012-01-02.jsonlog b/internal/backend/runtime/omni/audit/testdata/nextday/2012-01-02.jsonlog new file mode 100644 index 00000000..e416028b --- /dev/null +++ b/internal/backend/runtime/omni/audit/testdata/nextday/2012-01-02.jsonlog @@ -0,0 +1 @@ +{"user_agent":"Mozilla/5.0","ip_address":"10.10.0.3","email":"random_email3@example.com"} diff --git a/internal/backend/server.go b/internal/backend/server.go index e72ba4ef..dd1688db 100644 --- a/internal/backend/server.go +++ b/internal/backend/server.go @@ -352,13 +352,15 @@ func (s *Server) buildServerOptions() ([]grpc.ServerOption, error) { grpc_recovery.StreamServerInterceptor(recoveryOpt), } - unaryAuthInterceptors, streamAuthInterceptors, err := s.getAuthInterceptors() + authInterceptors, err := s.getAuthInterceptors() if err != nil { return nil, err } - unaryInterceptors = append(unaryInterceptors, unaryAuthInterceptors...) - streamInterceptors = append(streamInterceptors, streamAuthInterceptors...) + for _, authInterceptor := range authInterceptors { + unaryInterceptors = append(unaryInterceptors, authInterceptor.Unary()) + streamInterceptors = append(streamInterceptors, authInterceptor.Stream()) + } return []grpc.ServerOption{ grpc.MaxRecvMsgSize(constants.GRPCMaxMessageSize), @@ -368,48 +370,37 @@ func (s *Server) buildServerOptions() ([]grpc.ServerOption, error) { }, nil } -func (s *Server) getAuthInterceptors() ([]grpc.UnaryServerInterceptor, []grpc.StreamServerInterceptor, error) { - authEnabled := authres.Enabled(s.authConfig) - - authConfigInterceptor := interceptor.NewAuthConfig(authEnabled, s.logger) +type interceptorCreator interface { + Unary() grpc.UnaryServerInterceptor + Stream() grpc.StreamServerInterceptor +} - unaryInterceptors := []grpc.UnaryServerInterceptor{ - authConfigInterceptor.Unary(), - } +func (s *Server) getAuthInterceptors() ([]interceptorCreator, error) { + authEnabled := authres.Enabled(s.authConfig) - streamInterceptors := []grpc.StreamServerInterceptor{ - authConfigInterceptor.Stream(), - } + result := []interceptorCreator{interceptor.NewAuthConfig(authEnabled, s.logger)} if !authEnabled { - return unaryInterceptors, streamInterceptors, nil + return result, nil } // auth is enabled, add signature and jwt interceptors - signatureInterceptor := interceptor.NewSignature(s.authenticatorFunc(), s.logger) - - unaryInterceptors = append(unaryInterceptors, signatureInterceptor.Unary()) - streamInterceptors = append(streamInterceptors, signatureInterceptor.Stream()) + result = append(result, interceptor.NewSignature(s.authenticatorFunc(), s.logger)) switch { case s.authConfig.TypedSpec().Value.Auth0.Enabled: verifier, err := auth0.NewIDTokenVerifier(s.authConfig.TypedSpec().Value.GetAuth0().Domain) if err != nil { - return nil, nil, err + return nil, err } - jwtInterceptor := interceptor.NewJWT(verifier, s.logger) + result = append(result, interceptor.NewJWT(verifier, s.logger)) - unaryInterceptors = append(unaryInterceptors, jwtInterceptor.Unary()) - streamInterceptors = append(streamInterceptors, jwtInterceptor.Stream()) case s.authConfig.TypedSpec().Value.Saml.Enabled: - samlInterceptor := interceptor.NewSAML(s.omniRuntime.State(), s.logger) - - unaryInterceptors = append(unaryInterceptors, samlInterceptor.Unary()) - streamInterceptors = append(streamInterceptors, samlInterceptor.Stream()) + result = append(result, interceptor.NewSAML(s.omniRuntime.State(), s.logger)) } - return unaryInterceptors, streamInterceptors, nil + return result, nil } func (s *Server) authenticatorFunc() auth.AuthenticatorFunc { diff --git a/internal/pkg/auth/role/role.go b/internal/pkg/auth/role/role.go index 8efbc48f..90d50ef4 100644 --- a/internal/pkg/auth/role/role.go +++ b/internal/pkg/auth/role/role.go @@ -37,15 +37,15 @@ const ( var roles = []Role{None, Reader, Operator, Admin} -var indexes map[Role]int - -func init() { - indexes = make(map[Role]int, len(roles)) +var indexes = func() map[Role]int { + result := make(map[Role]int, len(roles)) for i, role := range roles { - indexes[role] = i + result[role] = i } -} + + return result +}() // Parse parses the role string. func Parse(role string) (Role, error) { diff --git a/internal/pkg/pool/pool.go b/internal/pkg/pool/pool.go new file mode 100644 index 00000000..b18bf84d --- /dev/null +++ b/internal/pkg/pool/pool.go @@ -0,0 +1,33 @@ +// Copyright (c) 2024 Sidero Labs, Inc. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. + +// Package pool provides a generic pool for a specific type. +package pool + +import "sync" + +// Pool is a generic pool for a specific type. +// The New field is a function that creates a new instance of the type. +// It should be set before calling Get. +// +//nolint:govet +type Pool[T any] struct { + New func() *T + + once sync.Once + pool sync.Pool +} + +// Get returns a new instance of the type from the pool. +func (p *Pool[T]) Get() *T { + p.once.Do(func() { p.pool.New = func() any { return p.New() } }) + + return p.pool.Get().(*T) //nolint:forcetypeassert +} + +// Put returns an instance of the type to the pool. +func (p *Pool[T]) Put(x *T) { + p.pool.Put(x) +}