Skip to content

Lambda (AWS Lambda) — Drift Coverage

Overview

TFDrift-Falco monitors AWS Lambda for configuration drift by tracking CloudTrail events related to functions, permissions, event source mappings, and concurrency settings. This enables real-time detection of manual changes made outside of Terraform workflows.

Supported CloudTrail Events

Function Management (4 events)

Event Description Priority Status
CreateFunction Lambda function created WARNING ✔
DeleteFunction Lambda function deleted CRITICAL ✔
UpdateFunctionCode Function code updated WARNING ✔
UpdateFunctionConfiguration Function configuration updated WARNING ✔

Permissions (2 events)

Event Description Priority Status
AddPermission Permission added to function WARNING ✔
RemovePermission Permission removed from function WARNING ✔

Event Source Mappings (3 events)

Event Description Priority Status
CreateEventSourceMapping Event source mapping created WARNING ✔
DeleteEventSourceMapping Event source mapping deleted WARNING ✔
UpdateEventSourceMapping Event source mapping updated WARNING ✔

Concurrency (1 event)

Event Description Priority Status
PutFunctionConcurrency Concurrency limit configured WARNING ✔

Total: 10 CloudTrail events

Note: Lambda alias events (CreateAlias, DeleteAlias, UpdateAlias) share the same event names with KMS aliases and cannot be distinguished without the eventSource field in the current implementation.

Supported Terraform Resources

  • aws_lambda_function — Lambda function configuration and code
  • aws_lambda_permission — Resource-based policy for function invocation
  • aws_lambda_event_source_mapping — Event source configuration (SQS, Kinesis, DynamoDB Streams, etc.)
  • aws_lambda_alias — Function version aliases (limited support due to KMS event name collision)

Monitored Drift Attributes

Lambda Functions

  • function_name — Function identifier
  • runtime — Runtime environment (python3.12, nodejs20.x, etc.)
  • handler — Function entry point
  • role — IAM role ARN for execution
  • memory_size — Memory allocation (MB)
  • timeout — Execution timeout (seconds)
  • environment — Environment variables
  • vpc_config — VPC configuration (subnets, security groups)
  • dead_letter_config — DLQ configuration
  • tracing_config — X-Ray tracing mode
  • kms_key_arn — Environment variable encryption key
  • layers — Lambda layer ARNs
  • reserved_concurrent_executions — Concurrency limit

Lambda Permissions

  • statement_id — Permission identifier
  • action — Allowed action (lambda:InvokeFunction)
  • principal — Service or account principal
  • source_arn — Event source ARN (e.g., API Gateway, S3 bucket)
  • source_account — AWS account ID

Event Source Mappings

  • event_source_arn — Source ARN (SQS queue, Kinesis stream, DynamoDB table)
  • function_name — Target Lambda function
  • enabled — Mapping enabled state
  • batch_size — Number of records per batch
  • maximum_batching_window_in_seconds — Batching window
  • starting_position — Stream reading position (LATEST, TRIM_HORIZON)
  • filter_criteria — Event filtering patterns

Falco Rule Examples

# Function Lifecycle
- rule: Lambda Function Created
  desc: Detect when a Lambda function is created
  condition: >
    ct.name="CreateFunction"
  output: >
    Lambda function created
    (user=%ct.user function=%ct.request.functionName runtime=%ct.request.runtime
     region=%ct.region account=%ct.account)
  priority: WARNING
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, serverless]

# Critical Deletion Event
- rule: Lambda Function Deleted
  desc: Detect when a Lambda function is deleted
  condition: >
    ct.name="DeleteFunction"
  output: >
    Lambda function deleted
    (user=%ct.user function=%ct.request.functionName
     region=%ct.region account=%ct.account)
  priority: CRITICAL
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, serverless, security]

# Code Deployment
- rule: Lambda Function Code Updated
  desc: Detect when Lambda function code is updated
  condition: >
    ct.name="UpdateFunctionCode"
  output: >
    Lambda function code updated
    (user=%ct.user function=%ct.request.functionName
     region=%ct.region account=%ct.account)
  priority: WARNING
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, deployment]

# Configuration Changes
- rule: Lambda Function Configuration Changed
  desc: Detect when Lambda function configuration is updated
  condition: >
    ct.name="UpdateFunctionConfiguration"
  output: >
    Lambda function configuration changed
    (user=%ct.user function=%ct.request.functionName
     region=%ct.region account=%ct.account)
  priority: WARNING
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, configuration]

# Permission Changes
- rule: Lambda Permission Added
  desc: Detect when permission is added to Lambda function
  condition: >
    ct.name="AddPermission"
  output: >
    Lambda permission added
    (user=%ct.user function=%ct.request.functionName principal=%ct.request.principal
     region=%ct.region account=%ct.account)
  priority: WARNING
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, security, iam]

# Event Source Mapping
- rule: Lambda Event Source Mapping Created
  desc: Detect when event source mapping is created
  condition: >
    ct.name="CreateEventSourceMapping"
  output: >
    Lambda event source mapping created
    (user=%ct.user function=%ct.request.functionName source=%ct.request.eventSourceArn
     region=%ct.region account=%ct.account)
  priority: WARNING
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, integration]

# Concurrency Settings
- rule: Lambda Concurrency Limit Set
  desc: Detect when concurrency limit is configured
  condition: >
    ct.name="PutFunctionConcurrency"
  output: >
    Lambda concurrency limit configured
    (user=%ct.user function=%ct.request.functionName limit=%ct.request.reservedConcurrentExecutions
     region=%ct.region account=%ct.account)
  priority: WARNING
  source: aws_cloudtrail
  tags: [terraform, drift, lambda, performance]

Example Drift Scenarios

Scenario 1: Function Memory Size Changed in Console

CloudTrail Event:

{
  "eventName": "UpdateFunctionConfiguration",
  "requestParameters": {
    "functionName": "process-orders",
    "memorySize": 1024,
    "timeout": 30
  },
  "userIdentity": {
    "principalId": "AIDAI23ABCD4EFGH5IJKL",
    "userName": "ops-engineer"
  }
}

TFDrift-Falco Alert:

🚨 Drift Detected: aws_lambda_function.process_orders
Changed: memory_size = 512 → 1024
Changed: timeout = 10 → 30
User: ops-engineer (IAM User)
Region: us-east-1
Severity: HIGH

Scenario 2: Unauthorized Permission Added

CloudTrail Event:

{
  "eventName": "AddPermission",
  "requestParameters": {
    "functionName": "secure-function",
    "statementId": "AllowS3Invoke",
    "action": "lambda:InvokeFunction",
    "principal": "s3.amazonaws.com",
    "sourceArn": "arn:aws:s3:::untrusted-bucket"
  }
}

TFDrift-Falco Alert:

🚨 Drift Detected: aws_lambda_permission.secure_function
Added: statement_id = AllowS3Invoke
Added: source_arn = arn:aws:s3:::untrusted-bucket
User: developer@example.com (Console)
Region: us-east-1
Severity: CRITICAL

Scenario 3: Event Source Mapping Modified

CloudTrail Event:

{
  "eventName": "UpdateEventSourceMapping",
  "requestParameters": {
    "uuid": "12345678-1234-1234-1234-123456789012",
    "functionName": "stream-processor",
    "batchSize": 500,
    "enabled": false
  }
}

TFDrift-Falco Alert:

🚨 Drift Detected: aws_lambda_event_source_mapping.stream_processor
Changed: batch_size = 100 → 500
Changed: enabled = true → false
User: admin (Assumed Role)
Region: us-east-1
Severity: HIGH

Scenario 4: Concurrency Limit Added

CloudTrail Event:

{
  "eventName": "PutFunctionConcurrency",
  "requestParameters": {
    "functionName": "high-traffic-api",
    "reservedConcurrentExecutions": 50
  }
}

TFDrift-Falco Alert:

🚨 Drift Detected: aws_lambda_function.high_traffic_api
Changed: reserved_concurrent_executions = null → 50
User: sre-team (Assumed Role)
Region: us-east-1
Severity: MEDIUM

Configuration Example

# config.yaml
drift_rules:
  - name: "Lambda Function Configuration"
    resource_types:
      - "aws_lambda_function"
    watched_attributes:
      - "runtime"
      - "handler"
      - "memory_size"
      - "timeout"
      - "environment"
      - "vpc_config"
      - "role"
    severity: "high"

  - name: "Lambda Permissions"
    resource_types:
      - "aws_lambda_permission"
    watched_attributes:
      - "principal"
      - "source_arn"
      - "action"
    severity: "critical"

  - name: "Lambda Event Sources"
    resource_types:
      - "aws_lambda_event_source_mapping"
    watched_attributes:
      - "event_source_arn"
      - "enabled"
      - "batch_size"
      - "filter_criteria"
    severity: "medium"

Grafana Dashboard Metrics

Function Metrics

  • Lambda function updates by region
  • Memory size changes over time
  • Runtime version distribution
  • Function deletion events

Permission Metrics

  • Permission additions by principal
  • Unauthorized permission attempts
  • Cross-account access grants

Event Source Metrics

  • Event source mapping changes
  • Batch size adjustments
  • Disabled/enabled transitions

User Activity

  • Top users making Lambda changes
  • Changes by source (Console, CLI, CloudFormation)
  • Changes by time of day

Known Limitations

1. Lambda Alias Events

  • CreateAlias, DeleteAlias, UpdateAlias events are shared with KMS
  • Context-specific detection requires eventSource field
  • Lambda aliases are mapped to KMS aliases in current implementation
  • Future versions may add context-aware mapping

2. Environment Variable Visibility

  • Environment variable values are omitted from CloudTrail logs for security
  • Only detects that environment configuration changed, not specific values
  • Use Terraform state comparison for detailed environment diff

3. Lambda Layer Versions

  • PublishLayerVersion event not currently tracked
  • Layer version changes detected via UpdateFunctionConfiguration
  • Consider monitoring layer ARN changes in function configuration

4. Function URL Configuration

  • CreateFunctionUrlConfig, UpdateFunctionUrlConfig events not tracked
  • Planned for future enhancement
  • Monitor function URL changes via Terraform state

5. Code Package Content

  • ZipFile parameter omitted from CloudTrail logs
  • Code changes detected by event, not by content diff
  • Use S3 versioning or ECR tags for code version tracking

Best Practices

1. Function Configuration Management

# Terraform - Separate code from configuration
resource "aws_lambda_function" "app" {
  function_name = "my-app"
  role          = aws_iam_role.lambda.arn

  # Configuration
  runtime       = "python3.12"
  handler       = "main.handler"
  memory_size   = 512
  timeout       = 30

  # Code (managed separately)
  s3_bucket         = aws_s3_bucket.lambda_code.id
  s3_key            = "app-${var.version}.zip"
  source_code_hash  = data.aws_s3_object.app_code.version_id

  # Environment variables (use sensitive values from SSM/Secrets Manager)
  environment {
    variables = {
      STAGE       = "production"
      LOG_LEVEL   = "INFO"
      DB_HOST_SSM = "/app/db/host"  # Reference, not actual value
    }
  }

  # Track all changes except source_code_hash
  lifecycle {
    ignore_changes = [source_code_hash]
  }
}

2. Permission Management

# Explicit permission resources
resource "aws_lambda_permission" "api_gateway" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.app.function_name
  principal     = "apigateway.amazonaws.com"

  # Scope to specific API
  source_arn = "${aws_api_gateway_rest_api.api.execution_arn}/*/*"
}

resource "aws_lambda_permission" "s3" {
  statement_id  = "AllowS3Invoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.app.function_name
  principal     = "s3.amazonaws.com"
  source_arn    = aws_s3_bucket.uploads.arn

  # Ensure bucket exists first
  depends_on = [aws_s3_bucket.uploads]
}

3. Event Source Mapping

# SQS trigger with filtering
resource "aws_lambda_event_source_mapping" "queue" {
  event_source_arn = aws_sqs_queue.orders.arn
  function_name    = aws_lambda_function.processor.arn

  batch_size                         = 10
  maximum_batching_window_in_seconds = 5

  # Event filtering
  filter_criteria {
    filter {
      pattern = jsonencode({
        body = {
          orderType = ["premium", "express"]
        }
      })
    }
  }

  # Error handling
  function_response_types = ["ReportBatchItemFailures"]
}

# Kinesis stream trigger
resource "aws_lambda_event_source_mapping" "stream" {
  event_source_arn  = aws_kinesis_stream.events.arn
  function_name     = aws_lambda_function.analytics.arn
  starting_position = "LATEST"

  batch_size                         = 100
  maximum_batching_window_in_seconds = 10
  parallelization_factor             = 10

  # Retry and error handling
  maximum_retry_attempts             = 3
  maximum_record_age_in_seconds      = 86400
  bisect_batch_on_function_error     = true
  destination_config {
    on_failure {
      destination_arn = aws_sqs_queue.dlq.arn
    }
  }
}

4. Concurrency Management

# Reserve concurrency for critical functions
resource "aws_lambda_function" "critical_api" {
  function_name = "critical-payment-processor"
  runtime       = "nodejs20.x"
  handler       = "index.handler"
  role          = aws_iam_role.lambda.arn

  # Reserve dedicated capacity
  reserved_concurrent_executions = 100

  # Ensure consistent performance
  memory_size = 1024
  timeout     = 60
}

# Unreserved concurrency for non-critical functions
resource "aws_lambda_function" "background_job" {
  function_name = "background-cleanup"
  runtime       = "python3.12"
  handler       = "main.handler"
  role          = aws_iam_role.lambda.arn

  # Share account concurrency pool
  reserved_concurrent_executions = -1  # No reservation
}

5. VPC Configuration

# VPC-enabled Lambda with monitoring
resource "aws_lambda_function" "vpc_app" {
  function_name = "vpc-app"
  runtime       = "python3.12"
  handler       = "app.handler"
  role          = aws_iam_role.lambda_vpc.arn

  # VPC configuration
  vpc_config {
    subnet_ids         = aws_subnet.private[*].id
    security_group_ids = [aws_security_group.lambda.id]
  }

  # Track VPC changes
  lifecycle {
    prevent_destroy = true
  }
}

# Security group for Lambda
resource "aws_security_group" "lambda" {
  name        = "lambda-app-sg"
  description = "Security group for Lambda function"
  vpc_id      = aws_vpc.main.id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "lambda-app"
  }
}

Security Considerations

1. IAM Role Permissions

  • Monitor changes to execution role ARN
  • Alert on privilege escalation via role changes
  • Use least-privilege IAM policies
  • Track AssumeRolePolicyDocument modifications

2. Function Permissions (Resource Policy)

  • Monitor AddPermission events for unauthorized access
  • Restrict principal to known services/accounts
  • Use source_arn to scope permissions
  • Alert on wildcard principals or source ARNs

3. Environment Variables

  • Never store secrets in environment variables
  • Use AWS Secrets Manager or SSM Parameter Store
  • Monitor environment configuration changes
  • Encrypt environment variables with KMS

4. VPC Configuration

  • Track changes to VPC, subnets, security groups
  • Alert on transitions from VPC to no-VPC
  • Monitor security group rule changes
  • Ensure private subnet routing for RDS/ElastiCache access

5. Code Source

  • Use S3 versioning or ECR for code storage
  • Monitor UpdateFunctionCode events
  • Verify code integrity with source_code_hash
  • Implement code signing for production functions

6. Concurrency Limits

  • Monitor PutFunctionConcurrency events
  • Alert on concurrency limit removal
  • Track regional concurrency pool exhaustion
  • Use reserved concurrency for critical functions

Troubleshooting

High Alert Volume

  • Problem: Too many alerts for frequent code deployments
  • Solution: Use lifecycle.ignore_changes for source_code_hash
  • Consider filtering UpdateFunctionCode events in CI/CD deployments

Missing Configuration Changes

  • Problem: UpdateFunctionConfiguration events not detected
  • Solution: Verify CloudTrail is logging Lambda events
  • Check Falco plugin configuration for Lambda event filtering
  • Ensure eventName extraction is working correctly

Permission Drift Not Detected

  • Problem: AddPermission events not generating alerts
  • Solution: Verify Lambda permissions are managed by Terraform
  • Check that statement_id matches between Terraform and CloudTrail
  • Ensure resource policy changes are monitored

Event Source Mapping Issues

  • Problem: Event source changes not appearing
  • Solution: Verify UUID extraction from CloudTrail events
  • Check that mapping is managed by Terraform (not console-created)
  • Ensure eventSourceArn matches Terraform configuration

Alias Event Collisions

  • Problem: Lambda alias changes detected as KMS changes
  • Solution: Current limitation due to shared event names
  • Use Terraform state diff to identify actual resource type
  • Future enhancement will add eventSource-aware mapping

Version History

  • v0.3.0 (2025 Q1) - Lambda Enhanced support with 10 CloudTrail events
  • Function management (create, delete, code update, configuration)
  • Permissions (add, remove)
  • Event source mappings (create, update, delete)
  • Concurrency management
  • Comprehensive drift detection for serverless applications