fix(apigateway): grant admin authorizer invoke via resource policy (#136)

Drop the broken AuthorizerCredentialsArn invoke role path that returned
500 without calling the authorizer, and adopt the live Lambda permission.
This commit is contained in:
Adam Moussa 2026-08-10 17:17:51 -04:00 • committed by GitHub
parent 24b2aaa70f
commit 60abc9fb50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 21 additions and 51 deletions

View file

@ -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}"
}

View file

@ -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
# ---------------------------------------------------------------------------