Skip to content

Latest commit

 

History

History
308 lines (233 loc) · 11.2 KB

SAMPLE02-Lambda-API-Gateway-Python.md

File metadata and controls

308 lines (233 loc) · 11.2 KB

SAMPLE-02: Provisioning Lambda Function, API Gateway and Reaching HTML Page in Python Code From Browser

This sample shows:

  • how to create Lambda function with Python code,
  • how to create Lambda Role, Policy, Policy-Role attachment, Lambda API-gateway permission, uploading code,
  • how to create API-gateway resource and method definition, Lambda-API-gateway connection, deploying API-gateway,
  • details on AWS Lambda, API-Gateway, IAM

3 Lambda-TF

There are 3 main parts:

  • lambda.tf: It includes lambda function, lambda role, policy, policy-role attachment, lambda api gateway permission, zipping code
  • api-gateway.tf: It includes api-gateway resource and method definition, lambda - api gateway connection, deploying api gateway, api-gateway deployment URL as output
  • code/main.py: It includes basic lambda handler with basic HTML code, and REST API response.

Code: https://github.com/omerbsezer/Fast-Terraform/tree/main/samples/lambda-role-policy-apigateway-python

Prerequisite

Steps

  • Create lambda.tf:
    • Terraform Configuration: Specifies the AWS provider version and Terraform version.
    • IAM Role and Policy: Creates an IAM role for the Lambda function and attaches a policy that allows the Lambda function to write logs to CloudWatch.
    • Zipping Lambda Code: Prepares the Python code by zipping it into a format that Lambda can execute.
    • Lambda Function: Creates a Lambda function using the specified IAM role, code, and runtime.
    • API Gateway Integration: Grants API Gateway permission to invoke the Lambda function.
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }
  required_version = ">= 1.2.0"
}

# Create IAM Role for lambda
resource "aws_iam_role" "lambda_role" {
 name   = "aws_lambda_role"
 assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

# IAM policy for the lambda
resource "aws_iam_policy" "iam_policy_for_lambda" {

  name         = "aws_iam_policy_for_aws_lambda_role"
  path         = "/"
  description  = "AWS IAM Policy for managing aws lambda role"
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*",
      "Effect": "Allow"
    }
  ]
}
EOF
}

# Role - Policy Attachment
resource "aws_iam_role_policy_attachment" "attach_iam_policy_to_iam_role" {
  role        = aws_iam_role.lambda_role.name
  policy_arn  = aws_iam_policy.iam_policy_for_lambda.arn
}

# Zipping the code, lambda wants the code as zip file
data "archive_file" "zip_the_python_code" {
 type        = "zip"
 source_dir  = "${path.module}/code/"
 output_path = "${path.module}/code/main.zip"
}

# Lambda Function, in terraform ${path.module} is the current directory.
resource "aws_lambda_function" "lambda_function" {
 filename                       = "${path.module}/code/main.zip"
 function_name                  = "Lambda-Function"
 role                           = aws_iam_role.lambda_role.arn
 handler                        = "main.lambda_handler"
 runtime                        = "python3.8"
 depends_on                     = [aws_iam_role_policy_attachment.attach_iam_policy_to_iam_role]
}

# With Lambda permission, API Gateway can invoke Lambda 
resource "aws_lambda_permission" "apigw" {
 statement_id  = "AllowAPIGatewayInvoke"
 action        = "lambda:InvokeFunction"
 function_name = aws_lambda_function.lambda_function.function_name
 principal     = "apigateway.amazonaws.com"
 # The "/*/*" portion grants access from any method on any resource within the API Gateway REST API.
 source_arn = "${aws_api_gateway_rest_api.example.execution_arn}/*/*"
}

Code: https://github.com/omerbsezer/Fast-Terraform/blob/main/samples/lambda-role-policy-apigateway-python/lambda.tf

image

  • Create api-gateway.tf:
    • Proxy Usage: The {proxy+} path is used to dynamically route all requests to the Lambda function, eliminating the need to define individual paths and methods.
    • Flexibility: The ANY method allows all HTTP methods, making the API flexible.
    • AWS_PROXY Integration: Simplifies the interaction between API Gateway and Lambda by passing the entire request data to Lambda, allowing it to process dynamically.
# Create API Gateway with Rest API type
resource "aws_api_gateway_rest_api" "example" {
  name        = "Serverless"
  description = "Serverless Application using Terraform"
}

resource "aws_api_gateway_resource" "proxy" {
   rest_api_id = aws_api_gateway_rest_api.example.id
   parent_id   = aws_api_gateway_rest_api.example.root_resource_id
   path_part   = "{proxy+}"     # with proxy, this resource will match any request path
}

resource "aws_api_gateway_method" "proxy" {
   rest_api_id   = aws_api_gateway_rest_api.example.id
   resource_id   = aws_api_gateway_resource.proxy.id
   http_method   = "ANY"       # with ANY, it allows any request method to be used, all incoming requests will match this resource
   authorization = "NONE"
}

# API Gateway - Lambda Connection
resource "aws_api_gateway_integration" "lambda" {
   rest_api_id = aws_api_gateway_rest_api.example.id
   resource_id = aws_api_gateway_method.proxy.resource_id
   http_method = aws_api_gateway_method.proxy.http_method
   integration_http_method = "POST"
   type                    = "AWS_PROXY"  # With AWS_PROXY, it causes API gateway to call into the API of another AWS service
   uri                     = aws_lambda_function.lambda_function.invoke_arn
}

# The proxy resource cannot match an empty path at the root of the API. 
# To handle that, a similar configuration must be applied to the root resource that is built in to the REST API object
resource "aws_api_gateway_method" "proxy_root" {
   rest_api_id   = aws_api_gateway_rest_api.example.id
   resource_id   = aws_api_gateway_rest_api.example.root_resource_id
   http_method   = "ANY"
   authorization = "NONE"
}

resource "aws_api_gateway_integration" "lambda_root" {
   rest_api_id = aws_api_gateway_rest_api.example.id
   resource_id = aws_api_gateway_method.proxy_root.resource_id
   http_method = aws_api_gateway_method.proxy_root.http_method
   integration_http_method = "POST"
   type                    = "AWS_PROXY"  # With AWS_PROXY, it causes API gateway to call into the API of another AWS service
   uri                     = aws_lambda_function.lambda_function.invoke_arn
}

# Deploy API Gateway
resource "aws_api_gateway_deployment" "example" {
   depends_on = [
     aws_api_gateway_integration.lambda,
     aws_api_gateway_integration.lambda_root,
   ]
   rest_api_id = aws_api_gateway_rest_api.example.id
   stage_name  = "test"
}

# Output to the URL 
output "base_url" {
  value = aws_api_gateway_deployment.example.invoke_url
}

Code: https://github.com/omerbsezer/Fast-Terraform/blob/main/samples/lambda-role-policy-apigateway-python/api-gateway.tf

image

  • Create main.py under code directory:
def lambda_handler(event, context):
   content = """
   <html>
   <h1> Hello Website running on Lambda! Deployed via Terraform </h1>
   </html>
   """
   response ={
     "statusCode": 200,
     "body": content,
     "headers": {"Content-Type": "text/html",}, 
   }
   return response

Code: https://github.com/omerbsezer/Fast-Terraform/blob/main/samples/lambda-role-policy-apigateway-python/code/main.py

image

  • Run init, validate command:
terraform init
terraform validate

image

  • Run plan, apply command:
terraform plan   # for dry-run
terraform apply

image

image

  • On AWS Lambda:

image

image

  • Create a test by clicking "Test" for lambda function:

image

  • Status code 200, OK is returned successfully:

image

  • Execution Role is created, seen on Lambda

image

  • Role on IAM:

image

  • Policy on IAM:

image

  • On AWS Lambda: With Lambda permission, API Gateway can invoke Lambda

image

  • Lambda is triggered by API-Gateway:

image

  • On AWS API-Gateway:

image

image

  • By clicking "Test" to test api-gateway

image

image

  • HTML page that runs on Lambda Function using API-Gateway can be reached. With API-Gateway, lambda function gets DNS and traffic from internet comes to the Lambda function.

image

  • Run destroy command:
terraform destroy

image

  • On AWS Lambda, function is deleted:

image

References