1

We are using Terraform to describe an AWS apiGw objects and Checkov to check our plan output. Originally we found we could not get Checkov to pass as it always failed on CKV2_AWS_4 "Ensure API Gateway stage have logging level defined as appropriate".

Since then we have tried using both the Checkov site example and the Terraform example in place of our production apiGw but these fail too. Link to Checkov example:-

https://docs.bridgecrew.io/docs/ensure-api-gateway-stage-have-logging-level-defined-as-appropiate

The notation for the Checkov test failing is:-

metadata:
  id: "CKV2_AWS_4"
  name: "Ensure API Gateway stage have logging level defined as appropriate"
  category: "LOGGING"
definition:
  and:
    - resource_types:
        - aws_api_gateway_stage
      connected_resource_types:
        - aws_api_gateway_method_settings
      operator:  exists
      cond_type: connection
    - or:  
      - cond_type: "attribute"
        resource_types: 
          - "aws_api_gateway_method_settings"
        attribute: "settings.logging_level"
        operator: "equals"
        value: "ERROR"
      - cond_type: "attribute"
        resource_types: 
          - "aws_api_gateway_method_settings"
        attribute: "settings.logging_level"
        operator: "equals"
        value: "INFO"
    - cond_type: "attribute"
      resource_types: 
        - "aws_api_gateway_method_settings"
      attribute: "settings.metrics_enabled"
      operator: "equals"
      value: true 
    - cond_type: filter
      attribute: resource_type
      value:
        - aws_api_gateway_stage
      operator: within

Here is our TF which is an expanded version of the Terraform apiGw example:-

data "aws_caller_identity" "current" {}

locals {
  # The target account number
  account_id = data.aws_caller_identity.current.account_id
  # Local variable this is likely to be one of the following: development, nonproduction, production, feature/{name}.
  name_suffix = terraform.workspace
}

resource "aws_api_gateway_rest_api" "example" {
  body = jsonencode({
    openapi = "3.0.1"
    info = {
      title   = "example"
      version = "1.0"
    }
    paths = {
      "/path1" = {
        get = {
          x-amazon-apigateway-integration = {
            httpMethod           = "GET"
            payloadFormatVersion = "1.0"
            type                 = "HTTP_PROXY"
            uri                  = "https://ip-ranges.amazonaws.com/ip-ranges.json"
          }
        }
      }
    }
  })

  name = "example"
}

resource "aws_api_gateway_deployment" "example" {
  rest_api_id = aws_api_gateway_rest_api.example.id

  triggers = {
    redeployment = sha1(jsonencode(aws_api_gateway_rest_api.example.body))
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_api_gateway_stage" "example" {
  deployment_id = "${aws_api_gateway_deployment.example.id}"
  rest_api_id   = "${aws_api_gateway_rest_api.example.id}"
  stage_name    = "example"
  cache_cluster_enabled = true
  cache_cluster_size = 6.1
  xray_tracing_enabled = true

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.transfer_apigw_log_group.arn
    format = "$context.identity.sourceIp,$context.identity.caller,$context.identity.user,$context.requestTime,$context.httpMethod,$context.resourcePath,$context.protocol,$context.status,$context.responseLength,$context.requestId,$context.extendedRequestId"
  }

}

resource "aws_api_gateway_method_settings" "all" {
  rest_api_id = "${aws_api_gateway_rest_api.example.id}"
  stage_name  = "${aws_api_gateway_stage.example.stage_name}"
  method_path = "*/*"

  settings {
    metrics_enabled = true
    logging_level   = "ERROR"
    caching_enabled = true
  }
}

resource "aws_api_gateway_method_settings" "path_specific" {
  rest_api_id = aws_api_gateway_rest_api.example.id
  stage_name  = aws_api_gateway_stage.example.stage_name
  method_path = "path1/GET"

  settings {
    metrics_enabled = true
    logging_level   = "INFO"
    caching_enabled = true
  }
}

resource "aws_cloudwatch_log_group" "transfer_apigw_log_group" {
  name              = "transfer_apigw_log_group-${var.region}-${local.name_suffix}"
  retention_in_days = 30
  kms_key_id        = "alias/aws/apigateway"

}

When TF plan runs we get this result which Checkov reads:-

{
  "format_version": "1.1",
  "terraform_version": "1.2.7",
  "planned_values": {
    "root_module": {
      "child_modules": [
        {
          "resources": [
            {
              "address": "module.api_gateway_uk.aws_api_gateway_deployment.example",
              "mode": "managed",
              "type": "aws_api_gateway_deployment",
              "name": "example",
              "provider_name": "registry.terraform.io/hashicorp/aws",
              "schema_version": 0,
              "values": {
                "description": null,
                "stage_description": null,
                "stage_name": null,
                "triggers": {
                  "redeployment": "145be397ea51cabb14595b0f0ace006017953f0a"
                },
                "variables": null
              },
              "sensitive_values": {
                "triggers": {}
              }
            },
            {
              "address": "module.api_gateway_uk.aws_api_gateway_method_settings.all",
              "mode": "managed",
              "type": "aws_api_gateway_method_settings",
              "name": "all",
              "provider_name": "registry.terraform.io/hashicorp/aws",
              "schema_version": 0,
              "values": {
                "method_path": "*/*",
                "settings": [
                  {
                    "caching_enabled": true,
                    "logging_level": "ERROR",
                    "metrics_enabled": true,
                    "throttling_burst_limit": -1,
                    "throttling_rate_limit": -1
                  }
                ],
                "stage_name": "example"
              },
              "sensitive_values": {
                "settings": [
                  {}
                ]
              }
            },
            {
              "address": "module.api_gateway_uk.aws_api_gateway_method_settings.path_specific",
              "mode": "managed",
              "type": "aws_api_gateway_method_settings",
              "name": "path_specific",
              "provider_name": "registry.terraform.io/hashicorp/aws",
              "schema_version": 0,
              "values": {
                "method_path": "path1/GET",
                "settings": [
                  {
                    "caching_enabled": true,
                    "logging_level": "INFO",
                    "metrics_enabled": true,
                    "throttling_burst_limit": -1,
                    "throttling_rate_limit": -1
                  }
                ],
                "stage_name": "example"
              },
              "sensitive_values": {
                "settings": [
                  {}
                ]
              }
            },
            {
              "address": "module.api_gateway_uk.aws_api_gateway_rest_api.example",
              "mode": "managed",
              "type": "aws_api_gateway_rest_api",
              "name": "example",
              "provider_name": "registry.terraform.io/hashicorp/aws",
              "schema_version": 0,
              "values": {
                "body": "{\"info\":{\"title\":\"example\",\"version\":\"1.0\"},\"openapi\":\"3.0.1\",\"paths\":{\"/path1\":{\"get\":{\"x-amazon-apigateway-integration\":{\"httpMethod\":\"GET\",\"payloadFormatVersion\":\"1.0\",\"type\":\"HTTP_PROXY\",\"uri\":\"https://ip-ranges.amazonaws.com/ip-ranges.json\"}}}}}",
                "minimum_compression_size": -1,
                "name": "example",
                "parameters": null,
                "put_rest_api_mode": null,
                "tags": null
              },
              "sensitive_values": {
                "binary_media_types": [],
                "endpoint_configuration": [],
                "tags_all": {}
              }
            },
            {
              "address": "module.api_gateway_uk.aws_api_gateway_stage.example",
              "mode": "managed",
              "type": "aws_api_gateway_stage",
              "name": "example",
              "provider_name": "registry.terraform.io/hashicorp/aws",
              "schema_version": 0,
              "values": {
                "access_log_settings": [
                  {
                    "format": "$context.identity.sourceIp,$context.identity.caller,$context.identity.user,$context.requestTime,$context.httpMethod,$context.resourcePath,$context.protocol,$context.status,$context.responseLength,$context.requestId,$context.extendedRequestId"
                  }
                ],
                "cache_cluster_enabled": true,
                "cache_cluster_size": "6.1",
                "canary_settings": [],
                "client_certificate_id": null,
                "description": null,
                "documentation_version": null,
                "stage_name": "example",
                "tags": null,
                "variables": null,
                "xray_tracing_enabled": true
              },
              "sensitive_values": {
                "access_log_settings": [
                  {}
                ],
                "canary_settings": [],
                "tags_all": {}
              }
            },
            {
              "address": "module.api_gateway_uk.aws_cloudwatch_log_group.transfer_apigw_log_group",
              "mode": "managed",
              "type": "aws_cloudwatch_log_group",
              "name": "transfer_apigw_log_group",
              "provider_name": "registry.terraform.io/hashicorp/aws",
              "schema_version": 0,
              "values": {
                "kms_key_id": "alias/aws/apigateway",
                "name": "transfer_apigw_log_group-uk-default",
                "retention_in_days": 30,
                "skip_destroy": false,
                "tags": null
              },
              "sensitive_values": {
                "tags_all": {}
              }
            }
          ],
          "address": "module.api_gateway_uk"
        }
<SNIP>

I'm wondering which rule is being broken in the Checkov test? Could it be the 'connection' between objects like the apiGw Stage and the rest api? I am not clear how the tf plan output shows connections between objects but the tf plan passes without any issues.

Thanks in advance.

Jon

jon
  • 83
  • 1
  • 11
  • 1
    Not sure, but the URL says the log level should be `"ERROR"` whilst you have set it to `logging_level = "INFO"` in the second settings resource. – Marko E Nov 22 '22 at 16:29
  • Hi Marko, I think either ERROR or INFO is okay if I read the Checkov test correctly, there's an OR statement for "settings.logging_level"? – jon Nov 22 '22 at 17:12
  • Checkov has mysterious ways so I can't say I understand it. :) This was just a guess. ‍♂️ – Marko E Nov 22 '22 at 17:20
  • you can always ask us directly on our slack channel slack.bridgecrew.io – James Woolfenden Nov 24 '22 at 14:00

0 Answers0