Terraform: настройка доставки подписки на журнал cloudwatch на lambda?
Мне нужно отправить журналы Cloudwatch в службу анализа журналов.
Я следил за этими статьями здесь и здесь, и все работало вручную, не беспокоясь.
Теперь я пытаюсь автоматизировать все это с помощью Terraform (роли / политики, группы безопасности, группа журналов cloudwatch, лямбда-выражения и запуск лямбда-выражения из группы журналов).
Но я не могу понять, как использовать TF для настройки AWS для запуска лямбды из журналов облачных часов.
Я могу связать два ресурса TF вручную, выполнив следующее (в пользовательском интерфейсе веб-консоли Lambda):
- перейдите в раздел "Триггеры" лямбда-функции
- нажмите "Добавить триггер"
- выберите "Журналы Cloudwatch" из списка типов триггеров
- выберите группу журналов, которую я хочу, чтобы вызвать лямбду
- введите имя фильтра
- оставьте шаблон фильтра пустым (подразумевается триггер для всех потоков журнала)
- убедитесь, что выбран "триггер включения"
- нажмите кнопку отправки
Как только это будет сделано, лямбда будет отображаться на консоли журналов cloudwatch в столбце подписок - отображается как "Lambda (cloudwatch-sumologic-lambda)".
Я пытался создать подписку со следующим ресурсом TF:
resource "aws_cloudwatch_log_subscription_filter" "cloudwatch-sumologic-lambda-subscription" {
name = "cloudwatch-sumologic-lambda-subscription"
role_arn = "${aws_iam_role.jordi-waf-cloudwatch-lambda-role.arn}"
log_group_name = "${aws_cloudwatch_log_group.jordi-waf-int-app-loggroup.name}"
filter_pattern = "logtype test"
destination_arn = "${aws_lambda_function.cloudwatch-sumologic-lambda.arn}"
}
Но это не так с:
* aws_cloudwatch_log_subscription_filter.cloudwatch-sumologic-lambda-subscription: InvalidParameterException: destinationArn for vendor lambda cannot be used with roleArn
Я нашел этот ответ о настройке аналогичной вещи для запланированного события, но это не похоже на то, что делают действия консоли, которые я описал выше (метод пользовательского интерфейса консоли не создает событие / правило, которое я вижу).
Может кто-нибудь дать мне указатель на то, что я делаю не так, пожалуйста?
1 ответ
У меня был неправильно определен ресурс "aws_cloudwatch_log_subscription_filter" - в этой ситуации не следует указывать аргумент "role_arn".
Вам также необходимо добавить ресурс aws_lambda_permission (с отношением "depen_on", определенным для фильтра, или TF может сделать это в неправильном порядке).
Обратите внимание, что интерфейс лямбда-консоли AWS незаметно добавляет вам разрешение на лямбду, поэтому имейте в виду, что "aws_cloudwatch_log_subscription_filter" будет работать без ресурса разрешений, если вы выполнили то же действие ранее в пользовательском интерфейсе консоли.
Необходимая конфигурация TF выглядит следующим образом (последние два ресурса являются соответствующими для настройки фактического триггера cloudwatch->lambda):
// intended for application logs (access logs, modsec, etc.)
resource "aws_cloudwatch_log_group" "test-app-loggroup" {
name = "test-app"
retention_in_days = 90
}
resource "aws_security_group" "cloudwatch-sumologic-lambda-sg" {
name = "cloudwatch-sumologic-lambda-sg"
tags {
Name = "cloudwatch-sumologic-lambda-sg"
}
description = "Security group for lambda to move logs from CWL to SumoLogic"
vpc_id = "${aws_vpc.dev-vpc.id}"
}
resource "aws_security_group_rule" "https-egress-cloudwatch-sumologic-to-internet" {
type = "egress"
from_port = 443
to_port = 443
protocol = "tcp"
security_group_id = "${aws_security_group.cloudwatch-sumologic-lambda-sg.id}"
cidr_blocks = ["0.0.0.0/0"]
}
resource "aws_iam_role" "test-cloudwatch-lambda-role" {
name = "test-cloudwatch-lambda-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy" "test-cloudwatch-lambda-policy" {
name = "test-cloudwatch-lambda-policy"
role = "${aws_iam_role.test-cloudwatch-lambda-role.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CopiedFromTemplateAWSLambdaVPCAccessExecutionRole1",
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface"
],
"Resource": "*"
},
{
"Sid": "CopiedFromTemplateAWSLambdaVPCAccessExecutionRole2",
"Effect": "Allow",
"Action": [
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface"
],
"Resource": "arn:aws:ec2:ap-southeast-2:${var.dev_vpc_account_id}:network-interface/*"
},
{
"Sid": "CopiedFromTemplateAWSLambdaBasicExecutionRole1",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:ap-southeast-2:${var.dev_vpc_account_id}:*"
},
{
"Sid": "CopiedFromTemplateAWSLambdaBasicExecutionRole2",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-southeast-2:${var.dev_vpc_account_id}:log-group:/aws/lambda/*"
]
},
{
"Sid": "CopiedFromTemplateAWSLambdaAMIExecutionRole",
"Effect": "Allow",
"Action": [
"ec2:DescribeImages"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_lambda_function" "cloudwatch-sumologic-lambda" {
function_name = "cloudwatch-sumologic-lambda"
filename = "${var.lambda_dir}/cloudwatchSumologicLambda.zip"
source_code_hash = "${base64sha256(file("${var.lambda_dir}/cloudwatchSumologicLambda.zip"))}"
handler = "cloudwatchSumologic.handler"
role = "${aws_iam_role.test-cloudwatch-lambda-role.arn}"
memory_size = "128"
runtime = "nodejs4.3"
// set low because I'm concerned about cost-blowout in the case of mis-configuration
timeout = "15"
vpc_config = {
subnet_ids = ["${aws_subnet.dev-private-subnet.id}"]
security_group_ids = ["${aws_security_group.cloudwatch-sumologic-lambda-sg.id}"]
}
}
resource "aws_lambda_permission" "test-app-allow-cloudwatch" {
statement_id = "test-app-allow-cloudwatch"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.cloudwatch-sumologic-lambda.arn}"
principal = "logs.ap-southeast-2.amazonaws.com"
source_arn = "${aws_cloudwatch_log_group.test-app-loggroup.arn}"
}
resource "aws_cloudwatch_log_subscription_filter" "test-app-cloudwatch-sumologic-lambda-subscription" {
depends_on = ["aws_lambda_permission.test-app-allow-cloudwatch"]
name = "cloudwatch-sumologic-lambda-subscription"
log_group_name = "${aws_cloudwatch_log_group.test-app-loggroup.name}"
filter_pattern = ""
destination_arn = "${aws_lambda_function.cloudwatch-sumologic-lambda.arn}"
}
Работа с Terraform v0.12.29
и поставщик AWS v3.1.0
Я столкнулся со странной проблемой, которая стоила мне нескольких часов отладки.
Чтобы сэкономить другим драгоценное время, я поделюсь им в качестве дополнения к принятому ответу.
Значение группы журналов cloudwatch arn:
${aws_cloudwatch_log_group.test-app-loggroup.arn}
Не интерполируется правильно - отсутствует ":*
"в конце вывода.
Это приводит к ошибке ниже:
Ошибка при создании {the-call-service}: InvalidCloudWatchLogsLogGroupArnException: проверьте группу журналов ARN: {the-call-service} не может проверить это.
Добавление :*
postfix решил проблему:
source_arn = "${aws_cloudwatch_log_group.test-app-loggroup.arn}:*" #<----Notice the :* postfix