GoogleCloudPlatform / terraform-validator

Terraform Validator is not an officially supported Google product; it is a library for conversion of Terraform plan data to CAI Assets. If you have been using terraform-validator directly in the past, we recommend migrating to `gcloud beta terraform vet`.
https://cloud.google.com/docs/terraform/policy-validation
Apache License 2.0
439 stars 95 forks source link

GCPZomputeZoneConstraintV1 does not detect invalid zones with TFV #134

Open eila-elyas opened 4 years ago

eila-elyas commented 4 years ago

Have a simple terraform file that deploys an instance in us-east4-c zone.

main tf

I modified the sample compute-zone.yaml constraint to only allow instances in asia-east1-b and placed it in my constraints directory.

constraint

Running terraform validator doesn't alert on the violation.

false negative

Have tried with gs://terraform-validator/releases/2019-11-07/terraform-validator-linux-amd64 and gs://terraform-validator/releases/2020-03-05/terraform-validator-linux-amd64.

Another funny behavior I noticed is that when I change the name of the 'constraints' directory within the 'policies' directory so that a 'constraints' directory no longer exists in the 'policies' directory, and then run terraform-validator, I still get no errors. However, if I change the name of the 'policies' directory so that the 'policy-library' directory no longer has a 'policies' directory, and then run terraform-validator, I get a 'no such file or directory' error.

Not sure why missing the 'constraints' directory doesn't trigger a 'no such file or directory' error.

Forseti Scanner correctly identifies violation with this same constraint setup.

morgante commented 4 years ago

Thanks for the report! This is indeed rather puzzling.

Could you try scanning the environment with CFT Scorecard and the same constraints to see if it detects a violation? That'll help to determine where the issue is occurring.

Another funny behavior I noticed is that when I change the name of the 'constraints' directory within the 'policies' directory so that a 'constraints' directory no longer exists in the 'policies' directory, and then run terraform-validator, I still get no errors.

This is expected/intended behavior. We actually pick up all the yaml files from the policies/ directory automatically so its internal organization doesn't matter. All that is actually required is a policy directory, you can organize within it how you like.

eila-elyas commented 4 years ago

Scanned environment using CFT Scorecard with the same constraints and violations were detected.

eila@cloudshell:~ (project_name)$ ./cft scorecard --policy-path=./policy-library/ --dir-path=inventory Generating CFT scorecard

6 total issues found

Other: 6 issues found

compute_zone_allowlist_one: 6 issues

Operational Efficiency: 0 issues found

Security: 0 issues found

Reliability: 0 issues found

morgante commented 4 years ago

@eila-elyas Sorry for the delay in looking at this. If this is still occurring, could you share the output of running the terraform-validator convert command?

robertojrojas commented 4 years ago

Hi @morgante I'm running into this issue as well. Where validations are not flagged and always get:

No violations found.

I'm not sure if this is related or not, but I see the following when I run it with --verbose flag Noticed the Failed to retrieve project_id line followed by ERROR log entries. The project id is a valid one, I just changed here in this output.

...
2020/06/18 11:26:31 [INFO] Instantiating Google Cloud Spanner client for path https://spanner.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating Google Cloud Dataproc client for path https://dataproc.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating Google Cloud Dataproc Beta client for path 
2020/06/18 11:26:31 [INFO] Instantiating Filestore client for path https://file.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating Google Cloud IoT Core client for path https://cloudiot.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating App Engine client for path https://appengine.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating Cloud Composer client for path https://composer.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating Service Networking client for path https://servicenetworking.googleapis.com/
2020/06/18 11:26:31 [INFO] Instantiating Google Cloud Storage Transfer client for path https://storagetransfer.googleapis.com/
2020/06/18 11:26:32 [INFO] Failed to retrieve project_id for //compute.googleapis.com/projects/myvalidprojectid/zones/us-west2-b/instances/test-validator from resource
ERROR: logging before flag.Parse: I0618 11:26:41.532895 1852886 validator.go:177] starting 24 workers
ERROR: logging before flag.Parse: I0618 11:26:41.532978 1852886 validator.go:186] worker 1 starting
ERROR: logging before flag.Parse: I0618 11:26:41.533049 1852886 validator.go:186] worker 0 starting
ERROR: logging before flag.Parse: I0618 11:26:41.533054 1852886 validator.go:186] worker 12 starting
ERROR: logging before flag.Parse: I0618 11:26:41.533076 1852886 validator.go:186] worker 9 starting
...

Here is how I ran it:

terraform-validator validate ./terraform.tfplan.json --policy-path=${POLICY_PATH}  --verbose=true

Here is the version I'm using:

terraform-validator version
Build version: 2020-03-05
morgante commented 4 years ago

@robertojrojas Can you share the Terraform config you're seeing this with?

robertojrojas commented 4 years ago

@morgante thanks for responding. Here is the TF config. It's pretty basic. Basically, I'm validating the zone, so you'll see that both values are different.

resource "google_compute_instance" "default" {
  name         = "test-validator"
  machine_type = "n1-standard-1"
  zone         = "us-west2-b"
  project      = "myvalidprojectid"

  tags = ["foo", "bar"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }

  // Local SSD disk
  scratch_disk {
    interface = "SCSI"
  }

  network_interface {
    network = "default"

    access_config {
      // Ephemeral IP
    }
  }

  metadata = {
    foo = "bar"
  }

  metadata_startup_script = "echo hi > /test.txt"

  service_account {
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
  }
}

And I'm using a validation policy from this repo's sample directory:

apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPComputeZoneConstraintV1
metadata:
  name: compute_zone_allowlist_one
  annotations:
    description: Checks the instances and Persistent Disks are in desired zones.
spec:
  severity: high
  parameters:
    mode: "allowlist"
    zones:
    - asia-east1-b
    exemptions: []
morgante commented 4 years ago

@robertojrojas Does myvalidprojectid already exist or are you attempting to create it in this same Terraform plan?

robertojrojas commented 4 years ago

@morgante Yes, the project already exists.

robertojrojas commented 4 years ago

Hi @morgante , have you made any progress on this issue?

tunaluna94 commented 3 years ago

Any update on this I am having a similar issue on "Build version: v0.3.0"? Running terraform-validator with one constraint in policy-library/policies/constraints/storage_location.yaml with slight adjustments mode: denylist, location - US and it validates with no violations found.

  required_providers {
    google = {
      source = "hashicorp/google"
      version = "3.75.0"
    }
  }

  backend "gcs" {
    bucket = "terraformstatedemo101"
    prefix = "terraform/state"
  }
}

provider "google" {
  region = "us-central1"
  zone = "us-central1-c"
  project = "$project"
}

resource "google_storage_bucket" "testing" {
  name = "tfvalidatortest"
  location = "US-WEST1"

}

constraint:
apiVersion: constraints.gatekeeper.sh/v1alpha1
kind: GCPStorageLocationConstraintV1
metadata:
  name: allow_some_storage_location
  annotations:
    description: Checks Cloud Storage bucket locations against allowed or disallowed
      locations.
    bundles.validator.forsetisecurity.org/healthcare-baseline-v1: security
spec:
  severity: high
  match:
    target: # {"$ref":"#/definitions/io.k8s.cli.setters.target"}
    - "organizations/**"
  parameters:
    mode: "denylist"
    locations:
    - US
    exemptions: []
daniel-cit commented 3 years ago

Hi @tunaluna94 the check that is done in the rule https://github.com/forseti-security/policy-library/blob/778c4b288627761ffa0dce81f0dd4dffd1db612f/policies/templates/gcp_storage_location_v1.yaml#L91-L96

# Check that location is in allowlist/denylist
target_locations := params.locations
asset_location := asset.resource.data.location
location_matches := ({upper(asset_location)} & cast_set(target_locations)) | ({lower(asset_location)} & cast_set(target_locations))
target_location_match_count(params.mode, desired_count)
count(location_matches) == desired_count

Is just checking if the lower case or upper case of the Asset(resource) location is in the deny list considering an equal. So it is just checking if US-WEST1 or us-west1 in in the deny list that contains "US", which is false, that is the reason for the no violations found. If you want to deny all the US regions you would need to list all of them in the denylist.

melinath commented 2 years ago

b/211493558