diff --git a/policies/s3/s3-require-ssl.sentinel b/policies/s3/s3-require-ssl.sentinel index 1ba081b..75cb17f 100644 --- a/policies/s3/s3-require-ssl.sentinel +++ b/policies/s3/s3-require-ssl.sentinel @@ -10,6 +10,7 @@ import "tfstate/v2" as tfstate import "tfresources" as tf import "report" as report import "strings" +import "types" import "collection" as collection import "collection/maps" as maps @@ -57,8 +58,19 @@ get_referenced_policy_statements = func(res) { if strings.has_prefix(res.module_address, const.module_prefix) { address = res.module_address + "." + address } - datasource = tf.state(tfstate.resources).mode("data").address(address).resources + if datasource is null or datasource is not defined or datasource is empty { + address = "data." + address + datasource = tf.config(tfconfig.resources).mode("data").address(address).resources + if datasource is null or datasource is not defined { + return [] + } + return filter datasource[0].config.statement as _, statement { + statement.actions.constant_value contains "*" or any statement.actions.constant_value as _, action { + strings.has_prefix(action, "s3:") + } + } + } return filter datasource[0].values.statement as _, statement { statement.actions contains "*" or any statement.actions as _, action { strings.has_prefix(action, "s3:") @@ -71,6 +83,12 @@ verify_ssl_status = func(conditions, desired_condition) { return false } return collection.find(conditions, func(condition) { + if (types.type_of(condition["test"]) is not "string" and types.type_of(condition["values"]) is not "string" and types.type_of(condition["variable"]) is not "string") { + return condition["test"].constant_value is "Bool" and + condition[const.values].constant_value contains desired_condition and + condition[const.variable].constant_value is "aws:SecureTransport" + + } return condition["test"] is "Bool" and condition[const.values] contains desired_condition and condition[const.variable] is "aws:SecureTransport" @@ -97,7 +115,7 @@ s3_bucket_resources = config_resources.type(const.resource_aws_s3_bucket).resour s3_bucket_policy_resources = config_resources.type(const.resource_aws_s3_bucket_policy).resources valid_bucket_policies = filter s3_bucket_policy_resources as _, res { any get_referenced_policy_statements(res) as _, stmt { - stmt["effect"] is "Deny" and is_ssl_disabled(stmt["condition"]) + (stmt["effect"] is "Deny" or (types.type_of(stmt["effect"]) is not "string" and stmt["effect"].constant_value is "Deny")) and (is_ssl_disabled(stmt["condition"])) } } s3_bucket_addresses = map valid_bucket_policies as _, res { diff --git a/policies/s3/test/s3-require-ssl/mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfconfig-v2.sentinel b/policies/s3/test/s3-require-ssl/mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfconfig-v2.sentinel new file mode 100644 index 0000000..3cc4337 --- /dev/null +++ b/policies/s3/test/s3-require-ssl/mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfconfig-v2.sentinel @@ -0,0 +1,144 @@ +import "strings" + +providers = { + "aws": { + "alias": "", + "config": { + "region": { + "constant_value": "us-west-2", + }, + }, + "full_name": "registry.terraform.io/hashicorp/aws", + "module_address": "", + "name": "aws", + "provider_config_key": "aws", + "version_constraint": "", + }, +} + +resources = { + "aws_s3_bucket.bucket": { + "address": "aws_s3_bucket.bucket", + "config": { + "bucket": { + "constant_value": "my-new-bucket-1234567890", + }, + }, + "count": {}, + "depends_on": [], + "for_each": {}, + "mode": "managed", + "module_address": "", + "name": "bucket", + "provider_config_key": "aws", + "provisioners": [], + "type": "aws_s3_bucket", + }, + "aws_s3_bucket_policy.bucket_policy": { + "address": "aws_s3_bucket_policy.bucket_policy", + "config": { + "bucket": { + "references": [ + "aws_s3_bucket.bucket.id", + "aws_s3_bucket.bucket", + ], + }, + "policy": { + "references": [ + "data.aws_iam_policy_document.bucket_policy_document.json", + "data.aws_iam_policy_document.bucket_policy_document", + ], + }, + }, + "count": {}, + "depends_on": [], + "for_each": {}, + "mode": "managed", + "module_address": "", + "name": "bucket_policy", + "provider_config_key": "aws", + "provisioners": [], + "type": "aws_s3_bucket_policy", + }, + "data.aws_iam_policy_document.bucket_policy_document": { + "address": "data.aws_iam_policy_document.bucket_policy_document", + "config": { + "statement": [ + { + "actions": { + "constant_value": [ + "s3:*", + ], + }, + "condition": [ + { + "test": { + "constant_value": "Bool", + }, + "values": { + "constant_value": [ + "false", + ], + }, + "variable": { + "constant_value": "aws:SecureTransport", + }, + }, + ], + "effect": { + "constant_value": "Deny", + }, + "principals": [ + { + "identifiers": { + "constant_value": [ + "*", + ], + }, + "type": { + "constant_value": "*", + }, + }, + ], + "resources": { + "references": [ + "aws_s3_bucket.bucket.arn", + "aws_s3_bucket.bucket", + "aws_s3_bucket.bucket.arn", + "aws_s3_bucket.bucket", + ], + }, + "sid": { + "constant_value": "AllowTLSonly", + }, + }, + ], + }, + "count": {}, + "depends_on": [], + "for_each": {}, + "mode": "data", + "module_address": "", + "name": "bucket_policy_document", + "provider_config_key": "aws", + "provisioners": [], + "type": "aws_iam_policy_document", + }, +} + +provisioners = {} + +variables = {} + +outputs = {} + +module_calls = {} + +strip_index = func(addr) { + s = strings.split(addr, ".") + for s as i, v { + s[i] = strings.split(v, "[")[0] + } + + return strings.join(s, ".") +} diff --git a/policies/s3/test/s3-require-ssl/mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfstate-v2.sentinel b/policies/s3/test/s3-require-ssl/mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfstate-v2.sentinel new file mode 100644 index 0000000..028a453 --- /dev/null +++ b/policies/s3/test/s3-require-ssl/mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfstate-v2.sentinel @@ -0,0 +1,5 @@ +terraform_version = undefined + +outputs = {} + +resources = {} diff --git a/policies/s3/test/s3-require-ssl/success-s3-traffic-deny-enabled-with-datasource-in-config.hcl b/policies/s3/test/s3-require-ssl/success-s3-traffic-deny-enabled-with-datasource-in-config.hcl new file mode 100644 index 0000000..1dab157 --- /dev/null +++ b/policies/s3/test/s3-require-ssl/success-s3-traffic-deny-enabled-with-datasource-in-config.hcl @@ -0,0 +1,31 @@ +mock "tfconfig/v2" { + module { + source = "./mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfconfig-v2.sentinel" + } +} + + +mock "tfstate/v2" { + module { + source = "./mocks/policy-success-s3-traffic-deny-enabled-with-datasource-in-config/mock-tfstate-v2.sentinel" + } +} + + +mock "tfresources" { + module { + source = "../../../../modules/tfresources/tfresources.sentinel" + } +} + +mock "report" { + module { + source = "../../../../modules/mocks/report/report.sentinel" + } +} + +test { + rules = { + main = true + } +} \ No newline at end of file