diff --git a/terraform/apigateway.tf b/terraform/apigateway.tf index e947e27..c58ade3 100644 --- a/terraform/apigateway.tf +++ b/terraform/apigateway.tf @@ -27,12 +27,15 @@ resource "aws_apigatewayv2_api" "order_api" { # Result caching is off. With caching, an expired Google token or an admin # removed from the allow-list would stay authorized for the cache TTL, and the # tokeninfo call dominates latency anyway. +# +# Invoke permission is a Lambda resource policy (below), not AuthorizerCredentialsArn. +# The credentials-role path returned 500 without invoking the authorizer in prod +# (PLAT-102); resource policy matches the submit-order route grants and the live hotfix. resource "aws_apigatewayv2_authorizer" "admin_google" { api_id = aws_apigatewayv2_api.order_api.id name = "AdminGoogleAuthorizer" authorizer_type = "REQUEST" authorizer_uri = aws_lambda_function.admin_authorizer.invoke_arn - authorizer_credentials_arn = aws_iam_role.admin_authorizer_invoke.arn authorizer_payload_format_version = "2.0" authorizer_result_ttl_in_seconds = 0 enable_simple_responses = true @@ -103,3 +106,20 @@ resource "aws_lambda_permission" "api_route" { principal = "apigateway.amazonaws.com" source_arn = "${aws_apigatewayv2_api.order_api.execution_arn}/*/${each.value.permission_source}" } + +# Grant API Gateway permission to invoke the admin authorizer Lambda. Source ARN +# is the authorizer itself (not a route), matching the AWS HTTP API docs. +# Import adopts the PLAT-102 live hotfix statement so the first apply does not +# attempt a duplicate AddPermission. +import { + to = aws_lambda_permission.admin_authorizer + id = "meal-order-manager-admin-authorizer/AllowApiGatewayInvokeAuthorizer" +} + +resource "aws_lambda_permission" "admin_authorizer" { + statement_id = "AllowApiGatewayInvokeAuthorizer" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.admin_authorizer.function_name + principal = "apigateway.amazonaws.com" + source_arn = "${aws_apigatewayv2_api.order_api.execution_arn}/authorizers/${aws_apigatewayv2_authorizer.admin_google.id}" +} diff --git a/terraform/iam.tf b/terraform/iam.tf index 5e49566..94139f5 100644 --- a/terraform/iam.tf +++ b/terraform/iam.tf @@ -172,56 +172,6 @@ resource "aws_iam_role_policy" "admin_authorizer" { policy = data.aws_iam_policy_document.admin_authorizer.json } -# Role API Gateway assumes to invoke the authorizer Lambda. The authorizer has -# no resource policy of its own; this identity-based grant is the only path. -# SourceAccount + execute-api ArnLike close the confused-deputy window without -# pinning the authorizer id (that would cycle: authorizer needs this role). -data "aws_iam_policy_document" "apigateway_assume" { - statement { - effect = "Allow" - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["apigateway.amazonaws.com"] - } - - condition { - test = "StringEquals" - variable = "aws:SourceAccount" - values = [local.account_id] - } - - condition { - test = "ArnLike" - variable = "aws:SourceArn" - values = ["arn:aws:execute-api:${var.aws_region}:${local.account_id}:${aws_apigatewayv2_api.order_api.id}/*"] - } - } -} - -resource "aws_iam_role" "admin_authorizer_invoke" { - name = "${local.project}-admin-authorizer-invoke" - path = "/tf-managed/" - assume_role_policy = data.aws_iam_policy_document.apigateway_assume.json - permissions_boundary = local.boundary_arn -} - -data "aws_iam_policy_document" "admin_authorizer_invoke" { - statement { - sid = "InvokeAdminAuthorizer" - effect = "Allow" - actions = ["lambda:InvokeFunction"] - resources = [aws_lambda_function.admin_authorizer.arn] - } -} - -resource "aws_iam_role_policy" "admin_authorizer_invoke" { - name = "invoke-admin-authorizer" - role = aws_iam_role.admin_authorizer_invoke.id - policy = data.aws_iam_policy_document.admin_authorizer_invoke.json -} - # --------------------------------------------------------------------------- # close-form # ---------------------------------------------------------------------------