英文:
Trouble viewing API Gateway CloudWatch logs and enabling through Terraform
问题
我正在使用Terraform来构建我的架构,具体来说是与CloudWatch Logs集成的API Gateway。然而,我遇到了一个问题,无法查看API Gateway CloudWatch日志。我已经集成了apigateway-sns,并且可以看到Lambda日志订阅了SNS主题,但我无法查看API Gateway方法的CloudWatch日志。
从控制台中,我注意到"CloudWatch Logs"选项未选中。我可以从控制台手动选中它,但我想通过Terraform进行配置。我已经检查了我的Terraform代码,但无法找出错误在哪里。
resource "aws_api_gateway_rest_api" "main" {
name = "gitlab-slack-api-${var.environment}"
description = "Gitlab Slack notifications integration"
endpoint_configuration {
types = ["REGIONAL"]
}
}
resource "aws_cloudwatch_log_group" "main_api_gw" {
name = "/aws/api-gw/${aws_api_gateway_rest_api.main.name}"
retention_in_days = 14
}
resource "aws_api_gateway_resource" "resource" {
path_part = "slack"
parent_id = aws_api_gateway_rest_api.main.root_resource_id
rest_api_id = aws_api_gateway_rest_api.main.id
}
resource "aws_api_gateway_method" "method" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = "POST"
authorization = "NONE"
request_parameters = {
"method.request.querystring.TopicArn" = false
"method.request.querystring.Message" = false
}
}
resource "aws_api_gateway_integration" "integration" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = aws_api_gateway_method.method.http_method
type = "AWS"
integration_http_method = "POST"
uri = "arn:aws:apigateway:${data.aws_region.region.name}:sns:action/Publish"
credentials = aws_iam_role.api_gateway_role.arn
request_parameters = {
"integration.request.querystring.TopicArn" = "'${aws_sns_topic.sns_topic_name.arn}'"
"integration.request.querystring.Message" = "method.request.body"
}
request_templates = {
"application/json" = <<EOF
{
"Message": "$input.body",
"TopicArn": "$input.params('TopicArn')"
}
EOF
}
}
resource "aws_api_gateway_method_response" "response_200" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = aws_api_gateway_method.method.http_method
status_code = "200"
}
resource "aws_api_gateway_integration_response" "integration_response" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = aws_api_gateway_method.method.http_method
status_code = aws_api_gateway_method_response.response_200.status_code
}
resource "aws_api_gateway_deployment" "deployment" {
depends_on = [aws_api_gateway_integration.integration]
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = var.environment
}
resource "aws_api_gateway_stage" "prod" {
depends_on = [aws_api_gateway_deployment.deployment]
stage_name = var.environment
rest_api_id = aws_api_gateway_rest_api.main.id
deployment_id = aws_api_gateway_deployment.deployment.id
access_log_settings {
destination_arn = aws_cloudwatch_log_group.main_api_gw.arn
format = jsonencode({
requestId = "$context.requestId",
requestTime = "$context.requestTime",
requestTimeEpoch = "$context.requestTimeEpoch",
path = "$context.path",
method = "$context.httpMethod",
status = "$context.status",
responseLength = "$context.responseLength"
})
}
}
resource "aws_api_gateway_method_settings" "all" {
rest_api_id = aws_api_gateway_rest_api.test_api_gateway.id
stage_name = aws_api_gateway_stage.prod.stage_name
method_path = "*/*"
settings {
logging_level = "INFO"
}
}
resource "aws_iam_policy" "api_gateway_sns_policy" {
name = "ApiGatewaySNSAccessPolicy"
description = "IAM policy for API Gateway to invoke SNS"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = ["sns:Publish"]
Resource = aws_sns_topic.sns_topic_name.arn
}
]
})
}
resource "aws_iam_role" "api_gateway_role" {
name = "ApiGatewaySNSAccessRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = { Service = "apigateway.amazonaws.com" }
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy_attachment" "api_gateway_role_policy_attachment" {
role = aws_iam_role.api_gateway_role.name
policy_arn = aws_iam_policy.api_gateway_sns_policy.arn
}
output "api_gateway_endpoint_url" {
value = aws_api_gateway_deployment.deployment.invoke_url
}
output "api_gateway_endpoint_arn" {
value = aws_api_gateway_rest_api.main.arn
}
希望这有助于解决您的问题。
英文:
I am using Terraform to build my architecture, specifically an API Gateway with CloudWatch Logs integration. However, I am encountering an issue where I cannot see the API Gateway CloudWatch logs. I have integrated the apigateway-sns and can see the Lambda logs subscribed to the SNS topic, but I am unable to view the CloudWatch logs for the API Gateway methods.
From the console, I noticed that the "CloudWatch Logs" option is unchecked. I can manually check it from the console, but I want to configure it through Terraform. I have checked my Terraform code, but I can't figure out where I am making a mistake.
resource "aws_api_gateway_rest_api" "main" {
name = "gitlab-slack-api-${var.environment}"
description = "Gitlab Slack notifications integration"
endpoint_configuration {
types = ["REGIONAL"]
}
}
resource "aws_cloudwatch_log_group" "main_api_gw" {
name = "/aws/api-gw/${aws_api_gateway_rest_api.main.name}"
retention_in_days = 14
}
resource "aws_api_gateway_resource" "resource" {
path_part = "slack"
parent_id = aws_api_gateway_rest_api.main.root_resource_id
rest_api_id = aws_api_gateway_rest_api.main.id
}
resource "aws_api_gateway_method" "method" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = "POST"
authorization = "NONE"
request_parameters = {
"method.request.querystring.TopicArn" = false
"method.request.querystring.Message" = false
}
}
resource "aws_api_gateway_integration" "integration" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = aws_api_gateway_method.method.http_method
type = "AWS"
integration_http_method = "POST"
uri = "arn:aws:apigateway:${data.aws_region.region.name}:sns:action/Publish"
credentials = aws_iam_role.api_gateway_role.arn
request_parameters = {
"integration.request.querystring.TopicArn" = "'${aws_sns_topic.sns_topic_name.arn}'"
"integration.request.querystring.Message" = "method.request.body"
}
request_templates = {
"application/json" = <<EOF
{
"Message": "$input.body",
"TopicArn": "$input.params('TopicArn')"
}
EOF
}
}
resource "aws_api_gateway_method_response" "response_200" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = aws_api_gateway_method.method.http_method
status_code = "200"
}
resource "aws_api_gateway_integration_response" "integration_response" {
rest_api_id = aws_api_gateway_rest_api.main.id
resource_id = aws_api_gateway_resource.resource.id
http_method = aws_api_gateway_method.method.http_method
status_code = aws_api_gateway_method_response.response_200.status_code
}
resource "aws_api_gateway_deployment" "deployment" {
depends_on = [aws_api_gateway_integration.integration]
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = var.environment
}
resource "aws_api_gateway_stage" "prod" {
depends_on = [aws_api_gateway_deployment.deployment]
stage_name = var.environment
rest_api_id = aws_api_gateway_rest_api.main.id
deployment_id = aws_api_gateway_deployment.deployment.id
access_log_settings {
destination_arn = aws_cloudwatch_log_group.main_api_gw.arn
format = jsonencode({
requestId = "$context.requestId"
requestTime = "$context.requestTime"
requestTimeEpoch = "$context.requestTimeEpoch"
path = "$context.path"
method = "$context.httpMethod"
status = "$context.status"
responseLength = "$context.responseLength"
})
}
}
resource "aws_api_gateway_method_settings" "all" {
rest_api_id = aws_api_gateway_rest_api.test_api_gateway.id
stage_name = aws_api_gateway_stage.prod.stage_name
method_path = "*/*"
settings {
logging_level = "INFO"
}
}
resource "aws_iam_policy" "api_gateway_sns_policy" {
name = "ApiGatewaySNSAccessPolicy"
description = "IAM policy for API Gateway to invoke SNS"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["sns:Publish"]
Resource = aws_sns_topic.sns_topic_name.arn
}
]
})
}
resource "aws_iam_role" "api_gateway_role" {
name = "ApiGatewaySNSAccessRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = { Service = "apigateway.amazonaws.com" }
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy_attachment" "api_gateway_role_policy_attachment" {
role = aws_iam_role.api_gateway_role.name
policy_arn = aws_iam_policy.api_gateway_sns_policy.arn
}
output "api_gateway_endpoint_url" {
value = aws_api_gateway_deployment.deployment.invoke_url
}
output "api_gateway_endpoint_arn" {
value = aws_api_gateway_rest_api.main.arn
}
答案1
得分: 1
您可以在阶段设置中为API Gateway启用日志记录,对应一个Terraform资源已存在。根据文档示例和您的代码,以下内容应该帮助您配置日志记录:
resource "aws_cloudwatch_log_group" "main_api_gw" {
name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.main.id}/${var.environment}"
retention_in_days = 14
}
resource "aws_api_gateway_stage" "main" {
stage_name = var.environment
access_log_settings {
destination_arn = aws_cloudwatch_log_group.main_api_gw.arn
format = "JSON" # 或 CLF/XML/CSV
}
}
为了避免循环依赖,您需要将阶段名称定义为一个变量,而在您的情况下似乎是 var.environment
。这是日志组 name
参数和API Gateway阶段资源的 stage_name
参数的一部分。另外,日志组的名称必须像这样,因为这是默认的API Gateway命名约定:
在启用此功能时管理CloudWatch日志组时,可以使用
aws_cloudwatch_log_group
资源,其中名称与API Gateway命名约定匹配。
format
参数是必需的,可以是 JSON/XML/CLF/CSV
中的一个,您可以在文档中了解更多信息。
编辑:由于原始帖子未显示所有代码,且阶段资源已存在并正确引用了日志组,需要更改的是日志组名称(如上所述)和IAM角色权限。除了在权限策略中允许SNS外,还需要添加CloudWatch日志:
resource "aws_iam_policy" "api_gateway_sns_policy" {
name = "ApiGatewaySNSAccessPolicy"
description = "API Gateway调用SNS的IAM策略"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = ["sns:Publish"],
Resource = aws_sns_topic.sns_topic_name.arn
},
{
Effect = "Allow",
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents",
"logs:GetLogEvents",
"logs:FilterLogEvents"
],
Resource = "*"
}
]
})
}
英文:
You can enable logging for API Gateway in the Stage settings, for which a terraform resource exists. Based on the example from the documentation and your code, the following should enable you to configure logging:
resource "aws_cloudwatch_log_group" "main_api_gw" {
name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.main.id}/${var.environment}"
retention_in_days = 14
}
resource "aws_api_gateway_stage" "main" {
stage_name = var.environment
access_log_settings {
destination_arn = aws_cloudwatch_log_group.main_api_gw.arn
format = "JSON" # or CLF/XML/CSV
}
}
In order to avoid circular dependency, you would need to define the stage name as a variable, which in your case seems to be var.environment
. This is a part of the log group name
argument and stage_name
argument of the API Gateway stage resource. Additionally, the name of the log group has to be like this, as this is the default API Gateway naming convention:
> To manage the CloudWatch Log Group when this feature is enabled, the aws_cloudwatch_log_group
resource can be used where the name matches the API Gateway naming convention.
The format
argument is required and can take in one of "JSON"/"XML"/"CLF"/"CSV"
, which you can read more about in the documentation.
EDIT: Since the original post didn't show all the code, and the stage resource was present, referencing the log group properly, what would need to change is the log group name (as described above) and the IAM role permissions. Besides having SNS allowed in the permissions policy, CloudWatch logs also need to be added:
resource "aws_iam_policy" "api_gateway_sns_policy" {
name = "ApiGatewaySNSAccessPolicy"
description = "IAM policy for API Gateway to invoke SNS"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["sns:Publish"]
Resource = aws_sns_topic.sns_topic_name.arn
},
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents",
"logs:GetLogEvents",
"logs:FilterLogEvents"
]
Resource = "*"
}
]
})
}
答案2
得分: 0
找到解决方案:
ApiGate 需要一个角色来允许 CloudWatch 发布日志,某种方式 Marko 的策略没有生效(不知道为什么)。我使用了 AWS 管理的角色 AmazonAPIGatewayPushToCloudWatchLogs 和资源 aws_api_gateway_method_settings 来启用日志记录(INFO、ERROR、OFF)。现在我可以在 CloudWatch 中看到 API Gateway 的日志。
谢谢 Marko,在这个问题上付出了一些努力。
以下是 Terraform 代码:
resource "aws_api_gateway_deployment" "deployment" {
depends_on = [aws_api_gateway_integration.integration]
rest_api_id = aws_api_gateway_rest_api.main.id
lifecycle {
create_before_destroy = true
}
}
resource "aws_api_gateway_stage" "prod" {
depends_on = [aws_cloudwatch_log_group.main_api_gw]
stage_name = var.environment
rest_api_id = aws_api_gateway_rest_api.main.id
deployment_id = aws_api_gateway_deployment.deployment.id
access_log_settings {
destination_arn = aws_cloudwatch_log_group.main_api_gw.arn
format = jsonencode({
requestId = "$context.requestId"
requestTime = "$context.requestTime"
requestTimeEpoch = "$context.requestTimeEpoch"
path = "$context.path"
method = "$context.httpMethod"
status = "$context.status"
responseLength = "$context.responseLength"
})
}
}
resource "aws_iam_role" "api_gateway_cloud_watch_role" {
name = "AmazonAPIGatewayPushToCloudWatchLogs"
assume_role_policy = <<-EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "api_gateway_cloudwatchlogs" {
role = aws_iam_role.api_gateway_cloud_watch_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
}
resource "aws_api_gateway_account" "api_gateway_account" {
cloudwatch_role_arn = aws_iam_role.api_gateway_cloud_watch_role.arn
}
resource "aws_api_gateway_method_settings" "api_gateway_log_settings" {
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = var.environment
method_path = "*/*"
settings {
metrics_enabled = true
logging_level = "INFO"
}
}
参考链接:
从这里获取了参考。
英文:
Found solution:
ApiGate needs a role to allow CloudWatch to publish logs, some how Marko's policy did not work(don't why). I have used the AWS managed role AmazonAPIGatewayPushToCloudWatchLogs and the resource aws_api_gateway_method_settings for enabling the logs(INFO, ERROR,OFF). Now I can see the API Gateway logs in CloudWatch.
Thank you Marko, put some effort on the issue.
Here is Terraform:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
resource "aws_api_gateway_deployment" "deployment" {
depends_on = [aws_api_gateway_integration.integration]
rest_api_id = aws_api_gateway_rest_api.main.id
lifecycle {
create_before_destroy = true
}
}
resource "aws_api_gateway_stage" "prod" {
depends_on = [aws_cloudwatch_log_group.main_api_gw]
stage_name = var.environment
rest_api_id = aws_api_gateway_rest_api.main.id
deployment_id = aws_api_gateway_deployment.deployment.id
access_log_settings {
destination_arn = aws_cloudwatch_log_group.main_api_gw.arn
format = jsonencode({
requestId = "$context.requestId"
requestTime = "$context.requestTime"
requestTimeEpoch = "$context.requestTimeEpoch"
path = "$context.path"
method = "$context.httpMethod"
status = "$context.status"
responseLength = "$context.responseLength"
})
}
}
resource "aws_iam_role" "api_gateway_cloud_watch_role" {
name = "AmazonAPIGatewayPushToCloudWatchLogs"
assume_role_policy = <<-EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "api_gateway_cloudwatchlogs" {
role = aws_iam_role.api_gateway_cloud_watch_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
}
resource "aws_api_gateway_account" "api_gateway_account" {
cloudwatch_role_arn = aws_iam_role.api_gateway_cloud_watch_role.arn
}
resource "aws_api_gateway_method_settings" "api_gateway_log_settings" {
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = var.environment
method_path = "*/*"
settings {
metrics_enabled = true
logging_level = "INFO"
}
}
<!-- end snippet -->
Ref:
Took Ref from here as well
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论