Ends in
00
days
00
hrs
00
mins
00
secs
ENROLL NOW

🎁 Get 20% Off - Christmas Big Sale on All Practice Exams, Video Courses, and eBooks!

Implementing IP Blocking and Unblocking Using AWS Lambda, Slack, and AWS Systems Manager

Home » Angular » Implementing IP Blocking and Unblocking Using AWS Lambda, Slack, and AWS Systems Manager

Implementing IP Blocking and Unblocking Using AWS Lambda, Slack, and AWS Systems Manager

Blocking IP addresses is a crucial security measure for protecting an organization’s infrastructure from various cyber threats, including DDoS attacks, brute-force login attempts, and unauthorized access. By blocking malicious or suspicious IPs, organizations can prevent system compromise, reduce unwanted traffic, and ensure that only trusted networks access critical resources. This helps maintain the performance and stability of the systems while ensuring compliance with security policies. Automating IP blocking using AWS Lambda and AWS Systems Manager (SSM) allows for a quick and efficient response to threats, securing environments with minimal manual intervention.

Managing IP access is an essential aspect of securing any application. This guide walks through the process of setting up a Lambda function in AWS to block or unblock IP addresses based on commands sent through Slack. By integrating AWS Lambda, Slack commands, AWS Systems Manager, and EC2 instances, you can automate IP blocking/unblocking. Below are the detailed steps for implementing this automation.

Step-by-Step Implementation

1. Create a New Lambda Function

  • Access the AWS Lambda console and select the Ohio region (us-east-2).
  • Choose “Create function”, and name it td-block-unblock-ip.
  • Enable the Lambda Function URL and set the Auth type to None.
  • Create the Lambda function and copy the Lambda function URL for later use.

This function will process Slack commands to block or unblock an IP.

2. Add the Code

Below is the Lambda function code that handles commands from Slack to block or unblock IP addresses:

import json
import os
import boto3
import hmac
import base64
import time
import hashlib
import urllib.parse
import ipaddress
import re

# Set up constants
SLACK_CHANNEL = os.environ["SLACK_CHANNEL"]
SLACK_HOOK = os.environ["SLACK_HOOK"]
SLACK_SIGNING_KEY = os.environ["SIGNING_KEY"]
EC2_INSTANCE_ID = os.environ.get("EC2_INSTANCE_ID")
SSM_DOC_UNBLOCK_IP = os.environ.get("SSM_DOC_UNBLOCK_IP")
SSM_DOC_BLOCK_IP = os.environ.get("SSM_DOC_BLOCK_IP")

def lambda_handler(event, context):
    try:
        # Parse event data from Slack
        slack_signature = event['headers']["x-slack-signature"]
        slack_timestamp = event['headers']['x-slack-request-timestamp']
        slack_payload = event['body']
        payload = parse_slack_payload(slack_payload)
        from_channel = payload["channel_name"]

        # Check if request originates from a valid source
        from_valid_source = verify_source(
            signing_key=SLACK_SIGNING_KEY.encode('utf-8'),
            timestamp=slack_timestamp,
            body=base64.b64decode(slack_payload).decode('utf-8'),
            slack_signature=slack_signature,
            from_channel=from_channel
        )

        # Parse the command and the IP from the payload
        command = urllib.parse.unquote(payload["command"])
        ip_address = extract_ip(urllib.parse.unquote(payload["text"]))

        # Check if request IP is valid
        from_valid_ip = is_valid_ip(ip_str=(ip_address))

        # Main Code
        if from_valid_source:
            if from_valid_ip:
                if command.startswith("/block-ip"):
                    return process_command(ip_address, SSM_DOC_BLOCK_IP, SLACK_HOOK, EC2_INSTANCE_ID, "IP BLOCKING")
                elif command.startswith("/unblock-ip"):
                    return process_command(ip_address, SSM_DOC_UNBLOCK_IP, SLACK_HOOK, EC2_INSTANCE_ID, "IP UNBLOCK")
                else:
                    return "Invalid command"
            else:
                return f"Your input, \"{ip_address}\", is not a valid IPv4 address. Please provide a valid IPv4 address."
        else:
            return "You're not authorized to perform this operation"
    except Exception as e:
        print(e)
        return str(e)


def parse_slack_payload(data):
    decoded_data_raw = base64.b64decode(data).decode('utf-8').split('&')
    decoded_data_formatted = {}
    for item in decoded_data_raw:
        data_object = item.split('=')
        decoded_data_formatted[data_object[0]] = data_object[1]
    return decoded_data_formatted


def verify_source(signing_key, timestamp, body, slack_signature, from_channel):
    basestring = f'v0:{timestamp}:{body}'
    hmac_digest = hmac.new(
        key=signing_key,
        msg=basestring.encode('utf-8'),
        digestmod=hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(slack_signature, f'v0={hmac_digest}') and SLACK_CHANNEL == from_channel

def extract_ip(text):
    # Regular expression pattern to match IPv4 address
    pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
    match = re.search(pattern, text)
    if match:
        return match.group()
    else:
        return text
        
def is_valid_ip(ip_str):
    try:
        ip = ipaddress.IPv4Address(ip_str)
        return True
    except ipaddress.AddressValueError:
        return False


def execute_ssm_document(instance_id, ssm_document, parameters):
    try:
        ssm = boto3.client('ssm')
        response = ssm.send_command(
            InstanceIds=[instance_id],
            DocumentName=ssm_document,
            Parameters=parameters,
            TimeoutSeconds=30
        )
        # Convert datetime objects to strings
        if 'RequestedDateTime' in response:
            response['RequestedDateTime'] = response['RequestedDateTime'].isoformat()
        return response
    except Exception as e:
        print(e)
        return str(e)


def process_command(ip_address, ssm_document, slack_hook, instance_id, message):
    parameters = {'ipAddress': [ip_address], 'slackHook': [slack_hook]}
    response = execute_ssm_document(instance_id, ssm_document, parameters)
    print('Command Parameters:', response.get('Command', {}).get('Parameters'))
    return {
        'statusCode': 200,
        'body': f'{message} request received and processing...'
    }
3. Set Up Environment Variables

Set the following environment variables for the Lambda function to operate:

  • EC2_INSTANCE_ID: The ID of the EC2 instance to manage.
  • Tutorials dojo strip
  • SIGNING_KEY: The signing key from Slack (Slack API > App Credentials).
  • SLACK_CHANNEL: The name of the Slack channel where the Lambda function will operate.
  • SLACK_HOOK: The Slack webhook URL for notifications.
  • SSM_DOC_UNBLOCK_IP: The name of the SSM document for unblocking IP addresses.
  • SSM_DOC_BLOCK_IP: The name of the SSM document for blocking IP addresses.
Environment Variables
 
4. Increase Lambda Timeout

Navigate to Configuration > General configuration, and set the timeout to 30 seconds.

5. Assign IAM Role to Lambda

Assign the appropriate IAM role to allow Lambda access to AWS Systems Manager. The role needs permission to send commands to SSM:

 {
  "Effect": "Allow",
  "Action": "ssm:SendCommand",
  "Resource": "*"
} 

Lambda Role

 
6. Create Slack Commands

In the Slack API or Slack App Management Console, create two commands:

  • /block-ip: For blocking an IP addressBlock IP Slack Commands
  • /unblock-ip: For unblocking an IP address

Unblock IP Slack Commands

Set the Request URL to the Lambda function URL you copied earlier.

7. Copy Needed Variables and 

  • From Slack, go to Settings > Basic Information > App Credentials > Signing Secret.
  • Copy the Signing Secret text and paste it into the Lambda function environmental variable SIGNING_KEY.

    Integrate Lambda Function URL

 

8. Create SSM Documents

Now, create two SSM documents in AWS Systems Manager for blocking and unblocking IPs.

SSM Document for Blocking IPs:

{
  "schemaVersion": "2.2",
  "description": "Block IP address and notify Slack",
  "parameters": {
    "ipAddress": {
      "type": "String",
      "description": "(Required) IP address to block."
    },
    "slackHook": {
      "type": "String",
      "description": "(Required) Slack Webhook URL for notifications."
    }
  },
  "mainSteps": [
    {
      "action": "aws:runShellScript",
      "name": "runShellScript",
      "inputs": {
        "runCommand": [
          "#!/bin/bash",
          "ip_address='{{ ipAddress }}'",
          "hook='{{ slackHook }}'",
          " sleep 1",
          "iptables_file=\"PATH_TO_IPBlockList.txt"",
          "if sudo ipset list tdojoBlockedIPs | grep \"$ip_address\" && sudo grep \"$ip_address\" \"$iptables_file\" ; then",
          " echo 'IP address is already listed as blockedIP in the IPTABLES.'",
          " # Notify Slack Channel",
          " curl -H \"Content-type: application/json\" -d '{\"text\": \"IP address: '$ip_address' is ALREADY LISTED in the IPTABLES.\"}' -X POST \"$hook\"",
          "else",
          " sudo ipset add tdojoBlockedIPs \"$ip_address\"",
          " sudo echo \"$ip_address\" >> \"$iptables_file\"",
          " echo \"Done adding IP address: '$ip_address' to the IPTABLES and IPBlocklist.txt.\"",
          " # Notify Slack Channel",
          " curl -H \"Content-type: application/json\" -d '{\"text\": \"Done adding IP address: '$ip_address' to the IPTABLES.\"}' -X POST \"$hook\"",
          "fi"
        ]
      }
    }
  ]
}

SSM Document for Unblocking IPs:

{
  "schemaVersion": "2.2",
  "description": "Block IP address and notify Slack",
  "parameters": {
    "ipAddress": {
      "type": "String",
      "description": "(Required) IP address to unblock."
    },
    "slackHook": {
      "type": "String",
      "description": "(Required) Slack Webhook URL for notifications."
    }
  },
  "mainSteps": [
    {
      "action": "aws:runShellScript",
      "name": "runShellScript",
      "inputs": {
        "runCommand": [
          "#!/bin/bash",
          "ip_address='{{ ipAddress }}'",
          "hook='{{ slackHook }}'",
          "iptables_file=\"PATH_TO_IPBlockList.txt"",
          " sleep 1",
          "if sudo ipset list tdojoBlockedIPs | grep \"$ip_address\" && sudo grep \"$ip_address\" \"$iptables_file\" ; then",
          " sudo sed -i \"/$ip_address/d\" \"$iptables_file\"",
          " sudo ipset del tdojoBlockedIPs \"$ip_address\"",
          " echo \"IP address: '$ip_address' has been unblocked in IPBlockList.txt & tdojoBlockedIps\"",
          " # Notify Slack Channel",
          " curl -H \"Content-type: application/json\" -d '{\"text\": \"'$ip_address' has been UNBLOCKED in IPBlockList.txt & tdojoBlockedIps\"}' -X POST \"$hook\"",
          "else",
          " echo  \"IP address'$ip_address' is not in the blockedIP list.\"",
          " # Notify Slack Channel",
          " curl -H \"Content-type: application/json\" -d '{\"text\":  \"NO RECORD of IP address: '$ip_address'\"}' -X POST \"$hook\"",
          "fi"
        ]
      }
    }
  ]
}

8. Testing

  1. Run Command in SSM: Execute the SSM documents manually by providing an IP address and the Slack webhook URL. Confirm the results by checking if the IP address is blocked or unblocked.

Run Command in SSM

     2. Use Slack Commands:

    Free AWS Courses
  • Now, that the SSM is working it’s time to test the Lambda.
  • Go to Slack and enter the Slack commands with the IP you want to block or unblock.

Use Slack Commands

9. Monitor Logs

  • Check for any issues or successful execution in CloudWatch Logs.

CloudWatch Logs

  • SSH into EC2: Access the EC2 instance and verify the IPBlockList.txt file:

SSH into EC2

Conclusion

This implementation allows seamless IP blocking and unblocking using Slack commands integrated with AWS Lambda and AWS Systems Manager. By following this guide, you can efficiently automate and secure your infrastructure. Monitor CloudWatch Logs and test the setup thoroughly to guarantee it functions as expected.

Get 20% Off – Christmas Big Sale on All Practice Exams, Video Courses, and eBooks!

Tutorials Dojo portal

Learn AWS with our PlayCloud Hands-On Labs

Tutorials Dojo Exam Study Guide eBooks

tutorials dojo study guide eBook

FREE AWS Exam Readiness Digital Courses

FREE AWS, Azure, GCP Practice Test Samplers

Subscribe to our YouTube Channel

Tutorials Dojo YouTube Channel

Follow Us On Linkedin

Recent Posts

Written by: Ace Kenneth Batacandulo

Ace is AWS Certified and a Junior Cloud Consultant at Tutorials Dojo Pte. Ltd. He is also the Co-Lead Organizer of K8SUG Philippines and a member of the Content Committee for Google Developer Groups Cloud Manila. Ace actively contributes to the tech community through his volunteer work with AWS User Group PH, GDG Cloud Manila, K8SUG Philippines, and Devcon PH. He is deeply passionate about technology and is dedicated to exploring and advancing his expertise in the field.

AWS, Azure, and GCP Certifications are consistently among the top-paying IT certifications in the world, considering that most companies have now shifted to the cloud. Earn over $150,000 per year with an AWS, Azure, or GCP certification!

Follow us on LinkedIn, YouTube, Facebook, or join our Slack study group. More importantly, answer as many practice exams as you can to help increase your chances of passing your certification exams on your first try!

View Our AWS, Azure, and GCP Exam Reviewers Check out our FREE courses

Our Community

~98%
passing rate
Around 95-98% of our students pass the AWS Certification exams after training with our courses.
200k+
students
Over 200k enrollees choose Tutorials Dojo in preparing for their AWS Certification exams.
~4.8
ratings
Our courses are highly rated by our enrollees from all over the world.

What our students say about us?