mondoohq / cnspec

An open source, cloud-native security to protect everything from build to runtime
https://cnspec.io
Other
275 stars 13 forks source link

🐛 cnspec asset filter that use "&&" incorrectly scans resources that do not match both expressions #691

Closed scottford-io closed 1 year ago

scottford-io commented 1 year ago

Describe the bug image

I have defined an asset filter in a policy for scanning terraform-hcl that uses && requiring that both queries in the filter match in order for the check to run against a specific Terraform resource. The filter does not respect the && and will incorrectly run against Terraform code that only matches one side of the expression.

The check that is incorrectly executing contains the following asset filter:

filters: asset.platform == "terraform-hcl" && terraform.resources.where( nameLabel == "aws_account_alternate_contact")

In order for the check to run it should match both sides of the expression:

  1. asset.platform == "terraform-hcl"
  2. There should be one resource discovered with the nameLabel == "aws_account_alternate_contact"

What I see is that if I scan a folder that does not contain any aws_account_alternate_contact resources, the check runs. cnspec shell validates that the folder I am scanning does not contain any aws_account_alternate_contact resources:

cnspec> terraform.resources
terraform.resources: [
  0: terraform.block type="resource" labels=[
  0: "aws_launch_configuration"
  1: "as_conf"
]
  1: terraform.block type="resource" labels=[
  0: "aws_autoscaling_group"
  1: "bar"
]
]

NOTE THIS DOES NOT HAPPEN WHEN SCANNING TERRAFORM PLAN FILES

To Reproduce

create terraform/autoscaling/main.tf

provider "aws" {
  region = "us-east-1"
}

data "aws_ami" "ubuntu2204" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"]
}

resource "aws_launch_configuration" "as_conf" {
  image_id                    = data.aws_ami.ubuntu2204.id
  instance_type               = "m4.large"
  associate_public_ip_address = false

  metadata_options {
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "bar" {
  name                 = "terraform-asg-example"
  max_size             = 5
  min_size             = 2
  launch_configuration = aws_launch_configuration.as_conf.name
}

Create security policy

policies:
    - uid: aws-security-hub
      name: AWS Security Hub
      version: 1.0.0
      scoring_system: 2
      authors:
        - name: Mondoo, Inc.
          email: hello@mondoo.com
      tags:
        mondoo.com/platform: aws,cloud
        mondoo.com/category: security
      groups: 
        - title: AWS account controls
          checks: 
            - uid: aws-security-hub-security-account-information-provided
            - uid: aws-security-hub-security-account-part-of-organizations
        - title: AWS Certificate Manager controls
          checks: 
            - uid: aws-security-hub-acm-certificate-expiration-check
            - uid: aws-security-hub-acm-certificate-rsa-check
        - title: API Gateway controls
          checks: 
            - uid: aws-security-hub-api-gw-execution-logging-enabled
            - uid: aws-security-hub-api-gw-ssl-enabled
            - uid: aws-security-hub-api-gw-xray-enabled
            - uid: aws-security-hub-api-gw-associated-with-waf
            - uid: aws-security-hub-api-gw-cache-encrypted
            - uid: aws-security-hub-api-gwv2-authorization-type-configured
            - uid: aws-security-hub-api-gwv2-access-logs-enabled
        - title: AWS AppSync controls
          checks:
            - uid: aws-security-hub-appsync-logging-enabled
        - title: Athena controls 
          checks: 
            - uid: aws-security-hub-athena-workgroup-encrypted-at-rest
        - title: Autoscaling controls 
          checks: 
            - uid: aws-security-hub-autoscaling-group-elb-healthcheck-required
            - uid: aws-security-hub-autoscaling-multiple-az
            - uid: aws-security-hub-autoscaling-launchconfig-requires-imdsv2
            - uid: aws-security-hub-autoscaling-launch-config-hop-limit
            - uid: aws-security-hub-autoscaling-launch-config-public-ip-disabled
            - uid: aws-security-hub-autoscaling-multiple-instance-types
            - uid: aws-security-hub-autoscaling-launch-template
queries:
  - uid: aws-security-hub-security-account-information-provided
    title: '[Account.1] Security contact information should be provided for an AWS account' 
    impact: 50 
    docs: 
      desc: |
        **Related requirements:** NIST.800-53.r5 CM-2, NIST.800-53.r5 CM-2(2)

        **Category:** Identify > Resource Configuration

        **Impact:** Medium

        **Resource type:** `AWS::::Account`

        This checks if an Amazon Web Services (AWS) account has security contact information. The check fails if security contact information is not provided for the account.

        Alternate security contacts allow AWS to contact another person about issues with your account in case you're unavailable. Notifications can be from AWS Support, or other AWS service teams about security-related topics associated with your AWS account usage.
    variants:
      - uid: aws-security-hub-security-account-information-provided-api
      - uid: aws-security-hub-security-account-information-provided-terraform-hcl
      - uid: aws-security-hub-security-account-information-provided-terraform-plan
  - uid: aws-security-hub-security-account-information-provided-api 
    filters: asset.platform == "aws"
    mql: true
    docs:
      remediation: 
        - id: console 
          desc: |
            #### Adding or updating alternate contacts

            Alternate contacts allows AWS to contact another person about issues with your account, even if you're unavailable. The alternate contact doesn't have to be a specific person. You could instead add an email distribution list if you have a team that manages billing, operations and security related issues.

            **To add or update alternate contacts**

            1. Sign in to the **Account** page in the Billing and Cost Management console at https://console.aws.amazon.com/billing/home?#/account.
            2. Under **Alternate contacts**, choose **Edit**.
            3. Enter your updated information and choose **Update**.
  - uid: aws-security-hub-security-account-information-provided-terraform-hcl 
    filters: asset.platform == "terraform-hcl" && terraform.resources.where( nameLabel == "aws_account_alternate_contact")
    mql: terraform.resources.where( nameLabel == "aws_account_alternate_contact" ).one( arguments['alternate_contact_type'] == "SECURITY" )
    docs:
      remediation:
        - id: terraform
          desc: |
            The `aws_account_alternate_contact` manages the specified alternate contact attached to an AWS Account.
        resource "aws_account_alternate_contact" "security" {

          alternate_contact_type = "SECURITY"

          name          = "Example"
          title         = "Example"
          email_address = "test@example.com"
          phone_number  = "+1234567890"
        }
        ```

Expected behavior A clear and concise description of what you expected to happen.

Screenshots or CLI Output If applicable, add screenshots or the CLI output to help explain your problem.

Desktop (please complete the following information):

Additional context Add any other context about the problem here.

scottford-io commented 1 year ago

@chris-rock was able to properly diagnose this, and it is not a bug. Per @chris-rock

.where is not a truthy condition as you use in filters: asset.platform == "terraform-hcl" && terraform.resources.where( nameLabel == "aws_account_alternate_contact")

I updated the filter to filters: asset.platform == "terraform-hcl" && terraform.resources.any( nameLabel == "aws_account_alternate_contact") and the issue was resolved.