Programming

My Terraform Drift Alert Could Not Explain the Drift

A

Admin User

Author

Jul 22, 2026
7 min read
12 views
My Terraform Drift Alert Could Not Explain the Drift

Summary

The Stack

Step 1: Publish Structured Drift Details

Step 2: Send the Event to SQS

resource "aws_sns_topic_subscription" "sqs" { topic_arn = aws_sns_topic.drift.arn protocol = "sqs" endpoint = aws_sqs_queue.drift_audit.arn }

The Queue Existed in the Wrong Region

Step 3: Classify Every Change with Lambda

# Severity definitions HIGH_RISK_TYPES = { "aws_security_group", "aws_security_group_rule", "aws_iam_role", "aws_iam_policy", "aws_iam_role_policy", "aws_iam_user", "aws_iam_group", "aws_iam_access_key", }

MEDIUM_RISK_TYPES = { "aws_instance", "aws_db_instance", "aws_ecs_cluster", "aws_ecs_service", "aws_ecs_task_definition", "aws_lb", "aws_lb_listener", "aws_lb_target_group", "aws_nat_gateway", "aws_route_table", "aws_network_acl", }

def classify_change(resource_type, actions): """Classify a single resource change by severity.""" if resource_type in HIGH_RISK_TYPES: return "HIGH" elif resource_type in MEDIUM_RISK_TYPES: # Delete or replace is more concerning than create if "delete" in actions or "replace" in actions: return "HIGH" return "MEDIUM" else: return "LOW"

def lambda_handler(event, context): """Process SNS message with drift details and classify severity.""" print(f"Received event: {json.dumps(event)}")

<span class="k">for</span> <span class="n">record</span> <span class="ow">in</span> <span class="n">event</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">Records</span><span class="sh">"</span><span class="p">,</span> <span class="p">[]):</span>
    <span class="c1"># SNS message is in the SNS record

sns_message = record.get("Sns", {}).get("Message", "{}")

    <span class="k">try</span><span class="p">:</span>
        <span class="n">drift_data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">loads</span><span class="p">(</span><span class="n">sns_message</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">json</span><span class="p">.</span><span class="n">JSONDecodeError</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Failed to parse SNS message: </span><span class="si">{</span><span class="n">sns_message</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">continue</span>

    <span class="n">timestamp</span> <span class="o">=</span> <span class="n">drift_data</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span>
        <span class="sh">"</span><span class="s">timestamp</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">datetime</span><span class="p">.</span><span class="nf">now</span><span class="p">(</span><span class="n">timezone</span><span class="p">.</span><span class="n">utc</span><span class="p">).</span><span class="nf">isoformat</span><span class="p">()</span>
    <span class="p">)</span>
    <span class="n">project</span> <span class="o">=</span> <span class="n">drift_data</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">project</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">unknown</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">changes</span> <span class="o">=</span> <span class="n">drift_data</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">changes</span><span class="sh">"</span><span class="p">,</span> <span class="p">[])</span>

    <span class="c1"># Classify each change

classified = {"HIGH": [], "MEDIUM": [], "LOW": []}

    <span class="k">for</span> <span class="n">change</span> <span class="ow">in</span> <span class="n">changes</span><span class="p">:</span>
        <span class="n">address</span> <span class="o">=</span> <span class="n">change</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">address</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">unknown</span><span class="sh">"</span><span class="p">)</span>
        <span class="n">resource_type</span> <span class="o">=</span> <span class="n">change</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">unknown</span><span class="sh">"</span><span class="p">)</span>
        <span class="n">actions</span> <span class="o">=</span> <span class="n">change</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">actions</span><span class="sh">"</span><span class="p">,</span> <span class="p">[])</span>

        <span class="n">severity</span> <span class="o">=</span> <span class="nf">classify_change</span><span class="p">(</span><span class="n">resource_type</span><span class="p">,</span> <span class="n">actions</span><span class="p">)</span>
        <span class="n">classified</span><span class="p">[</span><span class="n">severity</span><span class="p">].</span><span class="nf">append</span><span class="p">({</span>
            <span class="sh">"</span><span class="s">address</span><span class="sh">"</span><span class="p">:</span> <span class="n">address</span><span class="p">,</span>
            <span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="n">resource_type</span><span class="p">,</span>
            <span class="sh">"</span><span class="s">actions</span><span class="sh">"</span><span class="p">:</span> <span class="n">actions</span><span class="p">,</span>
        <span class="p">})</span>

    <span class="c1"># Build summary

summary = { "timestamp": timestamp, "project": project, "total_changes": len(changes), "high_count": len(classified["HIGH"]), "medium_count": len(classified["MEDIUM"]), "low_count": len(classified["LOW"]), "classified": classified, }

    <span class="c1"># Log the classified drift

print( f"Drift classification: {json.dumps(summary, indent=2)}" )

    <span class="c1"># TODO Phase 3: Auto-remediate HIGH severity changes

# TODO Phase 3: Alert on MEDIUM severity changes return {"statusCode": 200, "body": "Drift classified"}

The Lambda Package Needed Another Provider

Verification

What Is Next

Source

This article discusses content originally published by at Dev.to.

Read the original article

Share this article

Written by Adil Sher

Full stack developer building high-traffic platforms, AI services, and custom web applications. Explore my portfolio, learn about my background, or get in touch.

Related Articles

JavaScript's Type Coercion Will Haunt You Until You Stop Fighting It
Programming Aug 2

JavaScript's Type Coercion Will Haunt You Until You Stop Fighting It

I remember the exact moment I stopped being angry at JavaScript. I was debugging a production bug at 2 AM, staring at a comparison that made absolutely no sense on the surface. The code was doing something impossible according to basic math. I wanted to blame the language. Then I...