diff --git a/README.md b/README.md index 08a314c..292c9eb 100644 --- a/README.md +++ b/README.md @@ -42,4 +42,4 @@ After running `terraform apply`, the following outputs will be provided: ## This repo on the infrastructure -![Architecture Diagram](aws-infra-phase-3.png) +![Architecture Diagram](aws-infra-phase-4.png) diff --git a/app/cpf-policy-authorizer/src/handlers/hello-from-lambda.mjs b/app/cpf-policy-authorizer/src/handlers/hello-from-lambda.mjs index 00e8a6a..589f22c 100644 --- a/app/cpf-policy-authorizer/src/handlers/hello-from-lambda.mjs +++ b/app/cpf-policy-authorizer/src/handlers/hello-from-lambda.mjs @@ -21,7 +21,7 @@ export const handler = async (event, context, callback) => { } let token = generateAccessToken(jwtPayload); - let policy = generateAuthPolicy(cpf, event.routeArn, token); + let policy = generateAuthPolicy(cpf, event.methodArn, token); console.log(token); return policy; @@ -32,6 +32,6 @@ export const handler = async (event, context, callback) => { let token = generateAccessToken({ role: ["customer"] }); - return generateAuthPolicy(uuidv4(), event.routeArn, token); + return generateAuthPolicy(uuidv4(), event.methodArn, token); } }; diff --git a/aws-infra-phase-4.png b/aws-infra-phase-4.png new file mode 100644 index 0000000..ff535da Binary files /dev/null and b/aws-infra-phase-4.png differ diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..23bfc5b --- /dev/null +++ b/data.tf @@ -0,0 +1,78 @@ +# data "aws_vpc" "bmb_vpc" { +# filter { +# name = "tag:Name" +# values = [var.vpc_name] +# } + +# filter { +# name = "tag:Terraform" +# values = ["true"] +# } +# } + +# data "aws_subnets" "private_subnets" { +# filter { +# name = "vpc-id" +# values = [data.aws_vpc.bmb_vpc.id] +# } + +# filter { +# name = "tag:Terraform" +# values = ["true"] +# } + +# filter { +# name = "tag:kubernetes.io/role/internal-elb" +# values = ["1"] +# } +# } + +data "aws_lb" "eks_payment_elb" { + tags = { + "kubernetes.io/service-name" = "fiap-payment/api-internal" + } +} + +data "aws_lb" "eks_kitchen_elb" { + tags = { + "kubernetes.io/service-name" = "fiap-production/api-internal" + } +} + +data "aws_lb" "load_balancers" { + for_each = var.services + tags = { + "kubernetes.io/service-name" = "${each.value.namespace}/api-internal" + } +} + +# data "aws_lb" "service_elbs" { +# for_each = var.services +# tags = { +# "kubernetes.io/service-name" = "${each.value}/api-internal" +# } +# } + + +# data "aws_lb_listener" "payment_nlb_listener" { +# load_balancer_arn = data.aws_lb.eks_payment_elb.arn +# port = 80 +# } + + +# data "aws_lb_listener" "kitchen_nlb_listener" { +# load_balancer_arn = data.aws_lb.eks_kitchen_elb.arn +# port = 80 +# } + + +data "aws_cognito_user_pools" "bmb_selected_user_pool" { + name = var.user_pool_name +} + +data "archive_file" "lambda_zip" { + type = "zip" + source_dir = "${path.module}/app/cpf-policy-authorizer" + output_file_mode = "0666" + output_path = "${path.module}/files/lambda.zip" +} diff --git a/main.tf b/main.tf index 6fb1138..6775085 100644 --- a/main.tf +++ b/main.tf @@ -1,55 +1,3 @@ -data "aws_vpc" "bmb_vpc" { - filter { - name = "tag:Name" - values = [var.vpc_name] - } - - filter { - name = "tag:Terraform" - values = ["true"] - } -} - -data "aws_subnets" "private_subnets" { - filter { - name = "vpc-id" - values = [data.aws_vpc.bmb_vpc.id] - } - - filter { - name = "tag:Terraform" - values = ["true"] - } - - filter { - name = "tag:kubernetes.io/role/internal-elb" - values = ["1"] - } -} - -data "aws_lb" "eks_internal_elb" { - tags = { - "kubernetes.io/service-name" = "default/${var.nlb_name}" - } -} - -data "aws_lb_listener" "nlb_listener" { - load_balancer_arn = data.aws_lb.eks_internal_elb.arn - port = 80 -} - - -data "aws_cognito_user_pools" "bmb_selected_user_pool" { - name = var.user_pool_name -} - -data "archive_file" "lambda_zip" { - type = "zip" - source_dir = "${path.module}/app/cpf-policy-authorizer" - output_file_mode = "0666" - output_path = "${path.module}/files/lambda.zip" -} - module "authenticator_lambda_function" { source = "terraform-aws-modules/lambda/aws" version = "~> 7.7.1" @@ -94,18 +42,49 @@ module "authenticator_lambda_function" { } } -module "authenticator_api" { - source = "./modules/authenticator_agw" +# module "authenticator_api" { +# source = "./modules/authenticator_agw" + +# api_name = var.api_name +# vpc_id = data.aws_vpc.bmb_vpc.id +# payment_nlb_listener_arn = data.aws_lb.eks_kitchen_elb.arn +# kitchen_nlb_listener_arn = data.aws_lb_listener.kitchen_nlb_listener.arn +# kitchen_elb_name = data.aws_lb.eks_kitchen_elb.dns_name +# vpc_link_subnets = data.aws_subnets.private_subnets.ids +# # vpc_id = "dataaws_vpc.bmb_vpc.id" +# # nlb_listener_arn = "dataaws_lb_listener.nlb_listener.arn" +# # vpc_link_subnets = ["dataaws_subnets.private_subnets.ids"] +# profile = var.profile +# region = var.region +# authenticator_lambda_arn = module.authenticator_lambda_function.lambda_function_invoke_arn +# authenticator_lambda_name = module.authenticator_lambda_function.lambda_function_name +# } + +locals { + mock_elb_dns = { + for key, value in var.services : key => { + dns_name : "example.com" + auth = true + } + } + + elb_map = { + for key, value in var.services : key => { + dns_name = data.aws_lb.load_balancers[key].dns_name + auth = value.auth + elb_arn = data.aws_lb.load_balancers[key].arn + } + } +} + - api_name = var.api_name - vpc_id = data.aws_vpc.bmb_vpc.id - nlb_listener_arn = data.aws_lb_listener.nlb_listener.arn - vpc_link_subnets = data.aws_subnets.private_subnets.ids - # vpc_id = "dataaws_vpc.bmb_vpc.id" - # nlb_listener_arn = "dataaws_lb_listener.nlb_listener.arn" - # vpc_link_subnets = ["dataaws_subnets.private_subnets.ids"] +module "rest_api" { + source = "./modules/rest_api" + api_name = var.api_name + vpc_id = ".aws_vpc.bmb_vpc.id" profile = var.profile region = var.region + elb_map = local.elb_map authenticator_lambda_arn = module.authenticator_lambda_function.lambda_function_invoke_arn authenticator_lambda_name = module.authenticator_lambda_function.lambda_function_name } diff --git a/modules/authenticator_agw/main.tf b/modules/authenticator_agw/main.tf index be36e5b..99848f2 100644 --- a/modules/authenticator_agw/main.tf +++ b/modules/authenticator_agw/main.tf @@ -184,4 +184,4 @@ resource "aws_apigatewayv2_authorizer" "external" { # identity_sources = ["$context.authorizer.cacheKey"] enable_simple_responses = false authorizer_uri = var.authenticator_lambda_arn -} +} \ No newline at end of file diff --git a/modules/rest_api/main.tf b/modules/rest_api/main.tf new file mode 100644 index 0000000..3a693fb --- /dev/null +++ b/modules/rest_api/main.tf @@ -0,0 +1,118 @@ +resource "aws_api_gateway_rest_api" "api_gtw" { + name = var.api_name + description = "BMB REST API Gateway" + endpoint_configuration { + types = ["REGIONAL"] + } +} + +resource "aws_api_gateway_resource" "resource" { + for_each = var.elb_map + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + parent_id = aws_api_gateway_rest_api.api_gtw.root_resource_id + path_part = each.key +} + +resource "aws_api_gateway_resource" "proxy" { + for_each = var.elb_map + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + parent_id = aws_api_gateway_resource.resource[each.key].id + path_part = "{proxy+}" +} + +//https://gist.github.com/mendhak/8303d60cbfe8c9bf1905def3ccdb2176 +resource "aws_api_gateway_method" "proxy_method" { + for_each = var.elb_map + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + resource_id = aws_api_gateway_resource.proxy[each.key].id + http_method = "ANY" + + authorization = each.value.auth ? "CUSTOM" : "NONE" + + authorizer_id = each.value.auth ? aws_api_gateway_authorizer.cpf_auth.id : null + request_parameters = { + "method.request.path.proxy" = true + } +} + +resource "aws_api_gateway_integration" "integrations" { + for_each = var.elb_map + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + resource_id = aws_api_gateway_resource.proxy[each.key].id + http_method = aws_api_gateway_method.proxy_method[each.key].http_method + type = "HTTP_PROXY" + uri = "http://${each.value.dns_name}/{proxy}" + integration_http_method = "ANY" + connection_type = "VPC_LINK" + connection_id = aws_api_gateway_vpc_link.vpc_link[each.key].id + + timeout_milliseconds = 29000 + request_parameters = { + "integration.request.path.proxy" = "method.request.path.proxy" + "integration.request.header.accessToken" = "context.authorizer.accessToken" + } + +} + +resource "aws_api_gateway_authorizer" "cpf_auth" { + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + name = "cpf_authorizer" + type = "REQUEST" + authorizer_uri = var.authenticator_lambda_arn + identity_source = "method.request.header.cpf" + authorizer_result_ttl_in_seconds = 10 +} + +resource "aws_api_gateway_vpc_link" "vpc_link" { + for_each = var.elb_map + name = "${each.key}-vpc_link" + target_arns = [each.value.elb_arn] +} + +resource "aws_api_gateway_deployment" "dev" { + depends_on = [aws_api_gateway_integration.integrations] + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + stage_name = "dev" + description = sha1(jsonencode(aws_api_gateway_rest_api.api_gtw.body)) + lifecycle { + create_before_destroy = true + } + triggers = { + redeployment = sha1(jsonencode(aws_api_gateway_rest_api.api_gtw.body)) + } +} + +resource "aws_api_gateway_stage" "dev" { + count = 0 + rest_api_id = aws_api_gateway_rest_api.api_gtw.id + stage_name = aws_api_gateway_deployment.dev.stage_name + deployment_id = aws_api_gateway_deployment.dev.id + + access_log_settings { + destination_arn = aws_cloudwatch_log_group.api_gw_logs.arn + format = jsonencode({ + requestId = "$context.requestId" + 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" + }) + } +} + +resource "aws_cloudwatch_log_group" "api_gw_logs" { + name = "/aws/api-gateway/${var.api_name}" + retention_in_days = 1 +} + +resource "aws_lambda_permission" "lambda_agw_invoke_permission" { + action = "lambda:InvokeFunction" + function_name = var.authenticator_lambda_name + principal = "apigateway.amazonaws.com" + source_arn = "${aws_api_gateway_rest_api.api_gtw.execution_arn}/*/*" +} \ No newline at end of file diff --git a/modules/rest_api/output.tf b/modules/rest_api/output.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/rest_api/providers.tf b/modules/rest_api/providers.tf new file mode 100644 index 0000000..69638df --- /dev/null +++ b/modules/rest_api/providers.tf @@ -0,0 +1,5 @@ +provider "aws" { + profile = var.profile + region = var.region + alias = "us-east-1" +} diff --git a/modules/rest_api/variables.tf b/modules/rest_api/variables.tf new file mode 100644 index 0000000..2a546d2 --- /dev/null +++ b/modules/rest_api/variables.tf @@ -0,0 +1,71 @@ +variable "vpc_id" { + type = string +} + +variable "authenticator_lambda_arn" { + type = string +} + +variable "authenticator_lambda_name" { + type = string +} + +variable "api_name" { + description = "API Name" + type = string + default = "authenticator" +} + +variable "vpc_name" { + description = "VPC Name" + type = string + default = "eks-fiap-vpc" +} + +variable "profile" { + description = "AWS profile name" + type = string + default = "default" +} + +variable "region" { + description = "AWS region" + type = string + default = "us-east-1" +} + +variable "user_pool_name" { + type = string + description = "Cognito user pool name" + default = "bmb_users_pool" +} + +variable "elb_map" { + type = map(object({ + dns_name = string + auth = bool + elb_arn = string + })) + default = { + payment = { + dns_name = "local.domain.com" + auth = true + elb_arn = "arn:aws:elasticloadbalancing:us-east-1::loadbalancer/app/eks-payment-elb/1234567890123456" + } + general = { + dns_name = "local.domain.com" + auth = true + elb_arn = "arn:aws:elasticloadbalancing:us-east-1::loadbalancer/app/eks-orders-elb/1234567890123456" + } + kitchen = { + dns_name = "local.domain.com" + auth = true + elb_arn = "arn:aws:elasticloadbalancing:us-east-1::loadbalancer/app/eks-kitchen-elb/1234567890123456" + } + log = { + dns_name = "local.domain.com" + auth = false + elb_arn = "arn:aws:elasticloadbalancing:us-east-1::loadbalancer/app/eks-log-elb/1234567890123456" + } + } +} diff --git a/output.tf b/output.tf index f36c54c..898902b 100644 --- a/output.tf +++ b/output.tf @@ -1,38 +1,51 @@ -################################################################################ -# API -################################################################################ -output "api_endpoint" { - description = "API address" - value = module.authenticator_api.endpoint -} +# ################################################################################ +# # API +# ################################################################################ +# output "api_endpoint" { +# description = "API address" +# value = module.authenticator_api.endpoint +# } -output "api" { - description = "API address" - value = module.authenticator_api -} +# output "api" { +# description = "API address" +# value = module.authenticator_api +# } + +# ################################################################################ +# # VPC +# ################################################################################ +# # output "vpc" { +# # value = data.aws_vpc.bmb_vpc.id +# # } -################################################################################ -# VPC -################################################################################ -# output "vpc" { -# value = data.aws_vpc.bmb_vpc.id +# # output "subnets" { +# # value = data.aws_subnets.private_subnets.ids +# # } + + +# ################################################################################ +# # LB +# ################################################################################ +# # output "internal_elb" { +# # value = data.aws_lb_listener.nlb_listener.arn +# # } + +# output "payment_elb" { +# value = data.aws_lb.eks_payment_elb # } -# output "subnets" { -# value = data.aws_subnets.private_subnets.ids +# output "kitchen_elb" { +# value = data.aws_lb.eks_kitchen_elb # } -################################################################################ -# LB -################################################################################ -# output "internal_elb" { -# value = data.aws_lb_listener.nlb_listener.arn +# output "path" { +# value = "${path.cwd}/${data.archive_file.lambda_zip.id}" +# } +# output "file" { +# value = data.archive_file.lambda_zip # } -output "path" { - value = "${path.cwd}/${data.archive_file.lambda_zip.id}" +output "load_balancer_map" { + value = local.elb_map } -output "file" { - value = data.archive_file.lambda_zip -} \ No newline at end of file diff --git a/variables.tf b/variables.tf index cd3a572..629047d 100644 --- a/variables.tf +++ b/variables.tf @@ -7,7 +7,7 @@ variable "api_name" { variable "vpc_name" { description = "VPC Name" type = string - default = "eks-fiap-vpc" + default = "postech-fiap-vpc" } variable "profile" { @@ -22,15 +22,10 @@ variable "region" { default = "us-east-1" } -variable "nlb_name" { - type = string - default = "bmb-apgw-eks" -} - variable "user_pool_name" { type = string description = "Cognito user pool name" - default = "bmb-users-pool-local" + default = "bmb-users-pool-dev" } variable "jwt_secret" { @@ -41,10 +36,35 @@ variable "jwt_secret" { variable "jwt_audience" { type = string - default = "https://localhost:7001" + default = "https://localhost:7000" } variable "jwt_issuer" { type = string - default = "https://localhost:7001" + default = "https://localhost:7000" +} + +variable "services" { + type = map(object({ + namespace = string + auth = bool + })) + default = { + "payment" = { + namespace = "fiap-payment" + auth = true + } + "production" = { + namespace = "fiap-production" + auth = true + } + "orders" = { + namespace = "fiap-orders" + auth = true + } + # "log" = { + # namespace = "fiap-log" + # auth = false + # } + } }