Monday

18-08-2025 Vol 19

Going Serverless — Automating PDF Parsing with S3, Lambda & DynamoDB (Part 2)

Going Serverless: Automating PDF Parsing with S3, Lambda & DynamoDB (Part 2)

Welcome back to our serverless journey! In Part 1, we laid the groundwork for our PDF parsing automation system. We discussed the architecture, set up our AWS environment, and configured the S3 bucket to trigger Lambda functions upon PDF uploads. Now, in Part 2, we’ll dive deep into the core logic of our Lambda function: parsing the PDF, extracting relevant data, and storing it in DynamoDB. We’ll also cover error handling, logging, and best practices for building robust serverless applications.

Table of Contents

  1. Recap: Building the Foundation (Part 1)
  2. Developing the Lambda Function: The Core Logic
  3. Error Handling and Logging: Building a Robust System
  4. Testing and Deployment
  5. Optimization and Best Practices
  6. Conclusion: The Power of Serverless Automation

1. Recap: Building the Foundation (Part 1)

Before we jump into the code, let’s quickly recap what we achieved in Part 1. We covered:

  • Architecture Overview: Understanding the flow of data from S3 to Lambda to DynamoDB.
  • AWS Account Setup: Configuring your AWS account and creating necessary IAM roles.
  • S3 Bucket Creation: Creating an S3 bucket to store the PDF files.
  • S3 Event Trigger: Configuring the S3 bucket to trigger a Lambda function when a new PDF is uploaded.
  • Basic Lambda Function Skeleton: Setting up a basic Lambda function that receives the S3 event data.

If you haven’t already, make sure to review Part 1 to ensure you have a solid foundation before proceeding.

2. Developing the Lambda Function: The Core Logic

This is where the magic happens! We’ll now focus on developing the core logic of our Lambda function to parse the PDF, extract the desired data, and store it in DynamoDB.

2.1 Installing Dependencies: PDF Parsing Libraries

To parse PDF files, we’ll need a suitable library. Several options are available, each with its own strengths and weaknesses. Popular choices include:

  • PyPDF2: A pure-Python library that’s relatively easy to use, but can struggle with complex PDFs.
  • pdfminer.six: Another Python library that’s more robust than PyPDF2, but can be more complex to use.
  • tabula-py: A Python wrapper for Tabula, a Java library for extracting tables from PDFs. Excellent for structured data.
  • OCR tools (e.g., Tesseract OCR): Useful when dealing with scanned PDFs where the text is embedded as images.

For this example, we’ll use `PyPDF2` for its simplicity. To install it, we’ll use a `requirements.txt` file in our Lambda function directory:

PyPDF2==3.0.1
boto3==1.26.153

When we deploy our Lambda function, we’ll need to package these dependencies with our code. We’ll use a deployment package for that. Create a directory for your Lambda function (e.g., `pdf_parser`) and place the `requirements.txt` file inside. Then, run the following command to install the dependencies into a local directory:

pip install -r requirements.txt -t .

This will install `PyPDF2` and `boto3` (the AWS SDK for Python) into the current directory, ready to be packaged with your Lambda function.

2.2 Parsing the PDF: Extracting Text and Data

Now, let’s write the code to parse the PDF and extract the text. Here’s a Python code snippet using `PyPDF2`:


import boto3
import PyPDF2
import io
import os

# Initialize AWS clients outside the handler for better performance
s3 = boto3.client('s3')
dynamodb = boto3.resource('dynamodb')
table_name = os.environ.get('DYNAMODB_TABLE_NAME') # Get table name from environment variable
table = dynamodb.Table(table_name)

def lambda_handler(event, context):
    """
    This function is triggered by S3 when a PDF is uploaded.
    It parses the PDF, extracts text, and stores the data in DynamoDB.
    """
    try:
        # 1. Extract bucket name and file key from the S3 event
        bucket = event['Records'][0]['s3']['bucket']['name']
        key = event['Records'][0]['s3']['object']['key']

        # Log the event data
        print(f"Bucket: {bucket}, Key: {key}")

        # 2. Download the PDF file from S3
        response = s3.get_object(Bucket=bucket, Key=key)
        pdf_file = response['Body'].read()

        # 3. Parse the PDF file using PyPDF2
        pdf_file_obj = io.BytesIO(pdf_file)  # Wrap the bytes data in a BytesIO object
        pdf_reader = PyPDF2.PdfReader(pdf_file_obj)

        # 4. Extract text from all pages
        text = ""
        for page in pdf_reader.pages:
            text += page.extract_text()

        # 5. (Example) Extract the number of pages (for demonstration)
        num_pages = len(pdf_reader.pages)

        # Log the extracted text (truncated for brevity)
        print(f"Extracted text (first 100 characters): {text[:100]}...")
        print(f"Number of Pages: {num_pages}")


        # 6.  Prepare the data to be stored in DynamoDB
        item = {
            'pdf_name': key,
            'text': text,  # Store the entire text
            'num_pages': num_pages,
            's3_bucket': bucket,
            'extraction_timestamp': str(datetime.datetime.now()) # Adding a timestamp
        }

        # 7. Store the data in DynamoDB
        table.put_item(Item=item)

        # Log success message
        print(f"Successfully processed {key} and stored data in DynamoDB.")

        return {
            'statusCode': 200,
            'body': 'PDF parsed and data stored in DynamoDB'
        }

    except Exception as e:
        # Log the error and return an error response
        print(f"Error processing PDF: {e}")
        return {
            'statusCode': 500,
            'body': f'Error processing PDF: {e}'
        }

  

Let’s break down this code:

  1. Import Libraries: We import `boto3` for interacting with AWS services, `PyPDF2` for PDF parsing, `io` for handling in-memory file-like objects, and `os` for accessing environment variables.
  2. Initialize Clients: We initialize the S3 and DynamoDB clients *outside* the `lambda_handler` function. This is a crucial optimization. Lambda functions can be invoked multiple times for the same execution environment (“cold starts” are expensive). By initializing the clients outside the handler, they are reused for subsequent invocations, significantly improving performance.
  3. Get Table Name from Environment Variable: We retrieve the DynamoDB table name from an environment variable. This allows us to configure the table name without modifying the code. You will need to set this environment variable in your Lambda function configuration in the AWS console.
  4. Extract S3 Event Data: The `lambda_handler` function receives an `event` object containing information about the S3 event. We extract the bucket name and file key from this event.
  5. Download PDF from S3: We use the S3 client to download the PDF file from S3 into memory. We read the content of the response body.
  6. Parse PDF with PyPDF2: We create a `BytesIO` object from the PDF file data, which allows `PyPDF2` to read the PDF from memory without needing to write it to disk. We then create a `PdfReader` object to parse the PDF.
  7. Extract Text: We iterate through each page of the PDF and extract the text using the `extract_text()` method. We concatenate the text from all pages into a single string.
  8. (Example) Extract Number of Pages: As an example, we also extract the number of pages in the PDF. You would replace this with your specific data extraction logic.
  9. Prepare Data for DynamoDB: We create a dictionary containing the data we want to store in DynamoDB. This includes the PDF name, the extracted text, the number of pages, the S3 bucket name, and a timestamp.
  10. Store Data in DynamoDB: We use the DynamoDB client to put the item into the DynamoDB table.
  11. Error Handling: We wrap the entire process in a `try…except` block to catch any exceptions that might occur. We log the error and return an error response.

Important Considerations:

  • Memory Usage: Be mindful of the size of the PDF files. Loading large PDFs into memory can exceed the Lambda function’s memory limit. Consider streaming the PDF data or using a different parsing strategy for large files.
  • Character Encoding: Ensure the text is decoded correctly, especially if the PDF contains non-ASCII characters. You might need to specify the encoding when reading the PDF file.
  • Timeout: Lambda functions have a maximum execution time. Parsing complex PDFs can take a significant amount of time. Increase the Lambda function’s timeout if necessary.

2.3 Data Extraction Strategies: Identifying Key Information

The example code above extracts *all* the text from the PDF. In most real-world scenarios, you’ll want to extract specific pieces of information. Here are some strategies for identifying and extracting key information:

  • Regular Expressions: Use regular expressions to search for patterns in the text. This is useful for extracting data that follows a consistent format, such as dates, phone numbers, or email addresses.
  • Keyword Matching: Search for specific keywords or phrases that indicate the presence of relevant information. For example, you might search for the phrase “Invoice Number:” to identify the invoice number in the PDF.
  • Text Segmentation: Divide the text into segments based on whitespace, line breaks, or other delimiters. This can help you isolate specific sections of the PDF.
  • Layout Analysis: Analyze the layout of the PDF to identify tables, headings, and other structural elements. This can be more complex, but it can be very effective for extracting structured data. Libraries like `tabula-py` are specifically designed for this.
  • Machine Learning: For very complex documents, you can use machine learning techniques to train a model to identify and extract specific types of information. This is the most advanced approach and requires a significant investment in training data and model development.

Here’s an example of using regular expressions to extract an invoice number:


import re

def extract_invoice_number(text):
    """
    Extracts the invoice number from the text using a regular expression.
    """
    pattern = r"Invoice Number:\s*(\d+)"  # Matches "Invoice Number:" followed by whitespace and digits
    match = re.search(pattern, text)
    if match:
        return match.group(1)  # Returns the captured group (the invoice number)
    else:
        return None

# Inside the lambda_handler function:
invoice_number = extract_invoice_number(text)
if invoice_number:
    item['invoice_number'] = invoice_number
    print(f"Invoice Number: {invoice_number}")
else:
    print("Invoice number not found.")

  

Remember to tailor your data extraction strategy to the specific structure and content of the PDF documents you are processing.

2.4 DynamoDB Integration: Storing the Parsed Data

We’ve already seen the basic DynamoDB integration in the example code. Let’s dive a bit deeper into best practices for storing data in DynamoDB.

  • DynamoDB Table Design: Carefully design your DynamoDB table schema based on your query patterns. Choose a partition key and sort key that will allow you to efficiently retrieve the data you need. For this use case, using `pdf_name` as the partition key is a good starting point.
  • Data Types: Use the appropriate data types for your attributes. DynamoDB supports various data types, including strings, numbers, booleans, lists, and maps. Using the correct data types can improve performance and reduce storage costs.
  • Attribute Naming: Use descriptive and consistent attribute names. This will make your code easier to understand and maintain.
  • Error Handling: Handle potential errors when writing to DynamoDB. DynamoDB operations can fail due to various reasons, such as insufficient capacity or network issues. Implement retry logic to handle transient errors.
  • Batch Writes: If you need to write a large number of items to DynamoDB, use the `batch_write_item` operation. This is more efficient than writing items individually.
  • Consider DynamoDB Streams: If you need to react to changes in your DynamoDB table, consider using DynamoDB Streams. DynamoDB Streams allows you to capture a time-ordered sequence of item-level modifications in a DynamoDB table. You can then trigger other Lambda functions or services based on these changes.

Here’s an example of using `batch_write_item` (although not directly applicable to this PDF parsing scenario, it’s a useful DynamoDB concept):


import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('MyTable')

def batch_write_to_dynamodb(items):
    """
    Writes a batch of items to DynamoDB using batch_write_item.
    """
    with table.batch_writer() as batch:
        for item in items:
            batch.put_item(Item=item)

# Example usage:
items_to_write = [
    {'id': '1', 'name': 'Item 1'},
    {'id': '2', 'name': 'Item 2'},
    {'id': '3', 'name': 'Item 3'},
]

batch_write_to_dynamodb(items_to_write)
  

3. Error Handling and Logging: Building a Robust System

A robust system needs proper error handling and logging. This section covers the best practices for error handling and logging in your serverless PDF parsing application.

3.1 Implementing Error Handling in Lambda

Error handling in Lambda is crucial for preventing unexpected failures and ensuring your application’s reliability. Here are some key strategies:

  • Try-Except Blocks: Use `try…except` blocks to catch potential exceptions in your code. This allows you to handle errors gracefully and prevent your Lambda function from crashing.
  • Specific Exception Handling: Catch specific exceptions whenever possible. This allows you to handle different types of errors differently. For example, you might want to retry a DynamoDB write operation if it fails due to a throttling error, but you might want to log an error and skip the PDF if it’s corrupted.
  • Fallback Mechanisms: Implement fallback mechanisms to handle errors that you can’t recover from. For example, you might want to move the PDF to a “failed” S3 bucket or send an email notification to an administrator.
  • Dead-Letter Queues (DLQs): Configure a Dead-Letter Queue (DLQ) for your Lambda function. If a Lambda function fails to process an event after multiple retries, the event will be sent to the DLQ. This allows you to investigate the cause of the failure and reprocess the event manually.

Here’s an example of using a DLQ:

  1. Create an SQS Queue: Create an SQS queue to act as your DLQ.
  2. Configure DLQ in Lambda: In the Lambda function configuration, specify the ARN of the SQS queue as the Dead-Letter Queue. You can do this in the AWS console or using the AWS CLI.

Now, if your Lambda function fails to process an event, the event will be sent to the SQS queue. You can then use the SQS console to view the failed events and investigate the cause of the failure.

3.2 Effective Logging with CloudWatch

Logging is essential for monitoring your application’s health, debugging issues, and tracking performance. Here are some best practices for logging in Lambda functions:

  • Use `print()` Statements: The simplest way to log information in Lambda functions is to use `print()` statements. Lambda automatically captures the output of `print()` statements and sends it to CloudWatch Logs.
  • Structured Logging: Use structured logging to log data in a consistent and machine-readable format. This makes it easier to analyze your logs and identify trends. You can use libraries like `logging` in Python to format your logs.
  • Log Levels: Use different log levels to indicate the severity of the log message. Common log levels include DEBUG, INFO, WARNING, ERROR, and CRITICAL. Use DEBUG for detailed debugging information, INFO for general information, WARNING for potential problems, ERROR for errors that have occurred, and CRITICAL for critical errors that may cause the application to fail.
  • Contextual Information: Include contextual information in your log messages, such as the PDF name, the timestamp, and the Lambda function version. This will help you correlate log messages and identify the source of problems.
  • Avoid Logging Sensitive Information: Be careful not to log sensitive information, such as passwords or API keys. This could expose your application to security vulnerabilities.
  • CloudWatch Metrics: Use CloudWatch Metrics to track key performance indicators (KPIs) for your Lambda function, such as the number of invocations, the execution time, and the error rate. This will help you identify performance bottlenecks and optimize your application. You can embed custom metrics in your logs, which CloudWatch can then extract and graph.

Here’s an example of using the `logging` library:


import logging
import os

# Configure logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # Set the default log level

def lambda_handler(event, context):
    """
    This function is triggered by S3 when a PDF is uploaded.
    It parses the PDF, extracts text, and stores the data in DynamoDB.
    """
    try:
        # 1. Extract bucket name and file key from the S3 event
        bucket = event['Records'][0]['s3']['bucket']['name']
        key = event['Records'][0]['s3']['object']['key']

        # Log the event data
        logger.info(f"Processing PDF: s3://{bucket}/{key}")  # Using structured logging

        # ... (rest of the code)

    except Exception as e:
        # Log the error and return an error response
        logger.exception(f"Error processing PDF: {e}")  # Log the exception with traceback
        return {
            'statusCode': 500,
            'body': f'Error processing PDF: {e}'
        }
  

To view your CloudWatch logs, go to the CloudWatch console in the AWS Management Console and select “Logs” from the left-hand navigation menu. You can then search for log messages related to your Lambda function.

3.3 Retry Mechanisms: Handling Transient Errors

Transient errors are temporary errors that may resolve themselves if you retry the operation. Examples of transient errors include network outages, service unavailability, and throttling errors. To handle transient errors, implement retry mechanisms in your Lambda function.

There are two main ways to implement retry mechanisms:

  • Lambda’s Built-in Retry Mechanism: Lambda automatically retries function invocations for asynchronous events (such as S3 events) in case of errors. You can configure the number of retry attempts and the maximum event age in the Lambda function configuration.
  • Custom Retry Logic: You can implement custom retry logic in your code using a loop and a delay. This gives you more control over the retry process, such as the ability to implement exponential backoff.

Here’s an example of implementing custom retry logic with exponential backoff:


import time
import random
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('MyTable')

def put_item_with_retry(item, max_retries=3, base_delay=1):
    """
    Puts an item into DynamoDB with retry logic and exponential backoff.
    """
    for attempt in range(max_retries):
        try:
            table.put_item(Item=item)
            return  # Success!
        except Exception as e:
            if attempt == max_retries - 1:  # Last attempt
                raise  # Re-raise the exception
            else:
                delay = base_delay * (2 ** attempt) + random.random()  # Exponential backoff with jitter
                print(f"Retrying in {delay:.2f} seconds...")
                time.sleep(delay)

# Example usage:
item_to_put = {'id': '4', 'name': 'Item 4'}
try:
    put_item_with_retry(item_to_put)
    print("Item successfully put into DynamoDB.")
except Exception as e:
    print(f"Failed to put item into DynamoDB after multiple retries: {e}")

  

In this example, the `put_item_with_retry` function attempts to put an item into DynamoDB. If the operation fails, it retries up to `max_retries` times, with an exponential backoff delay between each attempt. The delay is calculated as `base_delay * (2 ** attempt) + random.random()`, which means that the delay increases exponentially with each attempt. The `random.random()` function adds a small amount of jitter to the delay, which helps to prevent multiple clients from retrying at the same time and overwhelming the DynamoDB service.

4. Testing and Deployment

Before deploying your Lambda function to production, it’s essential to test it thoroughly. This section covers the best practices for testing and deploying your serverless PDF parsing application.

4.1 Local Testing with Serverless Framework

While you can test directly in the AWS console, local testing is much faster and more convenient. The Serverless Framework provides excellent tools for local testing:

  • `serverless invoke local`:** This command allows you to invoke your Lambda function locally with a simulated S3 event. You can create a sample S3 event JSON file and pass it to the command.

First, create a `serverless.yml` file in your project directory (if you haven’t already). This file defines your serverless application. Here’s an example:


service: pdf-parser

provider:
  name: aws
  runtime: python3.9
  region: us-east-1 # Replace with your region
  iam:
    role:
      statements:
        - Effect: "Allow"
          Action:
            - "s3:GetObject"
          Resource: "arn:aws:s3:::your-s3-bucket/*" # Replace with your bucket ARN
        - Effect: "Allow"
          Action:
            - "dynamodb:PutItem"
          Resource: "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_ID:table/YourDynamoDBTable" # Replace with your table ARN and account ID

functions:
  pdf_parser:
    handler: handler.lambda_handler # Assuming your main file is handler.py
    environment:
      DYNAMODB_TABLE_NAME: YourDynamoDBTable # Replace with your DynamoDB table name
    events:
      - s3:
          bucket: your-s3-bucket # Replace with your bucket name
          event: s3:ObjectCreated:*
          rules:
            - suffix: .pdf

  

Replace the placeholder values with your actual bucket name, DynamoDB table name, region, and account ID. Also, make sure the IAM role has the necessary permissions to access S3 and DynamoDB.

Then, create a `handler.py` file with your Lambda function code (the code we discussed earlier).

Now, create a sample S3 event JSON file (e.g., `s3_event.json`):


{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-1",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisreallyfun"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "tf-test-bucket",
        "bucket": {
          "name": "your-s3-bucket",  # Replace with your bucket name
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::your-s3-bucket"  # Replace with your bucket ARN
        },
        "object": {
          "key": "test.pdf",  # Replace with the name of your test PDF file
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}
  

Replace the placeholder values with your actual bucket name and the name of a test PDF file that you have uploaded to your S3 bucket.

Finally, run the following command to invoke your Lambda function locally:

serverless invoke local -f pdf_parser -p s3_event.json

This will invoke your `pdf_parser` function with the event data from `s3_event.json`. The output of the function will be displayed in the console.

**Testing Steps:**

  1. Successful Parsing: Upload a valid PDF file to your S3 bucket and verify that the Lambda function is triggered and successfully parses the PDF and stores the data in DynamoDB. Check the CloudWatch logs for confirmation.
  2. Error Handling: Upload a corrupted PDF file or a file that is not a PDF to your S3 bucket and verify that the Lambda function correctly handles the error and logs an appropriate error message.
  3. Data Extraction: Upload a PDF file that contains the data you want to extract and verify that the Lambda function correctly extracts the data and stores it in DynamoDB.
  4. Performance Testing: Upload a large PDF file to your S3 bucket and measure the execution time of the Lambda function. Identify any performance bottlenecks and optimize your code accordingly.
  5. Security Testing: Test your Lambda function for security vulnerabilities, such as injection attacks and cross-site scripting (XSS). Use tools like OWASP ZAP to scan your application for vulnerabilities.

4.2 Deploying to AWS: Completing the Pipeline

Once you’ve thoroughly tested your Lambda function locally, you can deploy it to AWS using the Serverless Framework:

serverless deploy

This command will package your Lambda function and its dependencies, upload them to S3, and create or update the necessary AWS resources, such as the Lambda function, the IAM role, and the S3 event trigger.

After deployment, you can test your application by uploading a PDF file to your S3 bucket and verifying that the Lambda function is triggered and successfully parses the PDF and stores the data in DynamoDB. Check the CloudWatch logs for confirmation. Monitor your Lambda function using CloudWatch Metrics to track its performance and identify any issues.

5. Optimization and Best Practices

This section covers optimization techniques and best practices for building a cost-effective, secure, and performant serverless PDF parsing application.

5.1 Cost Optimization Strategies for Serverless Architectures

Serverless architectures can be very cost-effective, but it’s important to implement cost optimization strategies to avoid unnecessary expenses.

  • Lambda Function Memory: Choose the optimal memory allocation for your Lambda function. Lambda pricing is based on the amount of memory allocated and the execution time. Experiment with different memory allocations to find the sweet spot that provides the best performance at the lowest cost. Use CloudWatch Metrics to monitor the execution time of your Lambda function and identify any performance bottlenecks.
  • Lambda Function Timeout: Set an appropriate timeout for your Lambda function. The default timeout is 3 seconds, but you may need to increase it if your function takes longer to execute. However, setting a timeout that is too long can increase your costs.
  • Efficient Code: Write efficient code that minimizes the execution time of your Lambda function. Use profiling tools to identify performance bottlenecks and optimize your code accordingly.
  • Minimize Dependencies: Minimize the number of dependencies in your Lambda function. Each dependency adds to the size of your deployment package and increases the startup time of your function. Use only the dependencies that you absolutely need.
  • Connection Reuse: Reuse connections to other AWS services, such as DynamoDB. Creating a new connection for each invocation can be expensive. Initialize your AWS clients outside the `lambda_handler` function, as demonstrated earlier.
  • Data Storage Costs: Choose the appropriate storage class for your S3 bucket. If you don’t need immediate access to the PDF files, consider using the S3 Glacier or S3 Intelligent-Tiering storage classes, which are cheaper than the S3 Standard storage class. Also, consider deleting the PDF files from S3 after they have been processed to reduce storage costs.
  • DynamoDB Capacity: Provision the appropriate capacity for your DynamoDB table. DynamoDB offers two capacity modes: provisioned and on-demand. Provisioned capacity allows you to specify the read and write capacity units that your table needs. On-demand capacity automatically scales your table’s capacity based on your workload. Choose the capacity mode that is most cost-effective for your use case.
  • Use Reserved Concurrency: If you have a predictable workload, consider using reserved concurrency for your Lambda function. Reserved concurrency guarantees that your Lambda function will always have a certain amount of concurrency available, which can improve performance and reduce costs.

5.2 Security Best Practices for Lambda Functions and DynamoDB

Security is paramount in any application, and serverless applications are no exception. Here are some security best practices for your Lambda functions and DynamoDB:

  • Least Privilege: Grant your Lambda function only the minimum permissions that it needs to access other AWS resources. Use IAM roles to grant permissions to your Lambda function. Avoid using wildcard permissions (e.g., `s3:*`).
  • Environment Variables: Store sensitive information, such as passwords and API keys, in environment variables. Do not hardcode sensitive information in your code. Encrypt your environment variables using AWS Key Management Service (KMS).
  • Input Validation: Validate all input to your Lambda function. This includes data from S3 events, API Gateway requests, and other sources. Sanitize your input to prevent injection attacks.
  • Code Scanning:

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *