Articles

Getting Started With Stratoshark

Introduction Stratoshark is the newest piece of software coming from the Wireshark Foundation. For experienced network analysts like me, it promises to be a familiar interface and filtering engine for unfamiliar domains like cloud and system call internals. In particular, I’m really excited to be able to analyze system calls on Linux systems. This post summarizes what I’ve learned about how to set up a lab environment, install Stratoshark, and begin some analysis.

Troubleshoot Like a Doctor: HOPS

Introduction The last time we looked at how to diagnose like a doctor, we focused on the differential diagnosis (dDx). This is the mental model that doctors use to assess possible causes of an issue and prioritize tests to figure out what’s happening. For more information on differential diagnosis, you can read Part 1 of this series. Today, we need to talk through how we gather the best information to feed your dDx and how to make your diagnostic actions count.

An Argument for Increasing TCP's Initial Congestion Window ... Again

Introduction Google has a long history of performing networking research, making changes, and pushing those changes to the entire internet. In 2011, they published one of my favorite papers, which described their decision to increase the TCP initial congestion window from 1 to 10 on their entire infrastructure. This was soon followed by an RFC filed with the IETF, and eventually became an internet standard. I think it’s time to revisit that paper and update Google’s recommendations for the modern Internet.

The Pattern: Identifying Requests and Responses in Encrypted Traffic

Introduction Advances in cybersecurity frequently mean that it’s harder to troubleshoot issues. Some security solutions add a lot of complexity to a system, and sometimes the fact that traffic is encrypted means we can’t see everything we want to. When analyzing traffic in Wireshark, identifying requests and responses are key to understanding how two computers are interacting with each other over the network. Figuring out what the request and response sizes are is also important to figure out what particular network setting to look at.

Troubleshoot Like a Doctor: Differential Diagnosis

Introduction The IT field is terrible at teaching people how to troubleshoot. Sure, if you got a CompTIA A+ or a CCNA, there were modules that talked about how to solve problems, but how much time did you actually spend on those modules? The CCNA course I took spent all of 5 minutes on it, with the message “there’s probably going to be a question that will ask what order these steps come in.

Converting Flask to Lambda

I’ve worked out how to convert a local Flask app to AWS Lambda without having to involve extra modules, vendors, or middleware. Introduction Moving products from a prototype to a deployment can be tricky. In particular, I find myself writing small Flask apps for every little problem, and trying to deploy them to Lambda involves putting an entire layer of abstraction on top of them. Surveying the landscape, there seems to be one model of providing a developer a CLI tool that builds and deploys the entire project:

Converting Flask to Lambda

Published August 25, 2024

I’ve worked out how to convert a local Flask app to AWS Lambda without having to involve extra modules, vendors, or middleware.

Introduction

Moving products from a prototype to a deployment can be tricky. In particular, I find myself writing small Flask apps for every little problem, and trying to deploy them to Lambda involves putting an entire layer of abstraction on top of them.

Surveying the landscape, there seems to be one model of providing a developer a CLI tool that builds and deploys the entire project:

There’s another model of rewriting the web layer of your app:

And there’s a final model of a magic middleware layer that you can throw in with a bit of Terraform:

I don’t really like any of these options. For enterprise deployment, the products like Serverless and Zappa cost money. Alternative Python modules that require a web layer rewrite cease to function for local development unless you run the containerized Lambda simulator, which then requires additional software (namely Docker) on the desktop. And the magic middleware layer is a really nice option, but because it’s an AWS Labs product instead of a GA product, enterprise deployment with it is difficult.

AWS Lambda Architecture

A basic Lambda app has a few different components. Requests come in via an API Gateway or an Application Load Balancer. They’re then processed by the Lambda. Depending on the app, there might be backend calls to a database.

The reason there’s a couple layers to this architecture is because Lambda doesn’t natively use HTTP. Lambda is designed to ingest JSON, so we need to add something in front of it to convert the HTTP to a pure JSON payload.

JSON Payload Model

The key to this conversion is understanding how an HTTP request flows from the API Gateway to the Lambda.

A Lambda requires a handler function that ingests two variables, event and context. In the Python context, event is a dictionary that contains all the keys we would normally use Flask to scrape from the web request:

event.keys()

requestContext
httpMethod
path
queryStringParameters
headers
body
isBase64Encoded

Using event to route traffic

Using the path key along with match, a newer Python feature, we can easily route traffic:

def lambda_handler(event, context):

	request_path = event[path]
	response = ‘’ # initializing the variable

	match request_path.lower(): # make sure the string is normalized
		case ‘/‘:
			response = index()
		case ‘/some_other_web_page’:
			Response = some_other_function()
		case _: # underscore is the catch-all default case
			return {‘statusCode’: 404}

	return {
		‘statusCode’: 200,
		‘body’: json.dumps(response)
	}

But wait! This is just rewriting the web layer, isn’t it?

Integrating with an existing Flask app

It might be, except for the fact that there’s a good way to abstract the old Flask app in a way that preserves all the excellent templating built into it.

Let’s take a basic Flask app:

from flask import (
	blueprint,
	render_template,
	jsonify,
	response,
	request
)

web_app = Blueprint(‘web_app’, __name__)

@web_app.route(“/“)
def index() -> Response:
	return render_template(
		‘index.html’,
		title=“My Web App”,
	)

@web_app.route(“/some_other_route”)
def some_other_route() -> Response:
	input = request.args.get(‘param_name’)
	# TODO: Logic generating some output

	return jsonify(output)

We have 2 endpoints. There’s a basic index page attached to /, and a more complex /some_other_route that does some logic and returns a pure JSON response.

For the conversion, I want to move from this file to 3 separate files:

web_functions.py

from flask import (
	render_template,
	jsonify,
	response
)

def index() -> Response:
	return render_template(
		‘index.html’,
		title=“My Web App”,
	)

def some_other_route(input_data) -> Response:
	# TODO: Logic generating some output

	return jsonify(output)

flask_routes.py

import web_functions

from flask import (
	blueprint,
	response,
	request
)

web_app = blueprint(‘web_app’, __name__)

@web_app.route(“/“)
def index() -> Response:
	return web_functions.index()

@web_app.route(“/some_other_route”)
def some_other_route() -> Response:
	input = request.args.get(‘param_name’)
	return web_functions.some_other_route(input)

All we’re doing here is separating the Flask web functions (defining routes, dealing with input arguments, defining the web app) from the actual logic of the functions.

lambda_routes.py

import json
import web_functions

from Flask import Response

def lambda_handler(event, context) -> Response:

	request_path = event[path]
	

	match request_path.lower():
		case “/“:
			return web_functions.index()

		case “/some_other_route”:
			input = event[‘queryStringParameters’][’param_name’]
			return web_functions.some_other_route(input)

		case _:
			return {‘statusCode’: 404}

Let’s examine how this works for a minute.

If we want to develop this application locally, we just need to run it like a normal Flask app. Requests come through flask_routes.py and then get sent to web_functions.py.

And if we then deploy this code to AWS, the request will come through an Application Load Balancer or API Gateway to lambda_routes.py. The code in lambda_routes.py will then call web_functions.py.

Conclusion

So what did we do here?

We took a standard Flask app and abstracted it just a little bit. We separated the code the parses inputs and sends outputs from the code that does the request processing. This small change means that we can do our local web development in mostly native Flask. And we can also deploy this code directly to AWS Lambda and have it work natively.

We’ve created two doors that lead to the same room with minimal extra complexity, allowing us to have the best of both worlds for developing and deploying Flask apps.