web-dev-qa-db-fra.com

Terraform: configurer la livraison de l'abonnement aux journaux Cloudwatch à Lambda?

Je dois envoyer mes journaux cloudwatch à un service d'analyse de journaux.

J'ai suivi ces articles ici et ici et je l'ai fait fonctionner à la main, pas de soucis.

Maintenant, j'essaie d'automatiser tout cela avec Terraform (rôles/politiques, groupes de sécurité, groupe de journaux cloudwatch, lambda et déclencher le lambda à partir du groupe de journaux).

Mais je ne peux pas comprendre comment utiliser TF pour configurer AWS pour déclencher le lambda à partir des journaux cloudwatch.

Je peux lier les deux ressources TF ensemble à la main en procédant comme suit (dans l'interface utilisateur de la console Web Lambda):

  • aller dans la section "Déclencheurs" de la fonction lambda
  • cliquez sur "Ajouter un déclencheur"
  • sélectionnez "journaux cloudwatch" dans la liste des types de déclencheurs
  • sélectionnez le groupe de journaux que je veux déclencher le lambda
  • entrez un nom de filtre
  • laisser le modèle de filtre vide (impliquant un déclencheur sur tous les flux de journaux)
  • assurez-vous que "activer le déclencheur" est sélectionné
  • cliquez sur le bouton soumettre

Une fois cela fait, le lambda apparaît sur la console des journaux cloudwatch dans la colonne des abonnements - s'affiche comme "Lambda (cloudwatch-sumologic-lambda)".

J'ai essayé de créer l'abonnement avec la ressource TF suivante:

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

Mais cela échoue avec:

aws_cloudwatch_log_subscription_filter.cloudwatch-sumologic-lambda-subscription: InvalidParameterException: destinationArn pour le fournisseur lambda ne peut pas être utilisé avec roleArn

J'ai trouvé cette réponse sur la configuration d'une chose similaire pour un événement planifié, mais cela ne semble pas être équivalent à ce que font les actions de la console que j'ai décrites ci-dessus (la méthode de l'interface utilisateur de la console ne crée pas de événement/règle que je peux voir).

Quelqu'un peut-il me donner un pointeur sur ce que je fais mal s'il vous plaît?

22
Shorn

J'ai eu la ressource aws_cloudwatch_log_subscription_filter Mal définie - vous ne devez pas fournir l'argument role_arn Dans cette situation.

Vous devez également ajouter une ressource aws_lambda_permission (Avec une relation depends_on Définie sur le filtre ou TF peut le faire dans le mauvais ordre).

Notez que l'interface utilisateur de la console AWS lambda ajoute de manière invisible l'autorisation lambda pour vous, alors prenez garde que aws_cloudwatch_log_subscription_filter Fonctionnera sans la ressource d'autorisation si vous avez déjà fait la même action auparavant dans l'interface utilisateur de la console.

La configuration TF nécessaire ressemble à ceci (les deux dernières ressources sont celles pertinentes pour configurer le déclencheur cloudwatch->lambda Réel):

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

[~ # ~] modifier [~ # ~] : veuillez noter que le code TF ci-dessus a été écrit il y a des années, en utilisant la version 0.11.x - cela devrait encore fonctionner mais il peut y avoir de meilleures façons de faire les choses. Plus précisément, n'utilisez pas une politique en ligne comme celle-ci sauf si nécessaire, utilisez plutôt un aws_iam_policy_document - ils sont juste beaucoup plus faciles à maintenir au fil du temps.

41
Shorn