diff --git a/avd_docs/google/compute/AVD-GCP-0027/docs.md b/avd_docs/google/compute/AVD-GCP-0027/docs.md
index 5c1fdab0..62a5af84 100644
--- a/avd_docs/google/compute/AVD-GCP-0027/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0027/docs.md
@@ -1,10 +1,10 @@
Network security rules should not use very broad subnets.
-
Where possible, segments should be broken into smaller subnets and avoid using the /0
subnet.
+
### Impact
-The port is exposed for ingress from the internet
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0029/docs.md b/avd_docs/google/compute/AVD-GCP-0029/docs.md
index 082212e3..058f790f 100644
--- a/avd_docs/google/compute/AVD-GCP-0029/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0029/docs.md
@@ -1,8 +1,9 @@
VPC flow logs record information about all traffic, which is a vital tool in reviewing anomalous traffic.
+
### Impact
-Limited auditing capability and awareness
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0030/docs.md b/avd_docs/google/compute/AVD-GCP-0030/docs.md
index 00fbdf3a..a18c67ae 100644
--- a/avd_docs/google/compute/AVD-GCP-0030/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0030/docs.md
@@ -1,8 +1,9 @@
Use of project-wide SSH keys means that a compromise of any one of these key pairs can result in all instances being compromised. It is recommended to use instance-level keys.
+
### Impact
-Compromise of a single key pair compromises all instances
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0031/docs.md b/avd_docs/google/compute/AVD-GCP-0031/docs.md
index 673dafc3..165f84a8 100644
--- a/avd_docs/google/compute/AVD-GCP-0031/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0031/docs.md
@@ -1,8 +1,9 @@
Instances should not be publicly exposed to the internet
+
### Impact
-Direct exposure of an instance to the public internet
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0032/docs.md b/avd_docs/google/compute/AVD-GCP-0032/docs.md
index 8bb9a13c..140d959b 100644
--- a/avd_docs/google/compute/AVD-GCP-0032/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0032/docs.md
@@ -1,8 +1,9 @@
When serial port access is enabled, the access is not governed by network security rules meaning the port can be exposed publicly.
+
### Impact
-Unrestricted network access to the serial console of the instance
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0033/Terraform.md b/avd_docs/google/compute/AVD-GCP-0033/Terraform.md
index 686fe629..8a15b33e 100644
--- a/avd_docs/google/compute/AVD-GCP-0033/Terraform.md
+++ b/avd_docs/google/compute/AVD-GCP-0033/Terraform.md
@@ -1,5 +1,5 @@
-Use managed keys
+Use managed keys
```hcl
resource "google_service_account" "default" {
diff --git a/avd_docs/google/compute/AVD-GCP-0033/docs.md b/avd_docs/google/compute/AVD-GCP-0033/docs.md
index 85cfbc53..01ccf571 100644
--- a/avd_docs/google/compute/AVD-GCP-0033/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0033/docs.md
@@ -1,8 +1,9 @@
Using unmanaged keys makes rotation and general management difficult.
+
### Impact
-Using unmanaged keys does not allow for proper management
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0034/docs.md b/avd_docs/google/compute/AVD-GCP-0034/docs.md
index 45bf9f5d..01ccf571 100644
--- a/avd_docs/google/compute/AVD-GCP-0034/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0034/docs.md
@@ -1,8 +1,9 @@
Using unmanaged keys makes rotation and general management difficult.
+
### Impact
-Using unmanaged keys does not allow for proper key management.
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0035/docs.md b/avd_docs/google/compute/AVD-GCP-0035/docs.md
index de39ac9b..62a5af84 100644
--- a/avd_docs/google/compute/AVD-GCP-0035/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0035/docs.md
@@ -1,10 +1,10 @@
Network security rules should not use very broad subnets.
-
Where possible, segments should be broken into smaller subnets and avoid using the /0
subnet.
+
### Impact
-The port is exposed for egress to the internet
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0036/docs.md b/avd_docs/google/compute/AVD-GCP-0036/docs.md
index ef1c3093..a2db8c01 100644
--- a/avd_docs/google/compute/AVD-GCP-0036/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0036/docs.md
@@ -1,8 +1,9 @@
OS Login automatically revokes the relevant SSH keys when an IAM user has their access revoked.
+
### Impact
-Access via SSH key cannot be revoked automatically when an IAM user is removed.
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0037/docs.md b/avd_docs/google/compute/AVD-GCP-0037/docs.md
index ad6faf1d..badad856 100644
--- a/avd_docs/google/compute/AVD-GCP-0037/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0037/docs.md
@@ -1,8 +1,9 @@
Sensitive values such as raw encryption keys should not be included in your Terraform code, and should be stored securely by a secrets manager.
+
### Impact
-The encryption key should be considered compromised as it is not stored securely.
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0039/docs.md b/avd_docs/google/compute/AVD-GCP-0039/docs.md
index cc52743d..5378192c 100644
--- a/avd_docs/google/compute/AVD-GCP-0039/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0039/docs.md
@@ -1,8 +1,9 @@
TLS versions prior to 1.2 are outdated and insecure. You should use 1.2 as aminimum version.
+
### Impact
-Data in transit is not sufficiently secured
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0041/docs.md b/avd_docs/google/compute/AVD-GCP-0041/docs.md
index b3523ef9..2eb73faa 100644
--- a/avd_docs/google/compute/AVD-GCP-0041/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0041/docs.md
@@ -1,8 +1,9 @@
The virtual TPM provides numerous security measures to your VM.
+
### Impact
-Unable to prevent unwanted system state modification
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0042/docs.md b/avd_docs/google/compute/AVD-GCP-0042/docs.md
index ef1c3093..a2db8c01 100644
--- a/avd_docs/google/compute/AVD-GCP-0042/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0042/docs.md
@@ -1,8 +1,9 @@
OS Login automatically revokes the relevant SSH keys when an IAM user has their access revoked.
+
### Impact
-Access via SSH key cannot be revoked automatically when an IAM user is removed.
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0043/docs.md b/avd_docs/google/compute/AVD-GCP-0043/docs.md
index b64da5dc..60578172 100644
--- a/avd_docs/google/compute/AVD-GCP-0043/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0043/docs.md
@@ -1,8 +1,9 @@
Disabling IP forwarding ensures the instance can only receive packets addressed to the instance and can only send packets with a source address of the instance.
+
### Impact
-Instance can send/receive packets without the explicit instance address
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0044/docs.md b/avd_docs/google/compute/AVD-GCP-0044/docs.md
index 9b013753..cae97f2c 100644
--- a/avd_docs/google/compute/AVD-GCP-0044/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0044/docs.md
@@ -1,8 +1,9 @@
The default service account has full project access. Instances should instead be assigned the minimal access they need.
+
### Impact
-Instance has full access to the project
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0045/docs.md b/avd_docs/google/compute/AVD-GCP-0045/docs.md
index 80ab9276..4bbaa795 100644
--- a/avd_docs/google/compute/AVD-GCP-0045/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0045/docs.md
@@ -1,8 +1,9 @@
Integrity monitoring helps you understand and make decisions about the state of your VM instances.
+
### Impact
-No visibility of VM instance boot state.
+
{{ remediationActions }}
diff --git a/avd_docs/google/compute/AVD-GCP-0067/docs.md b/avd_docs/google/compute/AVD-GCP-0067/docs.md
index 0f5d76fb..ff531130 100644
--- a/avd_docs/google/compute/AVD-GCP-0067/docs.md
+++ b/avd_docs/google/compute/AVD-GCP-0067/docs.md
@@ -1,8 +1,9 @@
Secure boot helps ensure that the system only runs authentic software.
+
### Impact
-Unable to verify digital signature of boot components, and unable to stop the boot process if verification fails.
+
{{ remediationActions }}
diff --git a/checks/cloud/google/compute/disk_encryption_customer_key.go b/checks/cloud/google/compute/disk_encryption_customer_key.go
index 650d7438..cd84f570 100755
--- a/checks/cloud/google/compute/disk_encryption_customer_key.go
+++ b/checks/cloud/google/compute/disk_encryption_customer_key.go
@@ -25,7 +25,8 @@ var CheckDiskEncryptionCustomerKey = rules.Register(
Links: terraformDiskEncryptionCustomerKeyLinks,
RemediationMarkdown: terraformDiskEncryptionCustomerKeyRemediationMarkdown,
},
- Severity: severity.Low,
+ Severity: severity.Low,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, disk := range s.Google.Compute.Disks {
diff --git a/checks/cloud/google/compute/disk_encryption_customer_key.rego b/checks/cloud/google/compute/disk_encryption_customer_key.rego
new file mode 100644
index 00000000..82ef98b1
--- /dev/null
+++ b/checks/cloud/google/compute/disk_encryption_customer_key.rego
@@ -0,0 +1,40 @@
+# METADATA
+# title: Disks should be encrypted with customer managed encryption keys
+# description: |
+# Using unmanaged keys makes rotation and general management difficult.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0034
+# avd_id: AVD-GCP-0034
+# provider: google
+# service: compute
+# severity: LOW
+# short_code: disk-encryption-customer-key
+# recommended_action: Use managed keys to encrypt disks.
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_disk#kms_key_self_link
+# good_examples: checks/cloud/google/compute/disk_encryption_customer_key.tf.go
+# bad_examples: checks/cloud/google/compute/disk_encryption_customer_key.tf.go
+package builtin.google.compute.google0034
+
+import rego.v1
+
+deny contains res if {
+ some disk in input.google.compute.disks
+ not is_disk_encrypted(disk)
+ res := result.new(
+ "Disk is not encrypted with a customer managed key.",
+ object.get(disk, ["encryption", "kmskeylink"], disk),
+ )
+}
+
+is_disk_encrypted(disk) := disk.encryption.kmskeylink.value != ""
diff --git a/checks/cloud/google/compute/disk_encryption_customer_key_test.go b/checks/cloud/google/compute/disk_encryption_customer_key_test.go
deleted file mode 100644
index de3675c8..00000000
--- a/checks/cloud/google/compute/disk_encryption_customer_key_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckDiskEncryptionCustomerKey(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Disk missing KMS key link",
- input: compute.Compute{
- Disks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- KMSKeyLink: trivyTypes.String("", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Disk with KMS key link provided",
- input: compute.Compute{
- Disks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- KMSKeyLink: trivyTypes.String("kms-key-link", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckDiskEncryptionCustomerKey.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckDiskEncryptionCustomerKey.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/disk_encryption_customer_key_test.rego b/checks/cloud/google/compute/disk_encryption_customer_key_test.rego
new file mode 100644
index 00000000..cebc1611
--- /dev/null
+++ b/checks/cloud/google/compute/disk_encryption_customer_key_test.rego
@@ -0,0 +1,24 @@
+package builtin.google.compute.google0034_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0034 as check
+import data.lib.test
+
+test_deny_disk_is_not_encrypted if {
+ inp := {"google": {"compute": {"disks": [{"encryption": {"kmskeylink": {"value": ""}}}]}}}
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_deny_disk_encryption_is_not_specified if {
+ inp := {"google": {"compute": {"disks": [{}]}}}
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_disk_is_encrypted if {
+ inp := {"google": {"compute": {"disks": [{"encryption": {"kmskeylink": {"value": "something"}}}]}}}
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/disk_encryption_no_plaintext_key.go b/checks/cloud/google/compute/disk_encryption_no_plaintext_key.go
index 8ca3f038..695656d6 100755
--- a/checks/cloud/google/compute/disk_encryption_no_plaintext_key.go
+++ b/checks/cloud/google/compute/disk_encryption_no_plaintext_key.go
@@ -27,7 +27,8 @@ var CheckDiskEncryptionRequired = rules.Register(
Links: terraformDiskEncryptionNoPlaintextKeyLinks,
RemediationMarkdown: terraformDiskEncryptionNoPlaintextKeyRemediationMarkdown,
},
- Severity: severity.Critical,
+ Severity: severity.Critical,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/disk_encryption_no_plaintext_key.rego b/checks/cloud/google/compute/disk_encryption_no_plaintext_key.rego
new file mode 100644
index 00000000..9fac519a
--- /dev/null
+++ b/checks/cloud/google/compute/disk_encryption_no_plaintext_key.rego
@@ -0,0 +1,57 @@
+# METADATA
+# title: The encryption key used to encrypt a compute disk has been specified in plaintext.
+# description: |
+# Sensitive values such as raw encryption keys should not be included in your Terraform code, and should be stored securely by a secrets manager.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/compute/docs/disks/customer-supplied-encryption
+# custom:
+# id: AVD-GCP-0037
+# avd_id: AVD-GCP-0037
+# provider: google
+# service: compute
+# severity: CRITICAL
+# short_code: disk-encryption-no-plaintext-key
+# recommended_action: Reference a managed key rather than include the key in raw format.
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_disk#kms_key_self_link
+# good_examples: checks/cloud/google/compute/disk_encryption_no_plaintext_key.tf.go
+# bad_examples: checks/cloud/google/compute/disk_encryption_no_plaintext_key.tf.go
+package builtin.google.compute.google0037
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ disks := array.concat(
+ object.get(instance, "bootdisks", []),
+ object.get(instance, "attacheddisks", []),
+ )
+
+ some disk in disks
+ encryption_key_has_plaintext(disk)
+ res := result.new(
+ "Instance disk has encryption key provided in plaintext.",
+ disk.encryption.rawkey,
+ )
+}
+
+deny contains res if {
+ some disk in input.google.compute.disks
+ encryption_key_has_plaintext(disk)
+ res := result.new(
+ "Disk encryption key is supplied in plaintext.",
+ disk.encryption.rawkey,
+ )
+}
+
+encryption_key_has_plaintext(disk) := count(disk.encryption.rawkey.value) > 0
diff --git a/checks/cloud/google/compute/disk_encryption_no_plaintext_key_test.go b/checks/cloud/google/compute/disk_encryption_no_plaintext_key_test.go
deleted file mode 100644
index 89fa43bb..00000000
--- a/checks/cloud/google/compute/disk_encryption_no_plaintext_key_test.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckDiskEncryptionRequired(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Disk with plaintext encryption key",
- input: compute.Compute{
- Disks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- RawKey: trivyTypes.Bytes([]byte("b2ggbm8gdGhpcyBpcyBiYWQ"), trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance disk with plaintext encryption key",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- BootDisks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- RawKey: trivyTypes.Bytes([]byte("b2ggbm8gdGhpcyBpcyBiYWQ"), trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Disks with no plaintext encryption keys",
- input: compute.Compute{
- Disks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- RawKey: trivyTypes.Bytes([]byte(""), trivyTypes.NewTestMetadata()),
- },
- },
- },
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- BootDisks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- RawKey: trivyTypes.Bytes([]byte(""), trivyTypes.NewTestMetadata()),
- },
- },
- },
- AttachedDisks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- RawKey: trivyTypes.Bytes([]byte(""), trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckDiskEncryptionRequired.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckDiskEncryptionRequired.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/disk_encryption_no_plaintext_key_test.rego b/checks/cloud/google/compute/disk_encryption_no_plaintext_key_test.rego
new file mode 100644
index 00000000..300c0800
--- /dev/null
+++ b/checks/cloud/google/compute/disk_encryption_no_plaintext_key_test.rego
@@ -0,0 +1,40 @@
+package builtin.google.compute.google0037_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0037 as check
+import data.lib.test
+
+test_deny_disk_with_plaintext_encryption_key if {
+ inp := {"google": {"compute": {"disks": [{"encryption": {"rawkey": {"value": "b2ggbm8gdGhpcyBpcyBiYWQ"}}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_deny_instance_boot_disk_with_plaintext_encryption_key if {
+ inp := {"google": {"compute": {"instances": [{"bootdisks": [{"encryption": {"rawkey": {"value": "b2ggbm8gdGhpcyBpcyBiYWQ"}}}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_deny_instance_attached_disk_with_plaintext_encryption_key if {
+ inp := {"google": {"compute": {"instances": [{"attacheddisks": [{"encryption": {"rawkey": {"value": "b2ggbm8gdGhpcyBpcyBiYWQ"}}}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_disks_without_plaintext_encryption_key if {
+ inp := {"google": {"compute": {
+ "disks": [{"encryption": {"rawkey": {"value": ""}}}],
+ "instances": [{
+ "bootdisks": [{"encryption": {"rawkey": {"value": ""}}}],
+ "attacheddisks": [{"encryption": {"rawkey": {"value": ""}}}],
+ }],
+ }}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_im.go b/checks/cloud/google/compute/enable_shielded_vm_im.go
index 4a6a058d..cf0ff0b1 100755
--- a/checks/cloud/google/compute/enable_shielded_vm_im.go
+++ b/checks/cloud/google/compute/enable_shielded_vm_im.go
@@ -27,7 +27,8 @@ var CheckEnableShieldedVMIntegrityMonitoring = rules.Register(
Links: terraformEnableShieldedVmImLinks,
RemediationMarkdown: terraformEnableShieldedVmImRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/enable_shielded_vm_im.rego b/checks/cloud/google/compute/enable_shielded_vm_im.rego
new file mode 100644
index 00000000..c017f5e4
--- /dev/null
+++ b/checks/cloud/google/compute/enable_shielded_vm_im.rego
@@ -0,0 +1,37 @@
+# METADATA
+# title: Instances should have Shielded VM integrity monitoring enabled
+# description: |
+# Integrity monitoring helps you understand and make decisions about the state of your VM instances.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/security/shielded-cloud/shielded-vm#integrity-monitoring
+# custom:
+# id: AVD-GCP-0045
+# avd_id: AVD-GCP-0045
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: enable-shielded-vm-im
+# recommended_action: Enable Shielded VM Integrity Monitoring
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#enable_vtpm
+# good_examples: checks/cloud/google/compute/enable_shielded_vm_im.tf.go
+# bad_examples: checks/cloud/google/compute/enable_shielded_vm_im.tf.go
+package builtin.google.compute.google0045
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.shieldedvm.integritymonitoringenabled.value == false
+ res := result.new("Instance does not have shielded VM integrity monitoring enabled.", instance.shieldedvm.integritymonitoringenabled)
+}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_im_test.go b/checks/cloud/google/compute/enable_shielded_vm_im_test.go
deleted file mode 100644
index 94f768be..00000000
--- a/checks/cloud/google/compute/enable_shielded_vm_im_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckEnableShieldedVMIntegrityMonitoring(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance shielded VM integrity monitoring disabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ShieldedVM: compute.ShieldedVMConfig{
- Metadata: trivyTypes.NewTestMetadata(),
- IntegrityMonitoringEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance shielded VM integrity monitoring enabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ShieldedVM: compute.ShieldedVMConfig{
- Metadata: trivyTypes.NewTestMetadata(),
- IntegrityMonitoringEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckEnableShieldedVMIntegrityMonitoring.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckEnableShieldedVMIntegrityMonitoring.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_im_test.rego b/checks/cloud/google/compute/enable_shielded_vm_im_test.rego
new file mode 100644
index 00000000..40c097d3
--- /dev/null
+++ b/checks/cloud/google/compute/enable_shielded_vm_im_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0045_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0045 as check
+import data.lib.test
+
+test_deny_instance_shielded_vm_integrity_monitoring_disabled if {
+ inp := {"google": {"compute": {"instances": [{"shieldedvm": {"integritymonitoringenabled": {"value": false}}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_shielded_vm_integrity_monitoring_enabled if {
+ inp := {"google": {"compute": {"instances": [{"shieldedvm": {"integritymonitoringenabled": {"value": true}}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_sb.go b/checks/cloud/google/compute/enable_shielded_vm_sb.go
index d0b7abe7..16f7747b 100644
--- a/checks/cloud/google/compute/enable_shielded_vm_sb.go
+++ b/checks/cloud/google/compute/enable_shielded_vm_sb.go
@@ -27,7 +27,8 @@ var CheckEnableShieldedVMSecureBoot = rules.Register(
Links: terraformEnableShieldedVmSbLinks,
RemediationMarkdown: terraformEnableShieldedVmSbRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/enable_shielded_vm_sb.rego b/checks/cloud/google/compute/enable_shielded_vm_sb.rego
new file mode 100644
index 00000000..1c252d12
--- /dev/null
+++ b/checks/cloud/google/compute/enable_shielded_vm_sb.rego
@@ -0,0 +1,40 @@
+# METADATA
+# title: Instances should have Shielded VM secure boot enabled
+# description: |
+# Secure boot helps ensure that the system only runs authentic software.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/security/shielded-cloud/shielded-vm#secure-boot
+# custom:
+# id: AVD-GCP-0067
+# avd_id: AVD-GCP-0067
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: enable-shielded-vm-sb
+# recommended_action: Enable Shielded VM secure boot
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#enable_secure_boot
+# good_examples: checks/cloud/google/compute/enable_shielded_vm_sb.tf.go
+# bad_examples: checks/cloud/google/compute/enable_shielded_vm_sb.tf.go
+package builtin.google.compute.google0067
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.shieldedvm.securebootenabled.value == false
+ res := result.new(
+ "Instance does not have shielded VM secure boot enabled.",
+ instance.shieldedvm.securebootenabled,
+ )
+}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_sb_test.go b/checks/cloud/google/compute/enable_shielded_vm_sb_test.go
deleted file mode 100644
index a4f948e4..00000000
--- a/checks/cloud/google/compute/enable_shielded_vm_sb_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckEnableShieldedVMSecureBoot(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance shielded VM secure boot disabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ShieldedVM: compute.ShieldedVMConfig{
- Metadata: trivyTypes.NewTestMetadata(),
- SecureBootEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance shielded VM secure boot enabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ShieldedVM: compute.ShieldedVMConfig{
- Metadata: trivyTypes.NewTestMetadata(),
- SecureBootEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckEnableShieldedVMSecureBoot.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckEnableShieldedVMSecureBoot.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_sb_test.rego b/checks/cloud/google/compute/enable_shielded_vm_sb_test.rego
new file mode 100644
index 00000000..76d9821a
--- /dev/null
+++ b/checks/cloud/google/compute/enable_shielded_vm_sb_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0067_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0067 as check
+import data.lib.test
+
+test_deny_instance_shielded_vm_secure_boot_disabled if {
+ inp := {"google": {"compute": {"instances": [{"shieldedvm": {"securebootenabled": {"value": false}}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_shielded_vm_secure_boot_enabled if {
+ inp := {"google": {"compute": {"instances": [{"shieldedvm": {"securebootenabled": {"value": true}}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_vtpm.go b/checks/cloud/google/compute/enable_shielded_vm_vtpm.go
index 26786edb..650a7fe5 100755
--- a/checks/cloud/google/compute/enable_shielded_vm_vtpm.go
+++ b/checks/cloud/google/compute/enable_shielded_vm_vtpm.go
@@ -27,7 +27,8 @@ var CheckEnableShieldedVMVTPM = rules.Register(
Links: terraformEnableShieldedVmVtpmLinks,
RemediationMarkdown: terraformEnableShieldedVmVtpmRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/enable_shielded_vm_vtpm.rego b/checks/cloud/google/compute/enable_shielded_vm_vtpm.rego
new file mode 100644
index 00000000..043a4a12
--- /dev/null
+++ b/checks/cloud/google/compute/enable_shielded_vm_vtpm.rego
@@ -0,0 +1,40 @@
+# METADATA
+# title: Instances should have Shielded VM VTPM enabled
+# description: |
+# The virtual TPM provides numerous security measures to your VM.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/blog/products/identity-security/virtual-trusted-platform-module-for-shielded-vms-security-in-plaintext
+# custom:
+# id: AVD-GCP-0041
+# avd_id: AVD-GCP-0041
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: enable-shielded-vm-vtpm
+# recommended_action: Enable Shielded VM VTPM
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#enable_vtpm
+# good_examples: checks/cloud/google/compute/enable_shielded_vm_vtpm.tf.go
+# bad_examples: checks/cloud/google/compute/enable_shielded_vm_vtpm.tf.go
+package builtin.google.compute.google0041
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.shieldedvm.vtpmenabled.value == false
+ res := result.new(
+ "Instance does not have VTPM for shielded VMs enabled.",
+ instance.shieldedvm.vtpmenabled,
+ )
+}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_vtpm_test.go b/checks/cloud/google/compute/enable_shielded_vm_vtpm_test.go
deleted file mode 100644
index 40925a81..00000000
--- a/checks/cloud/google/compute/enable_shielded_vm_vtpm_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckEnableShieldedVMVTPM(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance shielded VM VTPM disabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ShieldedVM: compute.ShieldedVMConfig{
- Metadata: trivyTypes.NewTestMetadata(),
- VTPMEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance shielded VM VTPM enabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ShieldedVM: compute.ShieldedVMConfig{
- Metadata: trivyTypes.NewTestMetadata(),
- VTPMEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckEnableShieldedVMVTPM.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckEnableShieldedVMVTPM.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/enable_shielded_vm_vtpm_test.rego b/checks/cloud/google/compute/enable_shielded_vm_vtpm_test.rego
new file mode 100644
index 00000000..f808134c
--- /dev/null
+++ b/checks/cloud/google/compute/enable_shielded_vm_vtpm_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0041_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0041 as check
+import data.lib.test
+
+test_deny_instance_shielded_vm_vptm_disabled if {
+ inp := {"google": {"compute": {"instances": [{"shieldedvm": {"vtpmenabled": {"value": false}}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_shielded_vm_vptm_enabled if {
+ inp := {"google": {"compute": {"instances": [{"shieldedvm": {"vtpmenabled": {"value": true}}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/enable_vpc_flow_logs.go b/checks/cloud/google/compute/enable_vpc_flow_logs.go
index 060f9cff..ef88b095 100755
--- a/checks/cloud/google/compute/enable_vpc_flow_logs.go
+++ b/checks/cloud/google/compute/enable_vpc_flow_logs.go
@@ -25,7 +25,8 @@ var CheckEnableVPCFlowLogs = rules.Register(
Links: terraformEnableVpcFlowLogsLinks,
RemediationMarkdown: terraformEnableVpcFlowLogsRemediationMarkdown,
},
- Severity: severity.Low,
+ Severity: severity.Low,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, network := range s.Google.Compute.Networks {
diff --git a/checks/cloud/google/compute/enable_vpc_flow_logs.rego b/checks/cloud/google/compute/enable_vpc_flow_logs.rego
new file mode 100644
index 00000000..73ef9bd6
--- /dev/null
+++ b/checks/cloud/google/compute/enable_vpc_flow_logs.rego
@@ -0,0 +1,45 @@
+# METADATA
+# title: VPC flow logs should be enabled for all subnetworks
+# description: |
+# VPC flow logs record information about all traffic, which is a vital tool in reviewing anomalous traffic.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0029
+# avd_id: AVD-GCP-0029
+# provider: google
+# service: compute
+# severity: LOW
+# short_code: enable-vpc-flow-logs
+# recommended_action: Enable VPC flow logs
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_subnetwork#enable_flow_logs
+# good_examples: checks/cloud/google/compute/enable_vpc_flow_logs.tf.go
+# bad_examples: checks/cloud/google/compute/enable_vpc_flow_logs.tf.go
+package builtin.google.compute.google0029
+
+import rego.v1
+
+deny contains res if {
+ some subnetwork in input.google.compute.networks[_].subnetworks
+ not is_proxy_only_network(subnetwork)
+ is_flow_logs_disabled(subnetwork)
+ res := result.new(
+ "Subnetwork does not have VPC flow logs enabled.",
+ object.get(subnetwork, "enableflowlogs", subnetwork),
+ )
+}
+
+is_proxy_only_network(network) if network.purpose.value in {"REGIONAL_MANAGED_PROXY", "GLOBAL_MANAGED_PROXY"}
+
+is_flow_logs_disabled(network) if {
+ not network.enableflowlogs.value
+}
diff --git a/checks/cloud/google/compute/enable_vpc_flow_logs_test.go b/checks/cloud/google/compute/enable_vpc_flow_logs_test.go
deleted file mode 100644
index 30a31292..00000000
--- a/checks/cloud/google/compute/enable_vpc_flow_logs_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckEnableVPCFlowLogs(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Subnetwork VPC flow logs disabled",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Subnetworks: []compute.SubNetwork{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableFlowLogs: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Subnetwork VPC flow logs enabled",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Subnetworks: []compute.SubNetwork{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableFlowLogs: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- expected: false,
- },
- {
- name: "Proxy-only subnets and logs disabled",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Subnetworks: []compute.SubNetwork{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableFlowLogs: trivyTypes.BoolDefault(false, trivyTypes.NewTestMetadata()),
- Purpose: trivyTypes.String("REGIONAL_MANAGED_PROXY", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckEnableVPCFlowLogs.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckEnableVPCFlowLogs.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/enable_vpc_flow_logs_test.rego b/checks/cloud/google/compute/enable_vpc_flow_logs_test.rego
new file mode 100644
index 00000000..78d348a0
--- /dev/null
+++ b/checks/cloud/google/compute/enable_vpc_flow_logs_test.rego
@@ -0,0 +1,43 @@
+package builtin.google.compute.google0029_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0029 as check
+import data.lib.test
+
+test_deny_vpc_flow_logs_disabled if {
+ inp := {"google": {"compute": {"networks": [{"subnetworks": [{"enableflowlogs": {"value": false}}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_deny_vpc_flow_logs_is_not_specified if {
+ inp := {"google": {"compute": {"networks": [{"subnetworks": [{}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_vpc_flow_logs_enabled if {
+ inp := {"google": {"compute": {"networks": [{"subnetworks": [{"enableflowlogs": {"value": true}}]}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
+
+test_allow_vpc_flow_logs_disabled_for_proxy_only if {
+ inp := {"google": {"compute": {"networks": [{"subnetworks": [
+ {
+ "enableflowlogs": {"value": false},
+ "purpose": {"value": "REGIONAL_MANAGED_PROXY"},
+ },
+ {
+ "enableflowlogs": {"value": false},
+ "purpose": {"value": "GLOBAL_MANAGED_PROXY"},
+ },
+ ]}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_default_service_account.go b/checks/cloud/google/compute/no_default_service_account.go
index c2894b7c..9d7b3752 100755
--- a/checks/cloud/google/compute/no_default_service_account.go
+++ b/checks/cloud/google/compute/no_default_service_account.go
@@ -25,7 +25,8 @@ var CheckNoDefaultServiceAccount = rules.Register(
Links: terraformNoDefaultServiceAccountLinks,
RemediationMarkdown: terraformNoDefaultServiceAccountRemediationMarkdown,
},
- Severity: severity.Critical,
+ Severity: severity.Critical,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/no_default_service_account.rego b/checks/cloud/google/compute/no_default_service_account.rego
new file mode 100644
index 00000000..5508e7e7
--- /dev/null
+++ b/checks/cloud/google/compute/no_default_service_account.rego
@@ -0,0 +1,41 @@
+# METADATA
+# title: Instances should not use the default service account
+# description: |
+# The default service account has full project access. Instances should instead be assigned the minimal access they need.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0044
+# avd_id: AVD-GCP-0044
+# provider: google
+# service: compute
+# severity: CRITICAL
+# short_code: no-default-service-account
+# recommended_action: Remove use of default service account
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#
+# good_examples: checks/cloud/google/compute/no_default_service_account.tf.go
+# bad_examples: checks/cloud/google/compute/no_default_service_account.tf.go
+package builtin.google.compute.google0044
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ service_account := instance.serviceaccount
+ is_default_service_account(service_account)
+ res := result.new(
+ "Instance uses the default service account.",
+ object.get(service_account, "email", service_account),
+ )
+}
+
+is_default_service_account(service_account) := service_account.isdefault.value == true
diff --git a/checks/cloud/google/compute/no_default_service_account_test.go b/checks/cloud/google/compute/no_default_service_account_test.go
deleted file mode 100644
index a6aaab82..00000000
--- a/checks/cloud/google/compute/no_default_service_account_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoDefaultServiceAccount(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance service account not specified",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ServiceAccount: compute.ServiceAccount{
- Metadata: trivyTypes.NewTestMetadata(),
- Email: trivyTypes.String("", trivyTypes.NewTestMetadata()),
- IsDefault: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance service account using the default email",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ServiceAccount: compute.ServiceAccount{
- Metadata: trivyTypes.NewTestMetadata(),
- Email: trivyTypes.String("1234567890-compute@developer.gserviceaccount.com", trivyTypes.NewTestMetadata()),
- IsDefault: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance service account with email provided",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- ServiceAccount: compute.ServiceAccount{
- Metadata: trivyTypes.NewTestMetadata(),
- Email: trivyTypes.String("proper@email.com", trivyTypes.NewTestMetadata()),
- IsDefault: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoDefaultServiceAccount.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoDefaultServiceAccount.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_default_service_account_test.rego b/checks/cloud/google/compute/no_default_service_account_test.rego
new file mode 100644
index 00000000..15814b7b
--- /dev/null
+++ b/checks/cloud/google/compute/no_default_service_account_test.rego
@@ -0,0 +1,23 @@
+package builtin.google.compute.google0044_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0044 as check
+import data.lib.test
+
+test_deny_instance_use_default_service_account if {
+ inp := {"google": {"compute": {"instances": [{"serviceaccount": {"isdefault": {"value": true}}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_use_proper_service_account if {
+ inp := {"google": {"compute": {"instances": [{"serviceaccount": {
+ "isdefault": {"value": false},
+ "email": {"value": "proper@email.com"},
+ }}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_ip_forwarding.go b/checks/cloud/google/compute/no_ip_forwarding.go
index b14106fc..2f61be03 100755
--- a/checks/cloud/google/compute/no_ip_forwarding.go
+++ b/checks/cloud/google/compute/no_ip_forwarding.go
@@ -25,7 +25,8 @@ var CheckNoIpForwarding = rules.Register(
Links: terraformNoIpForwardingLinks,
RemediationMarkdown: terraformNoIpForwardingRemediationMarkdown,
},
- Severity: severity.High,
+ Severity: severity.High,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/no_ip_forwarding.rego b/checks/cloud/google/compute/no_ip_forwarding.rego
new file mode 100644
index 00000000..58c01de2
--- /dev/null
+++ b/checks/cloud/google/compute/no_ip_forwarding.rego
@@ -0,0 +1,35 @@
+# METADATA
+# title: Instances should not have IP forwarding enabled
+# description: |
+# Disabling IP forwarding ensures the instance can only receive packets addressed to the instance and can only send packets with a source address of the instance.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0043
+# avd_id: AVD-GCP-0043
+# provider: google
+# service: compute
+# severity: HIGH
+# short_code: no-ip-forwarding
+# recommended_action: Disable IP forwarding
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#can_ip_forward
+# good_examples: checks/cloud/google/compute/no_ip_forwarding.tf.go
+# bad_examples: checks/cloud/google/compute/no_ip_forwarding.tf.go
+package builtin.google.compute.google0043
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.canipforward.value == true
+ res := result.new("Instance has IP forwarding allowed", instance.canipforward)
+}
diff --git a/checks/cloud/google/compute/no_ip_forwarding_test.go b/checks/cloud/google/compute/no_ip_forwarding_test.go
deleted file mode 100644
index 24f7df6d..00000000
--- a/checks/cloud/google/compute/no_ip_forwarding_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoIpForwarding(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance IP forwarding enabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- CanIPForward: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance IP forwarding disabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- CanIPForward: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoIpForwarding.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoIpForwarding.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_ip_forwarding_test.rego b/checks/cloud/google/compute/no_ip_forwarding_test.rego
new file mode 100644
index 00000000..ee3b5169
--- /dev/null
+++ b/checks/cloud/google/compute/no_ip_forwarding_test.rego
@@ -0,0 +1,27 @@
+package builtin.google.compute.google0043_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0043 as check
+import data.lib.test
+
+test_deny_instance_ip_forwarding_enabled if {
+ inp := {"google": {"compute": {"instances": [{"canipforward": {"value": true}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_ip_forwarding_disabled if {
+ inp := {"google": {"compute": {"instances": [{"canipforward": {"value": false}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
+
+test_allow_instance_ip_forwarding_is_not_specified if {
+ inp := {"google": {"compute": {"instances": [{}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_oslogin_override.go b/checks/cloud/google/compute/no_oslogin_override.go
index 1a683440..73520307 100755
--- a/checks/cloud/google/compute/no_oslogin_override.go
+++ b/checks/cloud/google/compute/no_oslogin_override.go
@@ -25,7 +25,8 @@ var CheckNoOsloginOverride = rules.Register(
Links: terraformNoOsloginOverrideLinks,
RemediationMarkdown: terraformNoOsloginOverrideRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/no_oslogin_override.rego b/checks/cloud/google/compute/no_oslogin_override.rego
new file mode 100644
index 00000000..2a4f49e7
--- /dev/null
+++ b/checks/cloud/google/compute/no_oslogin_override.rego
@@ -0,0 +1,35 @@
+# METADATA
+# title: Instances should not override the project setting for OS Login
+# description: |
+# OS Login automatically revokes the relevant SSH keys when an IAM user has their access revoked.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0036
+# avd_id: AVD-GCP-0036
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: no-oslogin-override
+# recommended_action: Enable OS Login at project level and remove instance-level overrides
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#
+# good_examples: checks/cloud/google/compute/no_oslogin_override.tf.go
+# bad_examples: checks/cloud/google/compute/no_oslogin_override.tf.go
+package builtin.google.compute.google0036
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.osloginenabled.value == false
+ res := result.new("Instance has OS Login disabled.", instance.osloginenabled)
+}
diff --git a/checks/cloud/google/compute/no_oslogin_override_test.go b/checks/cloud/google/compute/no_oslogin_override_test.go
deleted file mode 100644
index 7704dfa6..00000000
--- a/checks/cloud/google/compute/no_oslogin_override_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoOsloginOverride(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance OS login disabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- OSLoginEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance OS login enabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- OSLoginEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoOsloginOverride.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoOsloginOverride.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_oslogin_override_test.rego b/checks/cloud/google/compute/no_oslogin_override_test.rego
new file mode 100644
index 00000000..54677433
--- /dev/null
+++ b/checks/cloud/google/compute/no_oslogin_override_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0036_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0036 as check
+import data.lib.test
+
+test_deny_instance_os_login_disabled if {
+ inp := {"google": {"compute": {"instances": [{"osloginenabled": {"value": false}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_os_login_enabled if {
+ inp := {"google": {"compute": {"instances": [{"osloginenabled": {"value": true}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_project_wide_ssh_keys.go b/checks/cloud/google/compute/no_project_wide_ssh_keys.go
index 6d9b1ca0..b9d43557 100755
--- a/checks/cloud/google/compute/no_project_wide_ssh_keys.go
+++ b/checks/cloud/google/compute/no_project_wide_ssh_keys.go
@@ -25,7 +25,8 @@ var CheckNoProjectWideSshKeys = rules.Register(
Links: terraformNoProjectWideSshKeysLinks,
RemediationMarkdown: terraformNoProjectWideSshKeysRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/no_project_wide_ssh_keys.rego b/checks/cloud/google/compute/no_project_wide_ssh_keys.rego
new file mode 100644
index 00000000..fc60bb8f
--- /dev/null
+++ b/checks/cloud/google/compute/no_project_wide_ssh_keys.rego
@@ -0,0 +1,35 @@
+# METADATA
+# title: Disable project-wide SSH keys for all instances
+# description: |
+# Use of project-wide SSH keys means that a compromise of any one of these key pairs can result in all instances being compromised. It is recommended to use instance-level keys.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0030
+# avd_id: AVD-GCP-0030
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: no-project-wide-ssh-keys
+# recommended_action: Disable project-wide SSH keys
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#
+# good_examples: checks/cloud/google/compute/no_project_wide_ssh_keys.tf.go
+# bad_examples: checks/cloud/google/compute/no_project_wide_ssh_keys.tf.go
+package builtin.google.compute.google0030
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.enableprojectsshkeyblocking.value == false
+ res := result.new("Instance allows use of project-level SSH keys.", instance.enableprojectsshkeyblocking)
+}
diff --git a/checks/cloud/google/compute/no_project_wide_ssh_keys_test.go b/checks/cloud/google/compute/no_project_wide_ssh_keys_test.go
deleted file mode 100644
index 981f9d45..00000000
--- a/checks/cloud/google/compute/no_project_wide_ssh_keys_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoProjectWideSshKeys(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance project level SSH keys blocked",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableProjectSSHKeyBlocking: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance project level SSH keys allowed",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableProjectSSHKeyBlocking: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoProjectWideSshKeys.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoProjectWideSshKeys.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_project_wide_ssh_keys_test.rego b/checks/cloud/google/compute/no_project_wide_ssh_keys_test.rego
new file mode 100644
index 00000000..be2d56d7
--- /dev/null
+++ b/checks/cloud/google/compute/no_project_wide_ssh_keys_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0030_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0030 as check
+import data.lib.test
+
+test_deny_project_level_ssh_key_blocking_disabled if {
+ inp := {"google": {"compute": {"instances": [{"enableprojectsshkeyblocking": {"value": false}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_project_level_ssh_key_blocking_enabled if {
+ inp := {"google": {"compute": {"instances": [{"enableprojectsshkeyblocking": {"value": true}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_public_egress.go b/checks/cloud/google/compute/no_public_egress.go
index 6c5cd00e..c05858fb 100755
--- a/checks/cloud/google/compute/no_public_egress.go
+++ b/checks/cloud/google/compute/no_public_egress.go
@@ -30,7 +30,8 @@ Where possible, segments should be broken into smaller subnets and avoid using t
Links: terraformNoPublicEgressLinks,
RemediationMarkdown: terraformNoPublicEgressRemediationMarkdown,
},
- Severity: severity.Critical,
+ Severity: severity.Critical,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, network := range s.Google.Compute.Networks {
diff --git a/checks/cloud/google/compute/no_public_egress.rego b/checks/cloud/google/compute/no_public_egress.rego
new file mode 100644
index 00000000..d521ef18
--- /dev/null
+++ b/checks/cloud/google/compute/no_public_egress.rego
@@ -0,0 +1,46 @@
+# METADATA
+# title: An outbound firewall rule allows traffic to /0.
+# description: |
+# Network security rules should not use very broad subnets.
+# Where possible, segments should be broken into smaller subnets and avoid using the /0
subnet.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/vpc/docs/using-firewalls
+# custom:
+# id: AVD-GCP-0035
+# avd_id: AVD-GCP-0035
+# provider: google
+# service: compute
+# severity: CRITICAL
+# short_code: no-public-egress
+# recommended_action: Set a more restrictive cidr range
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_firewall
+# good_examples: checks/cloud/google/compute/no_public_egress.tf.go
+# bad_examples: checks/cloud/google/compute/no_public_egress.tf.go
+package builtin.google.compute.google0035
+
+import rego.v1
+
+deny contains res if {
+ some network in input.google.compute.networks
+ some rule in network.firewall.egressrules
+ rule.firewallrule.isallow.value
+ rule.firewallrule.enforced.value
+ some destination in rule.destinationranges
+ cidr.is_public(destination.value)
+ cidr.count_addresses(destination.value) > 1
+ res := result.new(
+ "Firewall rule allows egress traffic to multiple addresses on the public internet.",
+ destination,
+ )
+}
diff --git a/checks/cloud/google/compute/no_public_egress_test.go b/checks/cloud/google/compute/no_public_egress_test.go
deleted file mode 100644
index a1c7250b..00000000
--- a/checks/cloud/google/compute/no_public_egress_test.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoPublicEgress(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Firewall egress rule with multiple public destination addresses",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Firewall: &compute.Firewall{
- Metadata: trivyTypes.NewTestMetadata(),
- EgressRules: []compute.EgressRule{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- FirewallRule: compute.FirewallRule{
- Metadata: trivyTypes.NewTestMetadata(),
- IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- DestinationRanges: []trivyTypes.StringValue{
- trivyTypes.String("0.0.0.0/0", trivyTypes.NewTestMetadata()),
- trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Firewall egress rule with public destination address",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Firewall: &compute.Firewall{
- Metadata: trivyTypes.NewTestMetadata(),
- EgressRules: []compute.EgressRule{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- FirewallRule: compute.FirewallRule{
- Metadata: trivyTypes.NewTestMetadata(),
- IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- DestinationRanges: []trivyTypes.StringValue{
- trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoPublicEgress.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoPublicEgress.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_public_egress_test.rego b/checks/cloud/google/compute/no_public_egress_test.rego
new file mode 100644
index 00000000..c7020430
--- /dev/null
+++ b/checks/cloud/google/compute/no_public_egress_test.rego
@@ -0,0 +1,35 @@
+package builtin.google.compute.google0035_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0035 as check
+import data.lib.test
+
+test_deny_egress_rule_with_multiple_public_destinations if {
+ inp := {"google": {"compute": {"networks": [{"firewall": {"egressrules": [{
+ "firewallrule": {
+ "isallow": {"value": true},
+ "enforced": {"value": true},
+ },
+ "destinationranges": [
+ {"value": "0.0.0.0/0"},
+ {"value": "1.2.3.4/32"},
+ ],
+ }]}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_egress_rule_with_public_destination if {
+ inp := {"google": {"compute": {"networks": [{"firewall": {"egressrules": [{
+ "firewallrule": {
+ "isallow": {"value": true},
+ "enforced": {"value": true},
+ },
+ "destinationranges": [{"value": "1.2.3.4/32"}],
+ }]}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_public_ingress.go b/checks/cloud/google/compute/no_public_ingress.go
index 729bdfb5..835e0d68 100755
--- a/checks/cloud/google/compute/no_public_ingress.go
+++ b/checks/cloud/google/compute/no_public_ingress.go
@@ -30,7 +30,8 @@ Where possible, segments should be broken into smaller subnets and avoid using t
Links: terraformNoPublicIngressLinks,
RemediationMarkdown: terraformNoPublicIngressRemediationMarkdown,
},
- Severity: severity.Critical,
+ Severity: severity.Critical,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, network := range s.Google.Compute.Networks {
diff --git a/checks/cloud/google/compute/no_public_ingress.rego b/checks/cloud/google/compute/no_public_ingress.rego
new file mode 100644
index 00000000..5ef3e608
--- /dev/null
+++ b/checks/cloud/google/compute/no_public_ingress.rego
@@ -0,0 +1,50 @@
+# METADATA
+# title: An inbound firewall rule allows traffic from /0.
+# description: |
+# Network security rules should not use very broad subnets.
+# Where possible, segments should be broken into smaller subnets and avoid using the /0
subnet.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/vpc/docs/using-firewalls
+# custom:
+# id: AVD-GCP-0027
+# avd_id: AVD-GCP-0027
+# provider: google
+# service: compute
+# severity: CRITICAL
+# short_code: no-public-ingress
+# recommended_action: Set a more restrictive cidr range
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_firewall#source_ranges
+# - https://www.terraform.io/docs/providers/google/r/compute_firewall.html
+# good_examples: checks/cloud/google/compute/no_public_ingress.tf.go
+# bad_examples: checks/cloud/google/compute/no_public_ingress.tf.go
+package builtin.google.compute.google0027
+
+import rego.v1
+
+deny contains res if {
+ some network in input.google.compute.networks
+ count(object.get(network.firewall, "sourcetags", [])) == 0
+ count(object.get(network.firewall, "targettags", [])) == 0
+
+ some rule in network.firewall.ingressrules
+ rule.firewallrule.isallow.value
+ rule.firewallrule.enforced.value
+ some source in rule.sourceranges
+ cidr.is_public(source.value)
+ cidr.count_addresses(source.value) > 1
+ res := result.new(
+ "Firewall rule allows ingress traffic from multiple addresses on the public internet.",
+ source,
+ )
+}
diff --git a/checks/cloud/google/compute/no_public_ingress_test.go b/checks/cloud/google/compute/no_public_ingress_test.go
deleted file mode 100644
index b5da484c..00000000
--- a/checks/cloud/google/compute/no_public_ingress_test.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoPublicIngress(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Firewall ingress rule with multiple public source addresses",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Firewall: &compute.Firewall{
- Metadata: trivyTypes.NewTestMetadata(),
- IngressRules: []compute.IngressRule{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- FirewallRule: compute.FirewallRule{
- Metadata: trivyTypes.NewTestMetadata(),
- IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- SourceRanges: []trivyTypes.StringValue{
- trivyTypes.String("0.0.0.0/0", trivyTypes.NewTestMetadata()),
- trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Firewall ingress rule with public source address",
- input: compute.Compute{
- Networks: []compute.Network{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Firewall: &compute.Firewall{
- Metadata: trivyTypes.NewTestMetadata(),
- IngressRules: []compute.IngressRule{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- FirewallRule: compute.FirewallRule{
- Metadata: trivyTypes.NewTestMetadata(),
- IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- SourceRanges: []trivyTypes.StringValue{
- trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoPublicIngress.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoPublicIngress.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_public_ingress_test.rego b/checks/cloud/google/compute/no_public_ingress_test.rego
new file mode 100644
index 00000000..3c175021
--- /dev/null
+++ b/checks/cloud/google/compute/no_public_ingress_test.rego
@@ -0,0 +1,35 @@
+package builtin.google.compute.google0027_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0027 as check
+import data.lib.test
+
+test_deny_ingress_rule_with_multiple_public_sources if {
+ inp := {"google": {"compute": {"networks": [{"firewall": {"ingressrules": [{
+ "firewallrule": {
+ "isallow": {"value": true},
+ "enforced": {"value": true},
+ },
+ "sourceranges": [
+ {"value": "0.0.0.0/0"},
+ {"value": "1.2.3.4/32"},
+ ],
+ }]}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_ingress_rule_with_public_source_address if {
+ inp := {"google": {"compute": {"networks": [{"firewall": {"ingressrules": [{
+ "firewallrule": {
+ "isallow": {"value": true},
+ "enforced": {"value": true},
+ },
+ "sourceranges": [{"value": "1.2.3.4/32"}],
+ }]}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_public_ip.go b/checks/cloud/google/compute/no_public_ip.go
index 0cc15a7d..469323f8 100755
--- a/checks/cloud/google/compute/no_public_ip.go
+++ b/checks/cloud/google/compute/no_public_ip.go
@@ -28,6 +28,7 @@ var CheckInstancesDoNotHavePublicIPs = rules.Register(
Links: []string{
"https://cloud.google.com/compute/docs/ip-addresses#externaladdresses",
},
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/no_public_ip.rego b/checks/cloud/google/compute/no_public_ip.rego
new file mode 100644
index 00000000..9cc029f1
--- /dev/null
+++ b/checks/cloud/google/compute/no_public_ip.rego
@@ -0,0 +1,38 @@
+# METADATA
+# title: Instances should not have public IP addresses
+# description: |
+# Instances should not be publicly exposed to the internet
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# related_resources:
+# - https://cloud.google.com/compute/docs/ip-addresses#externaladdresses
+# custom:
+# id: AVD-GCP-0031
+# avd_id: AVD-GCP-0031
+# provider: google
+# service: compute
+# severity: HIGH
+# short_code: no-public-ip
+# recommended_action: Remove public IP
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#access_config
+# good_examples: checks/cloud/google/compute/no_public_ip.tf.go
+# bad_examples: checks/cloud/google/compute/no_public_ip.tf.go
+package builtin.google.compute.google0031
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ some ni in instance.networkinterfaces
+ ni.haspublicip.value == true
+ res := result.new("Instance has a public IP allocated.", ni.haspublicip)
+}
diff --git a/checks/cloud/google/compute/no_public_ip_test.go b/checks/cloud/google/compute/no_public_ip_test.go
deleted file mode 100755
index 8855a5a7..00000000
--- a/checks/cloud/google/compute/no_public_ip_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckInstancesDoNotHavePublicIPs(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Network interface with public IP",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- NetworkInterfaces: []compute.NetworkInterface{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- HasPublicIP: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Network interface without public IP",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- NetworkInterfaces: []compute.NetworkInterface{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- HasPublicIP: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- }},
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckInstancesDoNotHavePublicIPs.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckInstancesDoNotHavePublicIPs.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_public_ip_test.rego b/checks/cloud/google/compute/no_public_ip_test.rego
new file mode 100644
index 00000000..f6e639ec
--- /dev/null
+++ b/checks/cloud/google/compute/no_public_ip_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0031_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0031 as check
+import data.lib.test
+
+test_deny_instance_network_interface_has_public_ip if {
+ inp := {"google": {"compute": {"instances": [{"networkinterfaces": [{"haspublicip": {"value": true}}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_network_interface_has_no_public_ip if {
+ inp := {"google": {"compute": {"instances": [{"networkinterfaces": [{"haspublicip": {"value": false}}]}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/no_serial_port.go b/checks/cloud/google/compute/no_serial_port.go
index 6f545a52..ebdb1049 100755
--- a/checks/cloud/google/compute/no_serial_port.go
+++ b/checks/cloud/google/compute/no_serial_port.go
@@ -25,7 +25,8 @@ var CheckNoSerialPort = rules.Register(
Links: terraformNoSerialPortLinks,
RemediationMarkdown: terraformNoSerialPortRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/no_serial_port.rego b/checks/cloud/google/compute/no_serial_port.rego
new file mode 100644
index 00000000..f69233e0
--- /dev/null
+++ b/checks/cloud/google/compute/no_serial_port.rego
@@ -0,0 +1,35 @@
+# METADATA
+# title: Disable serial port connectivity for all instances
+# description: |
+# When serial port access is enabled, the access is not governed by network security rules meaning the port can be exposed publicly.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0032
+# avd_id: AVD-GCP-0032
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: no-serial-port
+# recommended_action: Disable serial port access
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#
+# good_examples: checks/cloud/google/compute/no_serial_port.tf.go
+# bad_examples: checks/cloud/google/compute/no_serial_port.tf.go
+package builtin.google.compute.google0032
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ instance.enableserialport.value == true
+ res := result.new("Instance has serial port enabled.", instance.enableserialport)
+}
diff --git a/checks/cloud/google/compute/no_serial_port_test.go b/checks/cloud/google/compute/no_serial_port_test.go
deleted file mode 100644
index 7334a661..00000000
--- a/checks/cloud/google/compute/no_serial_port_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckNoSerialPort(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance serial port enabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableSerialPort: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance serial port disabled",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- EnableSerialPort: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckNoSerialPort.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoSerialPort.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/no_serial_port_test.rego b/checks/cloud/google/compute/no_serial_port_test.rego
new file mode 100644
index 00000000..746e7c42
--- /dev/null
+++ b/checks/cloud/google/compute/no_serial_port_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0032_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0032 as check
+import data.lib.test
+
+test_deny_instance_serial_port_enabled if {
+ inp := {"google": {"compute": {"instances": [{"enableserialport": {"value": true}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_serial_port_disabled if {
+ inp := {"google": {"compute": {"instances": [{"enableserialport": {"value": false}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/project_level_oslogin.go b/checks/cloud/google/compute/project_level_oslogin.go
index 6fb75955..87f65e10 100755
--- a/checks/cloud/google/compute/project_level_oslogin.go
+++ b/checks/cloud/google/compute/project_level_oslogin.go
@@ -25,7 +25,8 @@ var CheckProjectLevelOslogin = rules.Register(
Links: terraformProjectLevelOsloginLinks,
RemediationMarkdown: terraformProjectLevelOsloginRemediationMarkdown,
},
- Severity: severity.Medium,
+ Severity: severity.Medium,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
if s.Google.Compute.ProjectMetadata.Metadata.IsManaged() {
diff --git a/checks/cloud/google/compute/project_level_oslogin.rego b/checks/cloud/google/compute/project_level_oslogin.rego
new file mode 100644
index 00000000..d4d299ff
--- /dev/null
+++ b/checks/cloud/google/compute/project_level_oslogin.rego
@@ -0,0 +1,36 @@
+# METADATA
+# title: OS Login should be enabled at project level
+# description: |
+# OS Login automatically revokes the relevant SSH keys when an IAM user has their access revoked.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0042
+# avd_id: AVD-GCP-0042
+# provider: google
+# service: compute
+# severity: MEDIUM
+# short_code: project-level-oslogin
+# recommended_action: Enable OS Login at project level
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_project_metadata#
+# good_examples: checks/cloud/google/compute/project_level_oslogin.tf.go
+# bad_examples: checks/cloud/google/compute/project_level_oslogin.tf.go
+package builtin.google.compute.google0042
+
+import rego.v1
+
+deny contains res if {
+ metadata := input.google.compute.projectmetadata
+ isManaged(metadata)
+ not metadata.enableoslogin.value
+ res := result.new("OS Login is disabled at project level.", metadata)
+}
diff --git a/checks/cloud/google/compute/project_level_oslogin_test.go b/checks/cloud/google/compute/project_level_oslogin_test.go
deleted file mode 100644
index 6c16f198..00000000
--- a/checks/cloud/google/compute/project_level_oslogin_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckProjectLevelOslogin(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Compute OS login disabled",
- input: compute.Compute{
- ProjectMetadata: compute.ProjectMetadata{
- Metadata: trivyTypes.NewTestMetadata(),
- EnableOSLogin: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
- },
- },
- expected: true,
- },
- {
- name: "Compute OS login enabled",
- input: compute.Compute{
- ProjectMetadata: compute.ProjectMetadata{
- Metadata: trivyTypes.NewTestMetadata(),
- EnableOSLogin: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckProjectLevelOslogin.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckProjectLevelOslogin.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/project_level_oslogin_test.rego b/checks/cloud/google/compute/project_level_oslogin_test.rego
new file mode 100644
index 00000000..e5d96aa0
--- /dev/null
+++ b/checks/cloud/google/compute/project_level_oslogin_test.rego
@@ -0,0 +1,30 @@
+package builtin.google.compute.google0042_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0042 as check
+import data.lib.test
+
+test_deny_compute_os_login_disabled if {
+ inp := {"google": {"compute": {"projectmetadata": {"enableoslogin": {"value": false}}}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_compute_os_login_enabled if {
+ inp := {"google": {"compute": {"projectmetadata": {"enableoslogin": {"value": true}}}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
+
+test_allow_compute_os_login_is_not_managed if {
+ inp := {"google": {"compute": {"projectmetadata": {
+ "__defsec_metadata": {"managed": false},
+ "enableoslogin": {"value": false},
+ }}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/use_secure_tls_policy.go b/checks/cloud/google/compute/use_secure_tls_policy.go
index 8f25934d..71592f6f 100755
--- a/checks/cloud/google/compute/use_secure_tls_policy.go
+++ b/checks/cloud/google/compute/use_secure_tls_policy.go
@@ -25,7 +25,8 @@ var CheckUseSecureTlsPolicy = rules.Register(
Links: terraformUseSecureTlsPolicyLinks,
RemediationMarkdown: terraformUseSecureTlsPolicyRemediationMarkdown,
},
- Severity: severity.Critical,
+ Severity: severity.Critical,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, policy := range s.Google.Compute.SSLPolicies {
diff --git a/checks/cloud/google/compute/use_secure_tls_policy.rego b/checks/cloud/google/compute/use_secure_tls_policy.rego
new file mode 100644
index 00000000..123d42c4
--- /dev/null
+++ b/checks/cloud/google/compute/use_secure_tls_policy.rego
@@ -0,0 +1,37 @@
+# METADATA
+# title: SSL policies should enforce secure versions of TLS
+# description: |
+# TLS versions prior to 1.2 are outdated and insecure. You should use 1.2 as aminimum version.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0039
+# avd_id: AVD-GCP-0039
+# provider: google
+# service: compute
+# severity: CRITICAL
+# short_code: use-secure-tls-policy
+# recommended_action: Enforce a minimum TLS version of 1.2
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_ssl_policy#min_tls_version
+# good_examples: checks/cloud/google/compute/use_secure_tls_policy.tf.go
+# bad_examples: checks/cloud/google/compute/use_secure_tls_policy.tf.go
+package builtin.google.compute.google0039
+
+import rego.v1
+
+tls_v_1_2 := "TLS_1_2"
+
+deny contains res if {
+ some policy in input.google.compute.sslpolicies
+ policy.minimumtlsversion.value != tls_v_1_2
+ res := result.new("TLS policy does not specify a minimum of TLS 1.2", policy.minimumtlsversion)
+}
diff --git a/checks/cloud/google/compute/use_secure_tls_policy_test.go b/checks/cloud/google/compute/use_secure_tls_policy_test.go
deleted file mode 100644
index 5da9f4ca..00000000
--- a/checks/cloud/google/compute/use_secure_tls_policy_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckUseSecureTlsPolicy(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "SSL policy minimum TLS version 1.0",
- input: compute.Compute{
- SSLPolicies: []compute.SSLPolicy{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- MinimumTLSVersion: trivyTypes.String("TLS_1_0", trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: true,
- },
- {
- name: "SSL policy minimum TLS version 1.2",
- input: compute.Compute{
- SSLPolicies: []compute.SSLPolicy{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- MinimumTLSVersion: trivyTypes.String("TLS_1_2", trivyTypes.NewTestMetadata()),
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckUseSecureTlsPolicy.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckUseSecureTlsPolicy.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/use_secure_tls_policy_test.rego b/checks/cloud/google/compute/use_secure_tls_policy_test.rego
new file mode 100644
index 00000000..1e66d9a5
--- /dev/null
+++ b/checks/cloud/google/compute/use_secure_tls_policy_test.rego
@@ -0,0 +1,20 @@
+package builtin.google.compute.google0039_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0039 as check
+import data.lib.test
+
+test_deny_ssl_policy_minimum_tls_version_is_1 if {
+ inp := {"google": {"compute": {"sslpolicies": [{"minimumtlsversion": {"value": "TLS_1_0"}}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_ssl_policy_minimum_tls_version_is_1_2 if {
+ inp := {"google": {"compute": {"sslpolicies": [{"minimumtlsversion": {"value": check.tls_v_1_2}}]}}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/checks/cloud/google/compute/vm_disk_encryption_customer_key.go b/checks/cloud/google/compute/vm_disk_encryption_customer_key.go
index 6370e9cf..63ba66ad 100755
--- a/checks/cloud/google/compute/vm_disk_encryption_customer_key.go
+++ b/checks/cloud/google/compute/vm_disk_encryption_customer_key.go
@@ -25,7 +25,8 @@ var CheckVmDiskEncryptionCustomerKey = rules.Register(
Links: terraformVmDiskEncryptionCustomerKeyLinks,
RemediationMarkdown: terraformVmDiskEncryptionCustomerKeyRemediationMarkdown,
},
- Severity: severity.Low,
+ Severity: severity.Low,
+ Deprecated: true,
},
func(s *state.State) (results scan.Results) {
for _, instance := range s.Google.Compute.Instances {
diff --git a/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego b/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego
new file mode 100644
index 00000000..75a84b27
--- /dev/null
+++ b/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego
@@ -0,0 +1,47 @@
+# METADATA
+# title: VM disks should be encrypted with Customer Supplied Encryption Keys
+# description: |
+# Using unmanaged keys makes rotation and general management difficult.
+# scope: package
+# schemas:
+# - input: schema["cloud"]
+# custom:
+# id: AVD-GCP-0033
+# avd_id: AVD-GCP-0033
+# provider: google
+# service: compute
+# severity: LOW
+# short_code: vm-disk-encryption-customer-key
+# recommended_action: Use managed keys
+# input:
+# selector:
+# - type: cloud
+# subtypes:
+# - service: compute
+# provider: google
+# terraform:
+# links:
+# - https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#kms_key_self_link
+# good_examples: checks/cloud/google/compute/vm_disk_encryption_customer_key.tf.go
+# bad_examples: checks/cloud/google/compute/vm_disk_encryption_customer_key.tf.go
+package builtin.google.compute.google0033
+
+import rego.v1
+
+deny contains res if {
+ some instance in input.google.compute.instances
+ disks := array.concat(
+ object.get(instance, "bootdisks", []),
+ object.get(instance, "attacheddisks", []),
+ )
+
+ some disk in disks
+
+ not disk_is_encrypted(disk)
+ res := result.new(
+ "Instance disk encryption does not use a customer managed key.",
+ object.get(disk, ["encryption", "kmskeylink"], disk),
+ )
+}
+
+disk_is_encrypted(disk) := disk.encryption.kmskeylink.value != ""
diff --git a/checks/cloud/google/compute/vm_disk_encryption_customer_key_test.go b/checks/cloud/google/compute/vm_disk_encryption_customer_key_test.go
deleted file mode 100644
index 2bbcccdf..00000000
--- a/checks/cloud/google/compute/vm_disk_encryption_customer_key_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package compute
-
-import (
- "testing"
-
- trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
-
- "github.com/aquasecurity/trivy/pkg/iac/state"
-
- "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
- "github.com/aquasecurity/trivy/pkg/iac/scan"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestCheckVmDiskEncryptionCustomerKey(t *testing.T) {
- tests := []struct {
- name string
- input compute.Compute
- expected bool
- }{
- {
- name: "Instance disk missing encryption key link",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- BootDisks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- KMSKeyLink: trivyTypes.String("", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- expected: true,
- },
- {
- name: "Instance disk encryption key link provided",
- input: compute.Compute{
- Instances: []compute.Instance{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- AttachedDisks: []compute.Disk{
- {
- Metadata: trivyTypes.NewTestMetadata(),
- Encryption: compute.DiskEncryption{
- Metadata: trivyTypes.NewTestMetadata(),
- KMSKeyLink: trivyTypes.String("kms-key-link", trivyTypes.NewTestMetadata()),
- },
- },
- },
- },
- },
- },
- expected: false,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- var testState state.State
- testState.Google.Compute = test.input
- results := CheckVmDiskEncryptionCustomerKey.Evaluate(&testState)
- var found bool
- for _, result := range results {
- if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckVmDiskEncryptionCustomerKey.LongID() {
- found = true
- }
- }
- if test.expected {
- assert.True(t, found, "Rule should have been found")
- } else {
- assert.False(t, found, "Rule should not have been found")
- }
- })
- }
-}
diff --git a/checks/cloud/google/compute/vm_disk_encryption_customer_key_test.rego b/checks/cloud/google/compute/vm_disk_encryption_customer_key_test.rego
new file mode 100644
index 00000000..67dac348
--- /dev/null
+++ b/checks/cloud/google/compute/vm_disk_encryption_customer_key_test.rego
@@ -0,0 +1,30 @@
+package builtin.google.compute.google0033_test
+
+import rego.v1
+
+import data.builtin.google.compute.google0033 as check
+import data.lib.test
+
+test_deny_instance_boot_disk_is_not_encrypted if {
+ inp := {"google": {"compute": {"instances": [{"bootdisks": [{"encryption": {"kmskeylink": {"value": ""}}}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_deny_instance_attached_disk_is_not_encrypted if {
+ inp := {"google": {"compute": {"instances": [{"attacheddisks": [{"encryption": {}}]}]}}}
+
+ res := check.deny with input as inp
+ count(res) == 1
+}
+
+test_allow_instance_disks_is_encrypted if {
+ inp := {"google": {"compute": {
+ "bootdisks": [{"encryption": {"kmskeylink": {"value": "kms-key-link"}}}],
+ "attacheddisks": [{"disk": {"encryption": {"kmskeylink": {"value": "kms-key-link"}}}}],
+ }}}
+
+ res := check.deny with input as inp
+ res == set()
+}
diff --git a/test/rego/google_compute_test.go b/test/rego/google_compute_test.go
new file mode 100644
index 00000000..7c89e6e5
--- /dev/null
+++ b/test/rego/google_compute_test.go
@@ -0,0 +1,666 @@
+package test
+
+import (
+ "github.com/aquasecurity/trivy/pkg/iac/providers/google"
+ "github.com/aquasecurity/trivy/pkg/iac/providers/google/compute"
+ "github.com/aquasecurity/trivy/pkg/iac/state"
+ trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types"
+)
+
+func init() {
+ addTests(googleComputeTestCases)
+}
+
+var googleComputeTestCases = testCases{
+ "AVD-GCP-0034": {
+ {
+ name: "Disk missing KMS key link",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Disks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ KMSKeyLink: trivyTypes.String("", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Disk with KMS key link provided",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Disks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ KMSKeyLink: trivyTypes.String("kms-key-link", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0037": {
+ {
+ name: "Disk with plaintext encryption key",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Disks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ RawKey: trivyTypes.Bytes([]byte("b2ggbm8gdGhpcyBpcyBiYWQ"), trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance disk with plaintext encryption key",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ BootDisks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ RawKey: trivyTypes.Bytes([]byte("b2ggbm8gdGhpcyBpcyBiYWQ"), trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Disks with no plaintext encryption keys",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Disks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ RawKey: trivyTypes.Bytes([]byte(""), trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ BootDisks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ RawKey: trivyTypes.Bytes([]byte(""), trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ AttachedDisks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ RawKey: trivyTypes.Bytes([]byte(""), trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0045": {
+ {
+ name: "Instance shielded VM integrity monitoring disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ShieldedVM: compute.ShieldedVMConfig{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IntegrityMonitoringEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance shielded VM integrity monitoring enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ShieldedVM: compute.ShieldedVMConfig{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IntegrityMonitoringEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0067": {
+ {
+ name: "Instance shielded VM secure boot disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ShieldedVM: compute.ShieldedVMConfig{
+ Metadata: trivyTypes.NewTestMetadata(),
+ SecureBootEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance shielded VM secure boot enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ShieldedVM: compute.ShieldedVMConfig{
+ Metadata: trivyTypes.NewTestMetadata(),
+ SecureBootEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0041": {
+ {
+ name: "Instance shielded VM VTPM disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ShieldedVM: compute.ShieldedVMConfig{
+ Metadata: trivyTypes.NewTestMetadata(),
+ VTPMEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance shielded VM VTPM enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ShieldedVM: compute.ShieldedVMConfig{
+ Metadata: trivyTypes.NewTestMetadata(),
+ VTPMEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0029": {
+ {
+ name: "Subnetwork VPC flow logs disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Subnetworks: []compute.SubNetwork{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableFlowLogs: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Subnetwork VPC flow logs enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Subnetworks: []compute.SubNetwork{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableFlowLogs: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ {
+ name: "Proxy-only subnets and logs disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Subnetworks: []compute.SubNetwork{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableFlowLogs: trivyTypes.BoolDefault(false, trivyTypes.NewTestMetadata()),
+ Purpose: trivyTypes.String("REGIONAL_MANAGED_PROXY", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0044": {
+ {
+ name: "Instance service account not specified",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ServiceAccount: compute.ServiceAccount{
+ Metadata: trivyTypes.NewTestMetadata(),
+ Email: trivyTypes.String("", trivyTypes.NewTestMetadata()),
+ IsDefault: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance service account using the default email",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ServiceAccount: compute.ServiceAccount{
+ Metadata: trivyTypes.NewTestMetadata(),
+ Email: trivyTypes.String("1234567890-compute@developer.gserviceaccount.com", trivyTypes.NewTestMetadata()),
+ IsDefault: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance service account with email provided",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ ServiceAccount: compute.ServiceAccount{
+ Metadata: trivyTypes.NewTestMetadata(),
+ Email: trivyTypes.String("proper@email.com", trivyTypes.NewTestMetadata()),
+ IsDefault: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0043": {
+ {
+ name: "Instance IP forwarding enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ CanIPForward: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance IP forwarding disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ CanIPForward: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0036": {
+ {
+ name: "Instance OS login disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ OSLoginEnabled: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance OS login enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ OSLoginEnabled: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0030": {
+ {
+ name: "Instance project level SSH keys blocked",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableProjectSSHKeyBlocking: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance project level SSH keys allowed",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableProjectSSHKeyBlocking: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0035": {
+ {
+ name: "Firewall egress rule with multiple public destination addresses",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Firewall: &compute.Firewall{
+ Metadata: trivyTypes.NewTestMetadata(),
+ EgressRules: []compute.EgressRule{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ FirewallRule: compute.FirewallRule{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ DestinationRanges: []trivyTypes.StringValue{
+ trivyTypes.String("0.0.0.0/0", trivyTypes.NewTestMetadata()),
+ trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Firewall egress rule with public destination address",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Firewall: &compute.Firewall{
+ Metadata: trivyTypes.NewTestMetadata(),
+ EgressRules: []compute.EgressRule{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ FirewallRule: compute.FirewallRule{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ DestinationRanges: []trivyTypes.StringValue{
+ trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0027": {
+ {
+ name: "Firewall ingress rule with multiple public source addresses",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Firewall: &compute.Firewall{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IngressRules: []compute.IngressRule{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ FirewallRule: compute.FirewallRule{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ SourceRanges: []trivyTypes.StringValue{
+ trivyTypes.String("0.0.0.0/0", trivyTypes.NewTestMetadata()),
+ trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Firewall ingress rule with public source address",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Networks: []compute.Network{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Firewall: &compute.Firewall{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IngressRules: []compute.IngressRule{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ FirewallRule: compute.FirewallRule{
+ Metadata: trivyTypes.NewTestMetadata(),
+ IsAllow: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ Enforced: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ SourceRanges: []trivyTypes.StringValue{
+ trivyTypes.String("1.2.3.4/32", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0031": {
+ {
+ name: "Network interface with public IP",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ NetworkInterfaces: []compute.NetworkInterface{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ HasPublicIP: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Network interface without public IP",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ NetworkInterfaces: []compute.NetworkInterface{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ HasPublicIP: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0032": {
+ {
+ name: "Instance serial port enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableSerialPort: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance serial port disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableSerialPort: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0042": {
+ {
+ name: "Compute OS login disabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ ProjectMetadata: compute.ProjectMetadata{
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableOSLogin: trivyTypes.Bool(false, trivyTypes.NewTestMetadata()),
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Compute OS login enabled",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ ProjectMetadata: compute.ProjectMetadata{
+ Metadata: trivyTypes.NewTestMetadata(),
+ EnableOSLogin: trivyTypes.Bool(true, trivyTypes.NewTestMetadata()),
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0039": {
+ {
+ name: "SSL policy minimum TLS version 1.0",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ SSLPolicies: []compute.SSLPolicy{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ MinimumTLSVersion: trivyTypes.String("TLS_1_0", trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "SSL policy minimum TLS version 1.2",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ SSLPolicies: []compute.SSLPolicy{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ MinimumTLSVersion: trivyTypes.String("TLS_1_2", trivyTypes.NewTestMetadata()),
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+ "AVD-GCP-0033": {
+ {
+ name: "Instance disk missing encryption key link",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ BootDisks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ KMSKeyLink: trivyTypes.String("", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: true,
+ },
+ {
+ name: "Instance disk encryption key link provided",
+ input: state.State{Google: google.Google{Compute: compute.Compute{
+ Instances: []compute.Instance{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ AttachedDisks: []compute.Disk{
+ {
+ Metadata: trivyTypes.NewTestMetadata(),
+ Encryption: compute.DiskEncryption{
+ Metadata: trivyTypes.NewTestMetadata(),
+ KMSKeyLink: trivyTypes.String("kms-key-link", trivyTypes.NewTestMetadata()),
+ },
+ },
+ },
+ },
+ },
+ }}},
+ expected: false,
+ },
+ },
+}