If you have ever dealt with traditional Intrusion detection systems (IDS), you know the struggle: Heavy appliances, constant rule tuning, as well as the inability to stop false positives. And then the bills kept coming—it got really expensive even when traffic went down. I’ve experienced this before and it was frustrating. The good news? We don’t have to use IDS those ways anymore. By leveraging AWS’s serverless stack and a dash of machine learning, you can create a lightweight Intrusion detection systems that scale up when you need it, cost next to nothing when idle, and actually learn when to flag suspicious behavior.

Does this sound too good to be true? Let’s breakdown how to approach this step-by-step.


Why Go Serverless for Intrusion Detection?

Before we give the high-level architecture, let’s answer a simple question: why bother going serverless at all?

Think about this: Instead of maintaining a bulky IDS hardware appliance, you’re letting AWS take care of the scaling while you focus your efforts on developing, and refining, the intelligence.


Architecture Overview

The following is the high-level flow of a serverless IDS (Intrusion Detection System).

ASCII flow for the visual thinkers:

Auth Event → EventBridge → Lambda → SageMaker (score) → DynamoDB (log + risk) → SNS / Security Hub (alert)

It looks simple but what's happening in these components is where the magic occurs.


Developing the Anomaly Detection Model

The core of this IDS is the ML model. A natural choice for a starting point—and of all models this is specifically built for anomaly detection—is Random Cut Forest (RCF).

For example, you may detect unusual login times (such as 3 AM logins from an unfamiliar device located within a foreign country)—RCF will perform well in this case.

This is how you could setup your model in SageMaker:

import boto3, sagemaker 
from sagemaker import RandomCutForest
session = sagemaker.Session()
role = ""
rcf = RandomCutForest(    
    role=role,    
    instance_count=1,    
    instance_type="ml.m5.large",    
    num_samples_per_tree=512,    
    num_trees=50
)

Training data should be in CSV format, and should include your features [hour, geo, user_hash, device_hash].

train_data = "s3://my-bucket/auth-train.csv"
rcf.fit(s3_input(train_data))
predictor = rcf.deploy(    
  initial_instance_count=1,    
  instance_type="ml.m5.large",    
  endpoint_name="ids-anomaly-detector"
)

The model returns an anomaly score. The consequence is a higher score shows the login appears increasingly "weird".


Handling Events Using Lambda

Think of the Lambda function acting as the connector for the whole process. It takes the event in its raw form; it will take the pieces of information associated with the event and send those to your ML model for scoring and then record the score to DynamoDB. And it also has the capability to send an alert, if the score is high enough.

This is a simplified version of a handler that I would start with:

import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
import { SageMakerRuntimeClient, InvokeEndpointCommand } from "@aws-sdk/client-sagemaker-runtime";
const ddb = new DynamoDBClient();
const sm = new SageMakerRuntimeClient();
const TABLE = process.env.TABLE;
const ENDPOINT = process.env.ENDPOINT;
export const handler = async (event) => {  
  // Depending on the source of the log, it might have come wrapped in `detail`  
  const record = event.detail || event;  
  // Create features for the model, in this case, hour of login, geo hash, and device hash  
  const features = [record.hour, record.geoHash, record.deviceHash];  
  // Get the score of the event with SageMaker   
  const resp = await sm.send(    
      new InvokeEndpointCommand({      
            EndpointName: ENDPOINT,      
            Body: JSON.stringify(features),      
            ContentType: "application/json",    
          })  
      );  
  const { score } = JSON.parse(new TextDecoder().decode(resp.Body));  
  const risk = score > 3 ? "suspicious" : "legit";  
  // Write the results to DynamoDB  
  await ddb.send(    
      new PutItemCommand({      
        TableName: TABLE,      
        Item: {        
            eventId: { S: record.eventId },        
            userId: { S: record.userId },        
            score: { N: score.toString() },        
            risk: { S: risk },        
            ts: { S: new Date().toISOString() },      
          },    
        })  
    );  
  // If something seems suspicious, log it (or send it to SNS / Security Hub)  
  if (risk === "suspicious") {    
    console.warn("⚠️ Suspicious activity detected:", record);  
  }  
  return { status: "ok", risk };
};


Look at the steps—nice and clean right?extract → score → store → alert!


DynamoDB Schema Design

You should not have to be fancy with your DynamoDB table. A minimal schema is all that is needed:

Sometimes simple is all you need.


Lessons Learned (The Hard Way)

Cold Starts vs Latency

Feature Engineering is King

False Positives Hurt Trust

Cost Efficiency

Security Hygiene

No wildcards in IAM policies, ever.


Frequently Asked Questions


Summary

So take-away summary: you can build a intrusion detection system with AWS Lambda, DynamoDB and SageMaker that is serverless, scalable and intelligent.

In all honesty, it feels good to depart from the old static IDS world, where we fought against false positives and spent our weekends applying patches to physical boxes.

Now, question for you to consider: if you had this set up in place, how would you extend the functionality? Would you add a new capability to support blocking in the flows of your system, or monitor for a while before taking the active blocking step?

That is the nice part about building it—when you build it, you choose the level of balance between a fully automated process and one that actively seeks a human to be appraised of what is happening.