mirror of
https://github.com/Sea-Haven-Industries/procurement-ingest.git
synced 2026-09-30 06:03:14 +00:00
342 lines
12 KiB
HCL
342 lines
12 KiB
HCL
locals {
|
|
api_policy = jsonencode({
|
|
Version = "2012-10-17"
|
|
Statement = [
|
|
{
|
|
Sid = "ShocBackendDevDataRead"
|
|
Effect = "Allow"
|
|
Principal = {
|
|
AWS = local.shoc_consumer_role_arn
|
|
}
|
|
Action = "execute-api:Invoke"
|
|
Resource = [
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/work-orders",
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/work-orders/*",
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/purchase-orders",
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/purchase-orders/*",
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/verified-sites",
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/verified-sites/*",
|
|
]
|
|
},
|
|
{
|
|
Sid = "DocsTokenGatedRoutes"
|
|
Effect = "Allow"
|
|
Principal = { AWS = "*" }
|
|
Action = "execute-api:Invoke"
|
|
Resource = [
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/docs",
|
|
"arn:aws:execute-api:${var.aws_region}:${local.account_id}:${local.api_rest_api_id}/${local.api_stage_name}/GET/openapi.json",
|
|
]
|
|
}
|
|
]
|
|
})
|
|
|
|
# Live resource IDs (import). parent_key null => API root.
|
|
api_resources = {
|
|
work_orders = {
|
|
id = "h5iu4f"
|
|
parent_key = null
|
|
path_part = "work-orders"
|
|
}
|
|
work_order_id = {
|
|
id = "4uk6uh"
|
|
parent_key = "work_orders"
|
|
path_part = "{workOrderId}"
|
|
}
|
|
work_order_comments = {
|
|
id = "gfx0te"
|
|
parent_key = "work_order_id"
|
|
path_part = "comments"
|
|
}
|
|
purchase_orders = {
|
|
id = "pfn6qm"
|
|
parent_key = null
|
|
path_part = "purchase-orders"
|
|
}
|
|
po_number = {
|
|
id = "nclnn3"
|
|
parent_key = "purchase_orders"
|
|
path_part = "{poNumber}"
|
|
}
|
|
verified_sites = {
|
|
id = "vyst7e"
|
|
parent_key = null
|
|
path_part = "verified-sites"
|
|
}
|
|
site_code = {
|
|
id = "rmaawy"
|
|
parent_key = "verified_sites"
|
|
path_part = "{siteCode}"
|
|
}
|
|
docs = {
|
|
id = "k4vl85"
|
|
parent_key = null
|
|
path_part = "docs"
|
|
}
|
|
openapi_json = {
|
|
id = "xos715"
|
|
parent_key = null
|
|
path_part = "openapi.json"
|
|
}
|
|
}
|
|
|
|
api_iam_methods = {
|
|
work_orders_get = { resource = "work_orders", method = "GET" }
|
|
work_order_id_get = { resource = "work_order_id", method = "GET" }
|
|
work_order_id_patch = { resource = "work_order_id", method = "PATCH" }
|
|
work_order_comments_get = { resource = "work_order_comments", method = "GET" }
|
|
work_order_comments_post = { resource = "work_order_comments", method = "POST" }
|
|
purchase_orders_get = { resource = "purchase_orders", method = "GET" }
|
|
po_number_get = { resource = "po_number", method = "GET" }
|
|
verified_sites_get = { resource = "verified_sites", method = "GET" }
|
|
site_code_get = { resource = "site_code", method = "GET" }
|
|
}
|
|
|
|
api_none_methods = {
|
|
docs_get = { resource = "docs", method = "GET" }
|
|
openapi_json_get = { resource = "openapi_json", method = "GET" }
|
|
}
|
|
}
|
|
|
|
resource "aws_cloudwatch_log_group" "procurement_api" {
|
|
name = "/aws/lambda/procurement-api"
|
|
retention_in_days = 60
|
|
|
|
lifecycle {
|
|
prevent_destroy = true
|
|
}
|
|
}
|
|
|
|
resource "aws_lambda_function" "procurement_api" {
|
|
function_name = "procurement-api"
|
|
role = aws_iam_role.procurement_api.arn
|
|
handler = "handler.handler"
|
|
runtime = "python3.12"
|
|
architectures = ["arm64"]
|
|
memory_size = 256
|
|
timeout = 30
|
|
|
|
s3_bucket = aws_s3_bucket.artifacts.id
|
|
s3_key = aws_s3_object.lambda["procurement_api"].key
|
|
source_code_hash = data.archive_file.lambda["procurement_api"].output_base64sha256
|
|
|
|
environment {
|
|
variables = {
|
|
VERIFIED_SITES_TABLE = aws_dynamodb_table.verified_sites.name
|
|
WORK_ORDERS_TABLE = aws_dynamodb_table.work_orders.name
|
|
COMMENTS_TABLE = aws_dynamodb_table.work_order_comments.name
|
|
PO_TABLE = aws_dynamodb_table.purchase_orders.name
|
|
WEB_UI_AUTH_TOKEN_SECRET_ARN = var.web_ui_auth_token_secret_arn
|
|
}
|
|
}
|
|
|
|
depends_on = [
|
|
aws_s3_object.lambda,
|
|
aws_cloudwatch_log_group.procurement_api,
|
|
aws_iam_role_policy_attachment.procurement_api_basic,
|
|
aws_iam_role_policy.procurement_api_ddb,
|
|
aws_iam_role_policy.procurement_api_kms,
|
|
aws_iam_role_policy.procurement_api_secrets,
|
|
]
|
|
}
|
|
|
|
resource "aws_api_gateway_rest_api" "procurement" {
|
|
name = "procurement-api"
|
|
description = "Read API over procurement-ingest work orders + purchase orders; token-gated OpenAPI docs at /docs"
|
|
policy = local.api_policy
|
|
|
|
endpoint_configuration {
|
|
types = ["REGIONAL"]
|
|
}
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "work_orders" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_rest_api.procurement.root_resource_id
|
|
path_part = "work-orders"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "work_order_id" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_resource.work_orders.id
|
|
path_part = "{workOrderId}"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "work_order_comments" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_resource.work_order_id.id
|
|
path_part = "comments"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "purchase_orders" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_rest_api.procurement.root_resource_id
|
|
path_part = "purchase-orders"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "po_number" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_resource.purchase_orders.id
|
|
path_part = "{poNumber}"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "verified_sites" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_rest_api.procurement.root_resource_id
|
|
path_part = "verified-sites"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "site_code" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_resource.verified_sites.id
|
|
path_part = "{siteCode}"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "docs" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_rest_api.procurement.root_resource_id
|
|
path_part = "docs"
|
|
}
|
|
|
|
resource "aws_api_gateway_resource" "openapi_json" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
parent_id = aws_api_gateway_rest_api.procurement.root_resource_id
|
|
path_part = "openapi.json"
|
|
}
|
|
|
|
locals {
|
|
api_resource_ids = {
|
|
work_orders = aws_api_gateway_resource.work_orders.id
|
|
work_order_id = aws_api_gateway_resource.work_order_id.id
|
|
work_order_comments = aws_api_gateway_resource.work_order_comments.id
|
|
purchase_orders = aws_api_gateway_resource.purchase_orders.id
|
|
po_number = aws_api_gateway_resource.po_number.id
|
|
verified_sites = aws_api_gateway_resource.verified_sites.id
|
|
site_code = aws_api_gateway_resource.site_code.id
|
|
docs = aws_api_gateway_resource.docs.id
|
|
openapi_json = aws_api_gateway_resource.openapi_json.id
|
|
}
|
|
}
|
|
|
|
resource "aws_api_gateway_method" "iam" {
|
|
for_each = local.api_iam_methods
|
|
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
resource_id = local.api_resource_ids[each.value.resource]
|
|
http_method = each.value.method
|
|
authorization = "AWS_IAM"
|
|
}
|
|
|
|
resource "aws_api_gateway_method" "none" {
|
|
for_each = local.api_none_methods
|
|
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
resource_id = local.api_resource_ids[each.value.resource]
|
|
http_method = each.value.method
|
|
authorization = "NONE"
|
|
}
|
|
|
|
resource "aws_api_gateway_integration" "iam" {
|
|
for_each = local.api_iam_methods
|
|
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
resource_id = local.api_resource_ids[each.value.resource]
|
|
http_method = aws_api_gateway_method.iam[each.key].http_method
|
|
integration_http_method = "POST"
|
|
type = "AWS_PROXY"
|
|
uri = aws_lambda_function.procurement_api.invoke_arn
|
|
}
|
|
|
|
resource "aws_api_gateway_integration" "none" {
|
|
for_each = local.api_none_methods
|
|
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
resource_id = local.api_resource_ids[each.value.resource]
|
|
http_method = aws_api_gateway_method.none[each.key].http_method
|
|
integration_http_method = "POST"
|
|
type = "AWS_PROXY"
|
|
uri = aws_lambda_function.procurement_api.invoke_arn
|
|
}
|
|
|
|
resource "aws_lambda_permission" "api_gateway" {
|
|
statement_id = "AllowAPIGatewayInvoke"
|
|
action = "lambda:InvokeFunction"
|
|
function_name = aws_lambda_function.procurement_api.function_name
|
|
principal = "apigateway.amazonaws.com"
|
|
source_arn = "${aws_api_gateway_rest_api.procurement.execution_arn}/*/*"
|
|
}
|
|
|
|
resource "aws_api_gateway_deployment" "procurement" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
|
|
# Hash live method/integration/resource attributes (not just static locals)
|
|
# so path, auth, or proxy URI edits force a new stage deployment.
|
|
triggers = {
|
|
redeployment = sha1(jsonencode({
|
|
resources = {
|
|
work_orders = aws_api_gateway_resource.work_orders
|
|
work_order_id = aws_api_gateway_resource.work_order_id
|
|
work_order_comments = aws_api_gateway_resource.work_order_comments
|
|
purchase_orders = aws_api_gateway_resource.purchase_orders
|
|
po_number = aws_api_gateway_resource.po_number
|
|
verified_sites = aws_api_gateway_resource.verified_sites
|
|
site_code = aws_api_gateway_resource.site_code
|
|
docs = aws_api_gateway_resource.docs
|
|
openapi_json = aws_api_gateway_resource.openapi_json
|
|
}
|
|
methods_iam = aws_api_gateway_method.iam
|
|
methods_none = aws_api_gateway_method.none
|
|
integrations_iam = aws_api_gateway_integration.iam
|
|
integrations_none = aws_api_gateway_integration.none
|
|
policy = local.api_policy
|
|
lambda_hash = data.archive_file.lambda["procurement_api"].output_base64sha256
|
|
}))
|
|
}
|
|
|
|
lifecycle {
|
|
create_before_destroy = true
|
|
}
|
|
|
|
depends_on = [
|
|
aws_api_gateway_integration.iam,
|
|
aws_api_gateway_integration.none,
|
|
]
|
|
}
|
|
|
|
resource "aws_api_gateway_stage" "prod" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
deployment_id = aws_api_gateway_deployment.procurement.id
|
|
stage_name = local.api_stage_name
|
|
|
|
xray_tracing_enabled = false
|
|
}
|
|
|
|
resource "aws_api_gateway_method_settings" "prod_all" {
|
|
rest_api_id = aws_api_gateway_rest_api.procurement.id
|
|
stage_name = aws_api_gateway_stage.prod.stage_name
|
|
method_path = "*/*"
|
|
|
|
settings {
|
|
metrics_enabled = false
|
|
logging_level = "OFF"
|
|
data_trace_enabled = false
|
|
throttling_burst_limit = 100
|
|
throttling_rate_limit = 50
|
|
}
|
|
}
|
|
|
|
resource "aws_api_gateway_domain_name" "procurement" {
|
|
domain_name = local.api_domain_name
|
|
regional_certificate_arn = data.aws_ssm_parameter.procurement_api_cert_arn.value
|
|
security_policy = "TLS_1_2"
|
|
|
|
endpoint_configuration {
|
|
types = ["REGIONAL"]
|
|
}
|
|
}
|
|
|
|
resource "aws_api_gateway_base_path_mapping" "procurement" {
|
|
api_id = aws_api_gateway_rest_api.procurement.id
|
|
stage_name = aws_api_gateway_stage.prod.stage_name
|
|
domain_name = aws_api_gateway_domain_name.procurement.domain_name
|
|
}
|