Add Quantum LocalStack OpenTofu project

This commit is contained in:
2026-04-20 16:48:32 -03:00
commit 248fd37942
10 changed files with 470 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
.terraform/
.terraform.lock.hcl
terraform.tfstate
terraform.tfstate.*
*.tfplan
*.zip
crash.log
crash.*.log
override.tf
override.tf.json
*_override.tf
*_override.tf.json
.env
+94
View File
@@ -0,0 +1,94 @@
# aws-localstack
Projeto OpenTofu para provisionar recursos AWS simulados no LocalStack da aplicacao ficticia Quantum.
Endpoint LocalStack:
```text
https://localstack.paulononato.com.br
```
## Recursos
- S3 bucket para artefatos da aplicacao Quantum.
- SQS fila principal e DLQ.
- Lambda Python para processar eventos.
- IAM role e policies ficticias para a Lambda.
- CloudWatch Log Group.
- Secrets Manager com credenciais simuladas.
- Event source mapping SQS -> Lambda.
## Pre-requisitos
- OpenTofu instalado.
- AWS CLI opcional para testes.
- Acesso ao endpoint LocalStack.
Credenciais usadas pelo LocalStack:
```bash
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
```
No PowerShell:
```powershell
$env:AWS_ACCESS_KEY_ID="test"
$env:AWS_SECRET_ACCESS_KEY="test"
$env:AWS_DEFAULT_REGION="us-east-1"
```
## Como usar
Inicializar:
```bash
tofu init
```
Planejar:
```bash
tofu plan
```
Aplicar:
```bash
tofu apply
```
Destruir:
```bash
tofu destroy
```
## Testes rapidos
Listar buckets:
```bash
aws --endpoint-url https://localstack.paulononato.com.br s3 ls
```
Enviar mensagem para a fila Quantum:
```bash
aws --endpoint-url https://localstack.paulononato.com.br sqs send-message \
--queue-url "$(tofu output -raw quantum_queue_url)" \
--message-body '{"event":"quantum.order.created","orderId":"QTM-1001"}'
```
Ver segredo:
```bash
aws --endpoint-url https://localstack.paulononato.com.br secretsmanager get-secret-value \
--secret-id "$(tofu output -raw quantum_secret_name)"
```
## Observacao sobre RDS
RDS nao esta incluido na edicao Community do LocalStack provisionada no servidor. Este projeto evita RDS e usa apenas os servicos disponiveis na stack atual.
+1
View File
@@ -0,0 +1 @@
+14
View File
@@ -0,0 +1,14 @@
{
"event": "quantum.order.created",
"orderId": "QTM-1001",
"customer": {
"id": "CUS-9001",
"name": "Ada Lovelace"
},
"items": [
{
"sku": "QBIT-001",
"quantity": 2
}
]
}
+48
View File
@@ -0,0 +1,48 @@
import json
import os
def lambda_handler(event, context):
app_name = os.environ.get("APP_NAME", "Quantum")
bucket_name = os.environ.get("BUCKET_NAME", "unknown")
secret_name = os.environ.get("SECRET_NAME", "unknown")
records = event.get("Records", [])
processed = []
for record in records:
body = record.get("body", "{}")
try:
payload = json.loads(body)
except json.JSONDecodeError:
payload = {"raw": body}
processed.append(
{
"messageId": record.get("messageId"),
"payload": payload,
}
)
print(
json.dumps(
{
"app": app_name,
"bucket": bucket_name,
"secret": secret_name,
"processedCount": len(processed),
"records": processed,
}
)
)
return {
"statusCode": 200,
"body": json.dumps(
{
"message": "Quantum event batch processed",
"processedCount": len(processed),
}
),
}
+207
View File
@@ -0,0 +1,207 @@
locals {
name_prefix = "${var.project_name}-${var.environment}"
common_tags = {
Application = "Quantum"
Environment = var.environment
ManagedBy = "OpenTofu"
Runtime = "LocalStack"
}
}
data "archive_file" "quantum_lambda" {
type = "zip"
source_file = "${path.module}/lambda/handler.py"
output_path = "${path.module}/build/quantum_lambda.zip"
}
resource "aws_s3_bucket" "quantum_artifacts" {
bucket = "${local.name_prefix}-artifacts"
force_destroy = true
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-artifacts"
})
}
resource "aws_s3_bucket_versioning" "quantum_artifacts" {
bucket = aws_s3_bucket.quantum_artifacts.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_object" "sample_config" {
bucket = aws_s3_bucket.quantum_artifacts.id
key = "config/quantum-dev.json"
content_type = "application/json"
content = jsonencode({
appName = "Quantum"
environment = var.environment
featureToggle = "simulated-localstack"
owner = "platform-team"
})
tags = local.common_tags
}
resource "aws_sqs_queue" "quantum_dlq" {
name = "${local.name_prefix}-events-dlq"
message_retention_seconds = 1209600
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-events-dlq"
})
}
resource "aws_sqs_queue" "quantum_events" {
name = "${local.name_prefix}-events"
visibility_timeout_seconds = 45
message_retention_seconds = 345600
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.quantum_dlq.arn
maxReceiveCount = 3
})
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-events"
})
}
resource "aws_secretsmanager_secret" "quantum_app" {
name = "${local.name_prefix}/app"
recovery_window_in_days = 0
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-app-secret"
})
}
resource "aws_secretsmanager_secret_version" "quantum_app" {
secret_id = aws_secretsmanager_secret.quantum_app.id
secret_string = jsonencode({
databaseUrl = "postgres://quantum_user:fake_password@quantum-db.local:5432/quantum"
apiKey = "qtm_dev_fake_123456"
jwtSecret = "localstack-only-secret"
})
}
resource "aws_iam_role" "quantum_lambda" {
name = "${local.name_prefix}-lambda-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
tags = local.common_tags
}
resource "aws_iam_policy" "quantum_lambda" {
name = "${local.name_prefix}-lambda-policy"
description = "Permissoes simuladas da Lambda Quantum no LocalStack."
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
]
Resource = aws_sqs_queue.quantum_events.arn
},
{
Effect = "Allow"
Action = [
"secretsmanager:GetSecretValue"
]
Resource = aws_secretsmanager_secret.quantum_app.arn
},
{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
]
Resource = [
aws_s3_bucket.quantum_artifacts.arn,
"${aws_s3_bucket.quantum_artifacts.arn}/*"
]
}
]
})
tags = local.common_tags
}
resource "aws_iam_role_policy_attachment" "quantum_lambda" {
role = aws_iam_role.quantum_lambda.name
policy_arn = aws_iam_policy.quantum_lambda.arn
}
resource "aws_cloudwatch_log_group" "quantum_lambda" {
name = "/aws/lambda/${local.name_prefix}-processor"
retention_in_days = 14
tags = local.common_tags
}
resource "aws_lambda_function" "quantum_processor" {
function_name = "${local.name_prefix}-processor"
description = "Processador ficticio de eventos da aplicacao Quantum."
role = aws_iam_role.quantum_lambda.arn
runtime = "python3.11"
handler = "handler.lambda_handler"
filename = data.archive_file.quantum_lambda.output_path
source_code_hash = data.archive_file.quantum_lambda.output_base64sha256
timeout = 30
memory_size = 256
environment {
variables = {
APP_NAME = "Quantum"
BUCKET_NAME = aws_s3_bucket.quantum_artifacts.bucket
SECRET_NAME = aws_secretsmanager_secret.quantum_app.name
QUEUE_URL = aws_sqs_queue.quantum_events.url
}
}
depends_on = [
aws_cloudwatch_log_group.quantum_lambda,
aws_iam_role_policy_attachment.quantum_lambda
]
tags = local.common_tags
}
resource "aws_lambda_event_source_mapping" "quantum_events" {
event_source_arn = aws_sqs_queue.quantum_events.arn
function_name = aws_lambda_function.quantum_processor.arn
batch_size = 5
enabled = true
}
+34
View File
@@ -0,0 +1,34 @@
output "localstack_endpoint" {
description = "Endpoint LocalStack usado pelo provider."
value = var.localstack_endpoint
}
output "quantum_bucket_name" {
description = "Bucket S3 da aplicacao Quantum."
value = aws_s3_bucket.quantum_artifacts.bucket
}
output "quantum_queue_url" {
description = "URL da fila SQS principal."
value = aws_sqs_queue.quantum_events.url
}
output "quantum_dlq_url" {
description = "URL da fila DLQ."
value = aws_sqs_queue.quantum_dlq.url
}
output "quantum_lambda_name" {
description = "Nome da Lambda processadora."
value = aws_lambda_function.quantum_processor.function_name
}
output "quantum_log_group_name" {
description = "Log Group CloudWatch da Lambda."
value = aws_cloudwatch_log_group.quantum_lambda.name
}
output "quantum_secret_name" {
description = "Nome do segredo no Secrets Manager."
value = aws_secretsmanager_secret.quantum_app.name
}
+22
View File
@@ -0,0 +1,22 @@
provider "aws" {
region = var.aws_region
access_key = "test"
secret_key = "test"
s3_use_path_style = true
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
apigateway = var.localstack_endpoint
cloudformation = var.localstack_endpoint
cloudwatch = var.localstack_endpoint
iam = var.localstack_endpoint
lambda = var.localstack_endpoint
logs = var.localstack_endpoint
s3 = var.localstack_endpoint
secretsmanager = var.localstack_endpoint
sqs = var.localstack_endpoint
sts = var.localstack_endpoint
}
}
+23
View File
@@ -0,0 +1,23 @@
variable "aws_region" {
description = "Regiao AWS simulada no LocalStack."
type = string
default = "us-east-1"
}
variable "localstack_endpoint" {
description = "Endpoint HTTPS do LocalStack."
type = string
default = "https://localstack.paulononato.com.br"
}
variable "project_name" {
description = "Nome curto do projeto ficticio."
type = string
default = "quantum"
}
variable "environment" {
description = "Ambiente ficticio da aplicacao."
type = string
default = "dev"
}
+14
View File
@@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
archive = {
source = "hashicorp/archive"
version = "~> 2.4"
}
}
}