Skip to content

Commit 48349c4

Browse files
committed
feat(promtail): Adding S3 log parser support for AWS GuardDuty (grafana#13148)
Co-authored-by: James Callahan <https://github.com/james-callahan>ase enter the commit message for your changes. Lines starting
1 parent 8434b2f commit 48349c4

File tree

4 files changed

+53
-1
lines changed

4 files changed

+53
-1
lines changed

tools/lambda-promtail/lambda-promtail/s3.go

+14
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const (
5050
LB_NLB_TYPE string = "net"
5151
LB_ALB_TYPE string = "app"
5252
WAF_LOG_TYPE string = "WAFLogs"
53+
GUARDDUTY_LOG_TYPE string = "GuardDutyLogs"
5354
)
5455

5556
var (
@@ -75,13 +76,18 @@ var (
7576
// source: https://docs.aws.amazon.com/waf/latest/developerguide/logging-s3.html
7677
// format: aws-waf-logs-suffix[/prefix]/AWSLogs/aws-account-id/WAFLogs/region/webacl-name/year/month/day/hour/minute/aws-account-id_waflogs_region_webacl-name_timestamp_hash.log.gz
7778
// example: aws-waf-logs-test/AWSLogs/11111111111/WAFLogs/us-east-1/TEST-WEBACL/2021/10/28/19/50/11111111111_waflogs_us-east-1_TEST-WEBACL_20211028T1950Z_e0ca43b5.log.gz
79+
// AWS GuardDuty
80+
// source: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_exportfindings.html
81+
// format: my-bucket/AWSLogs/aws-account-id/GuardDuty/region/year/month/day/random-string.jsonl.gz
82+
// example: my-bucket/AWSLogs/123456789012/GuardDuty/us-east-1/2024/05/30/07a3f2ce-1485-3031-b842-e1f324c4a48d.jsonl.gz
7883
defaultFilenameRegex = regexp.MustCompile(`AWSLogs\/(?P<account_id>\d+)\/(?P<type>[a-zA-Z0-9_\-]+)\/(?P<region>[\w-]+)\/(?P<year>\d+)\/(?P<month>\d+)\/(?P<day>\d+)\/\d+\_(?:elasticloadbalancing|vpcflowlogs)_(?:\w+-\w+-(?:\w+-)?\d)_(?:(?P<lb_type>app|net)\.*?)?(?P<src>[a-zA-Z0-9\-]+)`)
7984
defaultTimestampRegex = regexp.MustCompile(`(?P<timestamp>\d+-\d+-\d+T\d+:\d+:\d+(?:\.\d+Z)?)`)
8085
cloudtrailFilenameRegex = regexp.MustCompile(`AWSLogs\/(?P<organization_id>o-[a-z0-9]{10,32})?\/?(?P<account_id>\d+)\/(?P<type>[a-zA-Z0-9_\-]+)\/(?P<region>[\w-]+)\/(?P<year>\d+)\/(?P<month>\d+)\/(?P<day>\d+)\/\d+\_(?:CloudTrail|CloudTrail-Digest)_(?:\w+-\w+-(?:\w+-)?\d)_(?:(?:app|nlb|net)\.*?)?.+_(?P<src>[a-zA-Z0-9\-]+)`)
8186
cloudfrontFilenameRegex = regexp.MustCompile(`(?P<prefix>.*)\/(?P<src>[A-Z0-9]+)\.(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)-(.+)`)
8287
cloudfrontTimestampRegex = regexp.MustCompile(`(?P<timestamp>\d+-\d+-\d+\s\d+:\d+:\d+)`)
8388
wafFilenameRegex = regexp.MustCompile(`AWSLogs\/(?P<account_id>\d+)\/(?P<type>WAFLogs)\/(?P<region>[\w-]+)\/(?P<src>[\w-]+)\/(?P<year>\d+)\/(?P<month>\d+)\/(?P<day>\d+)\/(?P<hour>\d+)\/(?P<minute>\d+)\/\d+\_waflogs\_[\w-]+_[\w-]+_\d+T\d+Z_\w+`)
8489
wafTimestampRegex = regexp.MustCompile(`"timestamp":\s*(?P<timestamp>\d+),`)
90+
guarddutyFilenameRegex = regexp.MustCompile(`AWSLogs\/(?P<account_id>\d+)\/GuardDuty\/(?P<region>[\w-]+)\/(?P<year>\d+)\/(?P<month>\d+)\/(?P<day>\d+)\/.*\.jsonl\.gz`)
8591
parsers = map[string]parserConfig{
8692
FLOW_LOG_TYPE: {
8793
logTypeLabel: "s3_vpc_flow",
@@ -122,6 +128,14 @@ var (
122128
timestampRegex: wafTimestampRegex,
123129
timestampType: "unix",
124130
},
131+
GUARDDUTY_LOG_TYPE: {
132+
logTypeLabel: "s3_guardduty",
133+
filenameRegex: guarddutyFilenameRegex,
134+
ownerLabelKey: "account_id",
135+
timestampFormat: time.RFC3339,
136+
timestampRegex: defaultTimestampRegex,
137+
timestampType: "string",
138+
},
125139
}
126140
)
127141

tools/lambda-promtail/lambda-promtail/s3_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,38 @@ func Test_getLabels(t *testing.T) {
9393
},
9494
wantErr: false,
9595
},
96+
{
97+
name: "s3_guardduty",
98+
args: args{
99+
record: events.S3EventRecord{
100+
AWSRegion: "us-east-1",
101+
S3: events.S3Entity{
102+
Bucket: events.S3Bucket{
103+
Name: "s3_guardduty_test",
104+
OwnerIdentity: events.S3UserIdentity{
105+
PrincipalID: "test",
106+
},
107+
},
108+
Object: events.S3Object{
109+
Key: "AWSLogs/123456789012/GuardDuty/us-east-1/2024/05/30/07a3f2ce-1485-3031-b842-e1f324c4a48d.jsonl.gz",
110+
},
111+
},
112+
},
113+
},
114+
want: map[string]string{
115+
"account_id": "123456789012",
116+
"bucket": "s3_guardduty_test",
117+
"bucket_owner": "test",
118+
"bucket_region": "us-east-1",
119+
"day": "30",
120+
"key": "AWSLogs/123456789012/GuardDuty/us-east-1/2024/05/30/07a3f2ce-1485-3031-b842-e1f324c4a48d.jsonl.gz",
121+
"month": "05",
122+
"region": "us-east-1",
123+
"type": GUARDDUTY_LOG_TYPE,
124+
"year": "2024",
125+
},
126+
wantErr: false,
127+
},
96128
{
97129
name: "s3_flow_logs",
98130
args: args{

tools/lambda-promtail/main.tf

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ resource "aws_s3_bucket_notification" "this" {
251251
lambda_function_arn = aws_lambda_function.this.arn
252252
events = ["s3:ObjectCreated:*"]
253253
filter_prefix = "AWSLogs/"
254-
filter_suffix = ".log.gz"
254+
filter_suffix = var.filter_suffix
255255
}
256256

257257
depends_on = [

tools/lambda-promtail/variables.tf

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ variable "bucket_names" {
1616
default = []
1717
}
1818

19+
variable "filter_suffix" {
20+
type = string
21+
description = "Suffix for S3 bucket notification filter"
22+
default = ".log.gz"
23+
}
24+
1925
variable "log_group_names" {
2026
type = set(string)
2127
description = "List of CloudWatch Log Group names to create Subscription Filters for."

0 commit comments

Comments
 (0)