Introducció

En aquest projecte, aprendrem a utilitzar Terraform per desplegar una aplicació sense servidor (serverless) utilitzant AWS Lambda i altres serveis relacionats. Les aplicacions sense servidor permeten executar codi sense gestionar servidors, la qual cosa simplifica la infraestructura i redueix els costos operatius.

Objectius del Projecte

  1. Crear una funció Lambda amb Terraform.
  2. Configurar un API Gateway per invocar la funció Lambda.
  3. Emmagatzemar dades en DynamoDB.
  4. Gestionar permisos amb IAM.

Requisits Previs

  • Coneixements bàsics de Terraform.
  • Compte d'AWS amb permisos suficients per crear recursos.
  • Instal·lació de Terraform i AWS CLI.

Passos del Projecte

  1. Configuració Inicial

1.1. Crear el Directori del Projecte

mkdir terraform-serverless
cd terraform-serverless

1.2. Fitxer main.tf

Crea un fitxer main.tf per definir els recursos de Terraform.

provider "aws" {
  region = "us-west-2"
}

resource "aws_iam_role" "lambda_role" {
  name = "lambda_basic_execution"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_policy" {
  role       = aws_iam_role.lambda_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

  1. Crear la Funció Lambda

2.1. Codi de la Funció Lambda

Crea un fitxer lambda_function.py amb el següent codi:

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': 'Hello from Lambda!'
    }

2.2. Definir la Funció Lambda a Terraform

Afegim la definició de la funció Lambda al fitxer main.tf.

resource "aws_lambda_function" "hello_world" {
  filename         = "lambda_function.zip"
  function_name    = "HelloWorldFunction"
  role             = aws_iam_role.lambda_role.arn
  handler          = "lambda_function.lambda_handler"
  runtime          = "python3.8"
  source_code_hash = filebase64sha256("lambda_function.zip")
}

2.3. Crear el Fitxer ZIP

zip lambda_function.zip lambda_function.py

  1. Configurar API Gateway

3.1. Definir l'API Gateway

Afegim la configuració de l'API Gateway al fitxer main.tf.

resource "aws_api_gateway_rest_api" "api" {
  name        = "ServerlessAPI"
  description = "API per a la funció Lambda"
}

resource "aws_api_gateway_resource" "resource" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  parent_id   = aws_api_gateway_rest_api.api.root_resource_id
  path_part   = "hello"
}

resource "aws_api_gateway_method" "method" {
  rest_api_id   = aws_api_gateway_rest_api.api.id
  resource_id   = aws_api_gateway_resource.resource.id
  http_method   = "GET"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "integration" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  resource_id = aws_api_gateway_resource.resource.id
  http_method = aws_api_gateway_method.method.http_method
  integration_http_method = "POST"
  type        = "AWS_PROXY"
  uri         = aws_lambda_function.hello_world.invoke_arn
}

resource "aws_lambda_permission" "apigw" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.hello_world.function_name
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_rest_api.api.execution_arn}/*/*"
}

  1. Emmagatzemar Dades en DynamoDB

4.1. Crear la Taula DynamoDB

Afegim la configuració de DynamoDB al fitxer main.tf.

resource "aws_dynamodb_table" "table" {
  name           = "ServerlessTable"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "ID"

  attribute {
    name = "ID"
    type = "S"
  }
}

4.2. Actualitzar la Funció Lambda per Interactuar amb DynamoDB

Actualitzem el codi de la funció Lambda per emmagatzemar dades a DynamoDB.

import boto3
import json

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

def lambda_handler(event, context):
    table.put_item(
        Item={
            'ID': '1',
            'Message': 'Hello from Lambda!'
        }
    )
    return {
        'statusCode': 200,
        'body': json.dumps('Data inserted into DynamoDB')
    }

  1. Gestionar Permisos amb IAM

5.1. Afegir Permisos a la Funció Lambda

Actualitzem el fitxer main.tf per afegir permisos a la funció Lambda.

resource "aws_iam_role_policy" "lambda_dynamodb_policy" {
  name = "lambda_dynamodb_policy"
  role = aws_iam_role.lambda_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "dynamodb:PutItem",
          "dynamodb:GetItem",
          "dynamodb:Scan",
          "dynamodb:Query"
        ]
        Effect   = "Allow"
        Resource = aws_dynamodb_table.table.arn
      },
    ]
  })
}

  1. Desplegar la Infraestructura

6.1. Inicialitzar Terraform

terraform init

6.2. Aplicar la Configuració

terraform apply

Conclusió

En aquest projecte, hem après a desplegar una aplicació sense servidor utilitzant AWS Lambda, API Gateway i DynamoDB amb Terraform. Hem cobert la creació de funcions Lambda, la configuració d'API Gateway per invocar aquestes funcions, l'emmagatzematge de dades en DynamoDB i la gestió de permisos amb IAM. Aquest projecte proporciona una base sòlida per desenvolupar aplicacions sense servidor més complexes.

Exercicis Pràctics

  1. Afegir una nova funció Lambda que llegeixi dades de DynamoDB i les retorni a través de l'API Gateway.
  2. Configurar un endpoint POST a l'API Gateway per inserir dades a DynamoDB des d'una petició HTTP.
  3. Implementar una política de seguretat que restringeixi l'accés a l'API Gateway a usuaris autenticats.

Solucions als Exercicis

Exercici 1: Afegir una nova funció Lambda

import boto3
import json

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

def lambda_handler(event, context):
    response = table.get_item(
        Key={
            'ID': '1'
        }
    )
    item = response.get('Item', {})
    return {
        'statusCode': 200,
        'body': json.dumps(item)
    }

Exercici 2: Configurar un endpoint POST

resource "aws_api_gateway_method" "post_method" {
  rest_api_id   = aws_api_gateway_rest_api.api.id
  resource_id   = aws_api_gateway_resource.resource.id
  http_method   = "POST"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "post_integration" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  resource_id = aws_api_gateway_resource.resource.id
  http_method = aws_api_gateway_method.post_method.http_method
  integration_http_method = "POST"
  type        = "AWS_PROXY"
  uri         = aws_lambda_function.hello_world.invoke_arn
}

Exercici 3: Implementar una política de seguretat

resource "aws_api_gateway_authorizer" "authorizer" {
  name                   = "CognitoAuthorizer"
  rest_api_id            = aws_api_gateway_rest_api.api.id
  identity_source        = "method.request.header.Authorization"
  provider_arns          = ["arn:aws:cognito-idp:us-west-2:123456789012:userpool/us-west-2_abcdefgh"]
  type                   = "COGNITO_USER_POOLS"
}

resource "aws_api_gateway_method" "secure_method" {
  rest_api_id   = aws_api_gateway_rest_api.api.id
  resource_id   = aws_api_gateway_resource.resource.id
  http_method   = "GET"
  authorization = "COGNITO_USER_POOLS"
  authorizer_id = aws_api_gateway_authorizer.authorizer.id
}

Amb aquests exercicis, hauràs reforçat els conceptes apresos i estaràs preparat per desenvolupar aplicacions sense servidor més avançades.

© Copyright 2024. Tots els drets reservats