-
Notifications
You must be signed in to change notification settings - Fork 531
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add first cloudstack check for user data (#985)
The user_data must not have sensitive data Co-authored-by: Liam Galvin <liam.galvin@aquasec.com>
- Loading branch information
Showing
7 changed files
with
169 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ var providers = []string{ | |
"Google", | ||
"Kubernetes", | ||
"OpenStack", | ||
"CloudStack", | ||
"Oracle", | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
internal/app/tfsec/rules/cloudstack/compute/no_sensitive_info_rule.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package compute | ||
|
||
// ATTENTION! | ||
// This rule was autogenerated! | ||
// Before making changes, consider updating the generator. | ||
|
||
import ( | ||
"encoding/base64" | ||
|
||
"github.com/aquasecurity/tfsec/internal/app/tfsec/block" | ||
"github.com/aquasecurity/tfsec/internal/app/tfsec/debug" | ||
"github.com/aquasecurity/tfsec/internal/app/tfsec/hclcontext" | ||
"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" | ||
"github.com/aquasecurity/tfsec/pkg/provider" | ||
"github.com/aquasecurity/tfsec/pkg/result" | ||
"github.com/aquasecurity/tfsec/pkg/rule" | ||
"github.com/aquasecurity/tfsec/pkg/severity" | ||
"github.com/owenrumney/squealer/pkg/squealer" | ||
) | ||
|
||
func init() { | ||
scanner.RegisterCheckRule(rule.Rule{ | ||
Provider: provider.CloudStackProvider, | ||
Service: "compute", | ||
ShortCode: "no-sensitive-info", | ||
Documentation: rule.RuleDocumentation{ | ||
Summary: "No sensitive data stored in user_data", | ||
Explanation: `When creating instances, user data can be used during the initial confiugtation. User data must not contain sensitive information`, | ||
Impact: "Sensitive credentials in the user data can be leaked", | ||
Resolution: "Don't use sensitive data in the user data section", | ||
BadExample: []string{` | ||
resource "cloudstack_instance" "web" { | ||
name = "server-1" | ||
service_offering = "small" | ||
network_id = "6eb22f91-7454-4107-89f4-36afcdf33021" | ||
template = "CentOS 6.5" | ||
zone = "zone-1" | ||
user_data = <<EOF | ||
export DATABASE_PASSWORD=\"SomeSortOfPassword\" | ||
EOF | ||
} | ||
`, ` | ||
resource "cloudstack_instance" "web" { | ||
name = "server-1" | ||
service_offering = "small" | ||
network_id = "6eb22f91-7454-4107-89f4-36afcdf33021" | ||
template = "CentOS 6.5" | ||
zone = "zone-1" | ||
user_data = "ZXhwb3J0IERBVEFCQVNFX1BBU1NXT1JEPSJTb21lU29ydE9mUGFzc3dvcmQi" | ||
} | ||
`}, | ||
GoodExample: []string{` | ||
resource "cloudstack_instance" "web" { | ||
name = "server-1" | ||
service_offering = "small" | ||
network_id = "6eb22f91-7454-4107-89f4-36afcdf33021" | ||
template = "CentOS 6.5" | ||
zone = "zone-1" | ||
user_data = <<EOF | ||
export GREETING="Hello there" | ||
EOF | ||
} | ||
`, ` | ||
resource "cloudstack_instance" "web" { | ||
name = "server-1" | ||
service_offering = "small" | ||
network_id = "6eb22f91-7454-4107-89f4-36afcdf33021" | ||
template = "CentOS 6.5" | ||
zone = "zone-1" | ||
user_data = "ZXhwb3J0IEVESVRPUj12aW1hY3M=" | ||
} | ||
`}, | ||
Links: []string{ | ||
"https://registry.terraform.io/providers/hashicorp/cloudstack/latest/docs/resources/instance#", | ||
}, | ||
}, | ||
RequiredTypes: []string{ | ||
"resource", | ||
}, | ||
RequiredLabels: []string{ | ||
"cloudstack_instance", | ||
}, | ||
DefaultSeverity: severity.High, | ||
CheckFunc: func(set result.Set, resourceBlock block.Block, _ *hclcontext.Context) { | ||
|
||
customDataAttr := resourceBlock.GetAttribute("user_data") | ||
|
||
if customDataAttr.IsNotNil() && customDataAttr.IsString() { | ||
encoded, err := base64.StdEncoding.DecodeString(customDataAttr.Value().AsString()) | ||
if err != nil { | ||
debug.Log("could not decode the base64 string in the terraform, trying with the string verbatim") | ||
encoded = []byte(customDataAttr.Value().AsString()) | ||
} | ||
if checkStringForSensitive(string(encoded)) { | ||
set.AddResult(). | ||
WithDescription("Resource '%s' has user_data_base64 with sensitive data.", resourceBlock.FullName()). | ||
WithAttribute(customDataAttr) | ||
} | ||
} | ||
|
||
}, | ||
}) | ||
} | ||
|
||
func checkStringForSensitive(stringToCheck string) bool { | ||
scanResult := squealer.NewStringScanner().Scan(stringToCheck) | ||
return scanResult.TransgressionFound | ||
} |
53 changes: 53 additions & 0 deletions
53
internal/app/tfsec/rules/cloudstack/compute/no_sensitive_info_rule_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package compute | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner" | ||
"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil" | ||
) | ||
|
||
func Test_CloudstackNoSensitiveInfo_FailureExamples(t *testing.T) { | ||
expectedCode := "cloudstack-compute-no-sensitive-info" | ||
|
||
rule, err := scanner.GetRuleById(expectedCode) | ||
if err != nil { | ||
t.FailNow() | ||
} | ||
for i, badExample := range rule.Documentation.BadExample { | ||
t.Logf("Running bad example for '%s' #%d", expectedCode, i+1) | ||
if strings.TrimSpace(badExample) == "" { | ||
t.Fatalf("bad example code not provided for %s", rule.ID()) | ||
} | ||
defer func() { | ||
if err := recover(); err != nil { | ||
t.Fatalf("Scan (bad) failed: %s", err) | ||
} | ||
}() | ||
results := testutil.ScanHCL(badExample, t) | ||
testutil.AssertCheckCode(t, rule.ID(), "", results) | ||
} | ||
} | ||
|
||
func Test_CloudstackNoSensitiveInfo_SuccessExamples(t *testing.T) { | ||
expectedCode := "cloudstack-compute-no-sensitive-info" | ||
|
||
rule, err := scanner.GetRuleById(expectedCode) | ||
if err != nil { | ||
t.FailNow() | ||
} | ||
for i, example := range rule.Documentation.GoodExample { | ||
t.Logf("Running good example for '%s' #%d", expectedCode, i+1) | ||
if strings.TrimSpace(example) == "" { | ||
t.Fatalf("good example code not provided for %s", rule.ID()) | ||
} | ||
defer func() { | ||
if err := recover(); err != nil { | ||
t.Fatalf("Scan (good) failed: %s", err) | ||
} | ||
}() | ||
results := testutil.ScanHCL(example, t) | ||
testutil.AssertCheckCode(t, "", rule.ID(), results) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters