【问题标题】:HowTo allow Role testing AWS API Gateway with Terraform如何允许使用 Terraform 对 AWS API Gateway 进行角色测试
【发布时间】:2019-12-18 02:31:30
【问题描述】:

我目前遇到了 AWS/Terraform 的权限问题。我创建了一个测试 CRUD Lambda/API 网关,包括自定义域:

resource "aws_iam_role" "role_lambda_exec" {
  name = "role_lambda_exec"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
    "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_lambda_function" "delete_test" {
  filename         = "./build/placeholder.zip"
  source_code_hash = filebase64sha256("./build/placeholder.zip")
  function_name    = "delete_test"
  role             = aws_iam_role.role_lambda_exec.arn
  handler          = "placeholder"
  runtime          = "go1.x"
  timeout          = 60
  publish          = true

  lifecycle {
    ignore_changes = [
      "last_modified",
      "qualified_arn",
      "source_code_hash",
      "version"
    ]
  }
}

resource "aws_lambda_function" "get_test" {
  filename         = "./build/placeholder.zip"
  source_code_hash = filebase64sha256("./build/placeholder.zip")
  function_name    = "get_test"
  role             = aws_iam_role.role_lambda_exec.arn
  handler          = "placeholder"
  runtime          = "go1.x"
  timeout          = 60
  publish          = true

  lifecycle {
    ignore_changes = [
      "last_modified",
      "qualified_arn",
      "source_code_hash",
      "version"
    ]
  }
}

resource "aws_lambda_function" "patch_test" {
  filename         = "./build/placeholder.zip"
  source_code_hash = filebase64sha256("./build/placeholder.zip")
  function_name    = "patch_test"
  role             = aws_iam_role.role_lambda_exec.arn
  handler          = "placeholder"
  runtime          = "go1.x"
  timeout          = 60
  publish          = true

  lifecycle {
    ignore_changes = [
      "last_modified",
      "qualified_arn",
      "source_code_hash",
      "version"
    ]
  }
}
resource "aws_lambda_function" "post_test" {
  filename         = "./build/placeholder.zip"
  source_code_hash = filebase64sha256("./build/placeholder.zip")
  function_name    = "post_test"
  role             = aws_iam_role.role_lambda_exec.arn
  handler          = "placeholder"
  runtime          = "go1.x"
  timeout          = 60
  publish          = true

  lifecycle {
    ignore_changes = [
      "last_modified",
      "qualified_arn",
      "source_code_hash",
      "version"
    ]
  }
}
resource "aws_lambda_function" "put_test" {
  filename         = "./build/placeholder.zip"
  source_code_hash = filebase64sha256("./build/placeholder.zip")
  function_name    = "put_test"
  role             = aws_iam_role.role_lambda_exec.arn
  handler          = "placeholder"
  runtime          = "go1.x"
  timeout          = 60
  publish          = true

  lifecycle {
    ignore_changes = [
      "last_modified",
      "qualified_arn",
      "source_code_hash",
      "version"
    ]
  }
}

data "template_file" "openapi" {
  template = file("openapi.yaml")
  vars     = {
    title                 = var.service_name_test
    description           = var.service_description_test
    server_testing_url    = var.service_url_test
    server_production_url = var.service_url_test
    delete_arn            = aws_lambda_function.delete_test.invoke_arn
    get_arn               = aws_lambda_function.get_test.invoke_arn
    patch_arn             = aws_lambda_function.patch_test.invoke_arn
    post_arn              = aws_lambda_function.post_test.invoke_arn
    put_arn               = aws_lambda_function.put_test.invoke_arn
  }
}

resource "aws_api_gateway_rest_api" "rest_api_test" {
  name        = var.service_name_test
  description = var.service_description_test
  body        = data.template_file.openapi.rendered

  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_deployment" "deployment_test" {
  rest_api_id = aws_api_gateway_rest_api.rest_api_test.id
  stage_name  = var.stage_name_test
}

resource "aws_api_gateway_domain_name" "domain_name_test" {
  domain_name              = var.service_domain_test
  regional_certificate_arn = var.cert_arn_domain
  security_policy          = "TLS_1_2"

  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_base_path_mapping" "base_path_mapping_test" {
  domain_name = var.service_domain_test
  api_id      = aws_api_gateway_rest_api.rest_api_test.id
  stage_name  = var.stage_name_test
}

resource "aws_route53_record" "route53_record_test" {
  type    = "A"
  name    = var.service_domain_test
  zone_id = data.aws_route53_zone.route53_zone_domain.id

  alias {
    evaluate_target_health = true
    name                   = aws_api_gateway_domain_name.domain_name_test.regional_domain_name
    zone_id                = aws_api_gateway_domain_name.domain_name_test.regional_zone_id
  }
}

resource "aws_lambda_permission" "apigateway_lambda_invoke_delete_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.delete_test.arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_deployment.deployment_test.execution_arn}/*/*"
}

resource "aws_lambda_permission" "apigateway_lambda_invoke_get_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.get_test.arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_deployment.deployment_test.execution_arn}/*/*"
}

resource "aws_lambda_permission" "apigateway_lambda_invoke_patch_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.patch_test.arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_deployment.deployment_test.execution_arn}/*/*"
}

resource "aws_lambda_permission" "apigateway_lambda_invoke_post_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.post_test.arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_deployment.deployment_test.execution_arn}/*/*"
}

resource "aws_lambda_permission" "apigateway_lambda_invoke_put_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.put_test.arn
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_deployment.deployment_test.execution_arn}/*/*"
}

当 CRUD (API) 按预期工作时(curl/insomia)。现在我正在尝试将策略传递给角色以测试(调用)lambda 和 API 网关,而第一部分(允许角色调用 lambda)非常简单,而第二部分(测试 API 网关)我得到了疯了:

data "aws_caller_identity" "current" {}

// new role developers, should allowed to manual trigger api-gateway and lambda tests

resource "aws_iam_role" "developers" {
  name = "developers"
  max_session_duration = "43200"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
    "Federated": "arn:aws:iam::${data.aws_caller_identity.current.account_id}:saml-provider/simplesamlphp"
      },
      "Action": "sts:AssumeRoleWithSAML",
      "Condition": {
    "StringEquals": {
      "SAML:aud": "https://signin.aws.amazon.com/saml"
    }
      }
    }
  ]
}
EOF
}

data "aws_iam_policy" "ReadOnlyAccess" {
  arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

resource "aws_iam_role_policy_attachment" "role_read_only_access" {
  policy_arn = data.aws_iam_policy.ReadOnlyAccess.arn
  role = aws_iam_role.developers.name
}

// allow developers to test lambda functions

resource "aws_lambda_permission" "role_lambda_invoke_get_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.get_test.arn
  principal     = aws_iam_role.developers.arn
}

resource "aws_lambda_permission" "role_lambda_invoke_delete_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.delete_test.arn
  principal     = aws_iam_role.developers.arn
}

resource "aws_lambda_permission" "role_lambda_invoke_patch_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.patch_test.arn
  principal     = aws_iam_role.developers.arn
}

resource "aws_lambda_permission" "role_lambda_invoke_post_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.post_test.arn
  principal     = aws_iam_role.developers.arn
}

resource "aws_lambda_permission" "role_lambda_invoke_put_test" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.put_test.arn
  principal     = aws_iam_role.developers.arn
}

data "aws_region" "current" {}

// this should allow testing api gateway trigger the lambda functions, but BROKEN!!!

resource "aws_iam_policy" "apigateway_invoke" {
  name = "apigateway_invoke"
  policy = <<EOF
{
    "Version":"2012-10-17",
    "Statement":[
    {
        "Effect":"Allow",
        "Action":[
            "apigateway:*"
        ],
        "Resource":[
            "arn:aws:apigateway:${data.aws_region.current.name}::/restapis/${aws_api_gateway_rest_api.rest_api_test.id}",
            "arn:aws:apigateway:${data.aws_region.current.name}::/restapis/${aws_api_gateway_rest_api.rest_api_test.id}/*"
        ]
    }
    ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "apigateway_invoke" {
  policy_arn = aws_iam_policy.apigateway_invoke.arn
  role = aws_iam_role.developers.name
}

日志告诉我,lambda 上存在无效权限,但我没有看到它......

Execution log for request b6f095a2-bbac-11e9-80e2-23b77a1af624
Sat Aug 10 20:23:28 UTC 2019 : Starting execution for request: b6f095a2-bbac-11e9-80e2-23b77a1af624
Sat Aug 10 20:23:28 UTC 2019 : HTTP Method: GET, Resource Path: /test
Sat Aug 10 20:23:28 UTC 2019 : Method request path: {uuid=test}
Sat Aug 10 20:23:28 UTC 2019 : Method request query string: {}
Sat Aug 10 20:23:28 UTC 2019 : Method request headers: {}
Sat Aug 10 20:23:28 UTC 2019 : Method request body before transformations: 
Sat Aug 10 20:23:28 UTC 2019 : Endpoint request URI: https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:XXXXXXXXXXX:function:get_test/invocations
Sat Aug 10 20:23:28 UTC 2019 : Endpoint request headers: {x-amzn-lambda-integration-tag=b6f095a2-bbac-11e9-80e2-23b77a1af624, Authorization=***************************************************************************************************************************************************************************************************************************************************************************************************************************65b8da, X-Amz-Date=20190810T202328Z, x-amzn-apigateway-api-id=9uzhf3d0od, X-Amz-Source-Arn=arn:aws:execute-api:eu-central-1:XXXXXXXXXXX:9uzhf3d0od/test-invoke-stage/GET/{uuid}, Accept=application/json, User-Agent=AmazonAPIGateway_9uzhf3d0od, X-Amz-Security-Token=AgoJb3JpZ2luX2VjECQaDGV1LWNlbnRyYWwtMSJIMEYCIQCfeL4YSUD8FjtyeEI2VRf/aofAdtm7/p29yzrbudB0+AIhAPjcgFav7vzo4i2te4p6KFViSuXUpirgCw4vE/VxCVanKukDCK3//////////wEQARoMNDc0MjQwMTQ2ODAyIgy/cIQQylFZ568eqJMqvQP861i5/+YeL9kCJLYoXqIwEsKJk0XKAmRPFMSvUb6AKBIUyUA2qjuaINkFqmOMagOJpWIZmvuOPyN1oweywfUsRndil5HmnBoThu3SPdJUp/TaTpgu0UMKTqRivZ3FwHFF+a8cND9P [TRUNCATED]
Sat Aug 10 20:23:28 UTC 2019 : Endpoint request body after transformations: {"resource":"/{uuid}","path":"/test","httpMethod":"GET","headers":null,"multiValueHeaders":null,"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":{"uuid":"test"},"stageVariables":null,"requestContext":{"resourceId":"6yd4vs","resourcePath":"/{uuid}","operationName":"get","httpMethod":"GET","extendedRequestId":"eOMmJFuJFiAFrPg=","requestTime":"10/Aug/2019:20:23:28 +0000","path":"/{uuid}","accountId":"XXXXXXXXXXX","protocol":"HTTP/1.1","stage":"test-invoke-stage","domainPrefix":"testPrefix","requestTimeEpoch":1565468608953,"requestId":"b6f095a2-bbac-11e9-80e2-23b77a1af624","identity":{"cognitoIdentityPoolId":null,"cognitoIdentityId":null,"apiKey":"test-invoke-api-key","principalOrgId":null,"cognitoAuthenticationType":null,"userArn":"arn:aws:sts::XXXXXXXXXXX:assumed-role/developers/uid","apiKeyId":"test-invoke-api-key-id","userAgent":"aws-internal/3 aws-sdk-java/1.11.590 Linux/4.9.137-0.1.ac.218.74.329.metal1.x86_64 OpenJDK_64-Bit_S [TRUNCATED]
Sat Aug 10 20:23:28 UTC 2019 : Sending request to https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:XXXXXXXXXXX:function:get_test/invocations
Sat Aug 10 20:23:28 UTC 2019 : Execution failed due to configuration error: Invalid permissions on Lambda function
Sat Aug 10 20:23:28 UTC 2019 : Method completed with status: 500

我的想法已经不多了... :-(

【问题讨论】:

    标签: amazon-web-services permissions aws-lambda aws-api-gateway terraform-provider-aws


    【解决方案1】:

    要调用 AWS API Gateway 资源,您的 AWS IAM 角色应该允许 "execute-api:Invoke" 操作。

    要调用 AWS Lambda 资源,您的 AWS IAM 角色应该允许 "lambda:InvokeFunction" 操作。

    我认为您缺少 AWS API Gateway 服务的 AWS Lambda 调用权限。在下面查看 Terraform 的代码参考。

    resource "aws_lambda_permission" "apigw_lambda" {
        statement_id  = "AllowExecutionFromAPIGateway"
        action        = "lambda:InvokeFunction"
        function_name = "${aws_lambda_function.lambda.function_name}"
        principal     = "apigateway.amazonaws.com"
        source_arn = "arn:aws:execute-api:${var.myregion}:${var.accountId}:${aws_api_gateway_rest_api.api.id}/*/${aws_api_gateway_method.method.http_method}${aws_api_gateway_resource.resource.path}"
    }
    

    此外,您需要将 "apigateway_invoke" 操作更新为 "execute-api:Invoke" 以允许开发人员调用您的 AWS API 网关。

    【讨论】:

    • 资源 apigateway_lambda_invoke_[delete|get|patch|post|put]_test 不应该这样做吗?另外,我已经使用以下块更新了 api_gateway_rest_api: policy = ", "Action": "execute-api:Invoke", "Resource": "" } ] } EOF 没有运气......
    • 尝试执行以下操作:使用 API Gateway 中的测试按钮确认您是否可以从其中调用您的 Lambda 函数。要评估您的资源策略,您需要调用 GetPolicy API;执行角色控制您的代码在 Lambda 中执行的操作,而不是谁可以调用它。您还可以在 API Gateway 中打开日志记录,这是一种更好地了解它代表您所做的事情的好方法。
    • 我已经更新了记录 lambda/api 网关的 tf 文件:gist.github.com/tburschka/a19c6651eb95d172dde5ee58c809284f 通过 curl 或测试按钮调用 lambda 时,日志很好......但是 API-Gateway 的日志只是一个大量空流(无需调用即可增长)=> 使用 API Gateway 中的测试按钮确认您是否可以从其中调用 Lambda 函数。正是这样不起作用,但是 curl 起作用了....
    【解决方案2】:

    在我通过 gui 创建方法后,会显示一个权限对话框,然后对该方法的测试和 api 调用起作用。所以查看了政策并在几分钟后看到了错误....源arn错误,我使用了部署arn但我必须使用rest_api arn

    ### wrong
    source_arn = "${aws_api_gateway_deployment.deployment_test.execution_arn}/*/*"
    
    ### correct
    source_arn = "${aws_api_gateway_rest_api.rest_api_test.execution_arn}/*/*"
    

    【讨论】:

      猜你喜欢
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 2017-04-09
      • 2017-06-23
      • 2021-02-08
      • 1970-01-01
      • 2019-12-31
      • 1970-01-01
      相关资源
      最近更新 更多