diff --git a/avd_docs/cloudstack/compute/AVD-CLDSTK-0001/docs.md b/avd_docs/cloudstack/compute/AVD-CLDSTK-0001/docs.md index 053db688..2bccc2a3 100644 --- a/avd_docs/cloudstack/compute/AVD-CLDSTK-0001/docs.md +++ b/avd_docs/cloudstack/compute/AVD-CLDSTK-0001/docs.md @@ -1,8 +1,9 @@ When creating instances, user data can be used during the initial configuration. User data must not contain sensitive information + ### Impact -Sensitive credentials in the user data can be leaked + {{ remediationActions }} diff --git a/checks/cloud/cloudstack/compute/no_sensitive_info.go b/checks/cloud/cloudstack/compute/no_sensitive_info.go index 1e31d477..abae467c 100755 --- a/checks/cloud/cloudstack/compute/no_sensitive_info.go +++ b/checks/cloud/cloudstack/compute/no_sensitive_info.go @@ -28,7 +28,8 @@ var CheckNoSensitiveInfo = rules.Register( Links: terraformNoSensitiveInfoLinks, RemediationMarkdown: terraformNoSensitiveInfoRemediationMarkdown, }, - Severity: severity.High, + Severity: severity.High, + Deprecated: true, }, func(s *state.State) (results scan.Results) { for _, instance := range s.CloudStack.Compute.Instances { diff --git a/checks/cloud/cloudstack/compute/no_sensitive_info.rego b/checks/cloud/cloudstack/compute/no_sensitive_info.rego new file mode 100644 index 00000000..6787938f --- /dev/null +++ b/checks/cloud/cloudstack/compute/no_sensitive_info.rego @@ -0,0 +1,37 @@ +# METADATA +# title: No sensitive data stored in user_data +# description: | +# When creating instances, user data can be used during the initial configuration. User data must not contain sensitive information +# scope: package +# schemas: +# - input: schema["cloud"] +# custom: +# id: AVD-CLDSTK-0001 +# avd_id: AVD-CLDSTK-0001 +# provider: cloudstack +# service: compute +# severity: HIGH +# short_code: no-sensitive-info +# recommended_action: Don't use sensitive data in the user data section +# input: +# selector: +# - type: cloud +# subtypes: +# - service: compute +# provider: cloudstack +# terraform: +# links: +# - https://registry.terraform.io/providers/hashicorp/cloudstack/latest/docs/resources/instance# +# good_examples: checks/cloud/cloudstack/compute/no_sensitive_info.tf.go +# bad_examples: checks/cloud/cloudstack/compute/no_sensitive_info.tf.go +package builtin.cloudstack.compute.cloudstack0001 + +import rego.v1 + +deny contains res if { + some instance in input.cloudstack.compute.instances + isManaged(instance) + scan_result := squealer.scan_string(instance.userdata.value) + scan_result.transgressionFound + res := result.new("Instance user data contains secret(s).", instance.userdata) +} diff --git a/checks/cloud/cloudstack/compute/no_sensitive_info_test.go b/checks/cloud/cloudstack/compute/no_sensitive_info_test.go deleted file mode 100644 index 61ccb264..00000000 --- a/checks/cloud/cloudstack/compute/no_sensitive_info_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/cloudstack/compute" - "github.com/aquasecurity/trivy/pkg/iac/scan" - - "github.com/stretchr/testify/assert" -) - -func TestCheckNoSensitiveInfo(t *testing.T) { - tests := []struct { - name string - input compute.Compute - expected bool - }{ - { - name: "Compute instance with sensitive information in user data", - input: compute.Compute{ - Instances: []compute.Instance{ - { - Metadata: trivyTypes.NewTestMetadata(), - UserData: trivyTypes.String(` export DATABASE_PASSWORD=\"SomeSortOfPassword\"`, trivyTypes.NewTestMetadata()), - }, - }, - }, - expected: true, - }, - { - name: "Compute instance with no sensitive information in user data", - input: compute.Compute{ - Instances: []compute.Instance{ - { - Metadata: trivyTypes.NewTestMetadata(), - UserData: trivyTypes.String(` export GREETING="Hello there"`, trivyTypes.NewTestMetadata()), - }, - }, - }, - expected: false, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - var testState state.State - testState.CloudStack.Compute = test.input - results := CheckNoSensitiveInfo.Evaluate(&testState) - var found bool - for _, result := range results { - if result.Status() == scan.StatusFailed && result.Rule().LongID() == CheckNoSensitiveInfo.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/cloudstack/compute/no_sensitive_info_test.rego b/checks/cloud/cloudstack/compute/no_sensitive_info_test.rego new file mode 100644 index 00000000..850ea78d --- /dev/null +++ b/checks/cloud/cloudstack/compute/no_sensitive_info_test.rego @@ -0,0 +1,20 @@ +package builtin.cloudstack.compute.cloudstack0001_test + +import rego.v1 + +import data.builtin.cloudstack.compute.cloudstack0001 as check +import data.lib.test + +test_deny_compute_instance_with_sensitive_data if { + inp := {"cloudstack": {"compute": {"instances": [{"userdata": {"value": " export DATABASE_PASSWORD=\"SomeSortOfPassword\""}}]}}} + + res := check.deny with input as inp + count(res) == 1 +} + +test_allow_compute_instance_without_sensitive_data if { + inp := {"cloudstack": {"compute": {"instances": [{"userdata": {"value": ` export GREETING="Hello there"`}}]}}} + + res := check.deny with input as inp + res == set() +} diff --git a/test/rego/cloudstack_test.go b/test/rego/cloudstack_test.go new file mode 100644 index 00000000..e946e63c --- /dev/null +++ b/test/rego/cloudstack_test.go @@ -0,0 +1,41 @@ +package test + +import ( + "github.com/aquasecurity/trivy/pkg/iac/providers/cloudstack" + "github.com/aquasecurity/trivy/pkg/iac/providers/cloudstack/compute" + "github.com/aquasecurity/trivy/pkg/iac/state" + trivyTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +func init() { + addTests(cloudStackTestCases) +} + +var cloudStackTestCases = testCases{ + "AVD-CLDSTK-0001": { + { + name: "Compute instance with sensitive information in user data", + input: state.State{CloudStack: cloudstack.CloudStack{Compute: compute.Compute{ + Instances: []compute.Instance{ + { + Metadata: trivyTypes.NewTestMetadata(), + UserData: trivyTypes.String(` export DATABASE_PASSWORD=\"SomeSortOfPassword\"`, trivyTypes.NewTestMetadata()), + }, + }, + }}}, + expected: true, + }, + { + name: "Compute instance with no sensitive information in user data", + input: state.State{CloudStack: cloudstack.CloudStack{Compute: compute.Compute{ + Instances: []compute.Instance{ + { + Metadata: trivyTypes.NewTestMetadata(), + UserData: trivyTypes.String(` export GREETING="Hello there"`, trivyTypes.NewTestMetadata()), + }, + }, + }}}, + expected: false, + }, + }, +}