Associate AWS WAFv2 web acl to ApiGatewayV2

Viewed 3284

I want to associate a WAFv2 Web ACL to an API GatewayV2 HTTP stage.

Following the terraform docs, I tried this:

resource "aws_wafv2_web_acl_association" "this" {
  resource_arn = aws_apigatewayv2_stage.this.arn
  web_acl_arn  = aws_wafv2_web_acl.this.arn
}

However, this was not accepted, with the error being:

Error: WAFInvalidParameterException: Error reason: The ARN isn’t valid. A valid ARN begins with arn: and includes other information separated by colons or slashes., field: RESOURCE_ARN, parameter: arn:aws:apigateway:eu-west-2::/apis/abcd1234/stages/my-stage

From the AWS docs, the pattern for the ARN is:

arn:aws:apigateway:region::/restapis/api-id/stages/stage-name

However, only the ARNs of the old API Gateway uses "restapis" in its ARN. The v2 gateways uses just "apis.

  1. Is this why the ARN is invalid?
  2. How can I associate a AWS API GatewayV2 HTTP Stage to an AWS WAFv2 Web ACL?

As requested, here is code for a gateway:

resource "aws_apigatewayv2_api" "this" {
  name          = "example-http-api"
  protocol_type = "HTTP"
}

resource "aws_lambda_function" "this" {
  filename      = "example.zip"
  function_name = "Example"
  role          = var.lambda_arn
  handler       = "index.handler"
  runtime       = "nodejs10.x"
}

resource "aws_apigatewayv2_integration" "get" {
  api_id             = aws_apigatewayv2_api.this.id
  integration_type   = "AWS_PROXY"
  integration_method = "GET"
  integration_uri    = aws_lambda_function.this.invoke_arn
}

resource "aws_apigatewayv2_route" "get" {
  api_id    = aws_apigatewayv2_api.this.id
  route_key = "$default"
  target    = "path/${aws_apigatewayv2_integration.get.id}"
}

resource "aws_apigatewayv2_stage" "this" {
  api_id = aws_apigatewayv2_api.this.id
  name   = "example-stage"
}

And code for a Web-ACL:

 resource "aws_wafv2_web_acl" "this" {
  scope       = "REGIONAL"

  default_action {
    allow {}
  }

  rule {
    name     = "common-rule-set"
    priority = 1

    override_action {
      none {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "common-rule-set"
      sampled_requests_enabled   = false
    }
  }
  
  visibility_config {
    cloudwatch_metrics_enabled = false
    metric_name                = "web-acl"
    sampled_requests_enabled   = false
  }
}
2 Answers

I think there's a mistake in your code. For the API Gateway stage, you are using this block:

resource "aws_apigatewayv2_stage" "example" {
  api_id = aws_apigatewayv2_api.this.id
  name   = "example-stage"
}

while in the WAF association you are using:

resource "aws_wafv2_web_acl_association" "this" {
  resource_arn = aws_apigatewayv2_stage.this.arn
  web_acl_arn  = aws_wafv2_web_acl.this.arn
}

Change the resource_arn = aws_apigatewayv2_stage.this.arn to resource_arn = aws_apigatewayv2_stage.example.arn. You named the API Gateway stage resource example but you were trying to access attributes of a resource named this, which doesn't exist.

Related