diff --git a/README.md b/README.md index 3c6f611..aecfc43 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ The s3hub command provides following features: |Name|README|implementation| |:--|:--|:--| |[Lambda batch with EventBridge (CloudWatch Events)](./cloudformation/lambda-batch/README.md)|✅|100%| +|[Lambda with API Gateway](./cloudformation/api-gateway-with-lambda/README.md)|✅|100%| |[CloudWatch Real User Monitoring (RUM)](./cloudformation/cloudwatch-rum/README.md)|✅|100%| diff --git a/cloudformation/api-gateway-with-lambda/.gitignore b/cloudformation/api-gateway-with-lambda/.gitignore new file mode 100644 index 0000000..fab0672 --- /dev/null +++ b/cloudformation/api-gateway-with-lambda/.gitignore @@ -0,0 +1 @@ +/bootstrap diff --git a/cloudformation/api-gateway-with-lambda/Makefile b/cloudformation/api-gateway-with-lambda/Makefile new file mode 100644 index 0000000..0ac2fe8 --- /dev/null +++ b/cloudformation/api-gateway-with-lambda/Makefile @@ -0,0 +1,28 @@ +.DEFAULT_GOAL := help + +BINARY_NAME = bootstrap +AWS_STACK_NAME = lambda-batch +TEMPLATE_FILE = template.yml + +.PHONY: help clean dependency_check build deploy +help: ## Show this help message + @grep -E '^[0-9a-zA-Z_-]+[[:blank:]]*:.*?## .*$$' $(MAKEFILE_LIST) | sort \ + | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[1;32m%-15s\033[0m %s\n", $$1, $$2}' + +clean: ## Clean project + -rm -rf $(BINARY_NAME) + +dependency_check: ## Check dependencies + @command -v sam > /dev/null 2>&1 || { echo "Error: sam is not installed. See https://github.com/aws/aws-sam-cli"; exit 1; } + +build: ## Build binary + @echo "Building for Lambda execution environment (Linux/ARM64)" + GOOS=linux GOARCH=arm64 go build -o $(BINARY_NAME) main.go + +deploy: dependency_check build ## Deploy CloudFormation Template + sam deploy --stack-name $(AWS_STACK_NAME) --template-file $(TEMPLATE_FILE) \ + --capabilities CAPABILITY_IAM --resolve-s3 --region ap-northeast-1 || { echo "SAM deployment failed"; exit 1; } + +test-deploy: build ## Deploy CloudFormation Template for test + samlocal deploy --stack-name $(AWS_STACK_NAME) --template-file $(TEMPLATE_FILE) \ + --capabilities CAPABILITY_IAM --resolve-s3 --region ap-northeast-1 || { echo "SAM deployment failed"; exit 1; } \ No newline at end of file diff --git a/cloudformation/api-gateway-with-lambda/README.md b/cloudformation/api-gateway-with-lambda/README.md new file mode 100644 index 0000000..b339be9 --- /dev/null +++ b/cloudformation/api-gateway-with-lambda/README.md @@ -0,0 +1,39 @@ +## API Gateway with Lambda +### Overview + +Lambda and API Gateway combined infrastructure is a powerful means for realizing serverless architecture. Lambda is a service for executing code, while API Gateway creates HTTP endpoints and forwards requests to Lambda functions. + +![lambda-with-apigateway](./lambda-with-apigateway.png) + +This combination offers the following characteristics: + +- Simplified Serverless Architecture: Combining API Gateway with Lambda allows for the creation of a serverless architecture, eliminating issues with server management and scaling. +- Cost Efficiency: Being billed only for the resources you use, costs can scale with traffic, reducing wasteful spending. +- Seamless Integration: API Gateway provides seamless integration with Lambda, allowing you to define API endpoints and route requests to Lambda functions. +- Facilitates the implementation of microservices architecture, allowing deployment of independent Lambda functions for each functionality. + +### Limitations +- Long Processing Time: Lambda functions are limited by execution time. If long processing is required, Lambda might not be suitable. Alternative methods should be explored for long-running processes. +- Heavy Data Processing: Lambda functions have resource limits. For tasks requiring heavy data processing or significant memory, other services or architectures might be more suitable. +- Always Active Services: Lambda is event-driven and goes to sleep when there are no requests. For services that need to be always active or for background processing, Lambda might not be appropriate. + + +### How to deploy +> [!NOTE] +> Before running `make deploy`, ensure you have configured AWS credentials and set the correct region. Otherwise, you use single sign-on (SSO). + +```shell +$ make deploy +``` + +### Endpoint Base URL Syntax +The URL syntax for the API Gateway endpoint is as follows: + +``` +https://.execute-api..amazonaws.com/ +``` + +- ``: The API Gateway ID. +- ``: The AWS region where the API Gateway is deployed. +- ``: The stage name of the API Gateway. + diff --git a/cloudformation/api-gateway-with-lambda/lambda-with-apigateway.drawio b/cloudformation/api-gateway-with-lambda/lambda-with-apigateway.drawio new file mode 100644 index 0000000..a754b3f --- /dev/null +++ b/cloudformation/api-gateway-with-lambda/lambda-with-apigateway.drawio @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cloudformation/api-gateway-with-lambda/lambda-with-apigateway.png b/cloudformation/api-gateway-with-lambda/lambda-with-apigateway.png new file mode 100644 index 0000000..a220008 Binary files /dev/null and b/cloudformation/api-gateway-with-lambda/lambda-with-apigateway.png differ diff --git a/cloudformation/api-gateway-with-lambda/main.go b/cloudformation/api-gateway-with-lambda/main.go new file mode 100644 index 0000000..8d951c2 --- /dev/null +++ b/cloudformation/api-gateway-with-lambda/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "context" + "encoding/json" + "log" + + "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" +) + +// HealthResponse struct defines the response structure +type HealthResponse struct { + Status string `json:"status"` +} + +// Handler is the Lambda function handler +func Handler(_ context.Context) (events.APIGatewayProxyResponse, error) { + // Create a response + responseBody, err := json.Marshal(HealthResponse{Status: "healthy"}) + if err != nil { + log.Printf("Error marshaling JSON response: %v", err) + return events.APIGatewayProxyResponse{StatusCode: 500, Body: `{"error":"Internal Server Error"}`}, nil + } + + // Return API Gateway response + return events.APIGatewayProxyResponse{ + StatusCode: 200, + Headers: map[string]string{"Content-Type": "application/json"}, + Body: string(responseBody), + }, nil +} + +func main() { + // Start the Lambda handler + lambda.Start(Handler) +} diff --git a/cloudformation/api-gateway-with-lambda/template.yml b/cloudformation/api-gateway-with-lambda/template.yml new file mode 100644 index 0000000..3901bb4 --- /dev/null +++ b/cloudformation/api-gateway-with-lambda/template.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: "2010-09-09" +Transform: + - AWS::Serverless-2016-10-31 +Description: "API Gateway with Lambda" + +Resources: + LambdaFuncttion: + Type: "AWS::Serverless::Function" + Properties: + FunctionName: lambda-function + Handler: "handler" + Runtime: provided.al2 + Architectures: [arm64] + Timeout: 10 + CodeUri: ./ + MemorySize: 128 + Policies: + - AWSLambdaBasicExecutionRole + Events: + GetApi: + Type: Api + Properties: + Path: /health + Method: get + RestApiId: !Ref API + + API: + Type: "AWS::Serverless::Api" + Properties: + Name: sam-test-get-api + EndpointConfiguration: REGIONAL + StageName: dev + + LambdaLogGroup: + Type: "AWS::Logs::LogGroup" + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + LogGroupName: !Sub "/aws/lambda/${LambdaFuncttion}" + RetentionInDays: 7 + KmsKeyId: !GetAtt LambdaLogGroupKMSKey.Arn + + LambdaLogGroupKMSKey: + Type: AWS::KMS::Key + UpdateReplacePolicy: Retain + DeletionPolicy: Retain + Properties: + Description: "KMS key for encrypting CloudWatch Logs" + EnableKeyRotation: true + KeyPolicy: + Version: "2012-10-17" + Id: "key-default" + Statement: + - Sid: "Allow administration of the key" + Effect: "Allow" + Principal: + AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" + Action: + - "kms:*" + Resource: "*" + - Sid: "Allow use of the key" + Effect: "Allow" + Principal: + Service: "logs.ap-northeast-1.amazonaws.com" + Action: + - "kms:Encrypt" + - "kms:Decrypt" + - "kms:ReEncrypt*" + - "kms:GenerateDataKey*" + - "kms:DescribeKey" + Resource: "*" \ No newline at end of file diff --git a/cloudformation/lambda-batch/template.yml b/cloudformation/lambda-batch/template.yml index a8962fb..ffc1461 100644 --- a/cloudformation/lambda-batch/template.yml +++ b/cloudformation/lambda-batch/template.yml @@ -53,7 +53,7 @@ Resources: Properties: LogGroupName: !Sub "/aws/lambda/${LambdaBatch}" RetentionInDays: 7 - KmsKeyId: !Ref LambdaLogGroupKMSKey + KmsKeyId: !GetAtt LambdaLogGroupKMSKey.Arn LambdaLogGroupKMSKey: Type: AWS::KMS::Key @@ -62,4 +62,25 @@ Resources: Properties: Description: "KMS key for encrypting CloudWatch Logs" EnableKeyRotation: true - \ No newline at end of file + KeyPolicy: + Version: "2012-10-17" + Id: "key-default" + Statement: + - Sid: "Allow administration of the key" + Effect: "Allow" + Principal: + AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" + Action: + - "kms:*" + Resource: "*" + - Sid: "Allow use of the key" + Effect: "Allow" + Principal: + Service: "logs.ap-northeast-1.amazonaws.com" + Action: + - "kms:Encrypt" + - "kms:Decrypt" + - "kms:ReEncrypt*" + - "kms:GenerateDataKey*" + - "kms:DescribeKey" + Resource: "*" \ No newline at end of file