Skip to content

Commit 19989c9

Browse files
committed
initial commit
0 parents  commit 19989c9

5 files changed

+506
-0
lines changed

.gitignore

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work
22+
### SAM+config ###
23+
# Ignore build directories for the AWS Serverless Application Model (SAM)
24+
# Info: https://aws.amazon.com/serverless/sam/
25+
# Docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html
26+
27+
**/.aws-sam
28+
29+
### SAM+config Patch ###
30+
# SAM config - exclude this file if sharing publicly
31+
samconfig.toml
32+
33+
# created by aws sam
34+
packaged.yml

LICENSE.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
license

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# aws-cloudwatch-firehose
2+
Forwards logs from cloudwatch to NewRelic through firehose
+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
3+
Parameters:
4+
LogGroupConfig:
5+
Description: "String representation of JSON array of objects of your CloudWatch Loggroup(s) and respective filter (if applicable)"
6+
Type: String
7+
LogGroupArns:
8+
Description: "Comma-separated list of CloudWatch Log Group ARNs to create subscription to Data Firehose"
9+
Type: CommaDelimitedList
10+
InvalidLogGroups:
11+
Description: "Comma-separated list of CloudWatch Log Groups provided in use input which are invalid and should be skipped."
12+
Type: CommaDelimitedList
13+
LoggingFirehoseStreamArn:
14+
Type: String
15+
Description: "Data Firehose arn to create cloudwatch log group subscription"
16+
17+
Conditions:
18+
HasValidLogGroups: !Not [!Equals [!Select [0, !Ref LogGroupArns], ""]]
19+
20+
Resources:
21+
CloudWatchLogGroupTriggers:
22+
Type: 'Custom::CloudWatchNotifications'
23+
Condition: HasValidLogGroups
24+
Properties:
25+
ServiceToken: !GetAtt CloudWatchEventCustomResourceLambda.Arn
26+
LoggingFirehoseStreamArn: !Ref LoggingFirehoseStreamArn
27+
LogGroupConfig: !Ref LogGroupConfig
28+
InvalidLogGroups: !Ref InvalidLogGroups
29+
30+
CustomCloudWatchLambdaExecutionRole:
31+
Type: "AWS::IAM::Role"
32+
Condition: HasValidLogGroups
33+
Properties:
34+
AssumeRolePolicyDocument:
35+
Version: "2012-10-17"
36+
Statement:
37+
- Effect: Allow
38+
Principal:
39+
Service:
40+
- lambda.amazonaws.com
41+
Action:
42+
- "sts:AssumeRole"
43+
Policies:
44+
- PolicyName: "LambdaExecutionPolicy"
45+
PolicyDocument:
46+
Version: "2012-10-17"
47+
Statement:
48+
- Effect: Allow
49+
Action:
50+
- logs:PutSubscriptionFilter
51+
Resource: !Ref LogGroupArns
52+
- Effect: Allow
53+
Action:
54+
- 'logs:CreateLogGroup'
55+
- 'logs:CreateLogStream'
56+
- 'logs:PutLogEvents'
57+
Resource: 'arn:aws:logs:*:*:*'
58+
- Effect: Allow
59+
Action:
60+
- 'iam:PassRole'
61+
Resource: !GetAtt CloudWatchFirehoseRole.Arn
62+
63+
CloudWatchFirehoseRole:
64+
Type: "AWS::IAM::Role"
65+
Properties:
66+
AssumeRolePolicyDocument:
67+
Version: "2012-10-17"
68+
Statement:
69+
- Effect: Allow
70+
Principal:
71+
Service:
72+
- logs.amazonaws.com
73+
Action:
74+
- "sts:AssumeRole"
75+
Policies:
76+
- PolicyName: "FirehoseWritePolicy"
77+
PolicyDocument:
78+
Version: "2012-10-17"
79+
Statement:
80+
- Effect: Allow
81+
Action:
82+
- firehose:PutRecord
83+
- firehose:PutRecordBatch
84+
Resource: !Ref LoggingFirehoseStreamArn
85+
86+
CloudWatchEventCustomResourceLambda:
87+
Type: 'AWS::Lambda::Function'
88+
Condition: HasValidLogGroups
89+
Properties:
90+
Environment:
91+
Variables:
92+
CloudWatchFirehoseRoleArn: !GetAtt CloudWatchFirehoseRole.Arn
93+
Code:
94+
ZipFile: |
95+
import json
96+
import boto3
97+
import cfnresponse
98+
import logging
99+
import os
100+
101+
logger = logging.getLogger()
102+
logger.setLevel(logging.INFO)
103+
104+
log_client = boto3.client('logs')
105+
106+
def lambda_handler(event, context):
107+
response = {}
108+
try:
109+
if event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
110+
event_data = event['ResourceProperties']
111+
firehose_arn = event_data.get('LoggingFirehoseStreamArn', '')
112+
113+
log_group_config_str = event_data.get('LogGroupConfig', [])
114+
invalid_log_groups = set(event_data.get('InvalidLogGroups', []))
115+
logger.info(f'Invalid Log Groups: {invalid_log_groups}')
116+
117+
# Parsing LogGroupConfig JSON array
118+
log_group_config = json.loads(log_group_config_str)
119+
for log_group in log_group_config:
120+
log_group_name = log_group['LogGroupName']
121+
if log_group_name in invalid_log_groups:
122+
logger.info(f'Log group {log_group_name} is invalid. Skipping...')
123+
continue
124+
filter_pattern = log_group['FilterPattern'] if 'FilterPattern' in log_group else ''
125+
126+
cloudwatch_firehose_role_arn = os.environ['CloudWatchFirehoseRoleArn']
127+
128+
response = log_client.put_subscription_filter(
129+
logGroupName=log_group_name,
130+
roleArn=cloudwatch_firehose_role_arn,
131+
filterName='LoggingFirehoseSubscription',
132+
filterPattern=filter_pattern,
133+
destinationArn=firehose_arn
134+
)
135+
136+
cfnresponse.send(event, context, cfnresponse.SUCCESS, response)
137+
except Exception as e:
138+
logger.error(f'Error: {str(e)}')
139+
cfnresponse.send(event, context, cfnresponse.FAILED, {}, reason=f'{str(e)}')
140+
Handler: index.lambda_handler
141+
Role: !GetAtt CustomCloudWatchLambdaExecutionRole.Arn
142+
Runtime: python3.12
143+
Timeout: 120

0 commit comments

Comments
 (0)