Skip to content

Commit

Permalink
Add upload event struct and log execution events (#35)
Browse files Browse the repository at this point in the history
* add new santa event upload and request types

* use new type and log upload events to stdout

* remove deprecated use of ioutil

* update go mod

* bump circleci config to go 1.20

---------

Co-authored-by: Brandon Friess <[email protected]>
  • Loading branch information
bfreezy and brandonfriess-stripe authored Dec 20, 2023
1 parent 7b53542 commit cdf7c51
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 34 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: 2
jobs:
build-go1.11:
build-go1.20:
docker:
- image: golang:1.11
- image: golang:1.20

working_directory: /go/src/github.com/groob/moroz
steps:
Expand All @@ -15,5 +15,5 @@ workflows:
version: 2
build:
jobs:
- build-go1.11
- build-go1.20

1 change: 1 addition & 0 deletions configs/global.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ client_mode = "MONITOR"
# blocked_path_regex = "^(?:/Users)/.*"
# allowed_path_regex = "^(?:/Users)/.*"
batch_size = 100
enable_all_event_upload = true
enable_bundles = false
enable_transitive_rules = true
clean_sync = true
Expand Down
13 changes: 9 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
module github.com/groob/moroz

go 1.20

require (
github.com/BurntSushi/toml v0.2.0
github.com/go-kit/kit v0.4.0
github.com/go-logfmt/logfmt v0.3.0 // indirect
github.com/go-stack/stack v1.7.0 // indirect
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect
github.com/gorilla/mux v1.6.1
github.com/kolide/kit v0.0.0-20180912215818-0c28f72eb2b0
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
github.com/oklog/run v1.0.0
github.com/pkg/errors v0.8.0
)

require (
github.com/go-logfmt/logfmt v0.3.0 // indirect
github.com/go-stack/stack v1.7.0 // indirect
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
golang.org/x/net v0.0.0-20180124060956-0ed95abb35c4 // indirect
)
36 changes: 20 additions & 16 deletions moroz/svc_upload_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
Expand All @@ -25,7 +24,13 @@ func (svc *SantaService) UploadEvent(ctx context.Context, machineID string, even
}

eventPath := filepath.Join(eventDir, fmt.Sprintf("%f.json", ev.UnixTime))
if err := ioutil.WriteFile(eventPath, ev.Content, 0644); err != nil {

eventInfoJSON, err := json.Marshal(ev.EventInfo)
if err != nil {
return errors.Wrap(err, "marshal event info to json")
}

if err := os.WriteFile(eventPath, eventInfoJSON, 0644); err != nil {
return errors.Wrapf(err, "write event to path %s", eventPath)
}
}
Expand Down Expand Up @@ -65,9 +70,7 @@ func decodeEventUpload(ctx context.Context, r *http.Request) (interface{}, error
}

// decode the JSON into individual log events.
var eventPayload = struct {
Events []json.RawMessage `json:"events"`
}{}
var eventPayload santa.EventUploadRequest

if err := json.NewDecoder(zr).Decode(&eventPayload); err != nil {
return nil, errors.Wrap(err, "decoding event upload request json")
Expand All @@ -76,10 +79,9 @@ func decodeEventUpload(ctx context.Context, r *http.Request) (interface{}, error
var events []santa.EventPayload
for _, ev := range eventPayload.Events {
var payload santa.EventPayload
if err := json.Unmarshal(ev, &payload); err != nil {
return nil, errors.Wrap(err, "decoding file sha from event upload json")
}
payload.Content = ev
payload.EventInfo = ev
payload.FileSHA = ev.FileSHA256
payload.UnixTime = ev.ExecutionTime
events = append(events, payload)
}

Expand All @@ -89,13 +91,15 @@ func decodeEventUpload(ctx context.Context, r *http.Request) (interface{}, error

func (mw logmw) UploadEvent(ctx context.Context, machineID string, events []santa.EventPayload) (err error) {
defer func(begin time.Time) {
_ = mw.logger.Log(
"method", "UploadEvent",
"machine_id", machineID,
"event_count", len(events),
"err", err,
"took", time.Since(begin),
)
for _, ev := range events {
_ = mw.logger.Log(
"method", "UploadEvent",
"machine_id", machineID,
"event", ev.EventInfo,
"err", err,
"took", time.Since(begin),
)
}
}(time.Now())

err = mw.next.UploadEvent(ctx, machineID, events)
Expand Down
57 changes: 51 additions & 6 deletions santa/santa.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
package santa

import (
"encoding/json"

"github.com/pkg/errors"
)

Expand All @@ -24,12 +22,13 @@ type Rule struct {
CustomMessage string `json:"custom_msg,omitempty" toml:"custom_msg,omitempty"`
}

// Preflight representssync response sent to a Santa client by the sync server.
// Preflight represents sync response sent to a Santa client by the sync server.
type Preflight struct {
ClientMode ClientMode `json:"client_mode" toml:"client_mode"`
BlockedPathRegex string `json:"blocked_path_regex" toml:"blocked_path_regex"`
AllowedPathRegex string `json:"allowed_path_regex" toml:"allowed_path_regex"`
BatchSize int `json:"batch_size" toml:"batch_size"`
EnableAllEventUpload bool `json:"enable_all_event_upload" toml:"enable_all_event_upload"`
EnableBundles bool `json:"enable_bundles" toml:"enable_bundles"`
EnableTransitiveRules bool `json:"enable_transitive_rules" toml:"enable_transitive_rules"`
CleanSync bool `json:"clean_sync" toml:"clean_sync"`
Expand All @@ -51,9 +50,55 @@ type PreflightPayload struct {

// EventPayload represents derived metadata for events uploaded with the UploadEvent endpoint.
type EventPayload struct {
FileSHA string `json:"file_sha256"`
UnixTime float64 `json:"execution_time"`
Content json.RawMessage `json:"-"`
FileSHA string `json:"file_sha256"`
UnixTime float64 `json:"execution_time"`
EventInfo EventUploadEvent
}

// EventUploadRequest encapsulation of an /eventupload POST body sent by a Santa client
type EventUploadRequest struct {
Events []EventUploadEvent `json:"events"`
}

// EventUploadEvent is a single event entry
type EventUploadEvent struct {
CurrentSessions []string `json:"current_sessions"`
Decision string `json:"decision"`
ExecutingUser string `json:"executing_user"`
ExecutionTime float64 `json:"execution_time"`
FileBundleBinaryCount int64 `json:"file_bundle_binary_count"`
FileBundleExecutableRelPath string `json:"file_bundle_executable_rel_path"`
FileBundleHash string `json:"file_bundle_hash"`
FileBundleHashMilliseconds float64 `json:"file_bundle_hash_millis"`
FileBundleID string `json:"file_bundle_id"`
FileBundleName string `json:"file_bundle_name"`
FileBundlePath string `json:"file_bundle_path"`
FileBundleShortVersionString string `json:"file_bundle_version_string"`
FileBundleVersion string `json:"file_bundle_version"`
FileName string `json:"file_name"`
FilePath string `json:"file_path"`
FileSHA256 string `json:"file_sha256"`
LoggedInUsers []string `json:"logged_in_users"`
ParentName string `json:"parent_name"`
ParentProcessID int `json:"ppid"`
ProcessID int `json:"pid"`
QuarantineAgentBundleID string `json:"quarantine_agent_bundle_id"`
QuarantineDataUrl string `json:"quarantine_data_url"`
QuarantineRefererUrl string `json:"quarantine_referer_url"`
QuarantineTimestamp float64 `json:"quarantine_timestamp"`
SigningChain []SigningEntry `json:"signing_chain"`
SigningID string `json:"signing_id"`
TeamID string `json:"team_id"`
}

// SigningEntry is optionally present when an event includes a binary that is signed
type SigningEntry struct {
CertificateName string `json:"cn"`
Organization string `json:"org"`
OrganizationalUnit string `json:"ou"`
SHA256 string `json:"sha256"`
ValidFrom int `json:"valid_from"`
ValidUntil int `json:"valid_until"`
}

// RuleType represents a Santa rule type.
Expand Down
5 changes: 2 additions & 3 deletions santa/santa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package santa

import (
"bytes"
"io/ioutil"
"os"
"testing"

Expand Down Expand Up @@ -64,7 +63,7 @@ func TestConfigMarshalUnmarshal(t *testing.T) {
func testConfig(t *testing.T, path string, replace bool) Config {
t.Helper()

file, err := ioutil.ReadFile(path)
file, err := os.ReadFile(path)
if err != nil {
t.Fatalf("loading config from path %q, err = %q\n", path, err)
}
Expand All @@ -80,7 +79,7 @@ func testConfig(t *testing.T, path string, replace bool) Config {
}

if replace {
if err := ioutil.WriteFile(path, buf.Bytes(), os.ModePerm); err != nil {
if err := os.WriteFile(path, buf.Bytes(), os.ModePerm); err != nil {
t.Fatalf("replace config at path %q, err = %q\n", path, err)
}
return testConfig(t, path, false)
Expand Down
1 change: 1 addition & 0 deletions santa/testdata/config_a_toml.golden
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ client_mode = "LOCKDOWN"
blocked_path_regex = "^(?:/Users)/.*"
allowed_path_regex = "^(?:/Users)/.*"
batch_size = 100
enable_all_event_upload = true
enable_bundles = false
enable_transitive_rules = true
clean_sync = true
Expand Down
3 changes: 1 addition & 2 deletions santaconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package santaconfig

import (
"context"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -72,7 +71,7 @@ func loadConfigs(path string) ([]santa.Config, error) {
if filepath.Ext(info.Name()) != ".toml" {
return nil
}
file, err := ioutil.ReadFile(path)
file, err := os.ReadFile(path)
if err != nil {
return err
}
Expand Down

0 comments on commit cdf7c51

Please sign in to comment.