55import requests
66import time
77import random
8- import re # Add this import for regex
8+ import re
9+ import base64
910from datetime import datetime
1011from typing import Dict , Any
1112from kubernetes import client , config
1819def is_invalid (value : str ) -> bool :
1920 return value is None or value .strip () in ["" , "[no value]" ]
2021
22+ def verify_basic_auth (event : Dict [str , Any ]) -> bool :
23+ """
24+ Verify Basic Authentication credentials from the request headers.
25+ Returns True if authentication is successful, False otherwise.
26+ """
27+ try :
28+ # Get headers from the event
29+ headers = event .get ('headers' , {})
30+ if not headers :
31+ logger .warning ("No headers found in the request" )
32+ return False
33+
34+ # Look for authorization header (case-insensitive)
35+ auth_header = None
36+ for key in headers :
37+ if key .lower () == 'authorization' :
38+ auth_header = headers [key ]
39+ break
40+
41+ if not auth_header or not auth_header .startswith ('Basic ' ):
42+ logger .warning ("No Basic Authorization header found" )
43+ return False
44+
45+ # Extract and decode credentials
46+ encoded_credentials = auth_header .split (' ' )[1 ]
47+ decoded_credentials = base64 .b64decode (encoded_credentials ).decode ('utf-8' )
48+ username , password = decoded_credentials .split (':' )
49+
50+ # Get expected credentials from AWS Secrets Manager
51+ secret_name = "grafana-webhook-credentials"
52+ region_name = os .environ .get ('AWS_REGION' , 'us-east-1' )
53+
54+ session = boto3 .session .Session ()
55+ client = session .client (
56+ service_name = 'secretsmanager' ,
57+ region_name = region_name
58+ )
59+
60+ response = client .get_secret_value (SecretId = secret_name )
61+ secret = json .loads (response ['SecretString' ])
62+
63+ # Validate credentials
64+ if username != secret ['username' ] or password != secret ['password' ]:
65+ logger .warning ("Invalid credentials provided" )
66+ return False
67+
68+ logger .info ("Authentication successful" )
69+ return True
70+
71+ except ClientError as e :
72+ logger .error (f"Error retrieving credentials from Secrets Manager: { str (e )} " )
73+ return False
74+ except Exception as e :
75+ logger .error (f"Authentication error: { str (e )} " )
76+ return False
77+
2178def extract_pod_info_from_valuestring (value_string : str ) -> Dict [str , str ]:
2279 """Extract pod information from Grafana alert valueString"""
2380 try :
@@ -184,13 +241,24 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
184241 # Check if this is a direct webhook call from Grafana
185242 if 'body' in event :
186243 logger .info ("Processing direct webhook from Grafana" )
244+
245+ # Verify authentication for webhook calls
246+ if not verify_basic_auth (event ):
247+ logger .warning ("Authentication failed" )
248+ return {
249+ 'statusCode' : 401 ,
250+ 'headers' : {'WWW-Authenticate' : 'Basic' },
251+ 'body' : json .dumps ({'error' : 'Authentication failed' })
252+ }
253+
187254 try :
188255 # Parse the webhook payload
189256 if isinstance (event ['body' ], str ):
190257 body = json .loads (event ['body' ])
191258 else :
192259 body = event ['body' ]
193260
261+ # Rest of your webhook handling code remains the same
194262 alerts = body .get ('alerts' , [])
195263 if not alerts :
196264 return {
@@ -200,6 +268,8 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
200268
201269 results = []
202270 for alert in alerts :
271+ # Your existing alert processing code...
272+ # No changes needed here
203273 if alert .get ('status' ) != 'firing' :
204274 logger .info ("Skipping resolved alert" )
205275 continue
0 commit comments