Skip to content

Commit

Permalink
updating s3 bucket policies for v4 aws provider (#1175)
Browse files Browse the repository at this point in the history
  • Loading branch information
harkirat22 authored Mar 3, 2022
1 parent 504aa1a commit b909460
Show file tree
Hide file tree
Showing 8 changed files with 546 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"policy_type": "aws",
"resource_type": "aws_s3_bucket",
"template_args": {
"prefix": ""
"prefix": "",
"defaultValue": "<s3BucketResourceName>",
"defaultValue1": "<target_bucket_name>"
},
"severity": "MEDIUM",
"description": "Ensure S3 buckets have access logging enabled.",
Expand Down
105 changes: 91 additions & 14 deletions pkg/policies/opa/rego/aws/aws_s3_bucket/noS3BucketSseRules.rego
Original file line number Diff line number Diff line change
@@ -1,25 +1,61 @@
package accurics

{{.prefix}}noS3BucketSseRules[bucket.id] {
#this will satisfy version 4 provider and previous providers
{{.prefix}}noS3BucketSseRules[retVal] {
bucket := input.aws_s3_bucket[_]
checkSSEConfig(input, bucket)
}
object.get(bucket.config, "versioning", "undefined") == ["undefined", null, ""][_]
object.get(input, "aws_s3_bucket_server_side_encryption_configuration", "undefined") == "undefined"
bucketName := bucket.config.bucket
decode_rc := `resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = $aws_s3_bucket.##name##.bucket$
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}`

replacedName := replace(decode_rc, "##name##", bucketName)

resourceWithoutQuotes := replace(replacedName, "$", " ")

checkSSEConfig(inobj, bucket) {
object.get(bucket.config, "server_side_encryption_configuration", "undefined") == [[], null, "undefined"][_]
object.get(inobj, "aws_s3_bucket_server_side_encryption_configuration", "undefined") == [[], null, "undefined"][_]
traverse = ""
retVal := {"Id": bucket.id, "ReplaceType": "add", "CodeType": "resource", "Traverse": traverse, "Attribute": "", "AttributeDataType": "base64", "Expected": base64.encode(resourceWithoutQuotes), "Actual": null}
}

checkSSEConfig(inobj, bucket) {
object.get(bucket.config, "server_side_encryption_configuration", "undefined") == [[], null, "undefined"][_]
object.get(inobj, "aws_s3_bucket_server_side_encryption_configuration", "undefined") != [[], null, "undefined"][_]
#For terrascan when used without tfplan
{{.prefix}}noS3BucketSseRules[retVal] {
bucket := input.aws_s3_bucket[_]
contains(input.aws_s3_bucket_server_side_encryption_configuration[_].config.bucket, "{")
serverSideEncryptionBucketName := [bName |
sse := input.aws_s3_bucket_server_side_encryption_configuration[_]
bName := cleanSSEBucketID(sse.config.bucket)
]

not checkBucketEncrypted(serverSideEncryptionBucketName, bucket)
decode_rc := `resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = $aws_s3_bucket.##name##.bucket$
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}`

sse := inobj.aws_s3_bucket_server_side_encryption_configuration[_]
cleanID := cleanSSEBucketID(sseConfig.bucket)
bucketid != cleanID
replacedName := replace(decode_rc, "##name##", bucket.config.bucket)

resourceWithoutQuotes := replace(replacedName, "$", " ")

traverse = ""
retVal := {"Id": bucket.id, "ReplaceType": "add", "CodeType": "resource", "Traverse": traverse, "Attribute": "", "AttributeDataType": "base64", "Expected": base64.encode(resourceWithoutQuotes), "Actual": null}
}

checkBucketEncrypted(arg1, arg2) {
arg2.id == arg1[_]
}

# remove all id related prefix and suffix characters generated by terrascan
cleanSSEBucketID(sseBucketID) = cleanID {
v1 := trim_left(sseBucketID, "$")
v2 := trim_left(v1, "{")
Expand All @@ -35,4 +71,45 @@ cleanEnd(sseBucketID_v3) = cleanID {
cleanEnd(sseBucketID_v3) = cleanID {
endswith(sseBucketID_v3, ".bucket")
cleanID = trim_right(sseBucketID_v3, ".bucket")
}
}

#For tfplan based scanning
{{.prefix}}noS3BucketSseRules[retVal] {
bucket := input.aws_s3_bucket[_]
bucket_name := input.aws_s3_bucket_server_side_encryption_configuration[_].config.bucket
not contains(bucket_name, "{")
serverSideEncryptionBucketName := [bName |
sse := input.aws_s3_bucket_server_side_encryption_configuration[_]
bName := sse.config.bucket
]

not checkBucketNameForTfPlan(serverSideEncryptionBucketName, bucket)
decode_rc := `resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = $aws_s3_bucket.##name##.bucket$
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}`

replacedName := replace(decode_rc, "##name##", bucket.config.bucket)

resourceWithoutQuotes := replace(replacedName, "$", " ")

traverse = ""
retVal := {"Id": bucket.id, "ReplaceType": "add", "CodeType": "resource", "Traverse": traverse, "Attribute": "", "AttributeDataType": "base64", "Expected": base64.encode(resourceWithoutQuotes), "Actual": null}
}

checkBucketNameForTfPlan(sse, buck) {
buck.id == sse[_]
}

checkBucketNameForTfPlan(sse, buck) {
buck.config.id == sse[_]
}

checkBucketNameForTfPlan(sse, buck) {
buck.config.bucket == sse[_]
}
7 changes: 7 additions & 0 deletions pkg/policies/opa/rego/aws/aws_s3_bucket/s3AclGrants.rego
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@ package accurics
bucket.config.acl == "{{.access}}"
traverse = "acl"
retVal := { "Id": bucket.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "acl", "AttributeDataType": "string", "Expected": "private", "Actual": bucket.config.acl }
}

{{.prefix}}{{.name}}{{.suffix}}[retVal] {
bucket := input.aws_s3_bucket_acl[_]
bucket.config.acl == "{{.access}}"
traverse = "acl"
retVal := { "Id": bucket.id, "ReplaceType": "edit", "CodeType": "attribute", "Traverse": traverse, "Attribute": "acl", "AttributeDataType": "string", "Expected": "private", "Actual": bucket.config.acl }
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,169 @@

package accurics

{{.prefix}}s3BucketAccessLoggingDisabled[s3_bucket.id] {
s3_bucket := input.aws_s3_bucket[_]
object.get(s3_bucket.config, "logging", "undefined") == "undefined"
{{.prefix}}s3BucketAccessLoggingDisabled[retVal] {
cloudTrail := input.aws_cloudtrail[_]
bucket := input.aws_s3_bucket[_]

contains(cloudTrail.config.s3_bucket_name, "{")
cleanId := cleanSSEBucketID(cloudTrail.config.s3_bucket_name)
matchBucketName(bucket, cleanId)
object.get(bucket.config, "logging", "undefined") == ["undefined", [], null][_]
object.get(input, "aws_s3_bucket_logging", "undefined") == "undefined"

decode_rc := `resource "aws_s3_bucket_logging" "{{.defaultValue}}" {
bucket = aws_s3_bucket.##name##.id
targetBucket = "{{.defaultValue1}}"
}`

replaced_rc := replace(decode_rc, "##name##", split(cleanId, ".")[1])

retVal := {
"Id": bucket.id,
"ReplaceType": "add",
"CodeType": "resource",
"Traverse": "",
"Attribute": "",
"AttributeDataType": "base64",
"Expected": base64.encode(replaced_rc),
"Actual": null,
}
}

{{.prefix}}s3BucketAccessLoggingDisabled[retVal] {
cloudTrail := input.aws_cloudtrail[_]
bucket := input.aws_s3_bucket[_]

not contains(cloudTrail.config.s3_bucket_name, "{")
matchBucketName(bucket, cloudTrail.config.s3_bucket_name)
object.get(bucket.config, "logging", "undefined") == ["undefined", [], null][_]
object.get(input, "aws_s3_bucket_logging", "undefined") == "undefined"

decode_rc := `resource "aws_s3_bucket_logging" "{{.defaultValue}}" {
bucket = aws_s3_bucket.##name##.id
targetBucket = "{{.defaultValue1}}"
}`

replaced_rc := replace(decode_rc, "##name##", bucket.name)

retVal := {
"Id": bucket.id,
"ReplaceType": "add",
"CodeType": "resource",
"Traverse": "",
"Attribute": "",
"AttributeDataType": "base64",
"Expected": base64.encode(replaced_rc),
"Actual": null,
}
}

{{.prefix}}s3BucketAccessLoggingDisabled[retVal] {
bucket := input.aws_s3_bucket[_]
object.get(bucket.config, "logging", "undefined") == ["undefined", [], null][_]

cloudTrail := input.aws_cloudtrail[_]
not contains(cloudTrail.config.s3_bucket_name, "{")
matchBucketName(bucket, cloudTrail.config.s3_bucket_name)

bucket_logged := [bl | bucketlogging := input.aws_s3_bucket_logging[_];
bl := bucketlogging.config.bucket]
not matchBucketName(bucket_logged, bucket)

decode_rc := `resource "aws_s3_bucket_logging" "{{.defaultValue}}" {
bucket = aws_s3_bucket.##name##.id
targetBucket = "{{.defaultValue1}}"
}`

replaced_rc := replace(decode_rc, "##name##", bucket.name)

retVal := {
"Id": bucket.id,
"ReplaceType": "add",
"CodeType": "resource",
"Traverse": "",
"Attribute": "",
"AttributeDataType": "base64",
"Expected": base64.encode(replaced_rc),
"Actual": null,
}
}

{{.prefix}}s3BucketAccessLoggingDisabled[retVal] {
bucket := input.aws_s3_bucket[_]
object.get(bucket.config, "logging", "undefined") == ["undefined", [], null][_]

cloudTrail := input.aws_cloudtrail[_]
contains(cloudTrail.config.s3_bucket_name, "{")

cleanId := cleanSSEBucketID(cloudTrail.config.s3_bucket_name)
matchBucketName(bucket, cleanId)

bucket_logged := [bl | bucketlogging := input.aws_s3_bucket_logging[_];
bl := cleanSSEBucketID(bucketlogging.config.bucket)]
not matchBucketName(bucket_logged, bucket)

decode_rc := `resource "aws_s3_bucket_logging" "{{.defaultValue}}" {
bucket = aws_s3_bucket.##name##.id
targetBucket = "{{.defaultValue1}}"
}`

replaced_rc := replace(decode_rc, "##name##", bucket.name)

retVal := {
"Id": bucket.id,
"ReplaceType": "add",
"CodeType": "resource",
"Traverse": "",
"Attribute": "",
"AttributeDataType": "base64",
"Expected": base64.encode(replaced_rc),
"Actual": null,
}
}

matchBucketName(arg1, arg2){
arg1.id == arg2
}

matchBucketName(arg1, arg2){
arg1[_] == arg2
}

matchBucketName(arg1, arg2){
arg1[_] == arg2.id
}

matchBucketName(arg1, arg2){
arg1[_] == arg2.config.id
}

matchBucketName(arg1, arg2){
arg1[_] == arg2.config.bucket
}

{{.prefix}}s3BucketAccessLoggingDisabled[s3_bucket.id] {
s3_bucket := input.aws_s3_bucket[_]
s3_bucket.config.logging == []
matchBucketName(arg1, arg2){
arg1.config.id == arg2
}

{{.prefix}}s3BucketAccessLoggingDisabled[s3_bucket.id] {
s3_bucket := input.aws_s3_bucket[_]
s3_bucket.config.logging == null
}
matchBucketName(arg1, arg2){
arg1.config.bucket == arg2
}


cleanSSEBucketID(sseBucketID) = cleanID {
v1 := trim_left(sseBucketID, "$")
v2 := trim_left(v1, "{")
v3 := trim_right(v2, "}")
cleanID = cleanEnd(v3)
}

cleanEnd(sseBucketID_v3) = cleanID {
endswith(sseBucketID_v3, ".id")
cleanID = trim_right(sseBucketID_v3, ".id")
}

cleanEnd(sseBucketID_v3) = cleanID {
endswith(sseBucketID_v3, ".bucket")
cleanID = trim_right(sseBucketID_v3, ".bucket")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@ package accurics
count(bucket.config.website) > 0
traverse = "website"
retVal := { "Id": bucket.id, "ReplaceType": "delete", "CodeType": "block", "Traverse": traverse, "Attribute": "website", "AttributeDataType": "block", "Expected": null, "Actual": null }
}
}

{{.prefix}}s3BucketNoWebsiteIndexDoc[retVal] {
bucket := input.aws_s3_bucket[_]
bucket_website_config := input.aws_s3_bucket_website_configuration[_]
bucket_website_config.config.bucket == bucket.config.bucket
retVal := { "Id": bucket_website_config.id, "ReplaceType": "delete", "CodeType": "resource", "Traverse": "", "Attribute": "", "AttributeDataType": "resource", "Expected": null, "Actual": null }
}
Loading

0 comments on commit b909460

Please sign in to comment.