Skip to content

Commit

Permalink
add local file saving and reading
Browse files Browse the repository at this point in the history
  • Loading branch information
bwagner5 committed Jan 27, 2023
1 parent 9814c64 commit 3ac6d63
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 13 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ Examples:
Flags:
-a, --api string API maps to EventName within CloudTrail Examples are DescribeInstances, TerminateInstances, etc
-c, --call-source string CallSource maps to SourceIP in CloudTrail but AWS services will include a named source IP like eks.amazonaws.com or autoscaling.amazonaws.com
-e, --end-time string End time for event filtering. Default: 30m ago (default "2023-01-26T14:28:12-06:00")
-e, --end-time string End time for event filtering. Default: 30m ago (default "2023-01-27T17:32:20Z")
--event-source string EventSource is the top-level service where the API call is made from (i.e. ec2.amazonaws.com)
-f, --file string File of json cloudtrail events to process
-h, --help help for aca
-i, --identity-user-name string IdentityUserName is included in the CloudTrailEvent.userIdentity.sessionContext.sessionIssuer.userName and is useful to scope the filtering to a specific instance of an application making API calls
-o, --output string Output (json|chart) Default: json (default "json")
-o, --output string Output (json|chart|stats) Default: json (default "json")
-r, --region string AWS Region
-s, --start-time string Start time for event filtering. Default: now (default "2023-01-26T13:58:12-06:00")
--save string Save filtered json events to a file. Default: a temp directory
-s, --start-time string Start time for event filtering. Default: now (default "2023-01-27T17:02:20Z")
-u, --user-agent string UserAgent partial will check if the passed string is contained within the user-agent field
-v, --version Verison information
```

## Installation
Expand Down
72 changes: 62 additions & 10 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"os"
"sort"
Expand Down Expand Up @@ -58,6 +59,10 @@ type Options struct {
Version bool
// Output json or chart
Output string
// File of json cloudtrail events to process rather than calling the cloudtrail API
File string
// Save will output the filtered json events to a file for further processing or inspection
Save string
}

var (
Expand Down Expand Up @@ -135,13 +140,53 @@ var rootCmd = &cobra.Command{
fmt.Printf("Commit: %s\n", commit)
return
}
total, events, err := filterEvents(cmd.Context(), processOpts(opts))
if err != nil {
log.Fatalln(err.Error())
var events []*CloudTrailEvent
var total int
var err error

// Process events from a local file
if opts.File != "" {
file, err := os.Open(opts.File)
if err != nil {
log.Fatalf("failed reading file: %s", err)
}
defer file.Close()
eventData, err := io.ReadAll(file)
if err != nil {
log.Fatalf("unable to read json events from file %s: %v", opts.File, err)
}
if err := json.Unmarshal(eventData, &events); err != nil {
log.Fatalf("unable to parse json events from file %s: %v", opts.File, err)
}
total = len(events)
} else { // Process events from the CloudTrail API
total, events, err = filterEvents(cmd.Context(), processOpts(opts))
if err != nil {
log.Fatalln(err.Error())
}
if len(events) == 0 {
log.Printf("All %d events did not match your filters\n", total)
os.Exit(1)
}
}

var outputFile *os.File
if opts.Save == "" {
outputFile, err = os.CreateTemp("", "aca")
if err != nil {
log.Printf("unable to open temp file, in dir %s, to output events: %v\n", os.TempDir(), err)
}
} else {
outputFile, err = os.Create(opts.Save)
if err != nil {
log.Printf("unable to open temp file (%s) to output events: %v\n", opts.Save, err)
}
}
if len(events) == 0 {
log.Printf("All %d events did not match your filters\n", total)
os.Exit(1)

if err := writeEvents(events, outputFile); err != nil {
log.Printf("unable to write events to file %s: %v\n", outputFile.Name(), err)
} else {
log.Printf("wrote events to file %s\n", outputFile.Name())
}

log.Printf("Filtered to %d events out of %d. The last event's timestamp is %s and the endtime filter was %s\n",
Expand All @@ -152,14 +197,17 @@ var rootCmd = &cobra.Command{
stats := computeStats(events)
outputStatsChart(stats)
} else {
outputJSON(events)
fmt.Println(asJSON(events))
}
},
}

func main() {
rootCmd.PersistentFlags().StringVarP(&opts.Region, "region", "r", "", "AWS Region")
rootCmd.PersistentFlags().StringVarP(&opts.Output, "output", "o", "json", "Output (json|chart|stats) Default: json")
rootCmd.PersistentFlags().BoolVarP(&opts.Version, "version", "v", false, "Version information")
rootCmd.PersistentFlags().StringVarP(&opts.File, "file", "f", "", "File of json cloudtrail events to process")
rootCmd.PersistentFlags().StringVar(&opts.Save, "save", "", "Save filtered json events to a file. Default: a temp directory")

rootCmd.PersistentFlags().StringVarP(&opts.CallSource, "call-source", "c", "", "CallSource maps to SourceIP in CloudTrail but AWS services will include a named source IP like eks.amazonaws.com or autoscaling.amazonaws.com")
rootCmd.PersistentFlags().StringVar(&opts.EventSource, "event-source", "", "EventSource is the top-level service where the API call is made from (i.e. ec2.amazonaws.com)")
Expand Down Expand Up @@ -274,13 +322,12 @@ func filterEvents(ctx context.Context, opts *Options) (int, []*CloudTrailEvent,
return rawEvents, filteredEvents, nil
}

func outputJSON(events []*CloudTrailEvent) {
log.Printf("Found %d events\n", len(events))
func asJSON(events []*CloudTrailEvent) string {
eventsJSON, err := json.MarshalIndent(events, "", " ")
if err != nil {
log.Fatalf(err.Error())
}
fmt.Println(string(eventsJSON))
return string(eventsJSON)
}

func outputChart(events []*CloudTrailEvent) {
Expand Down Expand Up @@ -361,3 +408,8 @@ func outputStatsChart(stats []*Stat) {
table.SetFooter([]string{"", "TOTAL", strconv.Itoa(totalCalls)})
table.Render()
}

func writeEvents(events []*CloudTrailEvent, file *os.File) error {
_, err := file.WriteString(asJSON(events))
return err
}

0 comments on commit 3ac6d63

Please sign in to comment.