AWS CDK Lambda Uptime Monitoring
After building and deploying my first AWS CDK project—a simple Lambda function and S3 bucket—I wanted to push the concept further.
The initial project taught me how to:
- Package and deploy Python-based Lambda functions
- Use AWS CDK to synthesize and deploy CloudFormation templates
- Handle IAM access securely (without using root credentials)
- Debug real-world issues like Lambda bundling and deployment errors
Building upon that foundation, I created a Serverless Uptime Checker that:
- Monitors websites every 5 minutes using an AWS Lambda triggered by EventBridge
- Logs uptime data to CloudWatch Logs
- Sends optional email alerts via SNS when a site becomes unreachable
This project demonstrates practical DevOps skills in automation, observability, and cloud infrastructure, using fully managed, serverless AWS services.
Skills Demonstrated:
- Infrastructure as Code (IaC): Provisioned cloud resources using AWS CDK and Python
- Monitoring and Observability: Built an automated uptime checker using AWS Lambda, Amazon EventBridge, CloudWatch Logs and Alarms, and SNS
- Secure Parameterization & IAM: Passed sensitive values at deploy time via CDK Parameters and applied least-privilege IAM permissions
Prerequisites:
- AWS account with programmatic access (via IAM user or role)
- AWS CLI: Install AWS CLI
- Python 3.8+
- Node.js (v14 or later) and NPM (for CDK CLI dependencies): https://nodejs.org/en
- AWS CDK v2:
npm install -g aws-cdk - (Optional) Python virtual environment tool like
venvfor dependency isolation
Project Setup
Project Initialization
Create and initialize your AWS CDK app:
mkdir uptime-checker && cd uptime-checker
cdk init app --language python
(Optional) Set up a Python virtual environment:
python -m venv .venv
source .venv/bin/activate # For Windows: .venv\Scripts\activate
After running this command, your project directory should now look like this:
uptime-checker/
├── README.md
├── app.py
├── cdk.json
├── uptime_checker/
│ ├── __init__.py
│ └── uptime_checker_stack.py
├── lambda/
│ ├── __init__.py
│ └── lambda_function.py
├── requirements.txt
├── .gitignore
└── .venv/ (optional, virtual environment)
Install Dependencies
Update requirements.txt to include:
aws-cdk-lib==2.x.x
constructs>=10.0.0,<11.0.0
requests
Then install dependencies:
pip install -r requirements.txt
Write Your Lambda Function
The Lambda function lambda/lambda_function.py reads a list of websites from an environment variable (WEBSITES_JSON), checks each URL, and logs whether the site is up, down, or returning an error status.
import os, json, requests
from datetime import datetime, timezone
WEBSITES = json.loads(os.environ['WEBSITES_JSON'])
def lambda_handler(event, context):
timestamp = datetime.now(timezone.utc).isoformat()
for site in WEBSITES:
name, url = site['name'], site['url']
try:
resp = requests.get(url, timeout=5)
status = "Up" if resp.status_code == 200 else f"Error {resp.status_code}"
except requests.RequestException:
status = "Down"
print(f"{timestamp} | {name} ({url}) → {status}")
return {'statusCode': 200}
Define Your Infrastructure Stack
This CDK stack uptime_checker/uptime_checker_stack.py defines the serverless infrastructure for your uptime checker by setting up:
- A Lambda function to check site status
- An EventBridge rule to run the Lambda every 5 minutes
- An environment variable (
WEBSITES_JSON) to pass monitored URLs securely
from aws_cdk import (
Stack,
Duration,
aws_lambda as _lambda,
aws_events as events,
aws_events_targets as targets,
)
from constructs import Construct
import json
class UptimeCheckerStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs):
super().__init__(scope, construct_id, **kwargs)
websites = [
{"name": "Portfolio", "url": "https://portfolio-4wj.pages.dev/"},
{"name": "TrustScience", "url": "https://trustscience.com"}
]
fn = _lambda.Function(
self, "UptimeCheckFn",
runtime=_lambda.Runtime.PYTHON_3_10,
handler="lambda_function.lambda_handler",
code=_lambda.Code.from_asset("lambda"),
environment={
"WEBSITES_JSON": json.dumps(websites)
},
timeout=Duration.seconds(10)
)
events.Rule(
self, "5MinRule",
schedule=events.Schedule.rate(Duration.minutes(5)),
targets=[targets.LambdaFunction(fn)]
)
Tip: For better flexibility, you can make the monitored websites configurable via environment variables, CDK context, or SSM Parameters.
Adding Email Alerts via SNS + CloudWatch Alarm (Secure & Parameterized)
To extend the functionality of our uptime checker with notifications, we will add:
- An SNS Topic to publish alerts
- An email subscription, passed as a CDK parameter
- A CloudWatch Alarm that triggers when the Lambda function records errors
Step 1: Update Your Stack (uptime_checker_stack.py)
from aws_cdk import (
Duration,
Stack,
aws_lambda as _lambda,
aws_events as events,
aws_events_targets as targets,
aws_logs as logs,
aws_sns as sns,
aws_sns_subscriptions as subs,
aws_cloudwatch as cw,
aws_cloudwatch_actions as cw_actions,
CfnParameter,
)
from constructs import Construct
import json
class UptimeCheckerStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# sns topic + email subscription
alert_email = CfnParameter(self, "AlertEmail", type="String", description="email for SNS alerts")
topic = sns.Topic(self, "UptimeAlertsTopic")
topic.add_subscription(subs.EmailSubscription(alert_email.value_as_string))
websites = [
{"name": "Portfolio", "url": "https://portfolio-4wj.pages.dev/"},
{"name": "TrustScience", "url": "https://trustscience.com"}
]
check_fn = _lambda.Function(
self, "CheckFn",
runtime=_lambda.Runtime.PYTHON_3_10,
handler="lambda_function.lambda_handler",
code=_lambda.Code.from_asset("lambda"),
environment={
"WEBSITES_JSON": json.dumps(websites)
},
timeout=Duration.seconds(10),
log_retention=logs.RetentionDays.ONE_DAY,
)
events.Rule(
self, "5MinRule",
schedule=events.Schedule.rate(Duration.minutes(5)),
targets=[targets.LambdaFunction(check_fn)]
)
# CloudWatch alarm: trigger if errors >= 1 in 5min window
error_metric = check_fn.metric_errors(
period=Duration.minutes(5),
statistic="Sum"
)
alarm=cw.Alarm(self, "LambdaErrorAlarm",
metric=error_metric,
threshold=1,
evaluation_periods=1,
datapoints_to_alarm=1,
treat_missing_data=cw.TreatMissingData.NOT_BREACHING,
alarm_description="Uptime Lambda error",
)
alarm_action = cw_actions.SnsAction(topic)
alarm.add_alarm_action(alarm_action)
Step 2: Deploy With Email Parameter
Deploy your stack and specify your email address to receive alerts:
cdk deploy --parameters AlertEmail=<your-email@example.com>
Note: You’ll receive a confirmation email from AWS SNS. You must click the confirmation link to activate alerts.
Security Notes
- Your email is never hardcoded in the source code; instead, it is passed securely at deploy time and not stored in version control
- For shared or team environments, consider using AWS SSM Parameters Store instead
Test Uptime Checker:
- Verify Lambda execution by checking CloudWatch Logs for the
UptimeCheckFnlog group. Review recent log entries to see uptime check results with timestamps. - Simulate a failure (e.g., invalid URL) and verify you receive an email alert triggered by the CloudWatch alarm.
Next Steps:
This project is a great base to build upon. Here are some optional next steps:
- Add persistent storage (e.g., DynamoDB or S3) for historical uptime data
- Create HTML reports or dashboards
- Integrate alerts with Slack or other channels using AWS Chatbot
- Automate deployments with CI/CD pipelines (e.g., GitHub Actions)
- Add custom CloudWatch metrics for response times
Happy Monitoring!