Automate Outdated AWS Lambda Runtime Updates

Python for devops v1.2 — Writing Python script to upgrade AWS lambda functions running outdated/unsupported runtimes.

Akhilesh Mishra
AWS Tip
6 min readJul 7, 2024

--

Photo by Conner Baker on Unsplash

This is the second blog post on my blog series Python for DevOps where I explore real-world devops use cases to write Python scripts.

Python for devops part 1 — Automate encryption of SQS queues
Python for Devops part 3— Building a RESTful API with Flask and PostgreSQL.

Scenario

Suppose you got a report from the security team complaining about hundreds of Lambda functions running unsupported runtime such as Python 3.8 and Node.js 14x. Remember, AWS won’t automatically update outdated runtimes for your Lambda functions.

Manually updating all these Lambda functions can be a pain. As a responsible Devops engineer, you want to avoid these manual tasks and write a reusable Python script to automate these tasks.

What we will be doing in this blog post?

In this blog post, I will teach you how to automate updating lambda runtimes. Our script will take the desired Python versions as arguments, list the lambdas running older versions, and upgrade the runtime to the desired version.

Note: Most of the time we provision AWS infra including lambda function using Terraform and we can easily update the version by updating the Terraform code.

Steps we would be following

  1. Create a boto3 client for Lambda.
  2. List all the Lambda functions within a region on your AWS account.
  3. Get the runtime for the lambda function.
  4. Validate if Lambda runtime is lower than the desired version.
  5. Upgrade the Lambda runtime to match the desired version.
  6. We will be following some of the best practices while writing the script.

Pre-requisite:

  • Configure the AWS credentials in your local machine by running aws configure command. Follow the instructions from my last blog post.
  • Create some sample Lambda functions running older versions of Python runtime by running AWS CLI commands.

Let’s do the pre-setup before proceeding with Python script development — Creating demo lambda functions.

1. Preparing Your Deployment Package

  • Create a directory for your Lambda function code.
mkdir my-lambda-function
cd my-lambda-function
  • Create your Lambda function code (e.g., lambda_function.py)
def lambda_handler(event, context):
return "Hello, World!"
  • Zip the contents of the directory
zip -r deployment-package.zip .

2. Create a Lambda Execution Role

  • Create a trust policy (e.g., trust-policy.json)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
  • Create the IAM role
aws iam create-role --role-name MyLambdaExecutionRole --assume-role-policy-document file://trust-policy.json
  • Attach the AWSLambdaBasicExecutionRole policy to the role
aws iam attach-role-policy --role-name MyLambdaExecutionRole --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

3. Deploy the Lambda function

  • AWS CLI command to create the lambda function should look something like this
aws lambda create-function \
--function-name MyPython38Function \
--runtime python3.8 \
--role arn:aws:iam::YOUR_ACCOUNT_ID:role/YOUR_LAMBDA_EXECUTION_ROLE \
--handler lambda_function.lambda_handler \
--zip-file fileb://path/to/your/deployment/package.zip
  • Now we will use the IAM role and deployment packages we created to deploy 3 lambda functions — medium-blog-lambda1-3 `
aws lambda create-function \
--function-name medium-blog-lambda1 \
--runtime python3.8 \
--role arn:aws:iam::366130468123:role/MyLambdaExecutionRole \
--handler lambda_function.lambda_handler \
--zip-file fileb://my-lambda-function/deployment-package.zip \
--timeout 15 \
--memory-size 128

You should endup with 3 Lambda functions like below

Now we are good to start writing the Python script.

Before we start writing some Python, let me set up the Python environments by following the best practices.

Create a Python virtual environment.

Creating a virtual environment in Python is important because it allows you to manage dependencies and packages for different projects independently.

# Create the virtual python environment
python3 -m venv medium_blog

# Activate the virtual environments
source medium_blog/bin/activate
  • Create requirements.txt and put the dependencies in that file.

boto3 is the Python library that allows you to communicate with AWS resources using Python.

# requirements.txt
boto3
  • Install the dependencies
pip install -r requirements.txt

Now that we have done the setup, let’s write the Python script

We can separate our code into small parts, aka functions, and each function does one job.

Note: I will place the complete code for the blog post in my public GitHub.

1. Import the Python modules and create a lambda client using boto3

2. A function that lists all lambdas — will return a list of lambda functions.

This function uses lambda_client to fetch a list of Lambda functions and return it.

Instead of using list_functions()[“Functions”], use list_functions().get(“Functions”, None) to avoid a KeyError if the “Functions” key is not present in the response. This ensures the code returns None by default, making it more robust and preventing runtime errors.

3. Get the lambda runtime.

This function extracts FunctionName and Runtime from dictionaries in lambda_json_list, filtering out entries without a Runtime value(in the case of container-based lambda functions), and returns a list of tuples containing name and runtime.

4. Compare the runtime with the desired and return True if the runtime is lower than desired.

The Version class from the packaging.version module is used to parse and compare version strings. In this function, it checks if the current runtime version is older than the specified version to compare against.

5. Update the Lambda runtime if the compare function returns a True value.

This function will update the Lambda function to a new runtime.

I have used try/except block for exception handling. It allows us to manage and respond to unexpected errors. We can attempt risky operations within try and handle any resulting exceptions in except, ensuring your program can recover from errors gracefully without crashing.

6. Putting pieces together

7. Running the script

Paste all code snippets into update_lambda_runtimes.py and run the below command to execute the script

python update_lambda_runtimes.py

Running the script with __name__ == ‘__main__’ ensures that run() is executed only when the script is run directly (not imported as a module)

To enhance the script’s usability, we should enable it to accept command-line arguments.

This function uses the argparse module in Python to create a command-line argument parser. It expects an argument-- python_version (short form -a) to be provided while running the script.

Running the script with command line argument

python update_lambda_runtimes.py --python-version python3.9

You can find the complete code for the blog post in my public GitHub Repo, use this link to access it.

What else to do?

  • Use logging.
  • Document the code and use type hinting.
  • Expand the script to include the other runtimes such as NodeJS, go, etc.

If you found this blog post useful, clap, follow, and subscribe so you don’t miss my future articles.

Connect with me on Linkedin: https://www.linkedin.com/in/akhilesh-mishra-0ab886124/

--

--

Self taught DevOps engineer with expertise in multi-cloud, and various DevOps tools. Open for mentorship - https://topmate.io/akhilesh_mishra