<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Esteban</title>
    <description>The latest articles on DEV Community by Esteban (@estebanpiero).</description>
    <link>https://dev.to/estebanpiero</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1173154%2Febce6bc4-38c1-495f-9602-95a3a86acefd.PNG</url>
      <title>DEV Community: Esteban</title>
      <link>https://dev.to/estebanpiero</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/estebanpiero"/>
    <language>en</language>
    <item>
      <title>Building Agentic AI with Amazon Bedrock – Part 1: Your First AI Agent (Beginner Friendly)</title>
      <dc:creator>Esteban</dc:creator>
      <pubDate>Fri, 14 Nov 2025 03:02:34 +0000</pubDate>
      <link>https://dev.to/aws-builders/building-agentic-ai-with-amazon-bedrock-part-1-your-first-ai-agent-beginner-friendly-5436</link>
      <guid>https://dev.to/aws-builders/building-agentic-ai-with-amazon-bedrock-part-1-your-first-ai-agent-beginner-friendly-5436</guid>
      <description>&lt;p&gt;Imagine an AI that doesn't just answer questions, but actually "does things" for you, for example, checking the weather, booking appointments, or analyzing data. These are called agentic AI systems, and they're transforming how we interact with artificial intelligence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;BTW, this is Part 1 of a four-part project series that I am building. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This series walks you step-by-step through building real agentic AI systems, from your sime first tool call, to a full production-ready knowledge assistant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project 1 — Weather Agent (Beginner)&lt;/strong&gt; -&amp;gt; Learn the core agent pattern: Define a tool → Call the model → Handle tool_use → Return results to Claude.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project 2 — Research Assistant (Intermediate)&lt;/strong&gt; -&amp;gt; Introduce multi-tool orchestration and build an agentic loop that handles multiple tool calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project 3 — Task Planner (Advanced)&lt;/strong&gt; -&amp;gt; Your agent plans its own execution, retries on failure, and reflects on improvements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project 4 — Knowledge Base Agent (Production)&lt;/strong&gt; -&amp;gt; Use Bedrock’s managed agents + RAG to build enterprise-ready assistants.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;My Approach: Applying Infrastructure as Code with Python&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why Python Scripts Instead of Manual Console Work?&lt;/p&gt;

&lt;p&gt;Throughout this tutorial, you'll notice that I use Python scripts to create and configure AWS resources rather than clicking through the AWS Console. This is intentional and reflects real-world best practices. Here's why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repeatability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why moving out from the GUI Approach:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• Make a mistake? Start over, clicking through 20+ screens
• Want to create in another region? Repeat all steps manually
• Team member needs to replicate? Send them a 50-step document
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Why is better with Python Scripting Approach:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• Make a mistake? Fix the script and re-run
• Different region? Change one variable
• Share with team? Send them the script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  Project 1: Build Your First AI Agent With Amazon Bedrock
&lt;/h2&gt;

&lt;p&gt;In this project you'll build your first AI agent from scratch using Amazon Bedrock and AWS Lambda. By the end, you'll have a fully functional weather assistant that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understands natural language requests&lt;/li&gt;
&lt;li&gt;Calls an external API to get real-time data&lt;/li&gt;
&lt;li&gt;Synthesizes information into helpful responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Amazon Bedrock is and how it works&lt;/li&gt;
&lt;li&gt;How to create AI agents that can use tools&lt;/li&gt;
&lt;li&gt;How to build Lambda functions as agent tools&lt;/li&gt;
&lt;li&gt;How to connect everything using Action Groups&lt;/li&gt;
&lt;li&gt;How to test and deploy your agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS account &lt;/li&gt;
&lt;li&gt;Basic Python knowledge (or use AI to help you, as I did)&lt;/li&gt;
&lt;li&gt;Terminal/command line familiarity&lt;/li&gt;
&lt;li&gt;20-40 minutes of your time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Concepts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Foundation Models&lt;/strong&gt;: Pre-trained AI models you can use via API. Bedrock offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude (Anthropic) - Advanced reasoning and tool use&lt;/li&gt;
&lt;li&gt;Llama (Meta)&lt;/li&gt;
&lt;li&gt;Amazon Titan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Agents&lt;/strong&gt;: AI systems that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand natural language&lt;/li&gt;
&lt;li&gt;Decide when to use tools&lt;/li&gt;
&lt;li&gt;Execute actions&lt;/li&gt;
&lt;li&gt;Synthesize responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Action Groups&lt;/strong&gt;: Collections of tools (functions) your agent can use. Think of them as the agent's "superpowers."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;: Functions your agent can call, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checking weather&lt;/li&gt;
&lt;li&gt;Querying databases&lt;/li&gt;
&lt;li&gt;Calling APIs&lt;/li&gt;
&lt;li&gt;Processing data&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How Bedrock Agents Work: The Big Picture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcr7mqvk7z7vwd8z9exy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcr7mqvk7z7vwd8z9exy.png" alt=" " width="678" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User asks: "What's the weather in NYC?"
          ↓
    [Bedrock Agent]
    - Powered by Claude
    - Has your instructions
    - Knows about action groups
          ↓
    Agent thinks: "I need weather data. 
                   I have a 'get_weather' action. 
                   I'll use that!"
          ↓
    [Action Group]
    - Knows this action calls a Lambda function
          ↓
    [Lambda Function]
    - Calls weather API
    - Gets real data
    - Returns it
          ↓
    [Back to Agent]
    - Receives weather data
    - Crafts natural response
          ↓
    User gets: "It's 52°F and rainy in New York City. 
                Bring an umbrella!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Enable Bedrock Model Access&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we start coding, check if you have access to Claude (or your AI model of preference)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws bedrock list-foundation-models \
--region us-east-1 \
--query 'modelSummaries[?contains(modelId,anthropic.claude`)].modelId'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you see an error, go to AWS Console → Bedrock → Model Access → Request Access to Claude 3.5 Sonnet models &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Building the Lambda Function
&lt;/h1&gt;

&lt;p&gt;What is Lambda? AWS Lambda is a service that runs your code without you managing servers.&lt;/p&gt;

&lt;p&gt;Perfect for our use case because:&lt;br&gt;
    - Agent calls Lambda only when user asks about weather&lt;br&gt;
    - Could be once an hour or 1000 times an hour - Lambda scales automatically&lt;br&gt;
    - You pay only for actual requests (free tier: 1M requests/month)&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;lambda_function.py&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json
import os
import urllib.request
import urllib.parse
from typing import Tuple, Optional, Dict

USER_AGENT = "WeatherAssistant/1.0"

def http_get_json(url: str, headers: Optional[Dict] = None, timeout: int = 8) -&amp;gt; dict:
    req = urllib.request.Request(url, headers=headers or {})
    with urllib.request.urlopen(req, timeout=timeout) as resp:
    return json.loads(resp.read().decode("utf-8"))

def geocode_city(city: str) -&amp;gt; Optional[Tuple[float, float]]:
    if not city:
        return None
    params = urllib.parse.urlencode({"q": city, "format": "json", "limit": 1})
    url = f"https://nominatim.openstreetmap.org/search?{params}"
    headers = {"User-Agent": USER_AGENT}
    try:
        results = http_get_json(url, headers=headers)
        if not results:
            return None
        return float(results[0]["lat"]), float(results[0]["lon"])
    except Exception as e:
        print(f"[ERROR] Geocoding failed: {e}")
        return None

def get_grid_endpoints(lat: float, lon: float) -&amp;gt; Tuple[str, str]:
    url = f"https://api.weather.gov/points/{lat:.4f},{lon:.4f}"
    headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
    data = http_get_json(url, headers=headers)
    props = data.get("properties", {})
    return props["forecast"], props["forecastHourly"]

def get_forecast(url: str) -&amp;gt; dict:
    headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
    return http_get_json(url, headers=headers)

def summarize_hourly_24h(hourly_json: dict) -&amp;gt; str:
    periods = hourly_json.get("properties", {}).get("periods", [])
    if not periods:
        return "No hourly forecast available."
    lines = []
    for p in periods[:24]:
        temp = p.get("temperature")
        unit = p.get("temperatureUnit", "F")
        short = p.get("shortForecast", "")
        wind = f"{p.get('windSpeed', '')} {p.get('windDirection', '')}".strip()
        lines.append(f"{temp}°{unit}, {short}, wind {wind}")
    return "Next 24 hours: " + " | ".join(lines[:6])

def lambda_handler(event, context):
    print(f"Received event: {json.dumps(event, default=str)}")
    api_path = event.get('apiPath', '/weather') # Extract parameters from Bedrock agent format
    http_method = event.get('httpMethod', 'GET')
    parameters = event.get('parameters', [])
    # Parse parameters
    city = None
    mode = "hourly"
    for param in parameters:
        if param['name'] == 'city':
            city = param['value']
        elif param['name'] == 'mode':
            mode = param['value']
    print(f"Parsed: city={city}, mode={mode}")
    # Validate input
    if not city:
        return {
            "messageVersion": "1.0",
            "response": {
                "actionGroup": event.get('actionGroup', 'weather-tools'),
                "apiPath": api_path,
                "httpMethod": http_method,
                "httpStatusCode": 400,
                "responseBody": {
                    "application/json": {
                        "body": json.dumps({"error": "Missing required parameter: city"})
                    }
                }
            }
        }
        try:
        # Geocode city
        coords = geocode_city(city)
        if not coords:
            return {
                "messageVersion": "1.0",
                "response": {
                    "actionGroup": event.get('actionGroup', 'weather-tools'),
                    "apiPath": api_path,
                    "httpMethod": http_method,
                    "httpStatusCode": 404,
                    "responseBody": {
                        "application/json": {
                            "body": json.dumps({"error": f"Could not find city: {city}"})
                        }
                    }
                }
            }
        lat, lon = coords
        print(f"Geocoded '{city}' to lat={lat}, lon={lon}")
        # Get weather
        forecast_url, hourly_url = get_grid_endpoints(lat, lon)
        data = get_forecast(hourly_url if mode == "hourly" else forecast_url)
        weather_report = summarize_hourly_24h(data)
        # Return in correct Bedrock format
        return {
            "messageVersion": "1.0",
            "response": {
                "actionGroup": event.get('actionGroup', 'weather-tools'),
                "apiPath": api_path,  # CRITICAL: Must match input
                "httpMethod": http_method,
                "httpStatusCode": 200,
                "responseBody": {
                    "application/json": {
                        "body": json.dumps({"weather_report": weather_report})
                    }
                }
            }
        }
        except Exception as e:
        print(f"[ERROR] {e}")
        return {
            "messageVersion": "1.0",
            "response": {
                "actionGroup": event.get('actionGroup', 'weather-tools'),
                "apiPath": api_path,
                "httpMethod": http_method,
                "httpStatusCode": 500,
                "responseBody": {
                    "application/json": {
                        "body": json.dumps({"error": "Weather service error"})
                    }
                }
            }
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Understanding the code:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;geocode_city&lt;/strong&gt;: Converts city names to GPS coordinates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;get_grid_endpoints&lt;/strong&gt;: Gets weather.gov forecast URLs for coordinates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;get_forecast&lt;/strong&gt;: Fetches weather data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;summarize_hourly_24h&lt;/strong&gt;: Formats data for easy reading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lambda_handler&lt;/strong&gt;: Main entry point that orchestrates everything&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lambda needs permission to write logs, for this we are going to create an IAM Role for the Lambda function&lt;/p&gt;

&lt;p&gt;Create trust-policy.json:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create the IAM role&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam create-role \
    --role-name WeatherLambdaRole \
    --assume-role-policy-document file://trust-policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Attach policy for CloudWatch logging&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam attach-role-policy \
    --role-name WeatherLambdaRole \
    --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Get the role ARN (save this!)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam get-role \
    --role-name WeatherLambdaRole \
    --query 'Role.Arn' \
    --output text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Save the ARN - it looks like: &lt;code&gt;arn:aws:iam::123456789012:role/WeatherLambdaRole&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy the Lambda Function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Package the code&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zip function.zip lambda_function.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Deploy to AWS (replace YOUR_ROLE_ARN with the ARN from step 2)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws lambda create-function \
    --function-name bedrock-weather-function \
    --runtime python3.11 \
    --role **YOUR_ROLE_ARN **\
    --handler lambda_function.lambda_handler \
    --zip-file fileb://function.zip \
    --timeout 30 \
        --memory-size 256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h1&gt;
  
  
  Creating the Bedrock Agent
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 1: Create IAM Role for the Agent
&lt;/h2&gt;

&lt;p&gt;The agent needs permissions to invoke Lambda and call Bedrock models.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;agent-trust-policy.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create &lt;code&gt;agent-permissions.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "lambda:InvokeFunction"
      ],
      "Resource": "arn:aws:lambda:us-east-1:*:function:bedrock-weather-function"
    },
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel"
      ],
      "Resource": "*"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create role&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam create-role \
    --role-name BedrockAgentRole \
    --assume-role-policy-document file://agent-trust-policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Attach permissions&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam put-role-policy \
    --role-name BedrockAgentRole \
    --policy-name AgentPermissions \
    --policy-document file://agent-permissions.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Get the role ARN (save this!)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam get-role \
    --role-name BedrockAgentRole \
    --query 'Role.Arn' \
    --output text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Wait for role to propagate&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sleep 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 2: Create the Agent
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;create_agent.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
import json
import time

client = boto3.client('bedrock-agent', region_name='us-east-1')

# Replace with your role ARN
ROLE_ARN = 'arn:aws:iam::YOUR_ACCOUNT:role/BedrockAgentRole'

print("Creating Bedrock agent...")

try:
    response = client.create_agent(
        agentName='weather-assistant',
        agentResourceRoleArn=ROLE_ARN,
        foundationModel='us.anthropic.claude-3-5-sonnet-20241022-v2:0',
        instruction=(
            "You are a helpful weather assistant. "
            "When users ask about weather in any US city, use the getWeather tool "
            "to fetch current conditions and forecasts. "
            "Provide friendly, conversational responses with relevant weather details. "
            "If asked about multiple cities, check each one. "
            "Always mention temperature, conditions, and any important weather alerts."
        ),
        idleSessionTTLInSeconds=600
    )

    agent_id = response['agent']['agentId']

    print(f"✅ Agent created successfully!")
    print(f"Agent ID: {agent_id}")
    print(f"Agent Name: {response['agent']['agentName']}")
    print(f"\nSave this Agent ID for the next steps!")

    # Save to file
    with open('agent-config.json', 'w') as f:
        json.dump({'agent_id': agent_id}, f)

except Exception as e:
    print(f"❌ Error: {str(e)}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run it:&lt;/p&gt;

&lt;p&gt;python3 create_agent.py&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create the Action Group
&lt;/h2&gt;

&lt;p&gt;Action Groups connect your Lambda function to the agent using an OpenAPI schema.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;create_action_group.py&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
import json

client = boto3.client('bedrock-agent', region_name='us-east-1')

    #Replace these with your values

AGENT_ID = 'YOUR_AGENT_ID'  # From previous step
LAMBDA_ARN = 'arn:aws:lambda:us-east-1:YOUR_ACCOUNT:function:bedrock-weather-function'

    #OpenAPI schema defining the tool

openapi_schema = {
    "openapi": "3.0.0",
    "info": {
        "title": "Weather API",
        "version": "1.0.0",
        "description": "API for getting weather forecasts for US cities"
    },
    "paths": {
        "/weather": {
            "get": {
                "summary": "Get weather forecast",
                "description": "Get weather forecast for a US city. Use when user asks about weather, temperature, or conditions.",
                "operationId": "getWeather",
                "parameters": [
                    {
                        "name": "city",
                        "in": "query",
                        "description": "US city name (e.g. 'Seattle', 'New York')",
                        "required": True,
                        "schema": {"type": "string"}
                    },
                    {
                        "name": "mode",
                        "in": "query",
                        "description": "Forecast type: 'hourly' or 'daily'",
                        "required": False,
                        "schema": {
                            "type": "string",
                            "enum": ["hourly", "daily"],
                            "default": "hourly"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Weather forecast",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "weather_report": {"type": "string"}
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

print("Creating action group...")

try:
    response = client.create_agent_action_group(
        agentId=AGENT_ID,
        agentVersion='DRAFT',
        actionGroupName='weather-tools',
        actionGroupExecutor={'lambda': LAMBDA_ARN},
        apiSchema={'payload': json.dumps(openapi_schema)},
        description='Tools for getting weather information',
        actionGroupState='ENABLED'
    )

    print("✅ Action group created!")
    print(f"Action Group ID: {response['agentActionGroup']['actionGroupId']}")

except Exception as e:
    print(f"❌ Error: {str(e)}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 create_action_group.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 4: Prepare and Deploy the Agent
&lt;/h2&gt;

&lt;p&gt;Prepare the agent (builds and validates)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws bedrock-agent prepare-agent --agent-id YOUR_AGENT_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Wait for preparation (30-60 seconds)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sleep 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create an alias for testing&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws bedrock-agent create-agent-alias \
    --agent-id YOUR_AGENT_ID \
    --agent-alias-name dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Save the alias ID from the output&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5: Testing Your Agent
&lt;/h2&gt;

&lt;p&gt;Create the Test Script called &lt;code&gt;test-agent.py&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
import json
import sys

client = boto3.client('bedrock-agent-runtime', region_name='us-east-1')

# Replace with your values
AGENT_ID = 'YOUR_AGENT_ID'
AGENT_ALIAS_ID = 'YOUR_ALIAS_ID'

def chat(message):
    """Send a message to the agent and display the response."""

    print(f"\n{'='*70}")
    print(f"You: {message}")
    print(f"{'='*70}\n")

    response = client.invoke_agent(
        agentId=AGENT_ID,
        agentAliasId=AGENT_ALIAS_ID,
        sessionId='test-session',
        inputText=message,
        enableTrace=True
    )

    print("Agent: ", end='', flush=True)

    for event in response['completion']:
        if 'chunk' in event:
            chunk = event['chunk']
            if 'bytes' in chunk:
                print(chunk['bytes'].decode('utf-8'), end='', flush=True)

        elif 'trace' in event:
            trace = event['trace']
            if 'trace' in trace:
                trace_data = trace['trace']
                if 'orchestrationTrace' in trace_data:
                    orch = trace_data['orchestrationTrace']

                    if 'invocationInput' in orch:
                        inv = orch['invocationInput']
                        if 'actionGroupInvocationInput' in inv:
                            action = inv['actionGroupInvocationInput']
                            params = {p['name']: p['value'] for p in action.get('parameters', [])}
                            print(f"\n[Calling tool with params: {params}]")

    print("\n" + "="*70 + "\n")

if __name__ == "__main__":
    # Interactive mode
    print("\n🌤️  Weather Agent - Type 'exit' to quit\n")

    while True:
        try:
            query = input("You: ").strip()
            if query.lower() in ['exit', 'quit']:
                break
            if query:
                chat(query)
        except KeyboardInterrupt:
            break

    print("\n👋 Goodbye!\n")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Test It!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 test-agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Try these queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What's the weather in NYC?"&lt;/li&gt;
&lt;li&gt;"How's the weather in Miami and New York?"&lt;/li&gt;
&lt;li&gt;"Is it going to rain in Boston today?"&lt;/li&gt;
&lt;li&gt;"What's the forecast for San Francisco?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Expected interaction:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: What's the weather in NYC?

[Calling tool with params: {'city': 'NYC', 'mode': 'hourly'}]

Agent: The weather in NYC is currently 52°F with partly cloudy skies. 
Wind is light at 5 mph from the west. Over the next few hours, temperatures 
will stay in the low 50s with continued partly cloudy conditions. It's a 
pleasant day in NYC!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Part 6: Understanding What You Built
&lt;/h2&gt;

&lt;p&gt;The Complete Flow&lt;/p&gt;

&lt;p&gt;Let's trace through what happens when you ask "What's the weather in NYC?":&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. User Input → Bedrock Agent&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You type: "What's the weather in NYC?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Agent Reasoning (Claude 3.5 Sonnet)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claude thinks: "The user wants weather information for NYC. 
I have a getWeather tool available. I should use it with city='NYC'."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. Agent → Action Group&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request to Action Group:
{
  "apiPath": "/weather",
  "parameters": [
    {"name": "city", "value": "NYC"}
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4. Action Group → Lambda Function&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bedrock invokes: bedrock-weather-function
With parameters: city=NYC, mode=hourly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;5. Lambda Execution&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: Geocode "NYC" → (40.7306,-73.9352)
Step 2: Call weather.gov/points/40.7306,-73.9352
Step 3: Get hourly forecast URL
Step 4: Fetch forecast data
Step 5: Format response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;6. Lambda → Agent&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Returns: {
  "weather_report": "Next 24 hours: 52°F, Partly Cloudy, wind 5 mph W | ..."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;7. Agent Synthesis&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claude reads the data and creates a natural response:
"The weather in NYC is currently 52°F with partly cloudy skies..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;8. Response → User&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You see the friendly, natural language response!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h1&gt;
  
  
  Key Concepts Demonstrated
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;1. Agentic Reasoning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The AI doesn't just follow a script—it &lt;em&gt;decides&lt;/em&gt; when and how to use tools based on the user's request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Tool Abstraction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You defined what the tool does (OpenAPI schema), and the AI figures out how to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Natural Language Interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Users don't need to know about APIs, parameters, or JSON—they just ask naturally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Error Handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Lambda function handles missing cities, API failures, and edge cases gracefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Serverless Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything scales automatically. No servers to manage, pay only for what you use.&lt;/p&gt;




&lt;h1&gt;
  
  
  Troubleshooting
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Common Issues and Solutions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Issue: "Invocation of model ID with on-demand throughput isn't supported"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Use inference profile instead of direct model ID:&lt;/p&gt;

&lt;p&gt;Update agent with correct model&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws bedrock-agent update-agent \
    --agent-id YOUR_AGENT_ID \
    --agent-name weather-assistant \
    --agent-resource-role-arn YOUR_ROLE_ARN \
    --foundation-model us.anthropic.claude-3-5-sonnet-20241022-v2:0

# Prepare agent
aws bedrock-agent prepare-agent --agent-id YOUR_AGENT_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Issue: "APIPath in Lambda response doesn't match input"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ensure Lambda returns &lt;code&gt;apiPath&lt;/code&gt; exactly as received:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return {
    "response": {
        "apiPath": event.get('apiPath', '/weather'),  # Must match input
        ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Issue: "City not found"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; OpenStreetMap couldn't geocode the city name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Try more specific names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ "Portland" → ✅ "Portland, OR"&lt;/li&gt;
&lt;li&gt;❌ "Springfield" → ✅ "Springfield, IL"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Issue: Lambda times out&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Increase timeout:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws lambda update-function-configuration \
    --function-name bedrock-weather-function \
    --timeout 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Issue: "Weather service temporarily unavailable"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cause:&lt;/strong&gt; weather.gov only covers US locations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; The API works only for US cities. For international weather, you'd need a different API (like OpenWeatherMap).&lt;/p&gt;

&lt;h3&gt;
  
  
  Viewing Lambda Logs for Debugging
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;View recent logs&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws logs tail /aws/lambda/bedrock-weather-function --follow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each function execution&lt;/li&gt;
&lt;li&gt;Print statements&lt;/li&gt;
&lt;li&gt;Errors with stack traces&lt;/li&gt;
&lt;li&gt;Execution duration and memory used&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Cost Analysis
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What Does This Cost to Run?
&lt;/h2&gt;

&lt;p&gt;Let's break down the costs for 1,000 weather queries per month:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Amazon Bedrock (Claude 3.5 Sonnet)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: ~200 tokens per query = 200K tokens&lt;/li&gt;
&lt;li&gt;Output: ~150 tokens per response = 150K tokens&lt;/li&gt;
&lt;li&gt;Cost: $3.00 per million input tokens, $15.00 per million output tokens&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monthly cost: $0.60 + $2.25 = $2.85&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. AWS Lambda&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 executions × 2 seconds each = 2,000 seconds&lt;/li&gt;
&lt;li&gt;256MB memory allocation&lt;/li&gt;
&lt;li&gt;First 1M requests free, then $0.20 per million&lt;/li&gt;
&lt;li&gt;First 400,000 GB-seconds free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly cost: $0.00&lt;/strong&gt; (within free tier)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. CloudWatch Logs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~5KB per execution = 5MB total&lt;/li&gt;
&lt;li&gt;First 5GB free per month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly cost: $0.00&lt;/strong&gt; (within free tier)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total: ~$3.00 per month for 1,000 queries&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;You've just built a fully functional AI agent that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses Claude 3.5 Sonnet for natural language understanding&lt;/li&gt;
&lt;li&gt;Autonomously decides when to use tools&lt;/li&gt;
&lt;li&gt;Calls external APIs to get real-time data&lt;/li&gt;
&lt;li&gt;Handles errors gracefully&lt;/li&gt;
&lt;li&gt;Costs less than $3/month for typical usage&lt;/li&gt;
&lt;li&gt;Scales automatically with demand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the foundation for building powerful AI applications. The pattern you learned—&lt;strong&gt;Agent → Action Group → Lambda → External API&lt;/strong&gt;—can be applied to countless use cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thank You!
&lt;/h2&gt;

&lt;p&gt;I hope this guide has shown you that building AI agents is not only possible but actually straightforward with the right tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coming in Part 2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building multi-tool agents that orchestrate complex workflows&lt;/li&gt;
&lt;li&gt;Adding Knowledge Bases for document retrieval (RAG)&lt;/li&gt;
&lt;li&gt;Implementing agent memory and conversation context&lt;/li&gt;
&lt;li&gt;Advanced error handling and recovery strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned!&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Setting Up Inter-Region VPC Communication Using AWS Transit Gateway</title>
      <dc:creator>Esteban</dc:creator>
      <pubDate>Wed, 07 May 2025 13:06:23 +0000</pubDate>
      <link>https://dev.to/aws-builders/setting-up-inter-region-vpc-communication-using-aws-transit-gateway-522m</link>
      <guid>https://dev.to/aws-builders/setting-up-inter-region-vpc-communication-using-aws-transit-gateway-522m</guid>
      <description>&lt;p&gt;As cloud environments grow across multiple AWS regions and accounts, managing a scalable and secure network architecture becomes essential. AWS Transit Gateway (TGW) offers a hub-and-spoke model that consolidates routing between VPCs and on-prem networks. Unlike traditional VPC peering (point-to-point), TGW enables centralized routing, dynamic scalability, and BGP-based routing for efficient inter-region communication.&lt;/p&gt;

&lt;p&gt;In this article, we’ll build a Transit Gateway-based Inter-Region VPC architecture, walk through step-by-step GUI and CLI setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture for this Setup
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyin7vsi7678u3za79k4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyin7vsi7678u3za79k4.png" alt="Image description" width="631" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Transit Gateway in each region (us-east-1, us-west-2)&lt;/li&gt;
&lt;li&gt;Two VPCs (VPC-East, VPC-West) with non-overlapping CIDRs&lt;/li&gt;
&lt;li&gt;Attach VPCs to their local TGWs&lt;/li&gt;
&lt;li&gt;Peer both TGWs across regions&lt;/li&gt;
&lt;li&gt;Create TGW Route Tables to enable traffic flow&lt;/li&gt;
&lt;li&gt;Simulate a blackhole scenario&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1: Create VPCs and Subnets&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the AWS Console for both regions (us-east-1 and us-west-2)&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;VPC → Create VPC&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select “VPC only”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Region A: CIDR block: 10.10.0.0/16, name: VPC-East&lt;/p&gt;

&lt;p&gt;For Region B: CIDR block: 10.20.0.0/16, name: VPC-West&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the left-hand menu, click &lt;strong&gt;“Subnets”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;“Create subnet”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the VPC you want to attach the subnet to.&lt;/li&gt;
&lt;li&gt;Add the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Region A:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name tag:&lt;/strong&gt; Subnet-East&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability Zone:&lt;/strong&gt; us-east-1a&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPv4 CIDR block:&lt;/strong&gt; 10.10.1.0/24&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Region B:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name tag:&lt;/strong&gt; Subnet-West&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability Zone:&lt;/strong&gt; us-west-2a&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPv4 CIDR block:&lt;/strong&gt; 10.20.1.0/24&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# VPC-East
aws ec2 create-vpc --cidr-block 10.10.0.0/16 --region us-east-1 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC-East}]'

# Subnet-East (in VPC-East)
aws ec2 create-subnet \
--vpc-id &amp;lt;vpc-east-id&amp;gt; \
--cidr-block 10.10.1.0/24 \
--availability-zone us-east-1a \
--region us-east-1 \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Subnet-East}]'


# VPC-West
aws ec2 create-vpc --cidr-block 10.20.0.0/16 --region us-west-2 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=VPC-West}]'

# Subnet-West (in VPC-West)
aws ec2 create-subnet \
--vpc-id &amp;lt;vpc-west-id&amp;gt; \
--cidr-block 10.20.1.0/24 \
--availability-zone us-west-2a \
--region us-west-2 \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Subnet-West}]'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2: Create Transit Gateways&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to VPC Console in Region A (us-east-1)&lt;/li&gt;
&lt;li&gt;Select “Transit Gateways” from the left menu&lt;/li&gt;
&lt;li&gt;Click “Create Transit Gateway”&lt;/li&gt;
&lt;li&gt;Configure settings:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8hmv94jaj11muu22jrs0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8hmv94jaj11muu22jrs0.png" alt="Image description" width="410" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwsz2x2sr4hvj4ats5no.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwsz2x2sr4hvj4ats5no.png" alt="Image description" width="720" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note: Repeat the same process in region B (us-west-2)&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create Transit Gateway in Region A
aws ec2 create-transit-gateway \
 — description “Transit Gateway for Region A” \
 — region us-east-1 \
 — tag-specifications ‘ResourceType=transit-gateway,Tags=[{Key=Name,Value=TGW-Region-A}]’

# Create Transit Gateway in Region B
aws ec2 create-transit-gateway \
 — description “Transit Gateway for Region B” \
 — region us-west-2 \
 — tag-specifications ‘ResourceType=transit-gateway,Tags=[{Key=Name,Value=TGW-Region-B}]’
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3: Attach VPCs to Transit Gateways&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In VPC Console, select “Transit Gateway Attachments”&lt;/li&gt;
&lt;li&gt;Click “Create Transit Gateway Attachment”&lt;/li&gt;
&lt;li&gt;Configure settings:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5o1ix7q8cxkkaafey29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5o1ix7q8cxkkaafey29.png" alt="Image description" width="297" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Attach VPC to Transit Gateway in Region A

aws ec2 create-transit-gateway-vpc-attachment \
 - transit-gateway-id tgw-xxxxx \
 - vpc-id vpc-xxxxx \
 - subnet-ids subnet-xxxxx subnet-yyyyy \
 - region us-east-1

# Attach VPC to Transit Gateway in Region B

aws ec2 create-transit-gateway-vpc-attachment \
 - transit-gateway-id tgw-yyyyy \
 - vpc-id vpc-yyyyy \
 - subnet-ids subnet-aaaaa subnet-bbbbb \
 - region us-west-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Create Transit Gateway Peering Attachment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Region A’s VPC Console&lt;/li&gt;
&lt;li&gt;Select “Transit Gateway Attachments”&lt;/li&gt;
&lt;li&gt;Click “Create Transit Gateway Attachment”&lt;/li&gt;
&lt;li&gt;Configure settings:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Attachment type: Peering Connection&lt;/li&gt;
&lt;li&gt;Transit Gateway (Accepter): Select Region B’s TGW ID&lt;/li&gt;
&lt;li&gt;Region: Select Region B&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create peering attachment
aws ec2 create-transit-gateway-peering-attachment \
 - transit-gateway-id tgw-xxxxx \
 - peer-transit-gateway-id tgw-yyyyy \
 - peer-region us-west-2 \
 - region us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5: Accept Peering Attachment&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Switch to Region B’s VPC Console&lt;/li&gt;
&lt;li&gt;Select “Transit Gateway Attachments”&lt;/li&gt;
&lt;li&gt;Select the pending peering attachment&lt;/li&gt;
&lt;li&gt;Click “Accept”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Accept peering attachment
aws ec2 accept-transit-gateway-peering-attachment \
 - transit-gateway-attachment-id tgw-attach-xxxxx \
 - region us-west-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 6: Configure Route Tables
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In each region’s VPC Console:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to “Transit Gateway Route Tables”&lt;/li&gt;
&lt;li&gt;Add routes pointing to the peered TGW&lt;/li&gt;
&lt;li&gt;Update VPC route tables to route inter-region traffic through TGW&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Add route to Transit Gateway route table in Region A
aws ec2 create-transit-gateway-route \
 - destination-cidr-block 10.20.0.0/16 \
 - transit-gateway-route-table-id tgw-rtb-xxxxx \
 - transit-gateway-attachment-id tgw-attach-xxxxx \
 - region us-east-1

# Add route to VPC route table in Region A
aws ec2 create-route \
 - route-table-id rtb-xxxxx \
 - destination-cidr-block 10.20.0.0/16 \
 - transit-gateway-id tgw-xxxxx \
 - region us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 7: Implementing Blackhole Routes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What Are Blackhole Routes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A blackhole route drops traffic that matches a destination CIDR. It’s useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blocking specific IP ranges&lt;/li&gt;
&lt;li&gt;Preventing unauthorized access&lt;/li&gt;
&lt;li&gt;Implementing security controls&lt;/li&gt;
&lt;li&gt;Avoiding routing loops&lt;/li&gt;
&lt;li&gt;Isolating problematic traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GUI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to VPC Console&lt;/li&gt;
&lt;li&gt;Select “Transit Gateway Route Tables”&lt;/li&gt;
&lt;li&gt;Select the appropriate route table&lt;/li&gt;
&lt;li&gt;Choose “Actions” → “Create static route”&lt;/li&gt;
&lt;li&gt;Configure the blackhole route:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;CIDR block: (specify the IP range to block)&lt;/li&gt;
&lt;li&gt;Choose “Blackhole”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a blackhole route in Region A
aws ec2 create-transit-gateway-route \
    --destination-cidr-block 10.0.0.0/16 \
    --blackhole \
    --transit-gateway-route-table-id tgw-rtb-xxxxx \
    --region us-east-1

# Create a blackhole route in Region B
aws ec2 create-transit-gateway-route \
    --destination-cidr-block 172.16.0.0/16 \
    --blackhole \
    --transit-gateway-route-table-id tgw-rtb-yyyyy \
    --region us-west-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Blackhole Route Use Cases:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Blocking Non-Routable Address Spaces:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Block RFC 1918 private addresses
aws ec2 create-transit-gateway-route \
 - destination-cidr-block 192.168.0.0/16 \
 - blackhole \
 - transit-gateway-route-table-id tgw-rtb-xxxxx

aws ec2 create-transit-gateway-route \
 - destination-cidr-block 172.16.0.0/12 \
 - blackhole \
 - transit-gateway-route-table-id tgw-rtb-xxxxx

aws ec2 create-transit-gateway-route \
 - destination-cidr-block 10.0.0.0/8 \
 - blackhole \
 - transit-gateway-route-table-id tgw-rtb-xxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Implementing Network Segmentation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Block access to specific environment
aws ec2 create-transit-gateway-route \
 - destination-cidr-block 10.100.0.0/16 \
 - blackhole \
 - transit-gateway-route-table-id tgw-rtb-xxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Best Practices for Blackhole Routes:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintain a list of all blackhole routes&lt;/li&gt;
&lt;li&gt;Document the purpose of each blackhole route&lt;/li&gt;
&lt;li&gt;Include expiration dates if temporary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with more specific routes (/32, /24) before broader ones&lt;/li&gt;
&lt;li&gt;Test in non-production environment first&lt;/li&gt;
&lt;li&gt;Implement gradually to minimize impact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor dropped packet metrics&lt;/li&gt;
&lt;li&gt;Set up CloudWatch alarms for blocked traffic&lt;/li&gt;
&lt;li&gt;Regular review of blackhole routes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 8: Verify Connectivity
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Monitor dropped packet metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch EC2 instances in both VPCs&lt;/li&gt;
&lt;li&gt;Test connectivity using ping or other network tools&lt;/li&gt;
&lt;li&gt;Check Transit Gateway route tables for proper route propagation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best Practices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor dropped packet metrics&lt;/li&gt;
&lt;li&gt;Use unique ASNs for each Transit Gateway&lt;/li&gt;
&lt;li&gt;Implement proper security groups and NACLs&lt;/li&gt;
&lt;li&gt;Monitor TGW CloudWatch metrics&lt;/li&gt;
&lt;li&gt;Use resource tagging for better management&lt;/li&gt;
&lt;li&gt;Document CIDR ranges and routing configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting Tips&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify route table configurations&lt;/li&gt;
&lt;li&gt;Check security group rules&lt;/li&gt;
&lt;li&gt;Ensure CIDR ranges don’t overlap&lt;/li&gt;
&lt;li&gt;Validate TGW attachment states&lt;/li&gt;
&lt;li&gt;Review VPC route tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cost Considerations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data transfer charges apply for inter-region traffic&lt;/li&gt;
&lt;li&gt;TGW attachment hours are billed&lt;/li&gt;
&lt;li&gt;Consider using AWS Cost Explorer for monitoring&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With AWS Transit Gateway, you unlock a scalable and resilient inter-region communication framework. Integrating blackhole routes enhances your network control and stability. Whether you’re working in a multi-account, global setup, or building DR strategies, this architecture sets you up for long-term success.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Automating AWS DNS Firewall Domain List Updates Using S3, Lambda, and CLI</title>
      <dc:creator>Esteban</dc:creator>
      <pubDate>Mon, 04 Nov 2024 15:42:29 +0000</pubDate>
      <link>https://dev.to/aws-builders/automating-aws-dns-firewall-domain-list-updates-using-s3-lambda-and-cli-5n2</link>
      <guid>https://dev.to/aws-builders/automating-aws-dns-firewall-domain-list-updates-using-s3-lambda-and-cli-5n2</guid>
      <description>&lt;p&gt;In a previous article, I outlined a ClickOps process for manually creating a DNS Firewall domain list on AWS [&lt;a href="https://aws.plainenglish.io/how-dns-query-filtering-on-aws-works-and-how-to-configure-it-714be46c2204" rel="noopener noreferrer"&gt;link&lt;/a&gt;]. While this manual approach is straightforward, automating updates to your DNS list can streamline management and enhance security by keeping your firewall rules current without requiring constant manual intervention. In this article, I’ll provide a step-by-step guide to automating DNS Firewall domain list updates using AWS S3, Lambda, and CLI methods, offering a more efficient way to maintain DNS protections dynamically and at scale.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Automation with AWS DNS Firewall&lt;br&gt;&lt;br&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: Automating DNS list updates saves time and reduces human error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Easily manage large lists of blocked domains across multiple VPCs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid Response&lt;/strong&gt;: Automatically incorporate threat intelligence and updates in real time, improving security posture.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Automation Methods
&lt;/h1&gt;

&lt;p&gt;Here are two ways to automate your AWS DNS Firewall updates:&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 1: Automate Updates with AWS S3 and Lambda
&lt;/h2&gt;

&lt;p&gt;This approach enables domain list updates whenever a file is uploaded to an S3 bucket.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiaeexzshxf9x5wrl3po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiaeexzshxf9x5wrl3po.png" alt="Image description" width="503" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepare the text file, compile the file containing all the domains you want to block or allow.&lt;/li&gt;
&lt;li&gt;Create a S3 Bucket.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1 — Create the S3 Bucket and Upload the File:&lt;br&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Upload a file (e.g., blocked_dns_list.txt) containing the domains you want to block to the designated S3 bucket.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2— Create the Lambda Function: &lt;br&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Lambda Console and click “Create Function”&lt;/li&gt;
&lt;li&gt;Enter a Name, and choose as the Runtime “Python 3.10”&lt;/li&gt;
&lt;li&gt;Click on “Create Function”. 
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frnamjzrqtyp3tduo0yje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frnamjzrqtyp3tduo0yje.png" alt="Image description" width="746" height="793"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the following Lambda function code to automate updates when a file is uploaded to S3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_firewall_domain_list_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r53resolver_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;paginator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r53resolver_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_paginator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;list_firewall_domain_lists&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;domain_list&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FirewallDomainLists&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;domain_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;list_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;domain_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Firewall domain list &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;list_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error getting firewall domain list ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3-BUCKET-NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;DOMAIN_LIST_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DOMAIN_LIST_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Records&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;source_bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Records&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bucket&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;source_bucket&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unexpected bucket: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source_bucket&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;s3_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;r53resolver_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;route53resolver&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;firewall_domain_list_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_firewall_domain_list_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r53resolver_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DOMAIN_LIST_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;file_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;domains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;file_content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r53resolver_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_firewall_domains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;FirewallDomainListId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;firewall_domain_list_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Operation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;REPLACE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Domains&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Successfully updated DNS Firewall Domain List with &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; domains&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Successfully updated DNS Firewall Domain List&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;domainsUpdated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;error_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error_message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Error updating DNS Firewall Domain List&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error_message&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3— Configure IAM Permissions for the Lambda Function:&lt;br&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;S3 Permissions:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;To ensure the Lambda function can access the S3 bucket and update the DNS Firewall domain list, assign it the following IAM permissions:&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;s3:GetObject&lt;/strong&gt; — This permission allows the Lambda function to read the content of the uploaded file in the S3 bucket, enabling it to retrieve the list of domains.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;s3:ListBucket&lt;/strong&gt; — While not strictly required for reading the file, this permission can be useful for verifying the existence of objects within the bucket, which aids in error handling and improves function reliability.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding these permissions to your Lambda function’s execution role ensures it can effectively retrieve and process domain lists from S3.&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-threat-intel-bucket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-threat-intel-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Route 53 Resolver Permissions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In addition to the S3 permissions, the Lambda function also interacts with Route 53 Resolver, necessitating the following permissions:&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;route53resolver:ListFirewallDomainLists&lt;/strong&gt; — This permission allows the Lambda function to list existing firewall domain lists in Route 53, which is necessary for retrieving the ID of the domain list to update.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;route53resolver:UpdateFirewallDomains&lt;/strong&gt; — This permission is essential for allowing the Lambda function to modify the contents of the specified firewall domain list, enabling the addition or replacement of domains.&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"route53resolver:ListFirewallDomainLists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"route53resolver:UpdateFirewallDomains"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4— Set Up S3 Trigger for Lambda:&lt;br&gt;&lt;br&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Configure S3 to invoke this Lambda function whenever a file is uploaded to your specified bucket. This trigger ensures that your DNS firewall domain list is automatically updated with each upload.&lt;/li&gt;
&lt;li&gt;Go to your S3 Bucket and click on “Properties”&lt;/li&gt;
&lt;li&gt;Create an Event Notification&lt;/li&gt;
&lt;li&gt;Enter a name, and at the Event Type choose “All object create event”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmesaeuongv7ztnwkgys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmesaeuongv7ztnwkgys.png" alt="Image description" width="736" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At “Destinations” choose Lambda Function, and select the name of function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflfm6g1mhsykyfqevanh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflfm6g1mhsykyfqevanh.png" alt="Image description" width="742" height="586"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 2: Automate with AWS CLI&lt;br&gt;&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;For users who prefer command-line automation, AWS CLI offers an alternative:&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;route&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="err"&gt;resolver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;update-firewall-domains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;--firewall-domain-list-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rslvr-fdl-&amp;lt;Your_Domain_List_ID&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;--operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;--domains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example1.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example2.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example3.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steps:&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace  with your Route 53 Resolver domain list ID.&lt;/li&gt;
&lt;li&gt;List your domains to block as arguments under the --domains parameter.&lt;/li&gt;
&lt;li&gt;Run the command in your CLI to quickly add or remove domains as needed.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Additional Tips&lt;br&gt;&lt;br&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automation Frequency&lt;/strong&gt;: Consider setting a schedule to update your lists based on threat intelligence feeds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging and Monitoring&lt;/strong&gt;: Enable CloudWatch logging for Lambda functions to track updates or errors.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Conclusion&lt;br&gt;&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;Automating DNS Firewall domain list updates can significantly improve your AWS environment’s security while reducing operational overhead. By following these methods, you’ll ensure that your firewall rules are up-to-date, scalable, and responsive to the latest threats.&lt;/p&gt;

</description>
      <category>community</category>
      <category>dns</category>
      <category>aws</category>
      <category>route53</category>
    </item>
    <item>
      <title>Best Practices for Monitoring Your Amazon VPC</title>
      <dc:creator>Esteban</dc:creator>
      <pubDate>Tue, 08 Oct 2024 15:13:30 +0000</pubDate>
      <link>https://dev.to/aws-builders/best-practices-for-monitoring-your-amazon-vpc-68m</link>
      <guid>https://dev.to/aws-builders/best-practices-for-monitoring-your-amazon-vpc-68m</guid>
      <description>&lt;p&gt;Monitoring your Amazon Virtual Private Cloud (VPC) is essential for ensuring optimal performance, security, and cost efficiency.&lt;/p&gt;

&lt;p&gt;Here are some best practices and tools to effectively monitor your VPC.&lt;/p&gt;




&lt;h2&gt;
  
  
  Amazon CloudWatch
&lt;/h2&gt;

&lt;p&gt;Amazon CloudWatch is a monitoring service that provides data and actionable insights. It allows you to track metrics and set alarms for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom Metrics&lt;/strong&gt;: Create metrics for specific VPC components like Elastic Load Balancers, NAT Gateways, and EC2 instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dashboards&lt;/strong&gt;: Visualize metrics using customizable dashboards to monitor the overall health of your VPC in real time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  VPC Flow Logs
&lt;/h2&gt;

&lt;p&gt;VPC Flow Logs capture information about the IP traffic going to and from network interfaces in your VPC. This data can help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Analyze Traffic Patterns:&lt;/strong&gt; Understand which resources are communicating and identify unusual traffic spikes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Troubleshoot Connectivity Issues:&lt;/strong&gt; Review flow logs to diagnose problems related to network traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Security Threats:&lt;/strong&gt; Set up alerts for unusual patterns, such as excessive traffic to or from specific IP addresses.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  AWS Config
&lt;/h2&gt;

&lt;p&gt;AWS Config provides visibility into your AWS resources and their configurations. By enabling AWS Config, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Track Configuration Changes:&lt;/strong&gt; Monitor changes to VPC resources like route tables, security groups, and network ACLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensure Compliance:&lt;/strong&gt; Set rules to verify that your VPC adheres to security policies, automating compliance checks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  AWS Trusted Advisor
&lt;/h2&gt;

&lt;p&gt;AWS Trusted Advisor provides real-time guidance to help you provision resources according to AWS best practices. It includes checks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost Optimization:&lt;/strong&gt; Identify underutilized resources that may be costing you money.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Best Practices:&lt;/strong&gt; Review your VPC security settings and access controls for potential vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Regular Audits and Reviews
&lt;/h2&gt;

&lt;p&gt;Conduct regular audits of your VPC configurations and security settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Review Security Groups:&lt;/strong&gt; Ensure that only necessary ports and protocols are open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check Route Tables:&lt;/strong&gt; Verify that routes are correctly configured and that there are no unintended access points.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Controls:&lt;/strong&gt; Regularly review IAM policies and roles associated with your VPC resources.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Alerting and Notification Systems
&lt;/h2&gt;

&lt;p&gt;Set up alerting mechanisms using CloudWatch Alarms or AWS Lambda to notify you of critical issues. Consider integrating with communication tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon SNS (Simple Notification Service):&lt;/strong&gt; Automatically send notifications via SMS or email when specific alarms are triggered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slack or Microsoft Teams:&lt;/strong&gt; Use webhooks to send real-time updates to your team.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Third-Party Monitoring Tools
&lt;/h2&gt;

&lt;p&gt;Consider using third-party monitoring solutions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Datadog:&lt;/strong&gt; Offers advanced monitoring and analytics for AWS resources, including VPC performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New Relic:&lt;/strong&gt; Provides application performance monitoring that can include network performance insights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nagios:&lt;/strong&gt; A powerful monitoring tool that can track your VPC resources and alert you to any issues.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Effective monitoring of your Amazon VPC is crucial for maintaining performance, security, and cost efficiency. By leveraging built-in AWS services and third-party tools, you can gain valuable insights, proactively address issues, and optimize your cloud infrastructure.&lt;/p&gt;

&lt;p&gt;Reference: &lt;em&gt;&lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudcomputing</category>
      <category>networking</category>
      <category>community</category>
    </item>
    <item>
      <title>AWS Network Firewall: A Simple Lab Setup Guide - ClickOps</title>
      <dc:creator>Esteban</dc:creator>
      <pubDate>Sat, 31 Aug 2024 02:41:48 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-network-firewall-a-simple-lab-setup-guide-clickops-2ij6</link>
      <guid>https://dev.to/aws-builders/aws-network-firewall-a-simple-lab-setup-guide-clickops-2ij6</guid>
      <description>&lt;p&gt;AWS Network Firewall is a powerful tool that empowers organizations to secure their applications and infrastructure in the cloud. Understanding how to set up and configure the AWS Network Firewall is crucial for ensuring a robust and resilient network environment. In this hands-on lab, we will go through the process of setting up an AWS environment that optimally utilizes AWS Network Firewall.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnexheta2v6l4u2kbvqri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnexheta2v6l4u2kbvqri.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Topology
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg946ezzj4x6m0xjrp3e2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg946ezzj4x6m0xjrp3e2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before delving into the lab setup, ensure that you have the following prerequisites in place:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An AWS account with the appropriate permissions to create and manage network resources.&lt;/li&gt;
&lt;li&gt;A foundational understanding of Amazon VPC concepts, EC2, and AWS services.&lt;/li&gt;
&lt;li&gt;Deployment of a VPC, public subnet, and internet gateway should be completed prior to commencing this lab.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 1: Setting up the environment.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Create a dedicated subnet for the Network Firewall&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
In your AWS Console go to VPC &amp;gt;&amp;gt; Subnets &amp;gt;&amp;gt; Create a Subnet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: A Network Firewall needs a dedicated subnet with a /28 or larger IP space.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcz4js46smb7k0qlzfry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcz4js46smb7k0qlzfry.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Firewall — Rule Groups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the subnet is ready, we can move on to creating Network Firewall Rule Groups.&lt;/p&gt;

&lt;p&gt;Think of a rule group as a set of rules that dictate how traffic is handled by AWS Network Firewall. These rules help us decide which network traffic is allowed or blocked based on specific criteria. Rule groups are vital for setting up and enforcing security policies for your AWS Network Firewall.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On you VPC Dashboard go to: Network Firewall &amp;gt;&amp;gt; Network Firewall rule groups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr67ddlgkjpo7l5bto5r3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr67ddlgkjpo7l5bto5r3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkflzkagerxkb4nzo1yr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkflzkagerxkb4nzo1yr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In AWS Network Firewall, there are two main types of rule groups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stateful&lt;/strong&gt;: These are like smart rules that understand the context of network traffic. They can allow or block traffic based on things like source, destination, and more. Think of them as traffic cops that can make decisions based on what they see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateless&lt;/strong&gt;: These are more like basic traffic filters. They follow simple rules to either allow or block traffic, without understanding the context. It’s like a list of specific traffic rules that are applied without considering the bigger picture.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz0t4haomg2z1cs6i0b7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz0t4haomg2z1cs6i0b7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will create three type of rule groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stateful group for Domain List&lt;/li&gt;
&lt;li&gt;Stateful group standard&lt;/li&gt;
&lt;li&gt;Stateless&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stateful group for Domain List&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Domain List Rule Group is designed to filter and control network traffic based on domain names, which are like web addresses. You can create a list of domain names that you want to allow or block. This rule group is especially useful for managing access to specific websites or online services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3e4o8n549bu5ut151asz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3e4o8n549bu5ut151asz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Capacity is the number of rules you expect to have in this rule group during its lifetime. You can’t change capacity after rule group creation, so leave room to grow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yv4g770v18bdk4kq9rm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yv4g770v18bdk4kq9rm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can list all the domains that you would like to inspect to either allow or deny.&lt;/p&gt;

&lt;p&gt;We will use the following examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com" rel="noopener noreferrer"&gt;www.google.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For now, we will keep the Action to “Allow”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stateful groups Standard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a more general-purpose rule group that can be customized to match your specific network security needs. It allows us to define rules based on unique requirements, making it versatile for various use cases.&lt;/p&gt;

&lt;p&gt;For example, we can specify the values for Layer 3 and Layer 4.&lt;/p&gt;

&lt;p&gt;For our lab, we will create an ICMP group rule, and as before, we keep the action as “Pass”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkuhhho4ma1vakug2vcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkuhhho4ma1vakug2vcg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcni17azkfu36h2p6qsd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcni17azkfu36h2p6qsd6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stateless group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A stateless rule group in AWS Network Firewall is like a basic set of traffic rules. It decides what traffic can come in and go out of your network, but it doesn’t remember previous actions or understand the bigger picture of the traffic flow. It’s a bit like a gatekeeper checking each person’s ID at the door without knowing anything about them except what’s on the ID. Simple and effective for straightforward security needs.&lt;/p&gt;

&lt;p&gt;For our lab, we will create a simple Stateless rule group for all the traffic in and out of our VPC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmbyk8xmyzy4fpx0yghs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmbyk8xmyzy4fpx0yghs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After all the Rule groups are created, we should have a list simimar to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed4vjfmx9u3e7vx2lqwy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed4vjfmx9u3e7vx2lqwy.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Creating a Network Firewall Policy
&lt;/h2&gt;

&lt;p&gt;An &lt;em&gt;AWS Network Firewall policy&lt;/em&gt; defines the monitoring and protection behavior for a firewall. The details of the behavior are defined in the rule groups that you add to your policy, and in some policy default settings. To use a firewall policy, you associate it with one or more firewalls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On your VPC Dashboard go to: &lt;em&gt;Network Firewall &amp;gt;&amp;gt; Firewall Policies and “Click” on create.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faf00lzltul9uv1z92f8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faf00lzltul9uv1z92f8n.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnsyvam2t70wxlbfbr1bv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnsyvam2t70wxlbfbr1bv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the Stateless rule group created previously.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9lzramo6cpofkpt2uk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9lzramo6cpofkpt2uk0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select both stateful rule group created previously.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9maoodcpplubixn4d1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9maoodcpplubixn4d1b.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;em&gt;“Create Firewall Policy”&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Creating a Network Firewall
&lt;/h2&gt;

&lt;p&gt;An &lt;em&gt;AWS Network Firewall&lt;/em&gt; connects a firewall policy, which defines network traffic monitoring and filtering behavior, to the VPC that you want to protect.&lt;/p&gt;

&lt;p&gt;The firewall configuration includes specifications for the Availability Zones and subnets where the firewall endpoints are placed. It also defines high-level settings like the firewall logging configuration and tagging on the AWS firewall resource.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On you VPC Dashboard go to: &lt;em&gt;Network Firewall &amp;gt;&amp;gt; Firewalls and click on create.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj35ijxqkkx6maleewbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj35ijxqkkx6maleewbg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsauys7sytmpgsjpkty6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsauys7sytmpgsjpkty6d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtgriktk7zdk5uv405iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtgriktk7zdk5uv405iw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We choose the VPC where we want our Firewall to inspect the traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ixfn8jgdbetsejrp41v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ixfn8jgdbetsejrp41v.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We associate the Firewall Policy created on the previous step with our Network Firewall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4oj24p40obrvopk8wd91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4oj24p40obrvopk8wd91.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Once the firewall creation is completed, go to the details and take note of the Endpoint ID. We will use that value later.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihmik2u330jhqyfcim7q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihmik2u330jhqyfcim7q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loggin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Network Firewall generates logs for stateful rule groups. You can configure different destinations for different log types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhq6hzc1kgy079mjq7a2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhq6hzc1kgy079mjq7a2e.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: You can record alert logs and flow logs from your Network Firewall stateful engine.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alert logs&lt;/strong&gt; report traffic that matches your stateful rules that have an action that sends an alert. A stateful rule sends alerts for the rule actions DROP, ALERT, and REJECT.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow logs&lt;/strong&gt; are standard network traffic flow logs. Each flow log record captures the network flow for a specific standard stateless rule group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep any other value as default and go all the way to “Create Firewall”.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Routing Configuration
&lt;/h2&gt;

&lt;p&gt;Up to this point, we have created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subnet for our Firewall&lt;/li&gt;
&lt;li&gt;Rule Groups (Stateful and Stateless)&lt;/li&gt;
&lt;li&gt;Firewall Policy&lt;/li&gt;
&lt;li&gt;Network Firewall&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before you begin testing out your firewall rules, you need to adjust routing to send traffic through the firewall.&lt;/p&gt;

&lt;p&gt;We need to create two new Route Tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internet gateway (IGW) ingress route table.&lt;/li&gt;
&lt;li&gt;Firewall subnet route table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Internet Gateway Route Table&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On your VPC Dashboard go to: Route Tables &amp;gt;&amp;gt; Create Route Table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When creating this Route Table, make sure to select the right VPC. On the &lt;strong&gt;Edit edge associations&lt;/strong&gt; section, click on edit and select the &lt;strong&gt;Internet gateway.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp65c5vpdy5kyvjilnoa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp65c5vpdy5kyvjilnoa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to create a route entry that will forward the incoming traffic to the Firewall.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;Destination&lt;/strong&gt;, enter use the CIDR of your public subnet network. In our lab the address is: 10.0.0.0/24&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Target&lt;/strong&gt;, select &lt;strong&gt;Gateway Load Balancer Endpoint&lt;/strong&gt; and search for the VPC firewall endpoint that starts with vpce-.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Use the Network Firewall Endpoint ID from step 3.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv53bejxmjhwniuiqroyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv53bejxmjhwniuiqroyz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firewall route table&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will create a new route table for our firewall and will direct all the outgoing traffic (0.0.0.0/0) to the internet gateway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5b2lkdwg8uawbdkpgya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5b2lkdwg8uawbdkpgya.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We associate this route table with the FirewallSubnet created on step 1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6pjusu7j5sucieh7i92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6pjusu7j5sucieh7i92.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we configure our Public Route table (part of the pre-requirement) to forward the outgoing traffic to the Firewall.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Use the Network Firewall Endpoint ID from step 3.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh70q27mrign94zu0s83t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh70q27mrign94zu0s83t.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point we should have the following three route tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public Route table&lt;/li&gt;
&lt;li&gt;Ingress Route table&lt;/li&gt;
&lt;li&gt;Firewall Route table&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: Testing
&lt;/h2&gt;

&lt;p&gt;We will verify network connectivity between the EC2 instances and the internet to evaluate the firewall’s ability to block or allow traffic based on your defined rules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7uon55fprl72s8mnor7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7uon55fprl72s8mnor7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connecting to our EC2 via CLI we can perform the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using “curl” we will check connectivity with the domains listed on the DomainList Rule Group&lt;/li&gt;
&lt;li&gt;Using “ping” we will test the Stateful Standard Rule Group created for ICMP traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point both Rule Groups are configured as Allow or Pass, then we should have the following behavior:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

curl www.example.com
&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Example Domain&amp;lt;/title&amp;gt;

    &amp;lt;meta charset="utf-8" /&amp;gt;
    &amp;lt;meta http-equiv="Content-type" content="text/html; charset=utf-8" /&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1" /&amp;gt;
    &amp;lt;style type="text/css"&amp;gt;
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 2em;
        background-color: #fdfdff;
        border-radius: 0.5em;
        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        div {
            margin: 0 auto;
            width: auto;
        }
    }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
&amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Example Domain&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;a href="https://www.iana.org/domains/example"&amp;gt;More information...&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ping 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=10.0 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=11.2 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=116 time=11.0 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=116 time=10.5 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 10.015/10.726/11.292/0.489 ms


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Everything seems to be working as expected. Now, we will modify the action on each of the Rule Groups to Deny or Drop.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl www.example.com --max-time 5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— max-time 5 tell the curl command to only try for 5 connections.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we can see, we are not able to connect to &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

--- 8.8.8.8 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4088ms


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The same result when using ping.&lt;/p&gt;

&lt;p&gt;This confirms that the &lt;strong&gt;Stateful Rule Groups&lt;/strong&gt; are working as expected and traffic is denied.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this simple lab, we have gained valuable insights into setting up an AWS environment that effectively utilizes AWS Network Firewall. This knowledge will enable us to design, implement, and manage secure networking infrastructures in the cloud, safeguarding our applications and data.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>community</category>
      <category>aws</category>
      <category>security</category>
    </item>
    <item>
      <title>AWS VPC Peering vs Transit Gateway: Which One Should You Use?</title>
      <dc:creator>Esteban</dc:creator>
      <pubDate>Tue, 27 Aug 2024 13:29:11 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-vpc-peering-vs-transit-gateway-which-one-should-you-use-4dmm</link>
      <guid>https://dev.to/aws-builders/aws-vpc-peering-vs-transit-gateway-which-one-should-you-use-4dmm</guid>
      <description>&lt;p&gt;Amazon Web Services (AWS) provides a robust set of networking services to enable seamless communication between resources in a Virtual Private Cloud (VPC).&lt;/p&gt;

&lt;p&gt;Two popular options for connecting VPCs are VPC peering and Transit Gateway.&lt;/p&gt;

&lt;p&gt;Let’s go over some key differences between the two.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is VPC peering?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jk7a68yeestakmar056.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jk7a68yeestakmar056.png" alt="https://disaster-recovery.workshop.aws/en/services/networking/vpc/vpc-peering.html" width="451" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VPC peering allows direct communication between two VPCs. It is a one-to-one connection, meaning you need to create peering connections &lt;strong&gt;for each pair of VPCs&lt;/strong&gt; you want to connect.&lt;/p&gt;

&lt;p&gt;VPC peering is relatively straightforward to set up. You establish a peering connection between two VPCs by configuring route tables and accepting connection requests.&lt;/p&gt;

&lt;p&gt;On regards to latency, peering connections are generally low-latency since traffic travels directly between the peered VPCs without additional hops.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind is that VPC peering is not transitive. If you have multiple VPCs that need to communicate with each other in a hub-and-spoke topology, &lt;strong&gt;you must create separate peering connections for each pair.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the main issues with this solutions is managing multiple peering connections, which can become complex as your network grows. This can lead to administrative overhead and increased potential for misconfigurations.&lt;/p&gt;

&lt;p&gt;As for cost, the data transfer costs are incurred for traffic that flows between peered VPCs. This can be a consideration in your cost management strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use VPC peering:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;VPC peering is a good option for connecting two VPCs when you need a simple, one-to-one connection with low latency. For example, you might use VPC peering to connect a production VPC to a development VPC.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is AWS transit gateway?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rp9kl7q0m9f3tabmueo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rp9kl7q0m9f3tabmueo.png" alt="Image description" width="739" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Transit Gateway is designed to **simplify and centralize network **connectivity. It acts as a hub that connects multiple VPCs, VPNs, and Direct Connect connections, making it a one-to-many or many-to-many solution. This allows TG to simplify network management by providing a single point of connectivity. You configure routing once and can connect numerous VPCs.&lt;/p&gt;

&lt;p&gt;While Transit Gateway introduces an additional network hop compared to VPC peering, the impact on latency is typically minimal and well within acceptable limits.&lt;/p&gt;

&lt;p&gt;On regards to traffic routing, Transit Gateway supports transitive routing, allowing traffic to flow between any attached VPCs, even if there is no direct peering connection between them. This makes it ideal for hub-and-spoke or full-mesh network architectures. Plus, this service scales easily, &lt;strong&gt;supporting hundreds of VPCs&lt;/strong&gt;, making it suitable for large and complex network infrastructures.&lt;/p&gt;

&lt;p&gt;As for cost, data transfer costs for traffic within Transit Gateway are generally lower than using VPC peering for the same level of connectivity due to its hub-and-spoke architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use Transit Gateway:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transit Gateway is a good option for connecting multiple VPCs together in a scalable and transitive way. It is especially well-suited for hub-and-spoke or full-mesh network architectures. If you have a complex network or need to connect a large number of VPCs, Transit Gateway is a good choice.&lt;/p&gt;

&lt;p&gt;It is also a good choice for organizations that need to connect their VPCs to on-premises networks or to other AWS services, such as AWS Direct Connect and AWS VPN. Transit Gateway provides a central point of connectivity for all of these resources, making it easier to manage and secure your network.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choosing the Right Solution
&lt;/h2&gt;

&lt;p&gt;The choice between VPC peering and Transit Gateway depends on your specific requirements and network design. Here are some considerations to help you decide:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple vs. Complex Networks:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For smaller, less complex networks with only a few VPCs that need to communicate, VPC peering might suffice. However, if your network is larger, more complex, or needs transitive routing, Transit Gateway is likely the better choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transit Gateway is the clear winner for scalability. If your network is expected to grow, or if you’re unsure about its size in the future, choosing Transit Gateway can save you from the complexities of managing numerous peering connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Transit Gateway often provides cost savings in terms of data transfer costs, especially in scenarios with multiple VPCs. Consider your budget and how data transfer charges might impact it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transitive Routing:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you require transitive routing (i.e., traffic can flow between VPCs without direct peering connections), Transit Gateway is the way to go.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both services are valuable tools for connecting VPCs in AWS, but they serve different purposes. While VPC peering is a good option for simple, one-to-one connections, Transit Gateway is a better choice for complex, scalable, and transitive network architectures.&lt;/p&gt;

&lt;p&gt;By understanding the differences between these two solutions, you can make informed decisions to meet your specific networking needs on AWS.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>aws</category>
      <category>cloud</category>
      <category>community</category>
    </item>
  </channel>
</rss>
