terraform.aws-baseline-infra/modules/ApplicationIntegration/apigw-lambda/main.tf

257 lines
8.1 KiB
Terraform
Raw Normal View History

2024-03-04 11:15:34 +08:00
resource "aws_api_gateway_rest_api" "api" {
name = var.name
description = var.description
dynamic "endpoint_configuration" {
for_each = [1]
content {
types = var.apigw-type == "private" ? ["PRIVATE"] : ["REGIONAL"]
vpc_endpoint_ids = var.apigw-type == "private" ? [aws_vpc_endpoint.apigw-vpcep[0].id] : null
}
2024-03-04 11:15:34 +08:00
}
}
# private endpoint for inbound access
# to connect to the private api gateway, provide the header x-apigw-api-id
# curl -IX GET -H 'x-apigw-api-id:<YOUR_API_ID>' https://<YOUR_VPCE_HOSTNAME>/<STAGE>
2024-03-04 11:15:34 +08:00
data "aws_region" "current" {}
resource "aws_vpc_endpoint" "apigw-vpcep" {
count = var.apigw-type == "private" ? 1 : 0
2024-03-04 11:15:34 +08:00
private_dns_enabled = false
security_group_ids = [var.apigw-security-group-id]
service_name = "com.amazonaws.${data.aws_region.current.name}.execute-api"
subnet_ids = var.apigw-subnet-ids
vpc_endpoint_type = "Interface"
vpc_id = var.apigw-vpc-id
}
# vpc link for outbound access
resource "aws_api_gateway_vpc_link" "api-vpc-link" {
count = var.create-vpc-link ? 1 : 0
name = "${var.name}-vpclink"
description = "VPC link for apigateway ${var.name}"
target_arns = var.apigw-vpc-link-target-arns
}
# Apigw resources, integration, method, responses
2024-03-04 11:15:34 +08:00
resource "aws_api_gateway_resource" "api-res" {
depends_on = [aws_api_gateway_rest_api_policy.api-policy]
for_each = var.resources
path_part = each.key
2024-03-04 11:15:34 +08:00
parent_id = aws_api_gateway_rest_api.api.root_resource_id
rest_api_id = aws_api_gateway_rest_api.api.id
}
resource "aws_api_gateway_method" "api-method" {
depends_on = [aws_api_gateway_resource.api-res]
for_each = var.resources
2024-03-04 11:15:34 +08:00
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.api-res[each.key].id
http_method = each.value["method"]
authorization = each.value["authorization"]
2024-03-04 11:15:34 +08:00
}
# non-proxy integration
2024-03-04 11:15:34 +08:00
resource "aws_api_gateway_integration" "api-integration" {
depends_on = [aws_api_gateway_method.api-method]
for_each = var.resources
2024-03-04 11:15:34 +08:00
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.api-res[each.key].id
http_method = aws_api_gateway_method.api-method[each.key].http_method
integration_http_method = each.value["method"]
type = each.value["integration-type"]
content_handling = each.value["content-handling"]
2024-03-04 11:15:34 +08:00
uri = aws_lambda_function.function.invoke_arn
}
resource "aws_api_gateway_method_response" "response_200" {
depends_on = [aws_api_gateway_method.api-method]
for_each = var.resources
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.api-res[each.key].id
http_method = aws_api_gateway_method.api-method[each.key].http_method
status_code = "200"
}
resource "aws_api_gateway_integration_response" "integration-response" {
depends_on = [aws_api_gateway_integration.api-integration]
for_each = var.resources
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.api-res[each.key].id
http_method = aws_api_gateway_method.api-method[each.key].http_method
status_code = aws_api_gateway_method_response.response_200[each.key].status_code
}
2024-03-04 11:15:34 +08:00
# apigw deployment and stage
resource "aws_api_gateway_deployment" "apigw-deployment" {
depends_on = [aws_api_gateway_integration.api-integration]
2024-03-04 11:15:34 +08:00
rest_api_id = aws_api_gateway_rest_api.api.id
triggers = {
redeployment = sha1(jsonencode(aws_api_gateway_rest_api.api.body))
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_api_gateway_stage" "apigw-stage" {
2024-03-04 14:12:59 +08:00
for_each = var.stages
depends_on = [aws_api_gateway_rest_api_policy.api-policy, aws_cloudwatch_log_group.this]
2024-03-04 11:15:34 +08:00
deployment_id = aws_api_gateway_deployment.apigw-deployment.id
rest_api_id = aws_api_gateway_rest_api.api.id
2024-03-04 14:12:59 +08:00
stage_name = each.key
description = each.value["description"]
variables = each.value["variables"]
access_log_settings {
destination_arn = aws_cloudwatch_log_group.this[each.key].arn
# https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html
format = jsonencode({
"requestId" : "$context.requestId",
"extendedRequestId" : "$context.extendedRequestId",
"ip" : "$context.identity.sourceIp",
"caller" : "$context.identity.caller",
"user" : "$context.identity.user",
"requestTime" : "$context.requestTime",
"httpMethod" : "$context.httpMethod",
"resourcePath" : "$context.resourcePath",
"status" : "$context.status",
"protocol" : "$context.protocol",
"responseLength" : "$context.responseLength"
}
)
}
2024-03-04 11:15:34 +08:00
}
resource "aws_api_gateway_method_settings" "apigw-method-settings" {
depends_on = [aws_api_gateway_rest_api_policy.api-policy]
2024-03-04 14:12:59 +08:00
for_each = aws_api_gateway_stage.apigw-stage
2024-03-04 11:15:34 +08:00
rest_api_id = aws_api_gateway_rest_api.api.id
2024-03-04 14:12:59 +08:00
stage_name = each.value.stage_name
2024-03-04 11:15:34 +08:00
method_path = "*/*"
settings {
metrics_enabled = true
logging_level = "INFO"
}
}
# Cloudwatch log group path: API-Gateway-Execution-Logs_{rest-api-id}/{stage_name}
resource "aws_cloudwatch_log_group" "this" {
2024-03-04 14:12:59 +08:00
for_each = var.stages
name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.api.id}/${each.key}"
2024-03-04 11:15:34 +08:00
retention_in_days = var.cloudwatchlog-retention
kms_key_id = var.cwl-cmk-key-id
2024-03-04 11:15:34 +08:00
}
# lambda function
resource "aws_cloudwatch_log_group" "lambda-logs" {
name = "/aws/lambda/${var.name}-lambda-function"
retention_in_days = var.cloudwatchlog-retention
kms_key_id = var.cwl-cmk-key-id
}
2024-03-04 11:15:34 +08:00
resource "aws_lambda_function" "function" {
filename = var.lambda-archive-file
function_name = "${var.name}-lambda-function"
handler = "main.lambda_handler"
role = aws_iam_role.lambda-exec-role.arn
runtime = var.lambda-runtime-version
# source_code_hash = local.source_code_hash
}
resource "aws_lambda_permission" "allow_api_gateway" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.function.function_name
principal = "apigateway.amazonaws.com"
}
# Lambda execution role
data "aws_caller_identity" "this" {}
resource "random_id" "this" {
byte_length = 4
}
resource "aws_iam_role" "lambda-exec-role" {
name = "lambda-apigw-${var.name}-${random_id.this.dec}"
assume_role_policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "lambda.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
}
)
}
resource "aws_iam_role_policy" "this" {
policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Sid" : "AllowCreationOfCloudwatchLogGroup",
"Effect" : "Allow",
"Action" : "logs:CreateLogGroup",
"Resource" : "arn:aws:logs:ap-east-1:${data.aws_caller_identity.this.account_id}:*"
},
{
"Sid" : "AllowWritingToCloudwatchLogGroup",
"Effect" : "Allow",
"Action" : [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource" : [
"arn:aws:logs:ap-east-1:${data.aws_caller_identity.this.account_id}:log-group:/aws/lambda/*"
]
}
]
}
)
role = aws_iam_role.lambda-exec-role.id
name = "LambdaExecutionPolicy"
}
# apigateway policy
data "aws_iam_policy_document" "api-policy" {
statement {
effect = "Allow"
principals {
type = "AWS"
identifiers = ["*"]
}
actions = ["execute-api:Invoke"]
resources = [aws_api_gateway_rest_api.api.execution_arn]
condition {
test = "IpAddress"
variable = "aws:SourceIp"
values = [data.aws_vpc.vpc.cidr_block]
}
}
}
data "aws_vpc" "vpc" {
id = var.apigw-vpc-id
}
resource "aws_api_gateway_rest_api_policy" "api-policy" {
rest_api_id = aws_api_gateway_rest_api.api.id
policy = data.aws_iam_policy_document.api-policy.json
}