diff --git a/README.md b/README.md index 5a0295bb1..55179fbe6 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,14 @@ The following resources are available in the InSpec GCP Profile - [google_container_clusters](docs/resources/google_container_clusters.md) - [google_container_node_pool](docs/resources/google_container_node_pool.md) - [google_container_node_pools](docs/resources/google_container_node_pools.md) +- [google_kms_crypto_key](docs/resources/google_kms_crypto_key.md) +- [google_kms_crypto_key_iam_binding](docs/resources/google_kms_crypto_key_iam_binding.md) +- [google_kms_crypto_key_iam_bindings](docs/resources/google_kms_crypto_key_iam_bindings.md) +- [google_kms_crypto_keys](docs/resources/google_kms_crypto_keys.md) +- [google_kms_key_ring](docs/resources/google_kms_key_ring.md) +- [google_kms_key_ring_iam_binding](docs/resources/google_kms_key_ring_iam_binding.md) +- [google_kms_key_ring_iam_bindings](docs/resources/google_kms_key_ring_iam_bindings.md) +- [google_kms_key_rings](docs/resources/google_kms_key_rings.md) - [google_project](docs/resources/google_project.md) - [google_project_iam_binding](docs/resources/google_project_iam_binding.md) - [google_project_iam_bindings](docs/resources/google_project_iam_bindings.md) diff --git a/docs/resources/google_kms_crypto_key.md b/docs/resources/google_kms_crypto_key.md new file mode 100644 index 000000000..7ecdd25e9 --- /dev/null +++ b/docs/resources/google_kms_crypto_key.md @@ -0,0 +1,62 @@ +--- +title: About the google_kms_crypto_key Resource +platform: gcp +--- + +# google\_kms\_crypto\_key + +Use the `google_kms_crypto_key` InSpec audit resource to test properties of a single GCP KMS crypto key. See [this page](https://cloud.google.com/kms/docs/object-hierarchy?hl=en_US&_ga=2.223343707.-1730338523.1522320263#cryptokeyversion) for useful background. + +
+ +## Syntax + +A `google_kms_crypto_key` resource block declares the tests for a single GCP KMS crypto key by project, location, key ring name and key name. + + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: 'crypto-key') do + it { should exist } + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that a GCP KMS crypto key was created recently + + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: 'crypto-key') do + its('create_time_date') { should be > Time.now - 365*60*60*24*10 } + end + +### Test when the next rotation time for a GCP KMS crypto key is scheduled + + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: 'crypto-key') do + its('next_rotation_time_date') { should be > Time.now - 100000 } + end + +### Check that the crypto key purpose is as expected + + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: 'crypto-key') do + its('purpose') { should eq "ENCRYPT_DECRYPT" } + end + +### Check that the crypto key primary is in "ENABLED" state + + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: 'crypto-key') do + its('primary_state') { should eq "ENABLED" } + end + + +
+ +## Properties + +* `create_time`, `create_time_date`, `name`, `crypto_key_name`, `crypto_key_url`, `next_rotation_time`, `next_rotation_time_date`, `primary_create_time`, `primary_create_time_date`, `primary_name`, `primary_state`, `purpose`, `rotation_period` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file diff --git a/docs/resources/google_kms_crypto_key_iam_binding.md b/docs/resources/google_kms_crypto_key_iam_binding.md new file mode 100644 index 000000000..1e8e243b5 --- /dev/null +++ b/docs/resources/google_kms_crypto_key_iam_binding.md @@ -0,0 +1,49 @@ +--- +title: About the google_kms_crypto_key_iam_binding Resource +platform: gcp +--- + +# google\_kms\_crypto\_key\_iam\_binding + +Use the `google_kms_crypto_key_iam_binding` InSpec audit resource to test properties of a single GCP KMS Crypto Key IAM Binding. + +
+ +## Syntax + +A `google_kms_crypto_key_iam_binding` resource block declares the tests for a single KMS Crypto Key IAM Binding for specified role. + + describe google_kms_crypto_key_iam_binding(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name', role: "roles/owner") do + it { should exist } + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that a GCP KMS Crypto Key IAM Binding exists for the specified role + + describe google_kms_crypto_key_iam_binding(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name', role: "roles/owner") do + it { should exist } + end + +### Test that a GCP KMS Crypto Key IAM Binding has the desired user included for the specified role + + describe google_kms_crypto_key_iam_binding(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name', role: "roles/owner") do + its('members') {should include 'user:someuser@domain.com' } + end + +
+ +## Properties + +* `members` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file diff --git a/docs/resources/google_kms_crypto_key_iam_bindings.md b/docs/resources/google_kms_crypto_key_iam_bindings.md new file mode 100644 index 000000000..b8dcdc5bd --- /dev/null +++ b/docs/resources/google_kms_crypto_key_iam_bindings.md @@ -0,0 +1,68 @@ +--- +title: About the google_kms_crypto_key_iam_bindings Resource +platform: gcp +--- + +# google\_kms\_crypto\_key\_iam\_bindings + +Use the `google_kms_crypto_key_iam_bindings` InSpec audit resource to test properties of all, or a filtered group of, GCP KMS Crypto Key IAM Bindings. + +
+ +## Syntax + +A `google_kms_crypto_key_iam_bindings` resource block collects GCP KMS Crypto Key IAM Bindings then tests that group. + + describe google_kms_crypto_key_iam_bindings(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name') do + it { should exist } + end + +Use this InSpec resource to enumerate roles then test in-depth using `google_kms_key_ring_iam_binding`. + + google_kms_crypto_key_iam_bindings(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name').iam_binding_roles.each do |iam_binding_role| + describe google_kms_crypto_key_iam_binding(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name', role: "roles/owner") do + it { should exist } + its('members') {should include 'user:someuser@domain.com' } + end + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that there are no more than a specified number of IAM bindings roles available for the crypto key + + describe google_kms_crypto_key_iam_bindings(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name') do + its('count') { should be <= 100} + end + +### Test that an expected IAM binding is available for the crypto key + + describe google_kms_crypto_key_iam_bindings(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name') do + its('iam_binding_roles') { should include "roles/storage.admin" } + end + +### Test that a particular role does not exist using filtering of the plural resource + + describe google_kms_crypto_key_iam_bindings(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name').where(iam_binding_role: "roles/iam.securityReviewer") do + it { should_not exist } + end + +
+ +## Filter Criteria + +This resource supports the following filter criteria: `iam_binding_role`. This may be used with `where`, as a block or as a method. + +## Properties + +* `iam_binding_roles` - an array of google_kms_crypto_key_iam_binding role strings e.g. `["roles/compute.admin", "roles/owner"]` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located.s \ No newline at end of file diff --git a/docs/resources/google_kms_crypto_keys.md b/docs/resources/google_kms_crypto_keys.md new file mode 100644 index 000000000..59005057d --- /dev/null +++ b/docs/resources/google_kms_crypto_keys.md @@ -0,0 +1,65 @@ +--- +title: About the google_kms_crypto_keys Resource +platform: gcp +--- + +# google\_kms\_crypto\_keys + +Use the `google_kms_crypto_keys` InSpec audit resource to test properties of all, or a filtered group of, GCP KMS crypto keys for supplied project, location and key ring name. + +
+ +## Syntax + +A `google_kms_crypto_keys` resource block collects GCP KMS crypto keys then tests that group. + + describe google_kms_crypto_keys(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring') do + it { should exist } + end + +Use this InSpec resource to enumerate IDs then test in-depth using `google_kms_crypto_key`. + + describe google_kms_crypto_keys(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring').crypto_key_names.each do |key_name| + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: key_name) do + it { should exist } + its('create_time_date') { should be > Time.now - 365*60*60*24*10 } + its('purpose') { should eq "ENCRYPT_DECRYPT" } + its('primary_state') { should eq "ENABLED" } + end + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that there are no more than a specified number of keys in the key ring + + describe google_kms_crypto_keys(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring') do + its('count') { should be <= 100} + end + +### Test that an expected key name is present in the key ring + + describe google_kms_crypto_keys(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring') do + its('crypto_key_names') { should include "my-crypto-key-name" } + end + +
+ +## Filter Criteria + +This resource supports the following filter criteria: `key_name`. This may be used with `where`, as a block or as a method. + +## Properties + +* `crypto_key_names` - an array of google_kms_crypto_key name strings e.g. `['key-name']` +* `crypto_key_urls` - an array of google_kms_crypto_key url strings e.g. `['projects/PROJECT/locations/LOCATION/keyRings/key-ring-name/cryptoKeys/key-name']` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file diff --git a/docs/resources/google_kms_key_ring.md b/docs/resources/google_kms_key_ring.md new file mode 100644 index 000000000..546d35006 --- /dev/null +++ b/docs/resources/google_kms_key_ring.md @@ -0,0 +1,51 @@ +--- +title: About the google_kms_key_ring Resource +platform: gcp +--- + +# google\_kms\_key\_ring + +Use the `google_kms_key_ring` InSpec audit resource to test properties of a single GCP kms key ring. + +
+ +## Syntax + +A `google_kms_key_ring` resource block declares the tests for a single GCP key ring by project and name. + + describe google_kms_key_ring(project: 'chef-inspec-gcp', location: 'us-east1', name: 'key-ring-name') do + it { should exist } + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that a GCP kms key ring exists + + describe google_kms_key_ring(project: 'chef-inspec-gcp', location: 'us-east1', name: 'key-ring-name') do + it { should exist } + end + +### Test that a GCP kms key ring is in the expected state + +For any existing key ring, below should definitely be true! + + describe google_kms_key_ring(project: 'chef-inspec-gcp', location: 'us-east1', name: 'key-ring-name') do + its('create_time_date') { should be > Time.now - 365*60*60*24*50 } + end + +
+ +## Properties + +* `create_time`, `create_time_date`, `name`, `key_ring_name`, `key_ring_url` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file diff --git a/docs/resources/google_kms_key_ring_iam_binding.md b/docs/resources/google_kms_key_ring_iam_binding.md new file mode 100644 index 000000000..19a68b00f --- /dev/null +++ b/docs/resources/google_kms_key_ring_iam_binding.md @@ -0,0 +1,50 @@ +--- +title: About the google_kms_key_ring_iam_binding Resource +platform: gcp +--- + +# google\_kms\_key\_ring\_iam\_binding + +Use the `google_kms_key_ring_iam_binding` InSpec audit resource to test properties of a single GCP KMS key ring IAM binding. + +
+ +## Syntax + +A `google_kms_key_ring_iam_binding` resource block declares the tests for a single GCP KMS key ring IAM binding by role. + + describe google_kms_key_ring_iam_binding(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring', role: 'roles/compute.admin') do + it { should exist } + its('members') {should include 'user:someuser@domain.com' } + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that a GCP project KMS key ring IAM binding exists + + describe google_kms_key_ring_iam_binding(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring', role: 'roles/compute.admin') do + it { should exist } + end + +### Test that a GCP project KMS key ring IAM binding has the desired user included + + describe google_kms_key_ring_iam_binding(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring', role: 'roles/compute.admin') do + its('members') {should include 'user:someuser@domain.com' } + end + +
+ +## Properties + +* `members` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file diff --git a/docs/resources/google_kms_key_ring_iam_bindings.md b/docs/resources/google_kms_key_ring_iam_bindings.md new file mode 100644 index 000000000..aae8df8df --- /dev/null +++ b/docs/resources/google_kms_key_ring_iam_bindings.md @@ -0,0 +1,68 @@ +--- +title: About the google_kms_key_ring_iam_bindings Resource +platform: gcp +--- + +# google\_kms\_key\_ring\_iam\_bindings + +Use the `google_kms_key_ring_iam_bindings` InSpec audit resource to test properties of all, or a filtered group of, GCP KMS key ring IAM bindings. + +
+ +## Syntax + +A `google_kms_key_ring_iam_bindings` resource block collects GCP KMS key ring IAM bindings then tests that group. + + describe google_kms_key_ring_iam_bindings(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring') do + it { should exist } + end + +Use this InSpec resource to enumerate roles then test in-depth using `google_kms_key_ring_iam_binding`. + + google_kms_key_ring_iam_bindings(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring').iam_binding_roles.each do |iam_binding_role| + describe google_kms_key_ring_iam_binding(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring', role: "roles/owner") do + it { should exist } + its('members') {should include 'user:someuser@domain.com' } + end + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that there are no more than a specified number of IAM bindings roles available for the key ring + + describe google_kms_key_ring_iam_bindings(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring') do + its('count') { should be <= 100} + end + +### Test that an expected IAM binding is available for the key ring + + describe google_kms_key_ring_iam_bindings(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring') do + its('iam_binding_roles') { should include "roles/storage.admin" } + end + +### Test that a particular role does not exist using filtering of the plural resource + + describe google_kms_key_ring_iam_bindings(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring').where(iam_binding_role: "roles/iam.securityReviewer") do + it { should_not exist } + end + +
+ +## Filter Criteria + +This resource supports the following filter criteria: `iam_binding_role`. This may be used with `where`, as a block or as a method. + +## Properties + +* `iam_binding_roles` - an array of google_kms_key_ring_iam_binding role strings e.g. `["roles/compute.admin", "roles/owner"]` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located.s \ No newline at end of file diff --git a/docs/resources/google_kms_key_rings.md b/docs/resources/google_kms_key_rings.md new file mode 100644 index 000000000..3b59591fb --- /dev/null +++ b/docs/resources/google_kms_key_rings.md @@ -0,0 +1,74 @@ +--- +title: About the google_kms_key_rings Resource +platform: gcp +--- + +# google\_kms\_key\_rings + +Use the `google_kms_key_rings` InSpec audit resource to test properties of all, or a filtered group of, GCP KMS key rings for a project in a particular location. + +
+ +## Syntax + +A `google_kms_key_rings` resource block collects GCP kms_key_rings by project then tests that group. + + describe google_kms_key_rings(project: 'chef-inspec-gcp', location: 'us-east1') do + it { should exist } + end + +Use this InSpec resource to enumerate IDs then test in-depth using `google_kms_key_ring`. + + google_kms_key_rings(project: 'chef-inspec-gcp', location: 'us-east1').kms_key_ring_names.each do |kms_key_ring_name| + describe google_kms_key_ring(project: 'chef-inspec-gcp', kms_key_ring: kms_key_ring_name) do + it { should exist } + its('kind') { should eq "compute#kms_key_ring" } + its('status') { should eq 'UP' } + end + end + +
+ +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test that there are no more than a specified number of kms_key_rings available for the project + + describe google_kms_key_rings(project: 'chef-inspec-gcp', location: 'us-east1') do + its('count') { should be <= 200} + end + +### Test that an expected kms_key_ring is available for the project + + describe google_kms_key_rings(project: 'chef-inspec-gcp', location: 'us-east1') do + its('key_ring_names') { should include "a-named-key" } + end + + +### Test that all KMS key rings were created in the past year + + describe google_kms_key_rings(project: gcp_project_id, location: 'us-east1').key_ring_names.each do |key_ring_name| + describe google_kms_key_ring(project: 'chef-inspec-gcp', location: 'us-east1', 'name: key_ring_name) do + it { should exist } + its('create_time_date') { should be > Time.now - 365*60*60*24 } + end + end + +
+ +## Filter Criteria + +This resource supports the following filter criteria: `key_ring_name`. This may be used with `where`, as a block or as a method. + +## Properties + +* `key_ring_names` - an array of google_kms_key_ring name strings e.g.`['key-ring-name']` +* `key_ring_urls` - an array of google_kms_key_ring name url strings e.g. `['projects/PROJECT/locations/LOCATION/keyRings/key-ring-name']` + +
+ + +## GCP Permissions + +Ensure the [Cloud Key Management Service (KMS) API](https://console.cloud.google.com/apis/library/cloudkms.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file diff --git a/docs/resources/google_project_iam_binding.md b/docs/resources/google_project_iam_binding.md index e53aee2e5..d7de9aa35 100644 --- a/docs/resources/google_project_iam_binding.md +++ b/docs/resources/google_project_iam_binding.md @@ -15,7 +15,6 @@ A `google_project_iam_binding` resource block declares the tests for a single GC describe google_project_iam_binding(project: 'chef-inspec-gcp', role: 'roles/compute.admin') do it { should exist } - its('members') {should include 'user:someuser@domain.com' } end
@@ -26,33 +25,25 @@ The following examples show how to use this InSpec audit resource. ### Test that a GCP project iam_binding exists - describe google_project_iam_binding(project: 'chef-inspec-gcp', iam_binding: 'us-east1-b') do + describe google_project_iam_binding(project: 'chef-inspec-gcp', role: 'roles/compute.admin') do it { should exist } end -### Test that a GCP project iam_binding is in the expected state - - describe google_project_iam_binding(project: 'chef-inspec-gcp', iam_binding: 'us-east1-b') do - its('status') { should eq 'UP' } - # or equivalently - it { should be_up } - end +### Test that a GCP project IAM binding role has the desired user included -### Test that a GCP project iam_binding has an expected CPU platform - - describe google_project_iam_binding(project: 'chef-inspec-gcp', iam_binding: 'us-east1-b') do - its('available_cpu_platforms') { should include "Intel Skylake" } + describe google_project_iam_binding(project: 'chef-inspec-gcp', role: 'roles/compute.admin') do + its('members') {should include 'user:someuser@domain.com' } end
## Properties -* `available_cpu_platforms`, `creation_timestamp`, `description`, `id`, `kind`, `name`, `region`, `status`, `region_name` +* `members`
## GCP Permissions -Ensure the [Compute Engine API](https://console.cloud.google.com/apis/library/project.googleapis.com/) is enabled for the project where the resource is located. \ No newline at end of file +Ensure the [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com/) is enabled for the project. \ No newline at end of file diff --git a/docs/resources/google_project_iam_bindings.md b/docs/resources/google_project_iam_bindings.md index 23becbc38..05bfad6cc 100644 --- a/docs/resources/google_project_iam_bindings.md +++ b/docs/resources/google_project_iam_bindings.md @@ -38,7 +38,7 @@ The following examples show how to use this InSpec audit resource. its('count') { should be <= 100} end -### Test that an expected iam_binding is available for the project +### Test that an expected role is available for the project describe google_project_iam_bindings(project: 'chef-inspec-gcp') do its('iam_binding_roles') { should include "roles/storage.admin" } diff --git a/libraries/google_kms_crypto_key.rb b/libraries/google_kms_crypto_key.rb new file mode 100644 index 000000000..ed0d057f1 --- /dev/null +++ b/libraries/google_kms_crypto_key.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'gcp_backend' +require 'time' +require 'google/apis/cloudkms_v1' + +module Inspec::Resources + class GoogleKMSCryptoKey < GcpResourceBase + name 'google_kms_crypto_key' + desc 'Verifies settings for a KMS key ring' + + example " + describe google_kms_crypto_key(project: 'chef-inspec-gcp', location: 'us-east1', key_ring_name: 'key-ring', name: 'crypto-key') do + it { should exist } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @display_name = opts[:name] + catch_gcp_errors do + @kms_crypto_key = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).get_project_location_key_ring_crypto_key("projects/#{opts[:project]}/locations/#{opts[:location]}/keyRings/#{opts[:key_ring_name]}/cryptoKeys/#{opts[:name]}") + create_resource_methods(@kms_crypto_key) + end + end + + def crypto_key_name + return false if !defined?(name) + name.split('/').last + end + + def create_time_date + return false if !defined?(create_time) + Time.parse(create_time) + end + + # this is added for completeness as crypto key IAM bindings use the crypto_key_url as an identifier + def crypto_key_url + return false if !defined?(name) + name + end + + def next_rotation_time_date + return false if !defined?(next_rotation_time) + Time.parse(next_rotation_time) + end + + def primary_create_time_date + return false if !defined?(primary.create_time) + Time.parse(primary.create_time) + end + + def primary_name + return false if !defined?(primary.name) + primary.name + end + + def primary_state + return false if !defined?(primary.state) + primary.state + end + + def exists? + !@kms_crypto_key.nil? + end + + def to_s + "Crytpo Key #{@display_name}" + end + end +end diff --git a/libraries/google_kms_crypto_key_iam_binding.rb b/libraries/google_kms_crypto_key_iam_binding.rb new file mode 100644 index 000000000..70975004e --- /dev/null +++ b/libraries/google_kms_crypto_key_iam_binding.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleKMSCryptoKeyIAMBinding < GcpResourceBase + name 'google_kms_crypto_key_iam_binding' + desc 'Verifies settings for a single KMS Crypto Key IAM binding' + + example " + describe google_kms_crypto_key_iam_binding(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name', role: 'roles/owner') do + it { should exist } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @crypto_key_url = opts[:crypto_key_url] + @role = opts[:role] + @iam_binding_exists = false + @members_list=[] + catch_gcp_errors do + # note this is the same call as for the plural iam_bindings resource because there isn't an easy way to pull out a singular binding + @iam_bindings = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).get_project_location_key_ring_crypto_key_iam_policy(@crypto_key_url) + raise Inspec::Exceptions::ResourceFailed, "google_kms_crypto_key_iam_binding is missing expected IAM policy 'bindings' property" if !@iam_bindings || !@iam_bindings.bindings + @iam_bindings.bindings.each do |binding| + next if binding.role != @role + @iam_binding_exists=true + @members_list=binding.members + end + end + end + + # return the list of users corresponding to the role + def members + @members_list + end + + def exists? + @iam_binding_exists + end + + def to_s + "Crypto Key IAM Binding #{@role}" + end + end +end diff --git a/libraries/google_kms_crypto_key_iam_bindings.rb b/libraries/google_kms_crypto_key_iam_bindings.rb new file mode 100644 index 000000000..d7abb480e --- /dev/null +++ b/libraries/google_kms_crypto_key_iam_bindings.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleKMSCryptoKeyIAMBindings < GcpResourceBase + name 'google_kms_crypto_key_iam_bindings' + desc 'Verifies settings for GCP KMS Crypto Key IAM Bindings in bulk' + + example " + describe google_kms_key_ring_iam_bindings(crypto_key_url: 'projects/project/locations/europe-west2/keyRings/key-ring/cryptoKeys/key-name') do + it { should exist } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @crypto_key_url = opts[:crypto_key_url] + end + + # FilterTable setup + filter_table_config = FilterTable.create + filter_table_config.add(:iam_binding_roles, field: :iam_binding_role) + filter_table_config.connect(self, :fetch_data) + + def fetch_data + iam_binding_rows = [] + catch_gcp_errors do + @iam_bindings = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).get_project_location_key_ring_crypto_key_iam_policy(@crypto_key_url) + end + return [] if !@iam_bindings || !@iam_bindings.bindings + @iam_bindings.bindings.map do |iam_binding| + iam_binding_rows+=[{ iam_binding_role: iam_binding.role }] + end + @table = iam_binding_rows + end + end +end diff --git a/libraries/google_kms_crypto_keys.rb b/libraries/google_kms_crypto_keys.rb new file mode 100644 index 000000000..40d722d80 --- /dev/null +++ b/libraries/google_kms_crypto_keys.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleKMSCryptoKeys < GcpResourceBase + name 'google_kms_crypto_keys' + desc 'Verifies settings for GCP KMS crypto keys in bulk' + + example " + describe google_kms_crypto_keys(project: 'chef-inspec-gcp', location: 'us-east1', crypto_key_name: 'key-ring') do + it { should exist } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @project = opts[:project] + @location = opts[:location] + @key_ring_name = opts[:key_ring_name] + end + + # FilterTable setup + filter_table_config = FilterTable.create + filter_table_config.add(:crypto_key_names, field: :crypto_key_name) + filter_table_config.add(:crypto_key_urls, field: :crypto_key_url) + filter_table_config.connect(self, :fetch_data) + + def fetch_data + crypto_key_rows = [] + catch_gcp_errors do + @crypto_keys = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).list_project_location_key_ring_crypto_keys("projects/#{@project}/locations/#{@location}/keyRings/#{@key_ring_name}") + end + return [] if !@crypto_keys || !@crypto_keys.crypto_keys + @crypto_keys.crypto_keys.map do |crypto_key| + crypto_key_rows+=[{ crypto_key_name: crypto_key.name.split('/').last, + crypto_key_url: crypto_key.name }] + end + @table = crypto_key_rows + end + end +end diff --git a/libraries/google_kms_key_ring.rb b/libraries/google_kms_key_ring.rb new file mode 100644 index 000000000..ef453b3ca --- /dev/null +++ b/libraries/google_kms_key_ring.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'gcp_backend' +require 'time' +require 'google/apis/cloudkms_v1' + +module Inspec::Resources + class GoogleKMSKeyRing < GcpResourceBase + name 'google_kms_key_ring' + desc 'Verifies settings for a KMS key ring' + + example " + describe google_kms_key_ring(project: 'chef-inspec-gcp', location: 'us-east1', name: 'key-ring-name') do + it { should exist } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @display_name = opts[:name] + catch_gcp_errors do + @kms_key_ring = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).get_project_location_key_ring("projects/#{opts[:project]}/locations/#{opts[:location]}/keyRings/#{opts[:name]}") + create_resource_methods(@kms_key_ring) + end + end + + def key_ring_name + return false if !defined?(name) + name.split('/').last + end + + def create_time_date + return false if !defined?(create_time) + Time.parse(create_time) + end + + # this is added for completeness as key ring IAM bindings use the key_ring_url as an identifier + def key_ring_url + return false if !defined?(name) + name + end + + def exists? + !@kms_key_ring.nil? + end + + def to_s + "Key Ring #{@display_name}" + end + end +end diff --git a/libraries/google_kms_key_ring_iam_binding.rb b/libraries/google_kms_key_ring_iam_binding.rb new file mode 100644 index 000000000..931c063fb --- /dev/null +++ b/libraries/google_kms_key_ring_iam_binding.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleKMSKeyRingIAMBinding < GcpResourceBase + name 'google_kms_key_ring_iam_binding' + desc 'Verifies settings for a single KMS Key Ring IAM binding' + + example " + describe google_kms_key_ring_iam_binding(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring', role: 'roles/compute.admin') do + it { should exist } + its('members') {should include 'user:someuser@domain.com' } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @key_ring_url = opts[:key_ring_url] + @role = opts[:role] + @iam_binding_exists = false + @members_list=[] + catch_gcp_errors do + # note this is the same call as for the plural iam_bindings resource because there isn't an easy way to pull out a singular binding + @iam_bindings = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).get_project_location_key_ring_iam_policy(@key_ring_url) + raise Inspec::Exceptions::ResourceFailed, "google_kms_key_ring_iam_binding is missing expected IAM policy 'bindings' property" if !@iam_bindings || !@iam_bindings.bindings + @iam_bindings.bindings.each do |binding| + next if binding.role != @role + @iam_binding_exists=true + @members_list=binding.members + end + end + end + + # return the list of users corresponding to the role + def members + @members_list + end + + def exists? + @iam_binding_exists + end + + def to_s + "Key Ring IAM Binding #{@role}" + end + end +end diff --git a/libraries/google_kms_key_ring_iam_bindings.rb b/libraries/google_kms_key_ring_iam_bindings.rb new file mode 100644 index 000000000..16a85a676 --- /dev/null +++ b/libraries/google_kms_key_ring_iam_bindings.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleKMSKeyRingIAMBindings < GcpResourceBase + name 'google_kms_key_ring_iam_bindings' + desc 'Verifies settings for GCP KMS key ring IAM bindings in bulk' + + example " + describe google_kms_key_ring_iam_bindings(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring') do + it { should exist } + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @key_ring_url = opts[:key_ring_url] + end + + # FilterTable setup + filter_table_config = FilterTable.create + filter_table_config.add(:iam_binding_roles, field: :iam_binding_role) + filter_table_config.connect(self, :fetch_data) + + def fetch_data + iam_binding_rows = [] + catch_gcp_errors do + @iam_bindings = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).get_project_location_key_ring_iam_policy(@key_ring_url) + end + return [] if !@iam_bindings || !@iam_bindings.bindings + @iam_bindings.bindings.map do |iam_binding| + iam_binding_rows+=[{ iam_binding_role: iam_binding.role }] + end + @table = iam_binding_rows + end + end +end diff --git a/libraries/google_kms_key_rings.rb b/libraries/google_kms_key_rings.rb new file mode 100644 index 000000000..96322268f --- /dev/null +++ b/libraries/google_kms_key_rings.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'gcp_backend' + +module Inspec::Resources + class GoogleKMSKeyRings < GcpResourceBase + name 'google_kms_key_rings' + desc 'Verifies settings for GCP KMS key rings in bulk' + + example " + describe google_kms_key_rings(project: 'chef-inspec-gcp', location: 'us-east1') do + it { should exist } + ... + end + " + + def initialize(opts = {}) + # Call the parent class constructor + super(opts) + @project = opts[:project] + @location = opts[:location] + end + + # FilterTable setup + filter_table_config = FilterTable.create + filter_table_config.add(:key_ring_names, field: :key_ring_name) + filter_table_config.add(:key_ring_urls, field: :key_ring_url) + filter_table_config.connect(self, :fetch_data) + + def fetch_data + key_ring_rows = [] + catch_gcp_errors do + @key_rings = @gcp.gcp_client(Google::Apis::CloudkmsV1::CloudKMSService).list_project_location_key_rings("projects/#{@project}/locations/#{@location}") + end + return [] if !@key_rings || !@key_rings.key_rings + @key_rings.key_rings.map do |key_ring| + key_ring_rows+=[{ key_ring_name: key_ring.name.split('/').last, + key_ring_url: key_ring.name }] + end + @table = key_ring_rows + end + end +end diff --git a/libraries/google_project_iam_binding.rb b/libraries/google_project_iam_binding.rb index 49c369dbd..cc7d3c605 100644 --- a/libraries/google_project_iam_binding.rb +++ b/libraries/google_project_iam_binding.rb @@ -5,19 +5,17 @@ module Inspec::Resources class GoogleProjectIAMBinding < GcpResourceBase name 'google_project_iam_binding' - desc 'Verifies settings for a single project IAM binding' + desc 'Verifies settings for a single GCP KMS key ring IAM bindings' example " - describe google_project_iam_binding(project: 'chef-inspec-gcp', role: 'roles/compute.admin') do + describe google_kms_key_ring_iam_binding(key_ring_url: 'projects/project/locations/europe-west2/keyRings/key-ring', role: 'roles/compute.admin') do it { should exist } - its('members') {should include 'user:someuser@domain.com' } end " def initialize(opts = {}) # Call the parent class constructor super(opts) - @display_name = opts[:name] @project = opts[:project] @role = opts[:role] @iam_binding_exists = false @@ -44,7 +42,7 @@ def exists? end def to_s - "Project IAM Binding #{@display_name}" + "Project IAM Binding #{@role}" end end end diff --git a/test/integration/build/gcp.tf b/test/integration/build/gcp.tf index 02b3ce1e9..6b037f20e 100644 --- a/test/integration/build/gcp.tf +++ b/test/integration/build/gcp.tf @@ -58,11 +58,17 @@ variable "gcp_kube_cluster_zone_extra2" {} variable "gcp_kube_cluster_master_user" {} variable "gcp_kube_cluster_master_pass" {} +variable "gcp_kms_key_ring_policy_name" {} +variable "gcp_kms_key_ring_binding_member_name" {} +variable "gcp_kms_crypto_key_name_policy" {} +variable "gcp_kms_crypto_key_name_binding" {} variable "gcp_storage_bucket_name" { default ="gcp-inspec" } +#variable "gcp_inspec_user_email" {} + variable "gcp_enable_privileged_resources" {} provider "google" { @@ -411,4 +417,98 @@ output "cluster_ca_certificate" { ############################################################## # End of the GKE cluster example -############################################################## \ No newline at end of file +############################################################## + +# Start GCP KMS resources +# This reuses service account email address that was created earlier to test IAM policies/binding/memberships + +#Note: google_kms_key_ring_iam_policy cannot be used in conjunction with google_kms_key_ring_iam_binding and google_kms_key_ring_iam_member or they will fight over what your policy should be. + +resource "google_kms_key_ring" "gcp_kms_key_ring_policy" { + count = "${var.gcp_enable_privileged_resources}" + project = "${var.gcp_project_id}" + name = "${var.gcp_kms_key_ring_policy_name}" + location = "${var.gcp_location}" +} + + +#Note: google_kms_key_ring_iam_binding resources can be used in conjunction with google_kms_key_ring_iam_member resources only if they do not grant privilege to the same role. + +resource "google_kms_key_ring" "gcp_kms_key_ring_binding_member" { + count = "${var.gcp_enable_privileged_resources}" + project = "${var.gcp_project_id}" + name = "${var.gcp_kms_key_ring_binding_member_name}" + location = "${var.gcp_location}" +} + +# Use the first key ring to attach an IAM policy + +data "google_iam_policy" "gcp_inspec_admin_key_ring" { + count = "${var.gcp_enable_privileged_resources}" + binding { + role = "roles/editor" + + members = [ + "serviceAccount:${google_service_account.generic_service_account_object_viewer.email}", + ] + } +} + +resource "google_kms_key_ring_iam_policy" "key_ring_policy" { + count = "${var.gcp_enable_privileged_resources}" + key_ring_id = "${google_kms_key_ring.gcp_kms_key_ring_policy.id}" + policy_data = "${data.google_iam_policy.gcp_inspec_admin_key_ring.policy_data}" +} + +# Use the second key ring to attach an IAM binding plus IAM member affecting different roles + +resource "google_kms_key_ring_iam_binding" "key_ring_binding" { + count = "${var.gcp_enable_privileged_resources}" + key_ring_id = "${google_kms_key_ring.gcp_kms_key_ring_binding_member.id}" + role = "roles/editor" + + members = [ + "serviceAccount:${google_service_account.generic_service_account_object_viewer.email}", + ] +} + +resource "google_kms_key_ring_iam_member" "key_ring_iam_member" { + count = "${var.gcp_enable_privileged_resources}" + key_ring_id = "${google_kms_key_ring.gcp_kms_key_ring_binding_member.id}" + role = "roles/owner" + member = "serviceAccount:${google_service_account.generic_service_account_object_viewer.email}" +} + +resource "google_kms_crypto_key" "crypto_key_policy" { + count = "${var.gcp_enable_privileged_resources}" + name = "${var.gcp_kms_crypto_key_name_policy}" + key_ring = "${google_kms_key_ring.gcp_kms_key_ring_policy.id}" + rotation_period = "100000s" +} + +resource "google_kms_crypto_key" "crypto_key_binding" { + count = "${var.gcp_enable_privileged_resources}" + name = "${var.gcp_kms_crypto_key_name_binding}" + key_ring = "${google_kms_key_ring.gcp_kms_key_ring_binding_member.id}" + rotation_period = "100000s" +} + +resource "google_kms_crypto_key_iam_member" "crypto_key_iam_member" { + count = "${var.gcp_enable_privileged_resources}" + crypto_key_id = "${google_kms_crypto_key.crypto_key_policy.id}" + role = "roles/editor" + member = "serviceAccount:${google_service_account.generic_service_account_object_viewer.email}" +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key_iam_binding" { + count = "${var.gcp_enable_privileged_resources}" + crypto_key_id = "${google_kms_crypto_key.crypto_key_binding.id}" + role = "roles/editor" + + members = [ + "serviceAccount:${google_service_account.generic_service_account_object_viewer.email}", + ] +} + + +# End GCP KMS resources \ No newline at end of file diff --git a/test/integration/configuration/gcp_inspec_config.rb b/test/integration/configuration/gcp_inspec_config.rb index f8c391b56..bb584c5ce 100644 --- a/test/integration/configuration/gcp_inspec_config.rb +++ b/test/integration/configuration/gcp_inspec_config.rb @@ -60,6 +60,11 @@ module GCPInspecConfig :gcp_kube_cluster_master_user => "gcp-inspec-kube-admin", :gcp_kube_cluster_master_pass => Passgen::generate(length: 20, uppercase: true, lowercase: true, symbols: true, digits: true), :gcp_kube_nodepool_name => "default-pool", + :gcp_inspec_user_email => "user:chef@example.com", + :gcp_kms_key_ring_policy_name => "gcp-inspec-kms-key-ring-#{(0...15).map { (65 + rand(26)).chr }.join.downcase}", + :gcp_kms_key_ring_binding_member_name => "gcp-inspec-kms-key-ring-#{(0...15).map { (65 + rand(26)).chr }.join.downcase}", + :gcp_kms_crypto_key_name_policy => "gcp-inspec-kms-crypto-key-policy-#{(0...15).map { (65 + rand(26)).chr }.join.downcase}", + :gcp_kms_crypto_key_name_binding => "gcp-inspec-kms-crypto-key-binding-#{(0...15).map { (65 + rand(26)).chr }.join.downcase}", # Some resources require elevated privileges to create and therefore test against. The below flag is used to control # both the terraform resource creation and the inspec test execution for those resources. Default behaviour is for this to # be disabled meaning a user needs no special GCP privileges to run the integration test pack. diff --git a/test/integration/verify/controls/google_kms_crypto_key.rb b/test/integration/verify/controls/google_kms_crypto_key.rb new file mode 100644 index 000000000..dd66d5c1f --- /dev/null +++ b/test/integration/verify/controls/google_kms_crypto_key.rb @@ -0,0 +1,24 @@ +title 'Test single GCP KMS Crypto Key' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_kms_key_ring_policy_name = attribute(:gcp_kms_key_ring_policy_name,default:'',description:'GCP key ring name to test against.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_kms_crypto_key_name_policy = attribute(:gcp_kms_crypto_key_name_policy, default: '', description: 'The GCP cryto key name.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') + +control 'gcp-kms-crypto-key-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure single GCP KMS Crypto Key has the correct properties.' + + describe google_kms_crypto_key(project: gcp_project_id, location: gcp_location, key_ring_name: gcp_kms_key_ring_policy_name, name: gcp_kms_crypto_key_name_policy) do + it { should exist } + its('create_time_date') { should be > Time.now - 365*60*60*24*10 } + its('crypto_key_name'){ should eq gcp_kms_crypto_key_name_policy } + its('primary_state') { should eq "ENABLED" } + its('purpose') { should eq "ENCRYPT_DECRYPT" } + its('next_rotation_time_date') { should be > Time.now - 100000 } + its('create_time_date') { should be > Time.now - 365*60*60*24*10 } + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_crypto_key_iam_binding.rb b/test/integration/verify/controls/google_kms_crypto_key_iam_binding.rb new file mode 100644 index 000000000..a7191659c --- /dev/null +++ b/test/integration/verify/controls/google_kms_crypto_key_iam_binding.rb @@ -0,0 +1,27 @@ +title 'GCP KMS Crypto Key IAM Binding Properties' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_kms_key_ring_policy_name = attribute(:gcp_kms_key_ring_policy_name,default:'',description:'GCP key ring name to test against.') +gcp_kms_crypto_key_name_policy = attribute(:gcp_kms_crypto_key_name_policy, default: '', description: 'The GCP cryto key name.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') +gcp_kms_crypto_key_name_binding = attribute(:gcp_kms_crypto_key_name_binding,default:'',description:'GCP key ring name to test against.') +gcp_kms_key_ring_binding_member_name = attribute(:gcp_kms_key_ring_binding_member_name, default: '', description: 'The GCP cryto key name.') + + +control 'gcp-crypto-key-iam-binding-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure single KMS Crypto Key IAM Binding has the correct properties' + + describe google_kms_crypto_key_iam_binding(crypto_key_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_binding_member_name}/cryptoKeys/#{gcp_kms_crypto_key_name_binding}", role: "roles/editor") do + it { should exist } + its('members.count') { should eq 1} + end + + describe google_kms_crypto_key_iam_binding(crypto_key_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_policy_name}/cryptoKeys/#{gcp_kms_crypto_key_name_policy}", role: "roles/editor") do + it { should exist } + its('members.count') { should eq 1} + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_crypto_key_iam_bindings.rb b/test/integration/verify/controls/google_kms_crypto_key_iam_bindings.rb new file mode 100644 index 000000000..78dc31712 --- /dev/null +++ b/test/integration/verify/controls/google_kms_crypto_key_iam_bindings.rb @@ -0,0 +1,20 @@ +title 'GCP KMS Crypto Key IAM Bindings Properties' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_kms_key_ring_binding_member_name = attribute(:gcp_kms_key_ring_binding_member_name,default:'',description:'GCP key ring name to test against.') +gcp_kms_crypto_key_name_binding = attribute(:gcp_kms_crypto_key_name_binding,default:'',description:'Key in key ring to test.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') + +control 'gcp-kms-crypto-key-iam-bindings-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure GCP KMS Crypto Key IAM Bindings have the correct properties in bulk' + + describe google_kms_crypto_key_iam_bindings(crypto_key_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_binding_member_name}/cryptoKeys/#{gcp_kms_crypto_key_name_binding}") do + it { should exist } + its('count') { should be <= 100} + its('iam_binding_roles') { should include "roles/editor" } + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_crypto_keys.rb b/test/integration/verify/controls/google_kms_crypto_keys.rb new file mode 100644 index 000000000..a6c51dabd --- /dev/null +++ b/test/integration/verify/controls/google_kms_crypto_keys.rb @@ -0,0 +1,29 @@ +title 'GCP KMS Crypto Keys Properties' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_kms_key_ring_policy_name = attribute(:gcp_kms_key_ring_policy_name,default:'',description:'GCP key ring name to test against.') +gcp_kms_crypto_key_name_policy = attribute(:gcp_kms_crypto_key_name_policy, default: '', description: 'The GCP cryto key name.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') +gcp_kms_crypto_key_name_binding = attribute(:gcp_kms_crypto_key_name_binding,default:'',description:'GCP key ring name to test against.') +gcp_kms_key_ring_binding_member_name = attribute(:gcp_kms_key_ring_binding_member_name, default: '', description: 'The GCP cryto key name.') + + +control 'gcp-crypto-keys-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure KMS crypto keys have the correct properties in bulk' + + describe google_kms_crypto_keys(project: gcp_project_id, location: gcp_location, key_ring_name: gcp_kms_key_ring_policy_name) do + it { should exist } + its('count') { should eq 1} + its ('crypto_key_names') { should include gcp_kms_crypto_key_name_policy } + end + + describe google_kms_crypto_keys(project: gcp_project_id, location: gcp_location, key_ring_name: gcp_kms_key_ring_binding_member_name) do + it { should exist } + its('count') { should eq 1} + its ('crypto_key_names') { should include gcp_kms_crypto_key_name_binding } + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_key_ring.rb b/test/integration/verify/controls/google_kms_key_ring.rb new file mode 100644 index 000000000..298e9a922 --- /dev/null +++ b/test/integration/verify/controls/google_kms_key_ring.rb @@ -0,0 +1,19 @@ +title 'Test single GCP KMS Key Ring' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') +gcp_kms_key_ring_policy_name = attribute(:gcp_kms_key_ring_policy_name,default:'',description:'GCP key ring name to test against.') + +control 'gcp-key-ring-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure single KMS Key Ring has the correct properties.' + + describe google_kms_key_ring(project: gcp_project_id, location: gcp_location, name: gcp_kms_key_ring_policy_name) do + it { should exist } + its('create_time_date') { should be > Time.now - 365*60*60*24*10 } + its('key_ring_name'){ should eq gcp_kms_key_ring_policy_name } + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_key_ring_iam_binding.rb b/test/integration/verify/controls/google_kms_key_ring_iam_binding.rb new file mode 100644 index 000000000..b8aa86f00 --- /dev/null +++ b/test/integration/verify/controls/google_kms_key_ring_iam_binding.rb @@ -0,0 +1,29 @@ +title 'Test single GCP KMS Key Ring IAM Binding' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_kms_key_ring_policy_name = attribute(:gcp_kms_key_ring_policy_name,default:'',description:'GCP key ring name to test against.') +gcp_kms_key_ring_binding_member_name = attribute(:gcp_kms_key_ring_binding_member_name,default:'',description:'GCP key ring name to test against.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') + +control 'gcp-kms-key-ring-iam-binding-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure single GCP GCP KMS Key Ring IAM bindings have the correct properties. Examples below include attaching an IAM policy, binding and member to a key ring.' + + describe google_kms_key_ring_iam_binding(key_ring_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_policy_name}", role: "roles/editor") do + it { should exist } + its ('members.count'){ should eq 1 } + end + + describe google_kms_key_ring_iam_binding(key_ring_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_binding_member_name}", role: "roles/editor") do + it { should exist } + its ('members.count'){ should eq 1 } + end + + describe google_kms_key_ring_iam_binding(key_ring_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_binding_member_name}", role: "roles/owner") do + it { should exist } + its ('members.count'){ should eq 1 } + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_key_ring_iam_bindings.rb b/test/integration/verify/controls/google_kms_key_ring_iam_bindings.rb new file mode 100644 index 000000000..c6ffbbbc0 --- /dev/null +++ b/test/integration/verify/controls/google_kms_key_ring_iam_bindings.rb @@ -0,0 +1,20 @@ +title 'GCP KMS Key Ring IAM Binding Properties' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_kms_key_ring_binding_member_name = attribute(:gcp_kms_key_ring_binding_member_name,default:'',description:'GCP key ring name to test against.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') + +control 'gcp-kms-key-ring-iam-bindings-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure GCP KMS Key Ring IAM bindings have the correct properties in bulk' + + describe google_kms_key_ring_iam_bindings(key_ring_url: "projects/#{gcp_project_id}/locations/#{gcp_location}/keyRings/#{gcp_kms_key_ring_binding_member_name}") do + it { should exist } + its('count') { should be <= 100} + its('iam_binding_roles') { should include "roles/owner" } + its('iam_binding_roles') { should include "roles/editor" } + end +end \ No newline at end of file diff --git a/test/integration/verify/controls/google_kms_key_rings.rb b/test/integration/verify/controls/google_kms_key_rings.rb new file mode 100644 index 000000000..2556317bd --- /dev/null +++ b/test/integration/verify/controls/google_kms_key_rings.rb @@ -0,0 +1,21 @@ +title 'GCP KMS Key Rings Properties' + +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_location = attribute(:gcp_location, default: '', description: 'The GCP region being used.') +gcp_enable_privileged_resources = attribute(:gcp_enable_privileged_resources,default:0,description:'Flag to enable privileged resources requiring elevated privileges in GCP.') +gcp_kms_key_ring_policy_name = attribute(:gcp_kms_key_ring_policy_name,default:'',description:'GCP key ring name to test against.') +gcp_kms_key_ring_binding_member_name = attribute(:gcp_kms_key_ring_binding_member_name,default:'',description:'GCP key ring name to test against.') + +control 'gcp-key-rings-1.0' do + + only_if { gcp_enable_privileged_resources.to_i == 1 } + impact 1.0 + title 'Ensure KMS key rings have the correct properties in bulk' + + describe google_kms_key_rings(project: gcp_project_id, location: gcp_location) do + it { should exist } + its ('key_ring_names') { should include gcp_kms_key_ring_policy_name } + its ('key_ring_names') { should include gcp_kms_key_ring_binding_member_name } + end + +end \ No newline at end of file