diff --git a/terraform/env/dev/main.tf b/terraform/env/dev/main.tf index 6c1f89c..49a4751 100644 --- a/terraform/env/dev/main.tf +++ b/terraform/env/dev/main.tf @@ -59,55 +59,3 @@ module "sqs" { project_name = var.project_name environment = var.environment } - -# Lambda -module "lambda" { - source = "../../modules/05.lambda" - project_name = var.project_name - environment = var.environment - aws_region = var.aws_region - ecr_api_repository_name = module.ecr.api_repository_name - ecr_api_repository_url = module.ecr.api_repository_url - ecr_builder_repository_name = module.ecr.builder_repository_name - ecr_builder_repository_url = module.ecr.builder_repository_url - ecr_builder_repository_arn = module.ecr.builder_repository_arn - ecr_notification_repository_name = module.ecr.notification_repository_name - ecr_notification_repository_url = module.ecr.notification_repository_url - ecr_notification_repository_arn = module.ecr.notification_repository_arn - image_tag = var.lambda_image_tag - lambda_timeout = var.lambda_timeout - lambda_memory_size = var.lambda_memory_size - log_retention_days = var.log_retention_days - url_service_tech = var.url_service_tech - prefix_api_version = var.prefix_api_version - service_url_registration_api_solana = var.service_url_registration_api_solana - service_api_key_registration_api_solana = var.service_api_key_registration_api_solana - tech_floripa_certificate_validate_url = var.tech_floripa_certificate_validate_url - tech_floripa_logo_url = var.tech_floripa_logo_url - builder_queue_url = module.sqs.builder_queue_url - builder_queue_arn = module.sqs.builder_queue_arn - notification_queue_arn = module.sqs.notification_queue_arn - notification_queue_url = module.sqs.notification_queue_url - dynamodb_table_arns = [ - module.certificates_table.table_arn, - module.orders_table.table_arn, - module.participants_table.table_arn, - module.products_table.table_arn - ] - ecr_repository_arn = module.ecr.api_repository_arn - s3_bucket_arn = module.s3.bucket_arn - s3_bucket_name = module.s3.bucket_name - api_gateway_download_url = module.api_gateway.api_endpoint_download_certificate -} - -# API Gateway -module "api_gateway" { - source = "../../modules/06.api-gateway" - project_name = var.project_name - environment = var.environment - lambda_function_name = module.lambda.function_name - lambda_invoke_arn = module.lambda.invoke_arn - throttle_rate_limit = var.api_throttle_rate_limit - throttle_burst_limit = var.api_throttle_burst_limit - api_key_value = var.api_key_value -} diff --git a/terraform/env/dev/outputs.tf b/terraform/env/dev/outputs.tf index ec39d65..986c04f 100644 --- a/terraform/env/dev/outputs.tf +++ b/terraform/env/dev/outputs.tf @@ -79,74 +79,3 @@ output "sqs_dlq_url" { description = "URL da Dead Letter Queue (builder)" value = module.sqs.builder_dlq_url } - -# Informações do Lambda -output "lambda_function_name" { - description = "Nome da função Lambda" - value = module.lambda.function_name -} - -output "lambda_function_arn" { - description = "ARN da função Lambda" - value = module.lambda.function_arn -} - -# Informações da Lambda de Notificação -output "lambda_notification_function_name" { - description = "Nome da função Lambda de Notificação" - value = module.lambda.notification_function_name -} - -output "lambda_notification_function_arn" { - description = "ARN da função Lambda de Notificação" - value = module.lambda.notification_function_arn -} - -# Informações do API Gateway -output "api_gateway_url" { - description = "URL base do API Gateway" - value = module.api_gateway.api_url -} - -output "api_gateway_endpoint_create_certificate" { - description = "URL completa do endpoint para criar certificado" - value = module.api_gateway.api_endpoint_create_certificate -} - -output "api_gateway_endpoint_download_certificate" { - description = "URL base do endpoint para download de certificados" - value = module.api_gateway.api_endpoint_download_certificate -} - -output "api_gateway_id" { - description = "ID do API Gateway" - value = module.api_gateway.api_id -} - -# Resumo completo da infraestrutura -output "infrastructure_summary" { - description = "Resumo completo da infraestrutura criada" - value = { - api_gateway = { - id = module.api_gateway.api_id - url = module.api_gateway.api_url - endpoint_create_cert = module.api_gateway.api_endpoint_create_certificate - } - lambda = { - function_name = module.lambda.function_name - function_arn = module.lambda.function_arn - notification_function_name = module.lambda.notification_function_name - notification_function_arn = module.lambda.notification_function_arn - } - ecr = { - repository_url = module.ecr.api_repository_url - api_repository_name = module.ecr.api_repository_name - } - sqs = { - queue_url = module.sqs.queue_url - dlq_url = module.sqs.builder_dlq_url - } - environment = var.environment - project = var.project_name - } -} diff --git a/terraform/env/dev/variables.tf b/terraform/env/dev/variables.tf index 474a277..da51a4f 100644 --- a/terraform/env/dev/variables.tf +++ b/terraform/env/dev/variables.tf @@ -52,87 +52,3 @@ variable "project_name" { # Configuração do DynamoDB - Modo de Baixo Custo # Todas as tabelas usam PAY_PER_REQUEST por padrão (paga apenas pelo que usar) - -# Variáveis para Lambda Function -variable "lambda_image_tag" { - description = "Tag da imagem Docker para o Lambda" - type = string - default = "latest" -} - -variable "lambda_timeout" { - description = "Timeout da função Lambda em segundos" - type = number - default = 60 -} - -variable "lambda_memory_size" { - description = "Memória alocada para a função Lambda em MB" - type = number - default = 512 -} - -variable "log_retention_days" { - description = "Dias de retenção dos logs do CloudWatch" - type = number - default = 3 -} - -variable "url_service_tech" { - description = "URL do serviço Tech Floripa" - type = string - default = "https://tech.floripa.br/wp-json/custom/v1" -} - -variable "prefix_api_version" { - description = "Prefixo da versão da API" - type = string - default = "/api/v1" -} - -# Variáveis para API Gateway -variable "api_throttle_rate_limit" { - description = "Limite de taxa por segundo para throttling do API Gateway" - type = number - default = 100 -} - -variable "api_throttle_burst_limit" { - description = "Limite de burst para throttling do API Gateway" - type = number - default = 200 -} - -variable "api_key_value" { - description = "Valor da API Key para autenticação do API Gateway (deve ser fornecido via terraform.tfvars)" - type = string - sensitive = true - - validation { - condition = can(regex("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", var.api_key_value)) - error_message = "A API Key deve estar no formato UUID válido (ex: 8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29)." - } -} - -# Variáveis para integração com API Solana -variable "service_url_registration_api_solana" { - description = "URL do serviço de registro da API Solana" - type = string -} - -variable "service_api_key_registration_api_solana" { - description = "API Key do serviço de registro da API Solana" - type = string - sensitive = true -} - -variable "tech_floripa_certificate_validate_url" { - description = "URL para validação de certificados do Tech Floripa" - type = string -} - -variable "tech_floripa_logo_url" { - description = "URL do logo do Tech Floripa" - type = string - default = "https://tech.floripa.br/wp-content/uploads/2025/03/Tech-Floripa-Qr.png" -} diff --git a/terraform/modules/05.lambda/main.tf b/terraform/modules/05.lambda/main.tf deleted file mode 100644 index b8e8f4b..0000000 --- a/terraform/modules/05.lambda/main.tf +++ /dev/null @@ -1,484 +0,0 @@ -# Módulo Lambda para Certified Builder API -# Responsável por criar a função Lambda que executa a aplicação containerizada - -# IAM Role para a função Lambda para acessar o ECR, SQS e S3 -resource "aws_iam_role" "lambda_execution_role" { - name = "${var.project_name}-lambda-role-${var.environment}" - - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = "lambda.amazonaws.com" - } - } - ] - }) - - tags = { - Name = "${var.project_name}-lambda-role-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Policy básica para execução do Lambda -resource "aws_iam_role_policy_attachment" "lambda_basic_execution" { - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - role = aws_iam_role.lambda_execution_role.name -} - -# Policy personalizada para acessar DynamoDB, SQS e ECR -resource "aws_iam_role_policy" "lambda_custom_policy" { - name = "${var.project_name}-lambda-policy-${var.environment}" - role = aws_iam_role.lambda_execution_role.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "dynamodb:GetItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem", - "dynamodb:Query", - "dynamodb:Scan" - ] - Resource = var.dynamodb_table_arns - }, - { - Effect = "Allow" - Action = [ - "sqs:SendMessage", - "sqs:ReceiveMessage", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes" - ] - Resource = [ - var.builder_queue_arn, - var.notification_queue_arn - ] - }, - { - Effect = "Allow" - Action = [ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage", - ] - Resource = [ - var.ecr_repository_arn, - "${var.ecr_repository_arn}:*" - ] - }, - { - Effect = "Allow" - Action = [ - "s3:GetObject", - "s3:GetObjectVersion", - "s3:PutObject", - "s3:DeleteObject", - "s3:ListBucket", - ] - Resource = [ - var.s3_bucket_arn, - "${var.s3_bucket_arn}/*" - ] - } - ] - }) -} - -resource "aws_iam_role" "lambda_builder_execution_role" { - name = "${var.project_name}-lambda-builder-role-${var.environment}" - - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = "lambda.amazonaws.com" - } - } - ] - }) - - tags = { - Name = "${var.project_name}-lambda-ecr-builder-execution-role-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Policy básica para execução do Lambda Builder -resource "aws_iam_role_policy_attachment" "lambda_builder_basic_execution" { - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - role = aws_iam_role.lambda_builder_execution_role.name -} - -# Policy para acessar ECR -resource "aws_iam_role_policy_attachment" "lambda_builder_execution" { - policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" - role = aws_iam_role.lambda_builder_execution_role.name -} - -resource "aws_iam_role_policy" "lambda_builder_custom_policy" { - name = "${var.project_name}-lambda-builder-policy-${var.environment}" - role = aws_iam_role.lambda_builder_execution_role.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" - ] - Resource = [ - var.ecr_builder_repository_arn, - "${var.ecr_builder_repository_arn}:*" - ] - }, - { - Effect = "Allow" - Action = [ - "s3:GetObject", - "s3:GetObjectVersion", - "s3:PutObject", - "s3:DeleteObject", - "s3:ListBucket", - ] - Resource = [ - var.s3_bucket_arn, - "${var.s3_bucket_arn}/*" - ] - }, - { - Effect = "Allow" - Action = [ - "sqs:SendMessage", - "sqs:ReceiveMessage", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" - ] - Resource = [ - var.builder_queue_arn, - var.notification_queue_arn - ] - }, - ] - }) -} - -# Data source para detectar mudanças na imagem ECR -data "aws_ecr_image" "api_lambda_image" { - repository_name = split("/", var.ecr_api_repository_url)[1] # Extrai o nome do repositório da URL - image_tag = var.image_tag -} - -# Função Lambda -resource "aws_lambda_function" "api_function" { - function_name = "${var.project_name}-api-${var.environment}" - role = aws_iam_role.lambda_execution_role.arn - - # Configuração da imagem Docker usando digest para forçar atualização - package_type = "Image" - image_uri = "${var.ecr_api_repository_url}@${data.aws_ecr_image.api_lambda_image.image_digest}" - - # Configurações de performance e timeout - timeout = var.lambda_timeout - memory_size = var.lambda_memory_size - - # Variáveis de ambiente baseadas no env.example - environment { - variables = { - REGION = var.aws_region - BUILDER_QUEUE_URL = var.builder_queue_url - S3_BUCKET_NAME = var.s3_bucket_name - ENVIRONMENT = var.environment - PROJECT_NAME = var.project_name - URL_SERVICE_TECH = var.url_service_tech - PREFIX_API_VERSION = var.prefix_api_version - } - } - - # Configuração para atualizar quando a imagem ECR mudar - lifecycle { - create_before_destroy = true - # Remove ignore_changes para permitir detecção automática de mudanças - } - - tags = { - Name = "${var.project_name}-api-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# CloudWatch Log Group para a função Lambda -resource "aws_cloudwatch_log_group" "lambda_logs" { - name = "/aws/lambda/${aws_lambda_function.api_function.function_name}" - retention_in_days = var.log_retention_days - - tags = { - Name = "${var.project_name}-lambda-logs-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Data source para detectar mudanças na imagem ECR do builder -data "aws_ecr_image" "builder_lambda_image" { - repository_name = split("/", var.ecr_builder_repository_url)[1] # Extrai o nome do repositório da URL - image_tag = var.image_tag -} - -resource "aws_lambda_function" "builder_function" { - function_name = "${var.project_name}-builder-${var.environment}" - role = aws_iam_role.lambda_builder_execution_role.arn - package_type = "Image" - # Configuração da imagem Docker usando digest para forçar atualização - image_uri = "${var.ecr_builder_repository_url}@${data.aws_ecr_image.builder_lambda_image.image_digest}" - timeout = var.lambda_timeout - memory_size = var.lambda_memory_size - - environment { - variables = { - REGION = var.aws_region - QUEUE_URL = var.notification_queue_url - BUCKET_NAME = var.s3_bucket_name - SERVICE_URL_REGISTRATION_API_SOLANA = var.service_url_registration_api_solana - SERVICE_API_KEY_REGISTRATION_API_SOLANA = var.service_api_key_registration_api_solana - TECH_FLORIPA_CERTIFICATE_VALIDATE_URL = var.tech_floripa_certificate_validate_url - TECH_FLORIPA_LOGO_URL = var.tech_floripa_logo_url - } - } - - # Configuração para atualizar quando a imagem ECR mudar - lifecycle { - create_before_destroy = true - # Remove ignore_changes para permitir detecção automática de mudanças - } - - tags = { - Name = "${var.project_name}-builder-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -resource "aws_cloudwatch_log_group" "builder_logs" { - name = "/aws/lambda/${aws_lambda_function.builder_function.function_name}" - retention_in_days = var.log_retention_days - - tags = { - Name = "${var.project_name}-builder-logs-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Event Source Mapping - Conecta a fila SQS builder com a função Lambda builder -# Quando uma mensagem chegar na fila, a Lambda será executada automaticamente -resource "aws_lambda_event_source_mapping" "builder_sqs_trigger" { - event_source_arn = var.builder_queue_arn - function_name = aws_lambda_function.builder_function.arn - - # Configurações do processamento em lote - batch_size = 1 # Processa 1 mensagem por vez - maximum_batching_window_in_seconds = 5 # Aguarda até 5 segundos para formar um lote - scaling_config { - maximum_concurrency = 3 - } - # Configurações de retry e erro - function_response_types = ["ReportBatchItemFailures"] - - tags = { - Name = "${var.project_name}-builder-sqs-trigger-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# IAM Role para a função Lambda de notificação -resource "aws_iam_role" "lambda_notification_execution_role" { - name = "${var.project_name}-lambda-notification-role-${var.environment}" - - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = "lambda.amazonaws.com" - } - } - ] - }) - - tags = { - Name = "${var.project_name}-lambda-notification-role-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Policy básica para execução do Lambda de notificação -resource "aws_iam_role_policy_attachment" "lambda_notification_basic_execution" { - policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - role = aws_iam_role.lambda_notification_execution_role.name -} - -# Policy personalizada para a Lambda de notificação acessar DynamoDB, S3 e SQS -resource "aws_iam_role_policy" "lambda_notification_custom_policy" { - name = "${var.project_name}-lambda-notification-policy-${var.environment}" - role = aws_iam_role.lambda_notification_execution_role.id - - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "dynamodb:GetItem", - "dynamodb:PutItem", - "dynamodb:UpdateItem", - "dynamodb:DeleteItem", - "dynamodb:Query", - "dynamodb:Scan" - ] - Resource = var.dynamodb_table_arns - }, - { - Effect = "Allow" - Action = [ - "sqs:SendMessage", - "sqs:ReceiveMessage", - "sqs:DeleteMessage", - "sqs:GetQueueAttributes" - ] - Resource = [ - var.builder_queue_arn, - var.notification_queue_arn - ] - }, - { - Effect = "Allow" - Action = [ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:BatchGetImage" - ] - Resource = [ - var.ecr_notification_repository_arn, - "${var.ecr_notification_repository_arn}:*" - ] - }, - { - Effect = "Allow" - Action = [ - "s3:GetObject", - "s3:PutObject", - "s3:DeleteObject", - "s3:ListBucket" - ] - Resource = [ - var.s3_bucket_arn, - "${var.s3_bucket_arn}/*" - ] - } - ] - }) -} - -# Data source para detectar mudanças na imagem ECR de notificação -data "aws_ecr_image" "notification_lambda_image" { - repository_name = split("/", var.ecr_notification_repository_url)[1] # Extrai o nome do repositório da URL - image_tag = var.image_tag -} - -# Função Lambda para processamento de notificações -resource "aws_lambda_function" "notification_function" { - function_name = "${var.project_name}-notification-${var.environment}" - role = aws_iam_role.lambda_notification_execution_role.arn - package_type = "Image" - - # Configuração da imagem Docker usando digest para forçar atualização - image_uri = "${var.ecr_notification_repository_url}@${data.aws_ecr_image.notification_lambda_image.image_digest}" - - # Configurações de performance e timeout - timeout = var.lambda_timeout - memory_size = var.lambda_memory_size - - # Variáveis de ambiente para a Lambda de notificação - environment { - variables = { - REGION = var.aws_region - S3_BUCKET_NAME = var.s3_bucket_name - ENVIRONMENT = var.environment - PROJECT_NAME = var.project_name - URL_SERVICE_TECH = var.url_service_tech - API_GATEWAY_DOWNLOAD_URL = var.api_gateway_download_url - } - } - - # Configuração para atualizar quando a imagem ECR mudar - lifecycle { - create_before_destroy = true - } - - tags = { - Name = "${var.project_name}-notification-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# CloudWatch Log Group para a função Lambda de notificação -resource "aws_cloudwatch_log_group" "notification_logs" { - name = "/aws/lambda/${aws_lambda_function.notification_function.function_name}" - retention_in_days = var.log_retention_days - - tags = { - Name = "${var.project_name}-notification-logs-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Event Source Mapping - Conecta a fila SQS de notificação com a função Lambda de notificação -# Quando uma mensagem chegar na fila de notificação, a Lambda será executada automaticamente -resource "aws_lambda_event_source_mapping" "notification_sqs_trigger" { - event_source_arn = var.notification_queue_arn - function_name = aws_lambda_function.notification_function.arn - - # Configurações do processamento em lote - batch_size = 1 # Processa 1 mensagem por vez - maximum_batching_window_in_seconds = 5 # Aguarda até 5 segundos para formar um lote - scaling_config { - maximum_concurrency = 2 # Limite menor para notificações - } - - # Configurações de retry e erro - function_response_types = ["ReportBatchItemFailures"] - - tags = { - Name = "${var.project_name}-notification-sqs-trigger-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} diff --git a/terraform/modules/05.lambda/outputs.tf b/terraform/modules/05.lambda/outputs.tf deleted file mode 100644 index 52d26f5..0000000 --- a/terraform/modules/05.lambda/outputs.tf +++ /dev/null @@ -1,75 +0,0 @@ -# Outputs do módulo Lambda - -output "function_name" { - description = "Nome da função Lambda" - value = aws_lambda_function.api_function.function_name -} - -output "function_arn" { - description = "ARN da função Lambda" - value = aws_lambda_function.api_function.arn -} - -output "invoke_arn" { - description = "ARN para invocar a função Lambda" - value = aws_lambda_function.api_function.invoke_arn -} - -output "role_arn" { - description = "ARN da role IAM da função Lambda" - value = aws_iam_role.lambda_execution_role.arn -} - -# Outputs da função Lambda Builder -output "builder_function_name" { - description = "Nome da função Lambda Builder" - value = aws_lambda_function.builder_function.function_name -} - -output "builder_function_arn" { - description = "ARN da função Lambda Builder" - value = aws_lambda_function.builder_function.arn -} - -output "builder_invoke_arn" { - description = "ARN para invocar a função Lambda Builder" - value = aws_lambda_function.builder_function.invoke_arn -} - -output "builder_role_arn" { - description = "ARN da role IAM da função Lambda Builder" - value = aws_iam_role.lambda_builder_execution_role.arn -} - -# Output do Event Source Mapping (trigger SQS → Lambda) -output "builder_sqs_trigger_uuid" { - description = "UUID do trigger SQS para Lambda Builder" - value = aws_lambda_event_source_mapping.builder_sqs_trigger.uuid -} - -# Outputs da função Lambda de Notificação -output "notification_function_name" { - description = "Nome da função Lambda de Notificação" - value = aws_lambda_function.notification_function.function_name -} - -output "notification_function_arn" { - description = "ARN da função Lambda de Notificação" - value = aws_lambda_function.notification_function.arn -} - -output "notification_invoke_arn" { - description = "ARN para invocar a função Lambda de Notificação" - value = aws_lambda_function.notification_function.invoke_arn -} - -output "notification_role_arn" { - description = "ARN da role IAM da função Lambda de Notificação" - value = aws_iam_role.lambda_notification_execution_role.arn -} - -# Output do Event Source Mapping (trigger SQS → Lambda Notification) -output "notification_sqs_trigger_uuid" { - description = "UUID do trigger SQS para Lambda de Notificação" - value = aws_lambda_event_source_mapping.notification_sqs_trigger.uuid -} diff --git a/terraform/modules/05.lambda/variables.tf b/terraform/modules/05.lambda/variables.tf deleted file mode 100644 index 0c17ef5..0000000 --- a/terraform/modules/05.lambda/variables.tf +++ /dev/null @@ -1,162 +0,0 @@ -# Variáveis para o módulo Lambda - -variable "project_name" { - description = "Nome do projeto" - type = string -} - -variable "environment" { - description = "Ambiente de deploy (dev, staging, prod)" - type = string -} - -variable "aws_region" { - description = "Região AWS" - type = string -} - -variable "ecr_api_repository_name" { - description = "Nome do repositório ECR" - type = string -} - -variable "ecr_api_repository_url" { - description = "URL do repositório ECR" - type = string -} - -variable "ecr_builder_repository_name" { - description = "Nome do repositório ECR" - type = string -} - -variable "ecr_builder_repository_url" { - description = "URL do repositório ECR" - type = string -} - -variable "ecr_builder_repository_arn" { - description = "ARN do repositório ECR" - type = string -} - -variable "ecr_notification_repository_name" { - description = "Nome do repositório ECR" - type = string -} - -variable "ecr_notification_repository_url" { - description = "URL do repositório ECR" - type = string -} - -variable "ecr_notification_repository_arn" { - description = "ARN do repositório ECR" - type = string -} - -variable "image_tag" { - description = "Tag da imagem Docker" - type = string - default = "latest" -} - -variable "lambda_timeout" { - description = "Timeout da função Lambda em segundos" - type = number - default = 60 -} - -variable "lambda_memory_size" { - description = "Memória alocada para a função Lambda em MB" - type = number - default = 512 -} - -variable "log_retention_days" { - description = "Dias de retenção dos logs do CloudWatch" - type = number - default = 3 -} - - -variable "builder_queue_url" { - description = "URL da fila SQS builder" - type = string -} - -variable "url_service_tech" { - description = "URL do serviço Tech Floripa" - type = string -} - -variable "prefix_api_version" { - description = "Prefixo da versão da API" - type = string - default = "/api/v1" -} - -# ARNs das tabelas DynamoDB para políticas IAM -variable "dynamodb_table_arns" { - description = "ARNs das tabelas DynamoDB" - type = list(string) -} - - -variable "builder_queue_arn" { - description = "ARN da fila SQS builder" - type = string -} - -variable "notification_queue_arn" { - description = "ARN da fila SQS notification" - type = string -} - -variable "notification_queue_url" { - description = "URL da fila SQS notification" - type = string -} - -# ARN do repositório ECR para políticas IAM -variable "ecr_repository_arn" { - description = "ARN do repositório ECR" - type = string -} - -# ARN do bucket S3 para políticas IAM -variable "s3_bucket_arn" { - description = "ARN do bucket S3" - type = string -} - -variable "s3_bucket_name" { - description = "Nome do bucket S3" - type = string -} - -variable "api_gateway_download_url" { - description = "URL base do endpoint de download do API Gateway" - type = string -} - -variable "service_url_registration_api_solana" { - description = "URL do serviço de registro da API Solana" - type = string -} - -variable "service_api_key_registration_api_solana" { - description = "API Key do serviço de registro da API Solana" - type = string - sensitive = true -} - -variable "tech_floripa_certificate_validate_url" { - description = "URL para validação de certificados do Tech Floripa" - type = string -} - -variable "tech_floripa_logo_url" { - description = "URL do logo do Tech Floripa" - type = string -} diff --git a/terraform/modules/06.api-gateway/README.md b/terraform/modules/06.api-gateway/README.md deleted file mode 100644 index c428e3d..0000000 --- a/terraform/modules/06.api-gateway/README.md +++ /dev/null @@ -1,175 +0,0 @@ -# API Gateway - Estrutura Escalável - -Este módulo implementa uma organização escalável e dinâmica para o AWS API Gateway usando Terraform. - -## ✨ Vantagens da Nova Estrutura - -### 🔄 **Antes (Código Manual)** -- ❌ Cada endpoint precisava de 4-5 recursos separados -- ❌ Código repetitivo e difícil manutenção -- ❌ Para adicionar `/api/v1/certificate/list` = +15 linhas de código -- ❌ CORS configurado manualmente para cada endpoint - -### 🚀 **Depois (Código Dinâmico)** -- ✅ Estrutura declarativa em `locals` -- ✅ Recursos criados automaticamente com `for_each` -- ✅ Para adicionar `/api/v1/certificate/list` = +7 linhas simples -- ✅ CORS automático para todos os endpoints - -## 📖 Como Adicionar Novos Endpoints - -### 1. **Novo Endpoint no Recurso Existente** - -Para adicionar `GET /api/v1/certificate/list`: - -```hcl -# No locals.api_structure, dentro de certificate.endpoints: -"list" = { - method = "GET" - authorization = "NONE" - lambda_integration = true - cors_enabled = true -} -``` - -### 2. **Novo Recurso Completo** - -Para adicionar `POST /api/v1/orders/create`: - -```hcl -# No locals.api_structure, dentro de v1: -"orders" = { - endpoints = { - "create" = { - method = "POST" - authorization = "NONE" - lambda_integration = true - cors_enabled = true - } - "list" = { - method = "GET" - authorization = "NONE" - lambda_integration = true - cors_enabled = true - } - } -} -``` - -### 3. **Nova Versão da API** - -Para adicionar `POST /api/v2/certificate/create`: - -```hcl -# No locals.api_structure, dentro de api: -"v2" = { - "certificate" = { - endpoints = { - "create" = { - method = "POST" - authorization = "NONE" - lambda_integration = true - cors_enabled = true - } - } - } -} -``` - -## ⚙️ Configurações Disponíveis - -### Opções por Endpoint: - -```hcl -"endpoint_name" = { - method = "POST|GET|PUT|DELETE|PATCH" # Método HTTP - authorization = "NONE|AWS_IAM|COGNITO_USER_POOLS" # Tipo de autorização - lambda_integration = true|false # Integração com Lambda - cors_enabled = true|false # Habilitar CORS automático -} -``` - -## 🔧 Funcionalidades Automáticas - -### 1. **Recursos Hierárquicos** -- Cria automaticamente toda a estrutura de recursos -- Gerencia dependências entre níveis -- Evita duplicação de recursos - -### 2. **CORS Inteligente** -- Métodos OPTIONS criados automaticamente -- Headers CORS configurados dinamicamente -- Permite métodos específicos por endpoint - -### 3. **Deployment Inteligente** -- Trigger automático quando estrutura muda -- Dependency tracking completo -- Zero downtime com `create_before_destroy` - -### 4. **Integração Lambda** -- Uma única permissão para todos os endpoints -- Proxy integration automática -- URN flexível para múltiplas funções - -## 📊 Exemplo de Estrutura Completa - -```hcl -api_structure = { - "api" = { - "v1" = { - "certificate" = { - endpoints = { - "create" = { method = "POST", authorization = "NONE", lambda_integration = true, cors_enabled = true } - "list" = { method = "GET", authorization = "NONE", lambda_integration = true, cors_enabled = true } - "status" = { method = "GET", authorization = "NONE", lambda_integration = true, cors_enabled = true } - } - } - "orders" = { - endpoints = { - "create" = { method = "POST", authorization = "NONE", lambda_integration = true, cors_enabled = true } - "list" = { method = "GET", authorization = "NONE", lambda_integration = true, cors_enabled = true } - } - } - "health" = { - endpoints = { - "check" = { method = "GET", authorization = "NONE", lambda_integration = true, cors_enabled = false } - } - } - } - "v2" = { - "certificate" = { - endpoints = { - "create" = { method = "POST", authorization = "AWS_IAM", lambda_integration = true, cors_enabled = true } - } - } - } - } -} -``` - -### URLs Geradas: -- `POST /api/v1/certificate/create` -- `GET /api/v1/certificate/list` -- `GET /api/v1/certificate/status` -- `POST /api/v1/orders/create` -- `GET /api/v1/orders/list` -- `GET /api/v1/health/check` -- `POST /api/v2/certificate/create` - -## 🚦 Migration Path - -Para migrar endpoints existentes: - -1. **Mantenha o código antigo** temporariamente -2. **Adicione o endpoint na nova estrutura** -3. **Teste que ambos funcionam** -4. **Remova o código antigo** -5. **Execute `terraform apply`** - -## 💡 Melhores Práticas - -1. **Sempre use `cors_enabled = true`** para endpoints web -2. **Mantenha estrutura hierárquica consistente** -3. **Use nomes descritivos para endpoints** -4. **Considere autenticação por endpoint** -5. **Teste mudanças em ambiente de desenvolvimento primeiro** diff --git a/terraform/modules/06.api-gateway/main.tf b/terraform/modules/06.api-gateway/main.tf deleted file mode 100644 index b129284..0000000 --- a/terraform/modules/06.api-gateway/main.tf +++ /dev/null @@ -1,440 +0,0 @@ -# Módulo API Gateway REST para Certified Builder API -# Responsável por criar o API Gateway REST com integração ao Lambda de forma escalável - -# Definição da estrutura de endpoints da API de forma declarativa -locals { - # Estrutura hierárquica dos endpoints - api_structure = { - "api" = { - "v1" = { - "certificate" = { - endpoints = { - "create" = { - method = "POST" - authorization = "NONE" - api_key_required = true # Exige API Key - lambda_integration = true - cors_enabled = true - } - # Exemplo de como adicionar novos endpoints facilmente: - # "list" = { - # method = "GET" - # authorization = "NONE" - # lambda_integration = true - # cors_enabled = true - # } - "fetch" = { - method = "GET" - query_string_parameters = { - /* Endpoint unificado para busca de certificados. - Suporta busca por order_id, email, product_id ou combinações. - - Query Parameters (todos opcionais, mas pelo menos um deve ser fornecido): - - order_id: Busca certificados por ID do pedido (string) - - email: Busca certificados por email do participante (string válido) - - product_id: Busca certificados por ID do produto (string) - - Combinações válidas: - - order_id (sozinho) - - email (sozinho) - - product_id (sozinho) - - email + product_id (combinação específica) - - order_id + product_id (para filtragem adicional) - */ - "order_id" = false # Query parameter opcional - "email" = false # Query parameter opcional - "product_id" = false # Query parameter opcional - } - authorization = "NONE" - api_key_required = true # Exige API Key - lambda_integration = true - cors_enabled = true - # Validação será realizada no Lambda, não no API Gateway - # pois precisamos verificar se pelo menos um parâmetro foi fornecido - } - "download" = { - method = "GET" - query_string_parameters = { - /* Endpoint para download de certificados via URL pré-assinada do S3. - - Query Parameters: - - id: UUID do certificado (obrigatório) - - Retorna: - - HTML com redirecionamento automático para URL pré-assinada (30min) - - HTML informativo se certificado não foi gerado - - 404 se certificado não encontrado ou UUID inválido - */ - "id" = true # UUID do certificado (obrigatório) - } - authorization = "NONE" - api_key_required = false # Não exige API Key para downloads - lambda_integration = true - cors_enabled = true - } - } - } - # Exemplo de como adicionar novos recursos facilmente: - # "orders" = { - # endpoints = { - # "create" = { - # method = "POST" - # authorization = "NONE" - # lambda_integration = true - # cors_enabled = true - # } - # } - # } - } - } - } - - # Flatten da estrutura para criar recursos dinamicamente - api_paths = flatten([ - for level1_key, level1_value in local.api_structure : [ - for level2_key, level2_value in level1_value : [ - for level3_key, level3_value in level2_value : [ - for endpoint_key, endpoint_config in level3_value.endpoints : { - path_key = "${level1_key}-${level2_key}-${level3_key}-${endpoint_key}" - level1 = level1_key - level2 = level2_key - level3 = level3_key - endpoint = endpoint_key - full_path = "/${level1_key}/${level2_key}/${level3_key}/${endpoint_key}" - config = endpoint_config - } - ] - ] - ] - ]) - - # Criar mapa para facilitar referências - paths_map = { - for path in local.api_paths : path.path_key => path - } -} - -# API Gateway REST API -resource "aws_api_gateway_rest_api" "api" { - name = "${var.project_name}-api-${var.environment}" - description = "API REST para Certified Builder API - ${var.environment}" - - endpoint_configuration { - types = ["REGIONAL"] - } - - tags = { - Name = "${var.project_name}-api-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Criação dinâmica dos recursos de primeiro nível (/api) -resource "aws_api_gateway_resource" "level1_resources" { - for_each = toset([for path in local.api_paths : path.level1]) - - rest_api_id = aws_api_gateway_rest_api.api.id - parent_id = aws_api_gateway_rest_api.api.root_resource_id - path_part = each.value -} - -# Criação dinâmica dos recursos de segundo nível (/api/v1) -resource "aws_api_gateway_resource" "level2_resources" { - for_each = toset([for path in local.api_paths : "${path.level1}/${path.level2}"]) - - rest_api_id = aws_api_gateway_rest_api.api.id - parent_id = aws_api_gateway_resource.level1_resources[split("/", each.value)[0]].id - path_part = split("/", each.value)[1] -} - -# Criação dinâmica dos recursos de terceiro nível (/api/v1/certificate) -resource "aws_api_gateway_resource" "level3_resources" { - for_each = toset([for path in local.api_paths : "${path.level1}/${path.level2}/${path.level3}"]) - - rest_api_id = aws_api_gateway_rest_api.api.id - parent_id = aws_api_gateway_resource.level2_resources["${split("/", each.value)[0]}/${split("/", each.value)[1]}"].id - path_part = split("/", each.value)[2] -} - -# Criação dinâmica dos recursos de quarto nível (/api/v1/certificate/create) -resource "aws_api_gateway_resource" "endpoint_resources" { - for_each = local.paths_map - - rest_api_id = aws_api_gateway_rest_api.api.id - parent_id = aws_api_gateway_resource.level3_resources["${each.value.level1}/${each.value.level2}/${each.value.level3}"].id - path_part = each.value.endpoint -} - -# Criação dinâmica dos métodos HTTP -resource "aws_api_gateway_method" "endpoint_methods" { - for_each = local.paths_map - - rest_api_id = aws_api_gateway_rest_api.api.id - resource_id = aws_api_gateway_resource.endpoint_resources[each.key].id - http_method = each.value.config.method - authorization = each.value.config.authorization - api_key_required = lookup(each.value.config, "api_key_required", false) - - # Configuração dos parâmetros de requisição incluindo query parameters - request_parameters = merge( - { - "method.request.header.Content-Type" = true - }, - # Adiciona query parameters se definidos na configuração do endpoint - can(each.value.config.query_string_parameters) ? { - for param_name, required in each.value.config.query_string_parameters : - "method.request.querystring.${param_name}" => required - } : {} - ) -} - -# Criação dinâmica das integrações com Lambda -resource "aws_api_gateway_integration" "lambda_integrations" { - for_each = { - for key, path in local.paths_map : key => path - if path.config.lambda_integration - } - - rest_api_id = aws_api_gateway_rest_api.api.id - resource_id = aws_api_gateway_resource.endpoint_resources[each.key].id - http_method = aws_api_gateway_method.endpoint_methods[each.key].http_method - - integration_http_method = "POST" - type = "AWS_PROXY" - uri = var.lambda_invoke_arn -} - -# Permissão para API Gateway invocar o Lambda -resource "aws_lambda_permission" "api_gateway_invoke" { - statement_id = "AllowExecutionFromAPIGateway" - action = "lambda:InvokeFunction" - function_name = var.lambda_function_name - principal = "apigateway.amazonaws.com" - - # Permite qualquer método do API Gateway (mais flexível para múltiplos endpoints) - source_arn = "${aws_api_gateway_rest_api.api.execution_arn}/*/*" -} - -# Criação dinâmica dos métodos OPTIONS para CORS -resource "aws_api_gateway_method" "cors_methods" { - for_each = { - for key, path in local.paths_map : key => path - if path.config.cors_enabled - } - - rest_api_id = aws_api_gateway_rest_api.api.id - resource_id = aws_api_gateway_resource.endpoint_resources[each.key].id - http_method = "OPTIONS" - authorization = "NONE" -} - -# Criação dinâmica das integrações MOCK para CORS -resource "aws_api_gateway_integration" "cors_integrations" { - for_each = { - for key, path in local.paths_map : key => path - if path.config.cors_enabled - } - - rest_api_id = aws_api_gateway_rest_api.api.id - resource_id = aws_api_gateway_resource.endpoint_resources[each.key].id - http_method = aws_api_gateway_method.cors_methods[each.key].http_method - - type = "MOCK" - - request_templates = { - "application/json" = "{\"statusCode\": 200}" - } -} - -# Criação dinâmica das respostas CORS -resource "aws_api_gateway_method_response" "cors_responses" { - for_each = { - for key, path in local.paths_map : key => path - if path.config.cors_enabled - } - - rest_api_id = aws_api_gateway_rest_api.api.id - resource_id = aws_api_gateway_resource.endpoint_resources[each.key].id - http_method = aws_api_gateway_method.cors_methods[each.key].http_method - status_code = "200" - - response_parameters = { - "method.response.header.Access-Control-Allow-Headers" = true - "method.response.header.Access-Control-Allow-Methods" = true - "method.response.header.Access-Control-Allow-Origin" = true - } -} - -# Criação dinâmica das respostas de integração CORS -resource "aws_api_gateway_integration_response" "cors_integration_responses" { - for_each = { - for key, path in local.paths_map : key => path - if path.config.cors_enabled - } - - rest_api_id = aws_api_gateway_rest_api.api.id - resource_id = aws_api_gateway_resource.endpoint_resources[each.key].id - http_method = aws_api_gateway_method.cors_methods[each.key].http_method - status_code = aws_api_gateway_method_response.cors_responses[each.key].status_code - - response_parameters = { - "method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" - "method.response.header.Access-Control-Allow-Methods" = "'${each.value.config.method},OPTIONS'" - "method.response.header.Access-Control-Allow-Origin" = "'*'" - } -} - -# Deployment do API Gateway com triggers dinâmicos -resource "aws_api_gateway_deployment" "api_deployment" { - depends_on = [ - aws_api_gateway_method.endpoint_methods, - aws_api_gateway_integration.lambda_integrations, - aws_api_gateway_method.cors_methods, - aws_api_gateway_integration.cors_integrations - ] - - rest_api_id = aws_api_gateway_rest_api.api.id - - # Triggers dinâmicos baseados na estrutura da API - triggers = { - redeployment = sha1(jsonencode([ - local.api_structure, - var.lambda_invoke_arn - ])) - } - - lifecycle { - create_before_destroy = true - } -} - -# Stage do API Gateway -resource "aws_api_gateway_stage" "api_stage" { - deployment_id = aws_api_gateway_deployment.api_deployment.id - rest_api_id = aws_api_gateway_rest_api.api.id - stage_name = var.environment - - # Configuração de logs (desabilitada por padrão para economizar) - xray_tracing_enabled = false - - tags = { - Name = "${var.project_name}-api-stage-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Configuração de throttling para controle de custos -resource "aws_api_gateway_method_settings" "api_throttling" { - rest_api_id = aws_api_gateway_rest_api.api.id - stage_name = aws_api_gateway_stage.api_stage.stage_name - method_path = "*/*" - - settings { - throttling_rate_limit = var.throttle_rate_limit - throttling_burst_limit = var.throttle_burst_limit - logging_level = "OFF" - data_trace_enabled = false - metrics_enabled = false - } -} - -# ============================== -# CONFIGURAÇÃO DE API KEY -# ============================== - -# API Key para autenticação -resource "aws_api_gateway_api_key" "main_api_key" { - name = "${var.project_name}-api-key-${var.environment}" - description = "API Key para autenticação do ${var.project_name} em ${var.environment}" - enabled = true - - # Valor da API Key configurável via variável - value = var.api_key_value - - tags = { - Name = "${var.project_name}-api-key-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Usage Plan para controlar o uso da API Key -resource "aws_api_gateway_usage_plan" "main_usage_plan" { - name = "${var.project_name}-usage-plan-${var.environment}" - description = "Usage plan para ${var.project_name} em ${var.environment}" - - api_stages { - api_id = aws_api_gateway_rest_api.api.id - stage = aws_api_gateway_stage.api_stage.stage_name - } - - quota_settings { - limit = 1000 # 1k requests por mês - period = "MONTH" - } - - throttle_settings { - rate_limit = var.throttle_rate_limit # requests por segundo - burst_limit = var.throttle_burst_limit # burst máximo - } - - tags = { - Name = "${var.project_name}-usage-plan-${var.environment}" - Environment = var.environment - Project = var.project_name - } -} - -# Vinculação da API Key ao Usage Plan -resource "aws_api_gateway_usage_plan_key" "main_usage_plan_key" { - key_id = aws_api_gateway_api_key.main_api_key.id - key_type = "API_KEY" - usage_plan_id = aws_api_gateway_usage_plan.main_usage_plan.id -} - -# Method settings específicos para endpoint de download com rate limit muito baixo -resource "aws_api_gateway_method_settings" "download_throttling" { - rest_api_id = aws_api_gateway_rest_api.api.id - stage_name = aws_api_gateway_stage.api_stage.stage_name - method_path = "*/certificate/download/GET" - - settings { - throttling_rate_limit = 0.083 # ~5 requests por minuto - throttling_burst_limit = 2 # burst máximo muito baixo - metrics_enabled = true - } -} - -# Usage Plan específico para endpoint de download com rate limit muito baixo -resource "aws_api_gateway_usage_plan" "download_usage_plan" { - name = "${var.project_name}-download-usage-plan-${var.environment}" - description = "Usage plan restritivo para endpoint de download de certificados" - - api_stages { - api_id = aws_api_gateway_rest_api.api.id - stage = aws_api_gateway_stage.api_stage.stage_name - } - - quota_settings { - limit = 50 # 50 requests por mês - period = "MONTH" - } - - throttle_settings { - rate_limit = 0.083 # ~5 requests por minuto (5/60 = 0.083) - burst_limit = 2 # burst máximo muito baixo - } - - tags = { - Name = "${var.project_name}-download-usage-plan-${var.environment}" - Environment = var.environment - Project = var.project_name - Purpose = "download-rate-limiting" - } -} - -# ============================== -# OUTPUTS PARA API KEY -# ============================== diff --git a/terraform/modules/06.api-gateway/outputs.tf b/terraform/modules/06.api-gateway/outputs.tf deleted file mode 100644 index 7cbeaa4..0000000 --- a/terraform/modules/06.api-gateway/outputs.tf +++ /dev/null @@ -1,56 +0,0 @@ -# Outputs do módulo API Gateway - -output "api_id" { - description = "ID do API Gateway" - value = aws_api_gateway_rest_api.api.id -} - -output "api_arn" { - description = "ARN do API Gateway" - value = aws_api_gateway_rest_api.api.arn -} - -output "api_url" { - description = "URL base do API Gateway" - value = "https://${aws_api_gateway_rest_api.api.id}.execute-api.${data.aws_region.current.id}.amazonaws.com/${aws_api_gateway_stage.api_stage.stage_name}" -} - -output "api_endpoint_create_certificate" { - description = "URL completa do endpoint para criar certificado" - value = "https://${aws_api_gateway_rest_api.api.id}.execute-api.${data.aws_region.current.id}.amazonaws.com/${aws_api_gateway_stage.api_stage.stage_name}/api/v1/certificate/create" -} - -output "stage_name" { - description = "Nome do stage do API Gateway" - value = aws_api_gateway_stage.api_stage.stage_name -} - -# Outputs da API Key -output "api_key_id" { - description = "ID da API Key" - value = aws_api_gateway_api_key.main_api_key.id -} - -output "api_key_value" { - description = "Valor da API Key (sensível)" - value = aws_api_gateway_api_key.main_api_key.value - sensitive = true -} - -output "usage_plan_id" { - description = "ID do Usage Plan" - value = aws_api_gateway_usage_plan.main_usage_plan.id -} - -output "api_endpoint_fetch_certificate" { - description = "URL completa do endpoint para buscar certificados" - value = "https://${aws_api_gateway_rest_api.api.id}.execute-api.${data.aws_region.current.id}.amazonaws.com/${aws_api_gateway_stage.api_stage.stage_name}/api/v1/certificate/fetch" -} - -output "api_endpoint_download_certificate" { - description = "URL base do endpoint para download de certificados" - value = "https://${aws_api_gateway_rest_api.api.id}.execute-api.${data.aws_region.current.id}.amazonaws.com/${aws_api_gateway_stage.api_stage.stage_name}/api/v1/certificate/download" -} - -# Data source para obter a região atual -data "aws_region" "current" {} diff --git a/terraform/modules/06.api-gateway/variables.tf b/terraform/modules/06.api-gateway/variables.tf deleted file mode 100644 index 4d2a42b..0000000 --- a/terraform/modules/06.api-gateway/variables.tf +++ /dev/null @@ -1,44 +0,0 @@ -# Variáveis para o módulo API Gateway - -variable "project_name" { - description = "Nome do projeto" - type = string -} - -variable "environment" { - description = "Ambiente de deploy (dev, staging, prod)" - type = string -} - -variable "lambda_function_name" { - description = "Nome da função Lambda" - type = string -} - -variable "lambda_invoke_arn" { - description = "ARN para invocar a função Lambda" - type = string -} - -variable "throttle_rate_limit" { - description = "Limite de taxa por segundo para throttling" - type = number - default = 100 -} - -variable "throttle_burst_limit" { - description = "Limite de burst para throttling" - type = number - default = 200 -} - -variable "api_key_value" { - description = "Valor da API Key para autenticação (deve ser um UUID válido)" - type = string - sensitive = true - - validation { - condition = can(regex("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", var.api_key_value)) - error_message = "A API Key deve estar no formato UUID válido (ex: 8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29)." - } -} diff --git a/terraform/modules/API_KEY_USAGE.md b/terraform/modules/API_KEY_USAGE.md deleted file mode 100644 index 5606070..0000000 --- a/terraform/modules/API_KEY_USAGE.md +++ /dev/null @@ -1,180 +0,0 @@ -# Configuração e Uso da API Key - -## 🔑 **Implementação Completa de API Key** - -A API agora exige autenticação via API Key para todos os endpoints protegidos. - -## 📋 **Configuração Implementada** - -### **1. Endpoints que Exigem API Key:** -- `POST /api/v1/certificate/create` -- `GET /api/v1/certificate/fetch` - -### **2. Header Obrigatório:** -``` -X-API-Key: 8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29 -``` - -### **3. Recursos Criados:** -- **API Key**: `aws_api_gateway_api_key.main_api_key` -- **Usage Plan**: `aws_api_gateway_usage_plan.main_usage_plan` -- **Vinculação**: `aws_api_gateway_usage_plan_key.main_usage_plan_key` - -## 🔧 **Como Funciona** - -### **1. Validação no API Gateway:** -- O API Gateway valida automaticamente o header `X-API-Key` -- Se não fornecido ou inválido: **HTTP 403 Forbidden** -- Se válido: request é encaminhado para a Lambda - -### **2. Controle de Uso:** -- **Quota**: 10.000 requests/mês -- **Rate Limit**: Configurável via `throttle_rate_limit` -- **Burst Limit**: Configurável via `throttle_burst_limit` - -## 🚀 **Como Usar na Aplicação** - -### **JavaScript/Node.js:** -```javascript -const response = await fetch('https://your-api-gateway-url/api/v1/certificate/create', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': '8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29' - }, - body: JSON.stringify({ - // seus dados aqui - }) -}); -``` - -### **cURL:** -```bash -curl -X POST \ - 'https://your-api-gateway-url/api/v1/certificate/create' \ - -H 'Content-Type: application/json' \ - -H 'X-API-Key: 8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29' \ - -d '{ - "order_id": "123", - "participant_email": "test@example.com" - }' -``` - -### **Python:** -```python -import requests - -headers = { - 'Content-Type': 'application/json', - 'X-API-Key': '8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29' -} - -response = requests.post( - 'https://your-api-gateway-url/api/v1/certificate/create', - headers=headers, - json={ - 'order_id': '123', - 'participant_email': 'test@example.com' - } -) -``` - -## 🔒 **Gerenciamento da API Key** - -### **1. Valor Atual:** -``` -8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29 -``` - -### **2. Alteração da API Key:** -```hcl -# No arquivo terraform.tfvars -api_key_value = "nova-uuid-aqui" -``` - -### **3. Rotação da API Key:** -1. Altere o valor em `terraform.tfvars` -2. Execute: `terraform apply` -3. Atualize todas as aplicações cliente -4. **Importante**: A API Key antiga para de funcionar imediatamente - -## 📊 **Monitoramento e Outputs** - -### **Outputs Disponíveis:** -```bash -# Obter informações da API Key -terraform output api_key_id -terraform output usage_plan_id - -# API Key value (sensível) -terraform output -json api_key_value -``` - -### **URLs dos Endpoints:** -```bash -# Endpoint de criação -terraform output api_endpoint_create_certificate - -# Endpoint de busca -terraform output api_endpoint_fetch_certificate -``` - -## 🛡️ **Segurança** - -### **1. API Key como Variável Sensível:** -- Marcada como `sensitive = true` -- Não aparece em logs do Terraform -- Protegida no state file - -### **2. Validação de Formato:** -- Só aceita UUIDs válidos -- Formato: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` - -### **3. Controle de Acesso:** -- Usage Plan limita o uso por API Key -- Throttling previne abuso -- Logs de acesso no CloudWatch - -## ⚠️ **Troubleshooting** - -### **403 Forbidden:** -```json -{ - "message": "Forbidden" -} -``` -**Solução**: Verificar se o header `X-API-Key` está correto. - -### **429 Too Many Requests:** -```json -{ - "message": "Too Many Requests" -} -``` -**Solução**: Aguardar ou ajustar limites no Usage Plan. - -### **Verificação da API Key:** -```bash -# No AWS CLI -aws apigateway get-api-key --api-key your-api-key-id --include-value -``` - -## 📝 **Exemplo Completo de Teste** - -```bash -# 1. Obter URL do endpoint -API_URL=$(terraform output -raw api_endpoint_create_certificate) - -# 2. Testar com API Key -curl -X POST "$API_URL" \ - -H "Content-Type: application/json" \ - -H "X-API-Key: 8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29" \ - -d '{"order_id": "test123", "participant_email": "test@example.com"}' - -# 3. Testar SEM API Key (deve falhar) -curl -X POST "$API_URL" \ - -H "Content-Type: application/json" \ - -d '{"order_id": "test123", "participant_email": "test@example.com"}' -``` - -A implementação está completa e todos os endpoints agora exigem a API Key especificada! diff --git a/terraform/variables.tf b/terraform/variables.tf index 474a277..da51a4f 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -52,87 +52,3 @@ variable "project_name" { # Configuração do DynamoDB - Modo de Baixo Custo # Todas as tabelas usam PAY_PER_REQUEST por padrão (paga apenas pelo que usar) - -# Variáveis para Lambda Function -variable "lambda_image_tag" { - description = "Tag da imagem Docker para o Lambda" - type = string - default = "latest" -} - -variable "lambda_timeout" { - description = "Timeout da função Lambda em segundos" - type = number - default = 60 -} - -variable "lambda_memory_size" { - description = "Memória alocada para a função Lambda em MB" - type = number - default = 512 -} - -variable "log_retention_days" { - description = "Dias de retenção dos logs do CloudWatch" - type = number - default = 3 -} - -variable "url_service_tech" { - description = "URL do serviço Tech Floripa" - type = string - default = "https://tech.floripa.br/wp-json/custom/v1" -} - -variable "prefix_api_version" { - description = "Prefixo da versão da API" - type = string - default = "/api/v1" -} - -# Variáveis para API Gateway -variable "api_throttle_rate_limit" { - description = "Limite de taxa por segundo para throttling do API Gateway" - type = number - default = 100 -} - -variable "api_throttle_burst_limit" { - description = "Limite de burst para throttling do API Gateway" - type = number - default = 200 -} - -variable "api_key_value" { - description = "Valor da API Key para autenticação do API Gateway (deve ser fornecido via terraform.tfvars)" - type = string - sensitive = true - - validation { - condition = can(regex("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$", var.api_key_value)) - error_message = "A API Key deve estar no formato UUID válido (ex: 8a3f1e2c-9d7b-4f4a-8453-bf3c1d2a6f29)." - } -} - -# Variáveis para integração com API Solana -variable "service_url_registration_api_solana" { - description = "URL do serviço de registro da API Solana" - type = string -} - -variable "service_api_key_registration_api_solana" { - description = "API Key do serviço de registro da API Solana" - type = string - sensitive = true -} - -variable "tech_floripa_certificate_validate_url" { - description = "URL para validação de certificados do Tech Floripa" - type = string -} - -variable "tech_floripa_logo_url" { - description = "URL do logo do Tech Floripa" - type = string - default = "https://tech.floripa.br/wp-content/uploads/2025/03/Tech-Floripa-Qr.png" -}