Skip to content

Commit

Permalink
Update Terrascan to use the latest policy format
Browse files Browse the repository at this point in the history
- Adds initial AWS and Azure policy set
- Adds command line switch for policy path
  • Loading branch information
Willie Sana authored and Yusuf Kanchwala committed Aug 10, 2020
1 parent 8fd495d commit 79cb369
Show file tree
Hide file tree
Showing 103 changed files with 1,764 additions and 117 deletions.
3 changes: 2 additions & 1 deletion cmd/terrascan/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func main() {
iacVersion = flag.String("iac-version", "default", "IaC version (supported values: 'v12' for terraform)")
iacFilePath = flag.String("f", "", "IaC file path")
iacDirPath = flag.String("d", "", "IaC directory path")
policyPath = flag.String("p", "", "Policy directory path")

// cloud flags
cloudType = flag.String("cloud", "", "cloud provider (supported values: aws)")
Expand All @@ -64,6 +65,6 @@ func main() {
} else {
logging.Init(*logType, *logLevel)
zap.S().Debug("running terrascan in cli mode")
cli.Run(*iacType, *iacVersion, *cloudType, *iacFilePath, *iacDirPath, *configFile)
cli.Run(*iacType, *iacVersion, *cloudType, *iacFilePath, *iacDirPath, *configFile, *policyPath)
}
}
4 changes: 2 additions & 2 deletions pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (
)

// Run executes terrascan in CLI mode
func Run(iacType, iacVersion, cloudType, iacFilePath, iacDirPath, configFile string) {
func Run(iacType, iacVersion, cloudType, iacFilePath, iacDirPath, configFile, policyPath string) {

// create a new runtime executor for processing IaC
executor, err := runtime.NewExecutor(iacType, iacVersion, cloudType, iacFilePath,
iacDirPath, configFile)
iacDirPath, configFile, policyPath)
if err != nil {
return
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "cloudfrontNoHTTPSTraffic",
"file": "cloudfrontNoHTTPSTraffic.rego",
"ruleTemplate": "cloudfrontNoHTTPSTraffic",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "HIGH",
"description": "Use encrypted connection between CloudFront and origin server",
"ruleReferenceId": "AWS.CloudFront.EncryptionandKeyManagement.High.0407",
"category": "Encryption and Key Management",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "cloudfrontNoSecureCiphers",
"file": "cloudfrontNoSecureCiphers.rego",
"ruleTemplate": "cloudfrontNoSecureCiphers",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "HIGH",
"description": "Secure ciphers are not used in CloudFront distribution",
"ruleReferenceId": "AWS.CloudFront.EncryptionandKeyManagement.High.0408",
"category": "Encryption and Key Management",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "cloudfrontNoLogging",
"file": "cloudfrontNoLogging.rego",
"ruleTemplate": "cloudfrontNoLogging",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "MEDIUM",
"description": "Ensure that your AWS Cloudfront distributions have the Logging feature enabled in order to track all viewer requests for the content delivered through the Content Delivery Network (CDN).",
"ruleReferenceId": "AWS.CloudFront.Logging.Medium.0567",
"category": "Logging",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package accurics

{{.prefix}}cloudfrontNoHTTPSTraffic[retVal]{
cloudfront = input.aws_cloudfront_distribution[_]
some i
orderedcachebehaviour = cloudfront.config.ordered_cache_behavior[i]
orderedcachebehaviour.viewer_protocol_policy == "allow-all"
traverse := sprintf("ordered_cache_behavior[%d].viewer_protocol_policy", [i])
retVal := { "Id": cloudfront.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "ordered_cache_behavior.viewer_protocol_policy", "AttributeDataType": "string", "Expected": "redirect-to-https", "Actual": orderedcachebehaviour.viewer_protocol_policy }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package accurics

{{.prefix}}cloudfrontNoLogging[retVal]{
cloudfront = input.aws_cloudfront_distribution[_]
not cloudfront.config.logging_config

rc = "ewogICJsb2dnaW5nX2NvbmZpZyI6IHsKICAgICJpbmNsdWRlX2Nvb2tpZXMiOiBmYWxzZSwKICAgICJidWNrZXQiOiAiPGJ1Y2tldD4iLAogICAgInByZWZpeCI6ICI8cHJlZml4PiIKICB9Cn0="

traverse = ""
retVal := { "Id": cloudfront.id, "ReplaceType": "add", "CodeType": "block", "Traverse": traverse, "Attribute": "logging_config", "AttributeDataType": "base64", "Expected": rc, "Actual": null }
}

{{.prefix}}cloudfrontNoLogging[retVal]{
cloudfront = input.aws_cloudfront_distribution[_]
cloudfront.config.logging_config == []

rc = "ewogICJsb2dnaW5nX2NvbmZpZyI6IHsKICAgICJpbmNsdWRlX2Nvb2tpZXMiOiBmYWxzZSwKICAgICJidWNrZXQiOiAiPGJ1Y2tldD4iLAogICAgInByZWZpeCI6ICI8cHJlZml4PiIKICB9Cn0="

traverse = ""
retVal := { "Id": cloudfront.id, "ReplaceType": "add", "CodeType": "block", "Traverse": traverse, "Attribute": "logging_config", "AttributeDataType": "base64", "Expected": rc, "Actual": null }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package accurics

{{.prefix}}cloudfrontNoSecureCiphers[retVal]{
cloudfront = input.aws_cloudfront_distribution[_]
some i
certificate = cloudfront.config.viewer_certificate[i]
certificate.cloudfront_default_certificate = false
not minimumAllowedProtocolVersion(certificate.minimum_protocol_version)
traverse := sprintf("viewer_certificate[%d].minimum_protocol_version", [i])
retVal := { "Id": cloudfront.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "viewer_certificate.minimum_protocol_version", "AttributeDataType": "string", "Expected": "TLSv1.2", "Actual": certificate.minimum_protocol_version }
}

minimumAllowedProtocolVersion(currentVersion) {
currentVersion == "TLSv1.1"
}

minimumAllowedProtocolVersion(currentVersion) {
currentVersion == "TLSv1.2"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "cloudTrailLogNotEncrypted",
"file": "cloudTrailLogNotEncrypted.rego",
"ruleTemplate": "cloudTrailLogNotEncrypted",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "HIGH",
"description": "Cloud Trail Log Not Enabled",
"ruleReferenceId": "AWS.CloudTrail.Logging.High.0399",
"category": "Logging",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "reme_enableSNSTopic",
"file": "enableSNSTopic.rego",
"ruleTemplate": "enableSNSTopic",
"ruleTemplateArgs": {
"prefix": "reme_"
},
"severity": "MEDIUM",
"description": "Ensure appropriate subscribers to each SNS topic",
"ruleReferenceId": "AWS.CloudTrail.Logging.Low.0559",
"category": "Logging",
"version": 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "cloudTrailMultiRegionNotCreated",
"file": "cloudTrailMultiRegionNotCreated.rego",
"ruleTemplate": "cloudTrailMultiRegionNotCreated",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "MEDIUM",
"description": "Cloud Trail Multi Region not enabled",
"ruleReferenceId": "AWS.CloudTrail.Logging.Medium.0460",
"category": "Logging",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package accurics

{{.prefix}}cloudTrailLogNotEncrypted[retVal]{
cloud_trail = input.aws_cloudtrail[_]
cloud_trail.config.kms_key_id == null

traverse = "kms_key_id"
retVal := { "Id": cloud_trail.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "kms_key_id", "AttributeDataType": "string", "Expected": "<kms_key_id>", "Actual": cloud_trail.config.kms_key_id }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package accurics

{{.prefix}}cloudTrailMultiRegionNotCreated[retVal]{
cloud_trail = input.aws_cloudtrail[_]
cloud_trail.config.is_multi_region_trail == false

traverse = "is_multi_region_trail"
retVal := { "Id": cloud_trail.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "is_multi_region_trail", "AttributeDataType": "bool", "Expected": true, "Actual": cloud_trail.config.is_multi_region_trail }
}
6 changes: 6 additions & 0 deletions pkg/policies/opa/rego/aws/aws_cloudtrail/enableSNSTopic.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package accurics

{{.prefix}}enableSNSTopic[sns.id] {
sns := input.aws_cloudtrail[_]
sns.config.sns_topic_name == null
}
13 changes: 13 additions & 0 deletions pkg/policies/opa/rego/aws/aws_db_instance/.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "rdsPubliclyAccessible",
"file": "rdsPubliclyAccessible.rego",
"ruleTemplate": "rdsPubliclyAccessible",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "HIGH",
"description": "RDS Instance publicly_accessible flag is true",
"ruleReferenceId": "",
"category": "Data Security",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package accurics

{{.prefix}}rdsPubliclyAccessible[retVal] {
db := input.aws_db_instance[_]
db.config.publicly_accessible == true
traverse = "publicly_accessible"
retVal := { "Id": db.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "publicly_accessible", "AttributeDataType": "bool", "Expected": false, "Actual": db.config.publicly_accessible }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ruleName": "noAccessKeyForRootAccount",
"file": "noAccessKeyForRootAccount.rego",
"ruleTemplate": "noAccessKeyForRootAccount",
"ruleTemplateArgs": {
"prefix": ""
},
"severity": "HIGH",
"description": "The root account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root account be removed. Removing access keys associated with the root account limits vectors by which the account can be compromised. Additionally, removing the root access keys encourages the creation and use of role based accounts that are least privileged.",
"ruleReferenceId": "AWS.IamUser.IAM.High.0390",
"category": "Identity and Access Management",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package accurics

{{.prefix}}noAccessKeyForRootAccount[retVal] {
access := input.aws_iam_access_key[_]
access.type == "aws_iam_access_key"
status = getStatus(access.config)
status == "Active"
access.config.user == "root"
traverse = "status"
retVal := { "Id": access.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "status", "AttributeDataType": "string", "Expected": "Inactive", "Actual": access.config.status }
}

getStatus(config) = "Active" {
# defaults to Active
not config.status
}

getStatus(config) = "Active" {
config.status == "Active"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"ruleName": "passwordRotateEvery90Days",
"file": "passwordRotateEvery90Days.rego",
"ruleTemplate": "passwordRotateEvery90Days",
"ruleTemplateArgs": {
"name": "passwordRotateEvery90Days",
"prefix": ""
},
"severity": "LOW",
"description": "Reducing the password lifetime increases account resiliency against brute force login attempts",
"ruleReferenceId": "AWS.Iam.IAM.Low.0540",
"category": "IAM",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"ruleName": "passwordRequireLowerCase",
"file": "passwordPolicyRequirement.rego",
"ruleTemplate": "passwordRequireLowerCase",
"ruleTemplateArgs": {
"name": "passwordRequireLowerCase",
"prefix": "",
"required_parameter": "require_lowercase_characters"
},
"severity": "MEDIUM",
"description": "Lower case alphabet not present in the Password, Password Complexity is not high. Increased Password complexity increases resiliency against brute force attack",
"ruleReferenceId": "AWS.Iam.IAM.Medium.0454",
"category": "IAM",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"ruleName": "passwordRequireNumber",
"file": "passwordPolicyRequirement.rego",
"ruleTemplate": "passwordRequireNumber",
"ruleTemplateArgs": {
"name": "passwordRequireNumber",
"prefix": "",
"required_parameter": "require_numbers"
},
"severity": "MEDIUM",
"description": "Number not present in the Password, Password Complexity is not high. Increased Password complexity increases resiliency against brute force attack",
"ruleReferenceId": "AWS.Iam.IAM.Medium.0455",
"category": "IAM",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"ruleName": "passwordRequireSymbol",
"file": "passwordPolicyRequirement.rego",
"ruleTemplate": "passwordRequireSymbol",
"ruleTemplateArgs": {
"name": "passwordRequireSymbol",
"prefix": "",
"required_parameter": "require_symbols"
},
"severity": "MEDIUM",
"description": "Special symbols not present in the Password, Password Complexity is not high. Increased Password complexity increases resiliency against brute force attack",
"ruleReferenceId": "AWS.Iam.IAM.Medium.0456",
"category": "IAM",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"ruleName": "passwordRequireUpperCase",
"file": "passwordPolicyRequirement.rego",
"ruleTemplate": "passwordRequireUpperCase",
"ruleTemplateArgs": {
"name": "passwordRequireUpperCase",
"prefix": "",
"required_parameter": "require_uppercase_characters"
},
"severity": "MEDIUM",
"description": "Upper case alphabet not present in the Password, Password Complexity is not high. Increased Password complexity increases resiliency against brute force attack",
"ruleReferenceId": "AWS.Iam.IAM.Medium.0457",
"category": "IAM",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ruleName": "passwordRequireMinLength14",
"file": "passwordMinLength.rego",
"ruleTemplate": "passwordRequireMinLength14",
"ruleTemplateArgs": {
"name": "passwordRequireMinLength14",
"parameter": "minimum_password_length",
"prefix": "",
"value": 14
},
"severity": "MEDIUM",
"description": "Setting a lengthy password increases account resiliency against brute force login attempts",
"ruleReferenceId": "AWS.Iam.IAM.Medium.0458",
"category": "IAM",
"version": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ruleName": "passwordRequireMinLength",
"file": "passwordMinLength.rego",
"ruleTemplate": "passwordRequireMinLength",
"ruleTemplateArgs": {
"name": "passwordRequireMinLength",
"parameter": "minimum_password_length",
"prefix": "",
"value": 7
},
"severity": "MEDIUM",
"description": "Setting a lengthy password increases account resiliency against brute force login attempts",
"ruleReferenceId": "AWS.Iam.IAM.Medium.0495",
"category": "IAM",
"version": 2
}
Loading

0 comments on commit 79cb369

Please sign in to comment.