A Lambda function that monitors AWS IAM Identity Center for repeated failed login attempts and sends an email alert when a user exceeds a configurable failure threshold within a rolling time window.
- Event ingestion — An EventBridge rule forwards CloudTrail
CredentialVerificationevents to this Lambda whenever a login failure occurs. - User identification — The function extracts the user UUID (and optionally the username) from the event's
additionalEventDataoruserIdentityfields. - Failure tracking — A DynamoDB item is atomically updated to increment the failure counter for that user within a rolling time window. If the window has expired, the counter resets.
- Threshold check — When the failure count reaches
FAILURE_THRESHOLD, the function looks up the user's primary email address via the IAM Identity Center Identity Store API (using a cross-account assumed role). - Email notification — A single alert email is sent over SMTP (e.g. Amazon SES). A
notificationSentflag prevents duplicate alerts within the same window.
CloudTrail → EventBridge → Lambda → DynamoDB (track failures)
→ Identity Store (resolve email)
→ SMTP (send alert)
- AWS IAM Identity Center enabled with users who have primary email addresses configured.
- A DynamoDB table with a partition key named
userId(String) and TTL enabled on thettlattribute. - An IAM role the Lambda can assume (
ASSUME_ROLE_ARN) that hasidentitystore:DescribeUserandidentitystore:GetUserIdpermissions on the target Identity Store. - An SMTP relay (e.g. Amazon SES with SMTP credentials) accessible from the Lambda's VPC/network.
- An EventBridge rule that routes
CredentialVerificationCloudTrail events to this Lambda.
| Variable | Required | Default | Description |
|---|---|---|---|
DYNAMODB_TABLE |
Yes | — | DynamoDB table name for failure tracking |
IDENTITY_STORE_ID |
Yes | — | IAM Identity Center Identity Store ID (e.g. d-xxxxxxxxxx) |
ASSUME_ROLE_ARN |
Yes | — | ARN of the role to assume for Identity Store access |
SMTP_HOST |
Yes | — | SMTP server hostname |
SMTP_USERNAME |
Yes | — | SMTP authentication username |
SMTP_PASSWORD |
Yes | — | SMTP authentication password |
SMTP_FROM |
Yes | — | Sender address for alert emails |
SMTP_PORT |
No | 587 |
SMTP server port (STARTTLS) |
FAILURE_THRESHOLD |
No | 3 |
Number of failures before an alert is sent |
GRACE_PERIOD_SECONDS |
No | 3600 |
Rolling window length in seconds (1 hour) |
| Attribute | Type | Description |
|---|---|---|
userId |
String (PK) | IAM Identity Center user UUID (or username if UUID unavailable) |
failureCount |
Number | Failures recorded in the current window |
windowStartTime |
Number | Unix timestamp when the current window opened |
lastFailureTime |
Number | Unix timestamp of the most recent failure |
notificationSent |
Boolean | true once an alert has been dispatched for this window |
ttl |
Number | Unix timestamp for DynamoDB TTL expiry (windowStart + 2 × GRACE_PERIOD_SECONDS) |
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:<region>:<account>:table/<DYNAMODB_TABLE>"
},
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "<ASSUME_ROLE_ARN>"
}The assumed role must allow:
{
"Effect": "Allow",
"Action": [
"identitystore:DescribeUser",
"identitystore:GetUserId"
],
"Resource": "*"
}- Create the DynamoDB table with partition key
userId(String) and enable TTL on thettlattribute. - Create the cross-account IAM role with the Identity Store permissions above and add the Lambda execution role as a trusted principal.
- Deploy the Lambda function (
src/handler.py) with a Python 3.12+ runtime and set all required environment variables. - Create an EventBridge rule with an event pattern targeting
CredentialVerificationevents from CloudTrail and set the Lambda as the target. - Verify SMTP credentials by sending a test email from the Lambda's network.
- Single alert per window — once
notificationSentistrue, no further emails are sent until the grace period expires and the window resets. - Window reset — if the gap between the last recorded failure and the next one exceeds
GRACE_PERIOD_SECONDS, the counter and window start fresh. - No email resolved — if the Identity Store lookup fails or the user has no primary email, the failure is still tracked but no email is sent; a warning is logged.
- Cross-account — the Lambda assumes
ASSUME_ROLE_ARNon every Identity Store call; credentials are short-lived (15 minutes) and not cached between invocations.