@@ -14,6 +14,7 @@ import (
1414 "iter"
1515 "log/slog"
1616 "regexp"
17+ "strings"
1718 "sync"
1819)
1920
@@ -30,77 +31,93 @@ var ec2InstanceRegexp = sync.OnceValue(func() *regexp.Regexp {
3031 return regexp .MustCompile (`^arn:aws:sts::.*?:assumed-role/(?P<role>.*?)/(?P<host>i-([0-9a-f]{8}|[0-9a-f]{17}))$` )
3132})
3233
33- func decodeCloudTrail (r io.Reader ) iter.Seq2 [s3Record , error ] {
34- return func (yield func (s3Record , error ) bool ) {
34+ func decodeCloudTrail (r io.Reader ) iter.Seq2 [string , error ] {
35+ return func (yield func (string , error ) bool ) {
3536 gz , err := gzip .NewReader (r )
3637 if err != nil {
37- yield (s3Record {} , fmt .Errorf ("decode cloudtrail gzip: %w" , err ))
38+ yield ("" , fmt .Errorf ("decode cloudtrail gzip: %w" , err ))
3839 return
3940 }
4041 defer gz .Close () //nolint:errcheck
4142
4243 dec := json .NewDecoder (gz )
4344
4445 if t , err := dec .Token (); err != nil || t != json .Delim ('{' ) {
45- yield (s3Record {} , errors .New ("decode cloudtrail: expected '{' at start of JSON" ))
46+ yield ("" , errors .New ("decode cloudtrail: expected '{' at start of JSON" ))
4647 return
4748 }
4849 if t , err := dec .Token (); err != nil || t != "Records" {
49- yield (s3Record {} , errors .New ("decode cloudtrail: expected 'Records' key" ))
50+ yield ("" , errors .New ("decode cloudtrail: expected 'Records' key" ))
5051 return
5152 }
5253 if t , err := dec .Token (); err != nil || t != json .Delim ('[' ) {
53- yield (s3Record {} , errors .New ("decode cloudtrail: expected '[' at start of Records array" ))
54+ yield ("" , errors .New ("decode cloudtrail: expected '[' at start of Records array" ))
5455 return
5556 }
5657
5758 for dec .More () {
58- var record map [ string ] any
59- if err := dec .Decode (& record ); err != nil {
60- yield (s3Record {} , fmt .Errorf ("decode cloudtrail record: %w" , err ))
59+ var raw json. RawMessage
60+ if err := dec .Decode (& raw ); err != nil {
61+ yield ("" , fmt .Errorf ("decode cloudtrail record: %w" , err ))
6162 return
6263 }
63-
64- msg , err := json .Marshal (record )
65- if err != nil {
66- yield (s3Record {}, fmt .Errorf ("marshal cloudtrail record: %w" , err ))
67- return
68- }
69-
70- host := cloudtrailHost (record )
71- if ! yield (s3Record {Message : string (msg ), Host : host }, nil ) {
64+ if ! yield (string (raw ), nil ) {
7265 return
7366 }
7467 }
7568 }
7669}
7770
78- func cloudtrailHostFromMessage (message string ) string {
79- var record map [ string ] any
80- if err := json . Unmarshal ([] byte ( message ), & record ) ; err != nil {
71+ func cloudtrailHost (message string ) string {
72+ dec := json . NewDecoder ( strings . NewReader ( message ))
73+ if t , err := dec . Token () ; err != nil || t != json . Delim ( '{' ) {
8174 return ""
8275 }
83- return cloudtrailHost (record )
84- }
8576
86- func cloudtrailHost (record map [string ]any ) string {
87- ui , ok := record [cloudTrailUserIdentityKey ].(map [string ]any )
88- if ! ok {
89- slog .Debug (cloudTrailUserIdentityKey + " key not found, cloudtrail host extraction skipped" )
90- return ""
91- }
92- arn , ok := ui [cloudTrailARNKey ].(string )
93- if ! ok {
94- slog .Debug (cloudTrailARNKey + " key not found, cloudtrail host extraction skipped" )
95- return ""
96- }
77+ for dec .More () {
78+ key , err := dec .Token ()
79+ if err != nil {
80+ return ""
81+ }
82+ if key != cloudTrailUserIdentityKey {
83+ var skip json.RawMessage
84+ if err := dec .Decode (& skip ); err != nil {
85+ return ""
86+ }
87+ continue
88+ }
9789
98- re := ec2InstanceRegexp ()
99- matches := re .FindStringSubmatch (arn )
100- if matches == nil {
101- slog .Debug (arn + " arn did not match an EC2 host instance, cloudtrail host extraction skipped" )
90+ if t , err := dec .Token (); err != nil || t != json .Delim ('{' ) {
91+ return ""
92+ }
93+
94+ for dec .More () {
95+ innerKey , err := dec .Token ()
96+ if err != nil {
97+ return ""
98+ }
99+ if innerKey != cloudTrailARNKey {
100+ var skip json.RawMessage
101+ if err := dec .Decode (& skip ); err != nil {
102+ return ""
103+ }
104+ continue
105+ }
106+
107+ var arn string
108+ if err := dec .Decode (& arn ); err != nil {
109+ return ""
110+ }
111+
112+ re := ec2InstanceRegexp ()
113+ matches := re .FindStringSubmatch (arn )
114+ if matches == nil {
115+ slog .Debug (arn + " arn did not match an EC2 host instance, cloudtrail host extraction skipped" )
116+ return ""
117+ }
118+ return matches [re .SubexpIndex ("host" )]
119+ }
102120 return ""
103121 }
104-
105- return matches [re .SubexpIndex ("host" )]
122+ return ""
106123}
0 commit comments