diff --git a/Makefile b/Makefile index e6c528cd..9aaf170b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ DYNAMIC_REGO_FOLDER=./checks/kubernetes/policies/dynamic +BUNDLE_FILE=bundle.tar.gz .PHONY: test test: @@ -44,9 +45,23 @@ create-bundle: .PHONY: verify-bundle verify-bundle: - cp bundle.tar.gz scripts/bundle.tar.gz + cp $(BUNDLE_FILE) scripts/$(BUNDLE_FILE) cd scripts && go run verify-bundle.go - rm scripts/bundle.tar.gz + rm scripts/$(BUNDLE_FILE) build-opa: - go build ./cmd/opa \ No newline at end of file + go build ./cmd/opa + +start-registry: + docker run --rm -it -d -p 5111:5000 --name registry registry:2 + +stop-registry: + docker stop registry + +push-bundle: create-bundle + @REPO=localhost:5111/trivy-checks:latest ;\ + echo "Pushing to repository: $$REPO" ;\ + docker run --rm -it --net=host -v $$PWD/${BUNDLE_FILE}:/${BUNDLE_FILE} bitnami/oras:latest push \ + $$REPO \ + --config "/dev/null:application/vnd.cncf.openpolicyagent.config.v1+json" \ + "$(BUNDLE_FILE):application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" diff --git a/checks/cloud/aws/apigateway/enable_access_logging.rego b/checks/cloud/aws/apigateway/enable_access_logging.rego index 11e1c61d..17da53cc 100644 --- a/checks/cloud/aws/apigateway/enable_access_logging.rego +++ b/checks/cloud/aws/apigateway/enable_access_logging.rego @@ -34,10 +34,11 @@ package builtin.aws.apigateway.aws0001 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some stage in input.aws.apigateway.v1.apis[_].stages - not logging_is_configured(stage) + logging_is_not_configured(stage) res := result.new( "Access logging is not configured.", metadata.obj_by_path(stage, ["accesslogging", "cloudwatchloggrouparn"]), @@ -46,14 +47,16 @@ deny contains res if { deny contains res if { some stage in input.aws.apigateway.v2.apis[_].stages - not logging_is_configured(stage) + logging_is_not_configured(stage) res := result.new( "Access logging is not configured.", metadata.obj_by_path(stage, ["accesslogging", "cloudwatchloggrouparn"]), ) } -logging_is_configured(stage) if { +logging_is_not_configured(stage) if { isManaged(stage) - stage.accesslogging.cloudwatchloggrouparn.value != "" + value.is_empty(stage.accesslogging.cloudwatchloggrouparn) } + +logging_is_not_configured(stage) if not stage.accesslogging.cloudwatchloggrouparn diff --git a/checks/cloud/aws/apigateway/enable_cache.rego b/checks/cloud/aws/apigateway/enable_cache.rego index 6cd4d742..885f1200 100644 --- a/checks/cloud/aws/apigateway/enable_cache.rego +++ b/checks/cloud/aws/apigateway/enable_cache.rego @@ -31,6 +31,7 @@ package builtin.aws.apigateway.aws0190 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some api in input.aws.apigateway.v1.apis @@ -39,9 +40,13 @@ deny contains res if { isManaged(stage) some settings in stage.restmethodsettings isManaged(settings) - not settings.cacheenabled.value + cache_is_not_enabled(settings) res := result.new( "Cache data is not enabled.", metadata.obj_by_path(settings, ["cacheenabled"]), ) } + +cache_is_not_enabled(settings) if value.is_false(settings.cacheenabled) + +cache_is_not_enabled(settings) if not settings.cacheenabled diff --git a/checks/cloud/aws/apigateway/enable_cache_encryption.rego b/checks/cloud/aws/apigateway/enable_cache_encryption.rego index ed5d19e8..0072e8fd 100644 --- a/checks/cloud/aws/apigateway/enable_cache_encryption.rego +++ b/checks/cloud/aws/apigateway/enable_cache_encryption.rego @@ -29,6 +29,7 @@ package builtin.aws.apigateway.aws0002 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some api in input.aws.apigateway.v1.apis @@ -38,10 +39,14 @@ deny contains res if { some settings in stage.restmethodsettings isManaged(settings) settings.cacheenabled.value - not settings.cachedataencrypted.value + cache_is_not_encrypted(settings) res := result.new( "Cache data is not encrypted.", metadata.obj_by_path(settings, ["cachedataencrypted"]), ) } + +cache_is_not_encrypted(settings) if value.is_false(settings.cachedataencrypted) + +cache_is_not_encrypted(settings) if not settings.cachedataencrypted diff --git a/checks/cloud/aws/apigateway/enable_tracing.rego b/checks/cloud/aws/apigateway/enable_tracing.rego index f3e4bff8..798b500f 100644 --- a/checks/cloud/aws/apigateway/enable_tracing.rego +++ b/checks/cloud/aws/apigateway/enable_tracing.rego @@ -29,15 +29,20 @@ package builtin.aws.apigateway.aws0003 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some api in input.aws.apigateway.v1.apis isManaged(api) some stage in api.stages isManaged(stage) - not stage.xraytracingenabled.value + tracing_is_not_enabled(stage) res := result.new( "X-Ray tracing is not enabled.", metadata.obj_by_path(stage, ["xraytracingenabled"]), ) } + +tracing_is_not_enabled(stage) if value.is_false(stage.xraytracingenabled) + +tracing_is_not_enabled(stage) if not stage.xraytracingenabled diff --git a/checks/cloud/aws/apigateway/no_public_access.rego b/checks/cloud/aws/apigateway/no_public_access.rego index fad776c7..71800d85 100644 --- a/checks/cloud/aws/apigateway/no_public_access.rego +++ b/checks/cloud/aws/apigateway/no_public_access.rego @@ -28,18 +28,24 @@ package builtin.aws.apigateway.aws0004 import rego.v1 +import data.lib.cloud.value + authorization_none := "NONE" deny contains res if { some api in input.aws.apigateway.v1.apis isManaged(api) some method in api.resources[_].methods - not method_is_option(method) - not is_apikey_required(api) + method_is_not_option(method) + apikey_is_not_required(api) method.authorizationtype.value == authorization_none res := result.new("Authorization is not enabled for this method.", method.authorizationtype) } -method_is_option(method) := method.httpmethod.value == "OPTION" +method_is_not_option(method) if value.is_not_equal(method.httpmethod, "OPTION") + +method_is_not_option(method) if not method.httpmethod + +apikey_is_not_required(api) if value.is_false(api.apikeyrequired) -is_apikey_required(api) := api.apikeyrequired.value +apikey_is_not_required(api) if not api.apikeyrequired diff --git a/checks/cloud/aws/athena/enable_at_rest_encryption.rego b/checks/cloud/aws/athena/enable_at_rest_encryption.rego index 46d44ddd..4a5afb1c 100644 --- a/checks/cloud/aws/athena/enable_at_rest_encryption.rego +++ b/checks/cloud/aws/athena/enable_at_rest_encryption.rego @@ -35,12 +35,13 @@ package builtin.aws.athena.aws0006 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value encryption_type_none := "" deny contains res if { some workgroup in input.aws.athena.workgroups - not is_encrypted(workgroup) + not_encrypted(workgroup) res := result.new( "Workgroup does not have encryption configured.", metadata.obj_by_path(workgroup, ["encryption", "type"]), @@ -49,13 +50,13 @@ deny contains res if { deny contains res if { some database in input.aws.athena.databases - not is_encrypted(database) + not_encrypted(database) res := result.new( "Database does not have encryption configured.", metadata.obj_by_path(database, ["encryption", "type"]), ) } -is_encrypted(obj) if { - obj.encryption.type.value != encryption_type_none -} +not_encrypted(encryptable) if value.is_equal(encryptable.encryption.type, encryption_type_none) + +not_encrypted(encryptable) if not encryptable.encryption.type diff --git a/checks/cloud/aws/cloudfront/enable_logging.rego b/checks/cloud/aws/cloudfront/enable_logging.rego index 4c39ef09..814dccd6 100644 --- a/checks/cloud/aws/cloudfront/enable_logging.rego +++ b/checks/cloud/aws/cloudfront/enable_logging.rego @@ -34,14 +34,17 @@ package builtin.aws.cloudfront.aws0010 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some dist in input.aws.cloudfront.distributions - not has_logging_bucket(dist) + without_logging_bucket(dist) res := result.new( "Distribution does not have logging enabled", metadata.obj_by_path(dist, ["logging", "bucket"]), ) } -has_logging_bucket(dist) := dist.logging.bucket.value != "" +without_logging_bucket(dist) if value.is_empty(dist.logging.bucket) + +without_logging_bucket(dist) if not dist.logging.bucket diff --git a/checks/cloud/aws/cloudfront/enable_waf.rego b/checks/cloud/aws/cloudfront/enable_waf.rego index c34cbe62..0488b452 100644 --- a/checks/cloud/aws/cloudfront/enable_waf.rego +++ b/checks/cloud/aws/cloudfront/enable_waf.rego @@ -33,13 +33,17 @@ package builtin.aws.cloudfront.aws0011 import rego.v1 +import data.lib.cloud.value + deny contains res if { some dist in input.aws.cloudfront.distributions - not is_waf_enabled(dist) + waf_not_enabled(dist) res := result.new( "Distribution does not utilise a WAF.", object.get(dist, "wafid", dist), ) } -is_waf_enabled(dist) := dist.wafid.value != "" +waf_not_enabled(dist) if value.is_empty(dist.wafid) + +waf_not_enabled(dist) if not dist.wafid diff --git a/checks/cloud/aws/cloudtrail/encryption_customer_key.rego b/checks/cloud/aws/cloudtrail/encryption_customer_key.rego index c5b586fe..fadaa292 100644 --- a/checks/cloud/aws/cloudtrail/encryption_customer_key.rego +++ b/checks/cloud/aws/cloudtrail/encryption_customer_key.rego @@ -37,14 +37,17 @@ package builtin.aws.cloudtrail.aws0015 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some trail in input.aws.cloudtrail.trails - not use_cms(trail) + without_cmk(trail) res := result.new( "CloudTrail does not use a customer managed key to encrypt the logs.", metadata.obj_by_path(trail, ["kmskeyid"]), ) } -use_cms(trail) if trail.kmskeyid.value != "" +without_cmk(trail) if value.is_empty(trail.kmskeyid) + +without_cmk(trail) if not trail.kmskeyid diff --git a/checks/cloud/aws/cloudtrail/ensure_cloudwatch_integration.rego b/checks/cloud/aws/cloudtrail/ensure_cloudwatch_integration.rego index a587c494..05388f6c 100644 --- a/checks/cloud/aws/cloudtrail/ensure_cloudwatch_integration.rego +++ b/checks/cloud/aws/cloudtrail/ensure_cloudwatch_integration.rego @@ -47,14 +47,17 @@ package builtin.aws.cloudtrail.aws0162 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some trail in input.aws.cloudtrail.trails - not is_logging_configured(trail) + logging_is_not_configured(trail) res := result.new( "Trail does not have CloudWatch logging configured", metadata.obj_by_path(trail, ["cloudwatchlogsloggrouparn"]), ) } -is_logging_configured(trail) if trail.cloudwatchlogsloggrouparn.value != "" +logging_is_not_configured(trail) if value.is_empty(trail.cloudwatchlogsloggrouparn) + +logging_is_not_configured(trail) if not trail.cloudwatchlogsloggrouparn diff --git a/checks/cloud/aws/cloudwatch/log_group_customer_key.rego b/checks/cloud/aws/cloudwatch/log_group_customer_key.rego index e128b4a8..8708763b 100644 --- a/checks/cloud/aws/cloudwatch/log_group_customer_key.rego +++ b/checks/cloud/aws/cloudwatch/log_group_customer_key.rego @@ -34,14 +34,17 @@ package builtin.aws.cloudwatch.aws0017 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some group in input.aws.cloudwatch.loggroups - not has_cms(group) + without_cmk(group) res := result.new( "Log group is not encrypted.", metadata.obj_by_path(group, ["kmskeyid"]), ) } -has_cms(group) if group.kmskeyid.value != "" +without_cmk(group) if value.is_empty(group.kmskeyid) + +without_cmk(group) if not group.kmskeyid diff --git a/checks/cloud/aws/documentdb/enable_log_export.rego b/checks/cloud/aws/documentdb/enable_log_export.rego index 041166a0..659f33ca 100644 --- a/checks/cloud/aws/documentdb/enable_log_export.rego +++ b/checks/cloud/aws/documentdb/enable_log_export.rego @@ -33,6 +33,8 @@ package builtin.aws.documentdb.aws0020 import rego.v1 +import data.lib.cloud.value + log_export_audit := "audit" log_export_profiler := "profiler" @@ -47,3 +49,8 @@ export_audit_or_profiler(cluster) if { some log in cluster.enabledlogexports log.value in [log_export_audit, log_export_profiler] } + +export_audit_or_profiler(cluster) if { + some log in cluster.enabledlogexports + value.is_unresolvable(log) +} diff --git a/checks/cloud/aws/documentdb/enable_log_export_test.rego b/checks/cloud/aws/documentdb/enable_log_export_test.rego index 95cb64a1..02154706 100644 --- a/checks/cloud/aws/documentdb/enable_log_export_test.rego +++ b/checks/cloud/aws/documentdb/enable_log_export_test.rego @@ -24,3 +24,8 @@ test_allow_export_mixed if { inp := {"aws": {"documentdb": {"clusters": [{"enabledlogexports": [{"value": "audit"}, {"value": "profiler"}]}]}}} test.assert_empty(check.deny) with input as inp } + +test_allow_export_mixed_with_unresolvable if { + inp := {"aws": {"documentdb": {"clusters": [{"enabledlogexports": [{"value": "foo"}, {"value": "bar", "unresolvable": true}]}]}}} + test.assert_empty(check.deny) with input as inp +} diff --git a/checks/cloud/aws/documentdb/encryption_customer_key.rego b/checks/cloud/aws/documentdb/encryption_customer_key.rego index 0c58ecb1..0778ae7f 100644 --- a/checks/cloud/aws/documentdb/encryption_customer_key.rego +++ b/checks/cloud/aws/documentdb/encryption_customer_key.rego @@ -34,11 +34,12 @@ package builtin.aws.documentdb.aws0022 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some cluster in input.aws.documentdb.clusters isManaged(cluster) - not has_cms(cluster) + without_cmk(cluster) res := result.new( "Cluster encryption does not use a customer-managed KMS key.", metadata.obj_by_path(cluster, ["kmskeyid"]), @@ -49,11 +50,13 @@ deny contains res if { some cluster in input.aws.documentdb.clusters some instance in cluster.instances isManaged(instance) - not has_cms(instance) + without_cmk(instance) res := result.new( "Instance encryption does not use a customer-managed KMS key.", metadata.obj_by_path(instance, ["kmskeyid"]), ) } -has_cms(obj) if obj.kmskeyid.value != "" +without_cmk(obj) if value.is_empty(obj.kmskeyid) + +without_cmk(obj) if not obj.kmskeyid diff --git a/checks/cloud/aws/dynamodb/enable_at_rest_encryption.rego b/checks/cloud/aws/dynamodb/enable_at_rest_encryption.rego index db6c7463..7415b02c 100644 --- a/checks/cloud/aws/dynamodb/enable_at_rest_encryption.rego +++ b/checks/cloud/aws/dynamodb/enable_at_rest_encryption.rego @@ -34,8 +34,19 @@ package builtin.aws.dynamodb.aws0023 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.dynamodb.daxclusters - cluster.serversideencryption.enabled.value == false - res := result.new("DAX encryption is not enabled.", cluster.serversideencryption.enabled) + not_encrypted(cluster) + + res := result.new( + "DAX encryption is not enabled.", + metadata.obj_by_path(cluster, ["serversideencryption", "enabled"]), + ) } + +not_encrypted(cluster) if value.is_false(cluster.serversideencryption.enabled) + +not_encrypted(cluster) if not cluster.serversideencryption.enabled diff --git a/checks/cloud/aws/dynamodb/enable_recovery.rego b/checks/cloud/aws/dynamodb/enable_recovery.rego index 3e19dca2..19bcdd56 100644 --- a/checks/cloud/aws/dynamodb/enable_recovery.rego +++ b/checks/cloud/aws/dynamodb/enable_recovery.rego @@ -31,16 +31,27 @@ package builtin.aws.dynamodb.aws0024 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.dynamodb.daxclusters - cluster.pointintimerecovery.value == false - - res := result.new("Point-in-time recovery is not enabled.", cluster.pointintimerecovery) + recovery_is_not_enabled(cluster) + res := result.new( + "Point-in-time recovery is not enabled.", + metadata.obj_by_path(cluster, ["pointintimerecovery"]), + ) } deny contains res if { some table in input.aws.dynamodb.tables - table.pointintimerecovery.value == false - - res := result.new("Point-in-time recovery is not enabled.", table.pointintimerecovery) + recovery_is_not_enabled(table) + res := result.new( + "Point-in-time recovery is not enabled.", + metadata.obj_by_path(table, ["pointintimerecovery"]), + ) } + +recovery_is_not_enabled(obj) if value.is_false(obj.pointintimerecovery) + +recovery_is_not_enabled(obj) if not obj.pointintimerecovery diff --git a/checks/cloud/aws/dynamodb/table_customer_key.rego b/checks/cloud/aws/dynamodb/table_customer_key.rego index a762aebc..344192ae 100644 --- a/checks/cloud/aws/dynamodb/table_customer_key.rego +++ b/checks/cloud/aws/dynamodb/table_customer_key.rego @@ -30,20 +30,31 @@ package builtin.aws.dynamodb.aws0025 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some table in input.aws.dynamodb.tables - table.serversideencryption.enabled.value == false - res := result.new("Table encryption does not use a customer-managed KMS key.", table.serversideencryption.enabled) + not_encrypted(table) + res := result.new( + "Table encryption does not use a customer-managed KMS key.", + metadata.obj_by_path(table, ["serversideencryption", "enabled"]), + ) } deny contains res if { some table in input.aws.dynamodb.tables table.serversideencryption.enabled.value - not valid_key(table.serversideencryption.kmskeyid.value) + non_valid_key(table) res := result.new("Table encryption explicitly uses the default KMS key.", table.serversideencryption.kmskeyid) } -valid_key(k) if { - k != "" - k != "alias/aws/dynamodb" -} +not_encrypted(table) if value.is_false(table.serversideencryption.enabled) + +not_encrypted(table) if not table.serversideencryption.enabled + +non_valid_key(table) if value.is_empty(table.serversideencryption.kmskeyid) + +non_valid_key(table) if value.is_equal(table.serversideencryption.kmskeyid, "alias/aws/dynamodb") + +non_valid_key(table) if not table.serversideencryption.kmskeyid diff --git a/checks/cloud/aws/ec2/add_description_to_security_group.rego b/checks/cloud/aws/ec2/add_description_to_security_group.rego index ae7d812f..1a7b8b59 100644 --- a/checks/cloud/aws/ec2/add_description_to_security_group.rego +++ b/checks/cloud/aws/ec2/add_description_to_security_group.rego @@ -39,11 +39,12 @@ package builtin.aws.ec2.aws0099 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some sg in input.aws.ec2.securitygroups isManaged(sg) - not has_description(sg) + without_description(sg) res := result.new( "Security group does not have a description.", metadata.obj_by_path(sg, ["description"]), @@ -57,4 +58,6 @@ deny contains res if { res := result.new("Security group explicitly uses the default description.", sg.description) } -has_description(sg) if sg.description.value != "" +without_description(sg) if value.is_empty(sg.description) + +without_description(sg) if not sg.description diff --git a/checks/cloud/aws/ec2/add_description_to_security_group_rule.rego b/checks/cloud/aws/ec2/add_description_to_security_group_rule.rego index e23c8a33..463a67dc 100644 --- a/checks/cloud/aws/ec2/add_description_to_security_group_rule.rego +++ b/checks/cloud/aws/ec2/add_description_to_security_group_rule.rego @@ -39,6 +39,7 @@ package builtin.aws.ec2.aws0124 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some group in input.aws.ec2.securitygroups @@ -46,11 +47,13 @@ deny contains res if { object.get(group, "egressrules", []), object.get(group, "ingressrules", []), ) - not has_description(rule) + without_description(rule) res := result.new( "Security group rule does not have a description.", metadata.obj_by_path(rule, ["description"]), ) } -has_description(rule) if rule.description.value != "" +without_description(rule) if value.is_empty(rule.description) + +without_description(rule) if not rule.description diff --git a/checks/cloud/aws/ec2/as_enforce_http_token_imds.rego b/checks/cloud/aws/ec2/as_enforce_http_token_imds.rego index ed22174e..29da56d7 100644 --- a/checks/cloud/aws/ec2/as_enforce_http_token_imds.rego +++ b/checks/cloud/aws/ec2/as_enforce_http_token_imds.rego @@ -40,11 +40,12 @@ package builtin.aws.ec2.aws0130 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some config in input.aws.ec2.launchconfigurations - not is_tokens_required(config) - not is_endpoint_disabled(config) + tokens_is_not_required(config) + endpoint_is_not_disabled(config) res := result.new( "Launch configuration does not require IMDS access to require a token", metadata.obj_by_path(config, ["metadataoptions", "httptokens"]), @@ -53,14 +54,18 @@ deny contains res if { deny contains res if { some tpl in input.aws.ec2.launchtemplates - not is_tokens_required(tpl.instance) - not is_endpoint_disabled(tpl.instance) + tokens_is_not_required(tpl.instance) + endpoint_is_not_disabled(tpl.instance) res := result.new( "Launch template does not require IMDS access to require a token", metadata.obj_by_path(tpl.instance, ["metadataoptions", "httptokens"]), ) } -is_tokens_required(instance) if instance.metadataoptions.httptokens.value == "required" +tokens_is_not_required(instance) if value.is_not_equal(instance.metadataoptions.httptokens, "required") -is_endpoint_disabled(instance) if instance.metadataoptions.httpendpoint.value == "disabled" +tokens_is_not_required(instance) if not instance.metadataoptions.httptokens + +endpoint_is_not_disabled(instance) if value.is_not_equal(instance.metadataoptions.httpendpoint, "disabled") + +endpoint_is_not_disabled(instance) if not instance.metadataoptions.httpendpoint diff --git a/checks/cloud/aws/ec2/encryption_customer_key.rego b/checks/cloud/aws/ec2/encryption_customer_key.rego index 2fc2cae7..596bd384 100644 --- a/checks/cloud/aws/ec2/encryption_customer_key.rego +++ b/checks/cloud/aws/ec2/encryption_customer_key.rego @@ -36,15 +36,18 @@ package builtin.aws.ec2.aws0027 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some volume in input.aws.ec2.volumes isManaged(volume) - not has_cms(volume) + without_cmk(volume) res := result.new( "EBS volume does not use a customer-managed KMS key.", metadata.obj_by_path(volume, ["encryption", "kmskeyid"]), ) } -has_cms(volume) if volume.encryption.kmskeyid.value != "" +without_cmk(volume) if value.is_empty(volume.encryption.kmskeyid) + +without_cmk(volume) if not volume.encryption.kmskeyid diff --git a/checks/cloud/aws/ec2/enforce_http_token_imds.rego b/checks/cloud/aws/ec2/enforce_http_token_imds.rego index b8cdc172..821d6fe2 100644 --- a/checks/cloud/aws/ec2/enforce_http_token_imds.rego +++ b/checks/cloud/aws/ec2/enforce_http_token_imds.rego @@ -35,17 +35,22 @@ package builtin.aws.ec2.aws0028 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some instance in input.aws.ec2.instances - not is_tokens_required(instance) - not is_endpoint_disabled(instance) + tokens_is_not_required(instance) + endpoint_is_not_disabled(instance) res := result.new( "Instance does not require IMDS access to require a token.", metadata.obj_by_path(instance, ["metadataoptions", "httptokens"]), ) } -is_tokens_required(instance) if instance.metadataoptions.httptokens.value == "required" +tokens_is_not_required(instance) if value.is_not_equal(instance.metadataoptions.httptokens, "required") -is_endpoint_disabled(instance) if instance.metadataoptions.httpendpoint.value == "disabled" +tokens_is_not_required(instance) if not instance.metadataoptions.httptokens + +endpoint_is_not_disabled(instance) if value.is_not_equal(instance.metadataoptions.httpendpoint, "disabled") + +endpoint_is_not_disabled(instance) if not instance.metadataoptions.httpendpoint diff --git a/checks/cloud/aws/ec2/enforce_http_token_imds_test.rego b/checks/cloud/aws/ec2/enforce_http_token_imds_test.rego index 919d8d92..d2ea6602 100644 --- a/checks/cloud/aws/ec2/enforce_http_token_imds_test.rego +++ b/checks/cloud/aws/ec2/enforce_http_token_imds_test.rego @@ -33,3 +33,12 @@ test_allow_instance_with_endpoint_disabled if { } build_input(meta_opts) := {"aws": {"ec2": {"instances": [{"metadataoptions": meta_opts}]}}} + +test_allow_instance_with_tokens_unresolvable if { + inp := build_input({ + "httptokens": {"value": "", "unresolvable": true}, + "httpendpoint": {"value": "enabled"}, + }) + + test.assert_empty(check.deny) with input as inp +} diff --git a/checks/cloud/aws/ec2/require_vpc_flow_logs_for_all_vpcs.rego b/checks/cloud/aws/ec2/require_vpc_flow_logs_for_all_vpcs.rego index a01bdace..b9b5ab53 100644 --- a/checks/cloud/aws/ec2/require_vpc_flow_logs_for_all_vpcs.rego +++ b/checks/cloud/aws/ec2/require_vpc_flow_logs_for_all_vpcs.rego @@ -27,8 +27,18 @@ package builtin.aws.ec2.aws0178 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some vpc in input.aws.ec2.vpcs - vpc.flowlogsenabled.value == false - res := result.new("VPC does not have VPC Flow Logs enabled.", vpc.flowlogsenabled) + logs_disabled(vpc) + res := result.new( + "VPC does not have VPC Flow Logs enabled.", + metadata.obj_by_path(vpc, ["flowlogsenabled"]), + ) } + +logs_disabled(vpc) if value.is_false(vpc.flowlogsenabled) + +logs_disabled(vpc) if not vpc.flowlogsenabled diff --git a/checks/cloud/aws/ecr/repository_customer_key.rego b/checks/cloud/aws/ecr/repository_customer_key.rego index a45aca9c..2bdfe078 100644 --- a/checks/cloud/aws/ecr/repository_customer_key.rego +++ b/checks/cloud/aws/ecr/repository_customer_key.rego @@ -34,23 +34,28 @@ package builtin.aws.ecr.aws0033 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some repo in input.aws.ecr.repositories - not is_encyption_type_kms(repo.encryption.type) + encyption_type_no_kms(repo) res := result.new("Repository is not encrypted using KMS.", repo.encryption.type) } deny contains res if { some repo in input.aws.ecr.repositories - is_encyption_type_kms(repo.encryption.type) - not has_cms(repo) + repo.encryption.type.value == "KMS" + without_cmk(repo) res := result.new( "Repository encryption does not use a customer managed KMS key.", metadata.obj_by_path(repo, ["encryption", "kmskeyid"]), ) } -is_encyption_type_kms(typ) if typ.value == "KMS" +encyption_type_no_kms(repo) if value.is_not_equal(repo.encryption.type, "KMS") -has_cms(repo) if repo.encryption.kmskeyid.value != "" +encyption_type_no_kms(repo) if not repo.encryption.type + +without_cmk(repo) if value.is_empty(repo.encryption.kmskeyid) + +without_cmk(repo) if not repo.encryption.kmskeyid diff --git a/checks/cloud/aws/eks/encrypt_secrets.rego b/checks/cloud/aws/eks/encrypt_secrets.rego index d2e0811c..22e1b18c 100644 --- a/checks/cloud/aws/eks/encrypt_secrets.rego +++ b/checks/cloud/aws/eks/encrypt_secrets.rego @@ -34,10 +34,11 @@ package builtin.aws.eks.aws0039 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some cluster in input.aws.eks.clusters - not secret_encryption_enabled(cluster) + secret_encryption_not_enabled(cluster) res := result.new( "Cluster does not have secret encryption enabled.", metadata.obj_by_path(cluster, ["encryption", "secrets"]), @@ -46,14 +47,18 @@ deny contains res if { deny contains res if { some cluster in input.aws.eks.clusters - secret_encryption_enabled(cluster) - not has_cms(cluster) + cluster.encryption.secrets.value + without_cmk(cluster) res := result.new( "Cluster encryption requires a KMS key ID, which is missing", metadata.obj_by_path(cluster, ["encryption", "kmskeyid"]), ) } -secret_encryption_enabled(cluster) if cluster.encryption.secrets.value == true +secret_encryption_not_enabled(cluster) if value.is_false(cluster.encryption.secrets) -has_cms(cluster) if cluster.encryption.kmskeyid.value != "" +secret_encryption_not_enabled(cluster) if not cluster.encryption.secrets + +without_cmk(cluster) if value.is_empty(cluster.encryption.kmskeyid) + +without_cmk(cluster) if not cluster.encryption.kmskeyid diff --git a/checks/cloud/aws/elasticache/add_description_for_security_group.rego b/checks/cloud/aws/elasticache/add_description_for_security_group.rego index 78135fdd..2b286d37 100644 --- a/checks/cloud/aws/elasticache/add_description_for_security_group.rego +++ b/checks/cloud/aws/elasticache/add_description_for_security_group.rego @@ -35,14 +35,17 @@ package builtin.aws.elasticache.aws0049 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some secgroup in input.aws.elasticache.securitygroups - not has_description(secgroup) + without_description(secgroup) res := result.new( "Security group does not have a description.", metadata.obj_by_path(secgroup, ["description"]), ) } -has_description(sg) if sg.description.value != "" +without_description(sg) if value.is_empty(sg.description) + +without_description(sg) if not sg.description diff --git a/checks/cloud/aws/elasticache/enable_backup_retention.rego b/checks/cloud/aws/elasticache/enable_backup_retention.rego index 0a8aa6fe..7458fbcb 100644 --- a/checks/cloud/aws/elasticache/enable_backup_retention.rego +++ b/checks/cloud/aws/elasticache/enable_backup_retention.rego @@ -33,10 +33,12 @@ package builtin.aws.elasticache.aws0050 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.elasticache.clusters cluster.engine.value == "redis" - cluster.nodetype.value != "cache.t1.micro" - cluster.snapshotretentionlimit.value == 0 + value.is_not_equal(cluster.nodetype, "cache.t1.micro") + value.is_equal(cluster.snapshotretentionlimit, 0) res := result.new("Cluster snapshot retention is not enabled.", cluster.snapshotretentionlimit) } diff --git a/checks/cloud/aws/iam/no_password_reuse.rego b/checks/cloud/aws/iam/no_password_reuse.rego index c822f6d0..588b076a 100644 --- a/checks/cloud/aws/iam/no_password_reuse.rego +++ b/checks/cloud/aws/iam/no_password_reuse.rego @@ -39,9 +39,11 @@ package builtin.aws.iam.aws0056 import rego.v1 +import data.lib.cloud.value + deny contains res if { policy := input.aws.iam.passwordpolicy isManaged(policy) - policy.reusepreventioncount.value < 5 + value.less_than(policy.reusepreventioncount, 5) res := result.new("Password policy allows reuse of recent passwords.", policy) } diff --git a/checks/cloud/aws/iam/remove_expired_certificates.rego b/checks/cloud/aws/iam/remove_expired_certificates.rego index d733ce7a..2f99c9e6 100644 --- a/checks/cloud/aws/iam/remove_expired_certificates.rego +++ b/checks/cloud/aws/iam/remove_expired_certificates.rego @@ -34,9 +34,11 @@ package builtin.aws.iam.aws0168 import rego.v1 +import data.lib.cloud.value + deny contains res if { some certificate in input.aws.iam.servercertificates + not value.is_unresolvable(certificate.expiration) time.parse_rfc3339_ns(certificate.expiration.value) < time.now_ns() - res := result.new("Certificate has expired", certificate) } diff --git a/checks/cloud/aws/iam/set_minimum_password_length.rego b/checks/cloud/aws/iam/set_minimum_password_length.rego index a7d5b86c..6f0c662b 100644 --- a/checks/cloud/aws/iam/set_minimum_password_length.rego +++ b/checks/cloud/aws/iam/set_minimum_password_length.rego @@ -39,11 +39,16 @@ package builtin.aws.iam.aws0063 import rego.v1 +import data.lib.cloud.value + msg := "Password policy allows a maximum password age of greater than 90 days" deny contains res if { policy := input.aws.iam.passwordpolicy isManaged(policy) - policy.minimumlength.value < 14 - res := result.new("Password policy allows a maximum password age of greater than 90 days", policy.minimumlength) + value.less_than(policy.minimumlength, 14) + res := result.new( + "Password policy allows a maximum password age of greater than 90 days", + policy.minimumlength, + ) } diff --git a/checks/cloud/aws/kinesis/enable_in_transit_encryption.rego b/checks/cloud/aws/kinesis/enable_in_transit_encryption.rego index 5ab7e363..bf7f6d2c 100644 --- a/checks/cloud/aws/kinesis/enable_in_transit_encryption.rego +++ b/checks/cloud/aws/kinesis/enable_in_transit_encryption.rego @@ -33,15 +33,32 @@ package builtin.aws.kinesis.aws0064 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some stream in input.aws.kinesis.streams - stream.encryption.type.value != "KMS" - res := result.new("Stream does not use KMS encryption.", stream.encryption.type) + encryption_is_not_kms(stream) + res := result.new( + "Stream does not use KMS encryption.", + metadata.obj_by_path(stream, ["encryption", "type"]), + ) } +encryption_is_not_kms(stream) if value.is_not_equal(stream.encryption.type, "KMS") + +encryption_is_not_kms(stream) if not stream.encryption.type + deny contains res if { some stream in input.aws.kinesis.streams stream.encryption.type.value == "KMS" - stream.encryption.kmskeyid.value == "" - res := result.new("Stream does not use a custom-managed KMS key.", stream.encryption.kmskeyid) + without_cmk(stream) + res := result.new( + "Stream does not use a custom-managed KMS key.", + metadata.obj_by_path(stream, ["encryption", "kmskeyid"]), + ) } + +without_cmk(stream) if value.is_empty(stream.encryption.kmskeyid) + +without_cmk(stream) if not stream.encryption.kmskeyid diff --git a/checks/cloud/aws/kms/auto_rotate_keys.rego b/checks/cloud/aws/kms/auto_rotate_keys.rego index be879027..804c9333 100644 --- a/checks/cloud/aws/kms/auto_rotate_keys.rego +++ b/checks/cloud/aws/kms/auto_rotate_keys.rego @@ -30,9 +30,23 @@ package builtin.aws.kms.aws0065 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some key in input.aws.kms.keys - key.usage.value != "SIGN_VERIFY" - key.rotationenabled.value == false - res := result.new("Key does not have rotation enabled.", key.rotationenabled) + is_not_sign_key(key) + rotation_disabled(key) + res := result.new( + "Key does not have rotation enabled.", + metadata.obj_by_path(key, ["rotationenabled"]), + ) } + +is_not_sign_key(key) if value.is_not_equal(key.usage, "SIGN_VERIFY") + +is_not_sign_key(key) if not key.usage + +rotation_disabled(key) if value.is_false(key.rotationenabled) + +rotation_disabled(key) if not key.rotationenabled diff --git a/checks/cloud/aws/lambda/restrict_source_arn.rego b/checks/cloud/aws/lambda/restrict_source_arn.rego index 5cbc9c6a..f197ab8d 100644 --- a/checks/cloud/aws/lambda/restrict_source_arn.rego +++ b/checks/cloud/aws/lambda/restrict_source_arn.rego @@ -35,10 +35,20 @@ package builtin.aws.lambda.aws0067 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some func in input.aws.lambda.functions some permission in func.permissions endswith(permission.principal.value, ".amazonaws.com") - permission.sourcearn.value == "" - res := result.new("Lambda permission lacks source ARN for *.amazonaws.com principal.", permission.sourcearn) + sourcearn_is_missed(permission) + res := result.new( + "Lambda permission lacks source ARN for *.amazonaws.com principal.", + metadata.obj_by_path(permission, ["sourcearn"]), + ) } + +sourcearn_is_missed(permission) if value.is_empty(permission.sourcearn) + +sourcearn_is_missed(permission) if not permission.sourcearn diff --git a/checks/cloud/aws/mq/enable_audit_logging.rego b/checks/cloud/aws/mq/enable_audit_logging.rego index 94eb0a9c..abe7ea30 100644 --- a/checks/cloud/aws/mq/enable_audit_logging.rego +++ b/checks/cloud/aws/mq/enable_audit_logging.rego @@ -33,9 +33,18 @@ package builtin.aws.mq.aws0070 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some broker in input.aws.mq.brokers - broker.logging.audit.value == false - - res := result.new("Broker does not have audit logging enabled.", broker.logging.audit) + logging_disabled(broker) + res := result.new( + "Broker does not have audit logging enabled.", + metadata.obj_by_path(broker, ["logging", "audit"]), + ) } + +logging_disabled(broker) if value.is_false(broker.logging.audit) + +logging_disabled(broker) if not broker.logging.audit diff --git a/checks/cloud/aws/mq/enable_general_logging.rego b/checks/cloud/aws/mq/enable_general_logging.rego index 82ec21e1..c1a6d4e1 100644 --- a/checks/cloud/aws/mq/enable_general_logging.rego +++ b/checks/cloud/aws/mq/enable_general_logging.rego @@ -33,8 +33,18 @@ package builtin.aws.mq.aws0071 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some broker in input.aws.mq.brokers - broker.logging.general.value == false - res := result.new("Broker does not have general logging enabled.", broker.logging.general) + logging_disabled(broker) + res := result.new( + "Broker does not have general logging enabled.", + metadata.obj_by_path(broker, ["logging", "general"]), + ) } + +logging_disabled(broker) if value.is_false(broker.logging.general) + +logging_disabled(broker) if not broker.logging.general diff --git a/checks/cloud/aws/neptune/encryption_customer_key.rego b/checks/cloud/aws/neptune/encryption_customer_key.rego index f70495d1..c4cc1d89 100644 --- a/checks/cloud/aws/neptune/encryption_customer_key.rego +++ b/checks/cloud/aws/neptune/encryption_customer_key.rego @@ -33,13 +33,17 @@ package builtin.aws.neptune.aws0128 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.neptune.clusters - not has_kms_key(cluster) + without_cmk(cluster) res := result.new( "Cluster does not encrypt data with a customer managed key.", object.get(cluster, "kmskeyid", cluster), ) } -has_kms_key(cluster) if cluster.kmskeyid.value != "" +without_cmk(cluster) if value.is_empty(cluster.kmskeyid) + +without_cmk(cluster) if not cluster.kmskeyid diff --git a/checks/cloud/aws/rds/encrypt_cluster_storage_data.rego b/checks/cloud/aws/rds/encrypt_cluster_storage_data.rego index dd4e51a7..f94848df 100644 --- a/checks/cloud/aws/rds/encrypt_cluster_storage_data.rego +++ b/checks/cloud/aws/rds/encrypt_cluster_storage_data.rego @@ -35,11 +35,12 @@ package builtin.aws.rds.aws0079 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some cluster in input.aws.rds.clusters isManaged(cluster) - not encryption_enabled(cluster) + encryption_disabled(cluster) res := result.new( "Cluster does not have storage encryption enabled.", metadata.obj_by_path(cluster, ["encryption", "encryptstorage"]), @@ -49,14 +50,18 @@ deny contains res if { deny contains res if { some cluster in input.aws.rds.clusters isManaged(cluster) - encryption_enabled(cluster) - not has_kms_key(cluster) + cluster.encryption.encryptstorage.value + without_cmk(cluster) res := result.new( "Cluster does not specify a customer managed key for storage encryption.", metadata.obj_by_path(cluster, ["encryption", "kmskeyid"]), ) } -encryption_enabled(cluster) := cluster.encryption.encryptstorage.value +encryption_disabled(cluster) if value.is_false(cluster.encryption.encryptstorage) -has_kms_key(cluster) := cluster.encryption.kmskeyid.value != "" +encryption_disabled(cluster) if not cluster.encryption.encryptstorage + +without_cmk(cluster) if value.is_empty(cluster.encryption.kmskeyid) + +without_cmk(cluster) if not cluster.encryption.kmskeyid diff --git a/checks/cloud/aws/rds/encrypt_instance_storage_data.rego b/checks/cloud/aws/rds/encrypt_instance_storage_data.rego index 196202e1..6ca4d2d4 100644 --- a/checks/cloud/aws/rds/encrypt_instance_storage_data.rego +++ b/checks/cloud/aws/rds/encrypt_instance_storage_data.rego @@ -35,15 +35,22 @@ package builtin.aws.rds.aws0080 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some instance in input.aws.rds.instances - not has_replication_source_arn(instance) - not instance.encryption.encryptstorage.value + without_replication_source_arn(instance) + encryption_disabled(instance) res := result.new( "Instance does not have storage encryption enabled.", metadata.obj_by_path(instance, ["encryption", "encryptstorage"]), ) } -has_replication_source_arn(instance) := instance.replciationsourcearn.value != "" +without_replication_source_arn(instance) if value.is_empty(instance.replciationsourcearn) + +without_replication_source_arn(instance) if not instance.replciationsourcearn + +encryption_disabled(instance) if value.is_false(instance.encryption.encryptstorage) + +encryption_disabled(instance) if not instance.encryption.encryptstorage diff --git a/checks/cloud/aws/rds/performance_insights_encryption_customer_key.rego b/checks/cloud/aws/rds/performance_insights_encryption_customer_key.rego index 42068773..13d60513 100644 --- a/checks/cloud/aws/rds/performance_insights_encryption_customer_key.rego +++ b/checks/cloud/aws/rds/performance_insights_encryption_customer_key.rego @@ -36,6 +36,8 @@ package builtin.aws.rds.aws0078 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.rds.clusters some instance in cluster.instances @@ -58,7 +60,9 @@ deny contains res if { kms_key_not_used(instance) if { isManaged(instance) instance.performanceinsights.enabled.value - not has_perfomance_insights_kms_key_id(instance) + perfomance_insights_kms_key_id_missed(instance) } -has_perfomance_insights_kms_key_id(instance) := instance.performanceinsights.kmskeyid.value != "" +perfomance_insights_kms_key_id_missed(instance) if value.is_empty(instance.performanceinsights.kmskeyid) + +perfomance_insights_kms_key_id_missed(instance) if not instance.performanceinsights.kmskeyid diff --git a/checks/cloud/aws/rds/specify_backup_retention.rego b/checks/cloud/aws/rds/specify_backup_retention.rego index dd6c0052..38e02d6d 100644 --- a/checks/cloud/aws/rds/specify_backup_retention.rego +++ b/checks/cloud/aws/rds/specify_backup_retention.rego @@ -34,6 +34,8 @@ package builtin.aws.rds.aws0077 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.rds.clusters has_low_backup_retention_period(cluster) @@ -54,8 +56,10 @@ deny contains res if { has_low_backup_retention_period(instance) if { isManaged(instance) - not has_replication_source(instance) - instance.backupretentionperioddays.value < 2 + without_replication_source(instance) + value.less_than(instance.backupretentionperioddays, 2) } -has_replication_source(instance) := instance.replicationsourcearn.value != "" +without_replication_source(instance) if value.is_empty(instance.replicationsourcearn) + +without_replication_source(instance) if not instance.replicationsourcearn diff --git a/checks/cloud/aws/redshift/add_description_to_security_group.rego b/checks/cloud/aws/redshift/add_description_to_security_group.rego index 329e677c..77431e20 100644 --- a/checks/cloud/aws/redshift/add_description_to_security_group.rego +++ b/checks/cloud/aws/redshift/add_description_to_security_group.rego @@ -29,13 +29,17 @@ package builtin.aws.redshift.aws0083 import rego.v1 +import data.lib.cloud.value + deny contains res if { some group in input.aws.redshift.securitygroups - not has_description(group) + without_description(group) res := result.new( "Security group has no description.", object.get(group, "description", group), ) } -has_description(group) if group.description.value != "" +without_description(group) if value.is_empty(group.description) + +without_description(group) if not group.description diff --git a/checks/cloud/aws/redshift/encryption_customer_key.rego b/checks/cloud/aws/redshift/encryption_customer_key.rego index a9c705f9..626e24de 100644 --- a/checks/cloud/aws/redshift/encryption_customer_key.rego +++ b/checks/cloud/aws/redshift/encryption_customer_key.rego @@ -33,9 +33,11 @@ package builtin.aws.redshift.aws0084 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.redshift.clusters - not is_encrypted(cluster) + is_not_encrypted(cluster) res := result.new( "Cluster does not have encryption enabled.", cluster.encryption, @@ -44,14 +46,18 @@ deny contains res if { deny contains res if { some cluster in input.aws.redshift.clusters - is_encrypted(cluster) - not has_kms_key(cluster) + cluster.encryption.enabled.value + without_cmk(cluster) res := result.new( "Cluster does not use a customer managed encryption key.", cluster.encryption, ) } -is_encrypted(cluster) if cluster.encryption.enabled.value +is_not_encrypted(cluster) if value.is_false(cluster.encryption.enabled) + +is_not_encrypted(cluster) if not cluster.encryption.enabled + +without_cmk(cluster) if value.is_empty(cluster.encryption.kmskeyid) -has_kms_key(cluster) if cluster.encryption.kmskeyid.value != "" +without_cmk(cluster) if not cluster.encryption.kmskeyid diff --git a/checks/cloud/aws/redshift/use_vpc.rego b/checks/cloud/aws/redshift/use_vpc.rego index ac83e72c..1a712aca 100644 --- a/checks/cloud/aws/redshift/use_vpc.rego +++ b/checks/cloud/aws/redshift/use_vpc.rego @@ -34,13 +34,17 @@ package builtin.aws.redshift.aws0127 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.aws.redshift.clusters - not has_subnet_group_name(cluster) + subnet_group_name_missed(cluster) res := result.new( "Cluster is deployed outside of a VPC.", object.get(cluster, "subnetgroupname", cluster), ) } -has_subnet_group_name(cluster) if cluster.subnetgroupname.value != "" +subnet_group_name_missed(cluster) if value.is_empty(cluster.subnetgroupname) + +subnet_group_name_missed(cluster) if not cluster.subnetgroupname diff --git a/checks/cloud/aws/s3/encryption_customer_key.rego b/checks/cloud/aws/s3/encryption_customer_key.rego index 92f679df..6529cb84 100644 --- a/checks/cloud/aws/s3/encryption_customer_key.rego +++ b/checks/cloud/aws/s3/encryption_customer_key.rego @@ -33,14 +33,16 @@ package builtin.aws.s3.aws0132 import rego.v1 +import data.lib.cloud.value + deny contains res if { some bucket in input.aws.s3.buckets # Log buckets don't support non AES256 encryption - this rule doesn't apply here # https://aws.amazon.com/premiumsupport/knowledge-center/s3-server-access-log-not-delivered/ - not is_log_bucket(bucket) + non_log_bucket(bucket) - not has_encryption(bucket) + without_cmk(bucket) res := result.new( "Bucket does not encrypt data with a customer managed key.", @@ -48,6 +50,13 @@ deny contains res if { ) } -is_log_bucket(bucket) := lower(bucket.acl.value) == "log-delivery-write" +non_log_bucket(bucket) if { + not value.is_unresolvable(bucket.acl) + lower(bucket.acl.value) != "log-delivery-write" +} + +non_log_bucket(bucket) if not bucket.acl + +without_cmk(bucket) if value.is_empty(bucket.encryption.kmskeyid) -has_encryption(bucket) := bucket.encryption.kmskeyid.value != "" +without_cmk(bucket) if not bucket.encryption.kmskeyid diff --git a/checks/cloud/aws/sam/enable_api_access_logging.rego b/checks/cloud/aws/sam/enable_api_access_logging.rego index 247c9e6c..8f052c1f 100644 --- a/checks/cloud/aws/sam/enable_api_access_logging.rego +++ b/checks/cloud/aws/sam/enable_api_access_logging.rego @@ -28,12 +28,19 @@ package builtin.aws.sam.aws0113 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some api in input.aws.sam.apis isManaged(api) - api.accesslogging.cloudwatchloggrouparn.value == "" + without_logging(api) res := result.new( "Access logging is not configured.", - api.accesslogging, + metadata.obj_by_path(api, ["accesslogging", "cloudwatchloggrouparn"]), ) } + +without_logging(api) if value.is_empty(api.accesslogging.cloudwatchloggrouparn) + +without_logging(api) if not api.accesslogging.cloudwatchloggrouparn diff --git a/checks/cloud/aws/sam/enable_http_api_access_logging.rego b/checks/cloud/aws/sam/enable_http_api_access_logging.rego index fbdddcec..b6a24470 100644 --- a/checks/cloud/aws/sam/enable_http_api_access_logging.rego +++ b/checks/cloud/aws/sam/enable_http_api_access_logging.rego @@ -28,12 +28,19 @@ package builtin.aws.sam.aws0116 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some api in input.aws.sam.httpapis isManaged(api) - api.accesslogging.cloudwatchloggrouparn.value == "" + without_logging(api) res := result.new( "Access logging is not configured.", - api.accesslogging, + metadata.obj_by_path(api, ["accesslogging", "cloudwatchloggrouparn"]), ) } + +without_logging(api) if value.is_empty(api.accesslogging.cloudwatchloggrouparn) + +without_logging(api) if not api.accesslogging.cloudwatchloggrouparn diff --git a/checks/cloud/aws/sns/enable_topic_encryption.rego b/checks/cloud/aws/sns/enable_topic_encryption.rego index d41a659e..c31860fd 100644 --- a/checks/cloud/aws/sns/enable_topic_encryption.rego +++ b/checks/cloud/aws/sns/enable_topic_encryption.rego @@ -33,11 +33,18 @@ package builtin.aws.sns.aws0095 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some topic in input.aws.sns.topics - topic.encryption.kmskeyid.value == "" + not_encrypted(topic) res := result.new( "Topic does not have encryption enabled.", - topic.encryption.kmskeyid, + metadata.obj_by_path(topic, ["encryption", "kmskeyid"]), ) } + +not_encrypted(topic) if value.is_empty(topic.encryption.kmskeyid) + +not_encrypted(topic) if not topic.encryption.kmskeyid diff --git a/checks/cloud/aws/sns/enable_topic_encryption_test.rego b/checks/cloud/aws/sns/enable_topic_encryption_test.rego index 31dea02d..0ee6db84 100644 --- a/checks/cloud/aws/sns/enable_topic_encryption_test.rego +++ b/checks/cloud/aws/sns/enable_topic_encryption_test.rego @@ -16,3 +16,9 @@ test_allow_topic_with_encryption if { test.assert_empty(check.deny) with input as inp } + +test_allow_topic_without_encryption_but_unresolvable if { + inp := {"aws": {"sns": {"topics": [{"encryption": {"kmskeyid": {"value": "", "unresolvable": true}}}]}}} + + test.assert_empty(check.deny) with input as inp +} diff --git a/checks/cloud/aws/sqs/enable_queue_encryption.rego b/checks/cloud/aws/sqs/enable_queue_encryption.rego index d5e4395a..68eabade 100644 --- a/checks/cloud/aws/sqs/enable_queue_encryption.rego +++ b/checks/cloud/aws/sqs/enable_queue_encryption.rego @@ -33,10 +33,20 @@ package builtin.aws.sqs.aws0096 import rego.v1 +import data.lib.cloud.value + deny contains res if { some queue in input.aws.sqs.queues isManaged(queue) - queue.encryption.kmskeyid.value == "" - queue.encryption.managedencryption.value == false + without_cmk(queue) + not_encrypted(queue) res := result.new("Queue is not encrypted", queue.encryption) } + +without_cmk(queue) if value.is_empty(queue.encryption.kmskeyid) + +without_cmk(queue) if not queue.encryption.kmskeyid + +not_encrypted(queue) if value.is_false(queue.encryption.managedencryption) + +not_encrypted(queue) if not queue.encryption.managedencryption diff --git a/checks/cloud/aws/ssm/secret_use_customer_key.rego b/checks/cloud/aws/ssm/secret_use_customer_key.rego index 152c330b..e99cc390 100644 --- a/checks/cloud/aws/ssm/secret_use_customer_key.rego +++ b/checks/cloud/aws/ssm/secret_use_customer_key.rego @@ -33,9 +33,11 @@ package builtin.aws.ssm.aws0098 import rego.v1 +import data.lib.cloud.value + deny contains res if { some secret in input.aws.ssm.secrets - secret.kmskeyid.value == "" + without_cmk(secret) res := result.new("Secret is not encrypted with a customer managed key.", secret.kmskeyid) } @@ -44,3 +46,7 @@ deny contains res if { secret.kmskeyid.value == "alias/aws/secretsmanager" res := result.new("Secret explicitly uses the default key.", secret.kmskeyid) } + +without_cmk(secret) if value.is_empty(secret.kmskeyid) + +without_cmk(secret) if not secret.kmskeyid diff --git a/checks/cloud/azure/appservice/account_identity_registered.rego b/checks/cloud/azure/appservice/account_identity_registered.rego index b01c6ada..27232d4e 100644 --- a/checks/cloud/azure/appservice/account_identity_registered.rego +++ b/checks/cloud/azure/appservice/account_identity_registered.rego @@ -29,15 +29,18 @@ package builtin.azure.appservice.azure0002 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some service in input.azure.appservice.services isManaged(service) - not has_identity_type(service) + identity_type_missed(service) res := result.new( "App service does not have an identity type.", metadata.obj_by_path(service, ["identity", "type"]), ) } -has_identity_type(service) := service.identity.type.value != "" +identity_type_missed(service) if value.is_empty(service.identity.type) + +identity_type_missed(service) if not service.identity.type diff --git a/checks/cloud/azure/container/configured_network_policy.rego b/checks/cloud/azure/container/configured_network_policy.rego index da371e3e..8026be4e 100644 --- a/checks/cloud/azure/container/configured_network_policy.rego +++ b/checks/cloud/azure/container/configured_network_policy.rego @@ -31,14 +31,17 @@ package builtin.azure.container.azure0043 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some cluster in input.azure.container.kubernetesclusters - not has_network_policy(cluster) + network_policy_missed(cluster) res := result.new( "Kubernetes cluster does not have a network policy set.", metadata.obj_by_path(cluster, ["networkprofile", "networkpolicy"]), ) } -has_network_policy(cluster) := cluster.networkprofile.networkpolicy.value != "" +network_policy_missed(cluster) if value.is_empty(cluster.networkprofile.networkpolicy) + +network_policy_missed(cluster) if not cluster.networkprofile.networkpolicy diff --git a/checks/cloud/azure/database/no_public_access.rego b/checks/cloud/azure/database/no_public_access.rego index 227b392b..e73ed07b 100644 --- a/checks/cloud/azure/database/no_public_access.rego +++ b/checks/cloud/azure/database/no_public_access.rego @@ -35,11 +35,9 @@ import data.lib.cloud.metadata deny contains res if { some server in database.all_servers - is_public_access_enabled(server) + server.enablepublicnetworkaccess.value res := result.new( - "Database server does not have public access enabled.", - metadata.obj_by_path(server, "enablepublicnetworkaccess"), + "Database server has public network access enabled.", + server.enablepublicnetworkaccess, ) } - -is_public_access_enabled(server) := server.enablepublicnetworkaccess.value == true diff --git a/checks/cloud/azure/database/retention_period_set.rego b/checks/cloud/azure/database/retention_period_set.rego index e7d88620..929c8f66 100644 --- a/checks/cloud/azure/database/retention_period_set.rego +++ b/checks/cloud/azure/database/retention_period_set.rego @@ -33,11 +33,13 @@ package builtin.azure.database.azure0025 import rego.v1 +import data.lib.cloud.value + deny contains res if { some server in input.azure.database.mssqlservers some policy in server.extendedauditingpolicies - policy.retentionindays.value < 90 - policy.retentionindays.value != 0 + value.less_than(policy.retentionindays, 90) + value.is_not_equal(policy.retentionindays, 0) res := result.new( "Server has a retention period of less than 90 days.", diff --git a/checks/cloud/azure/keyvault/content_type_for_secret.rego b/checks/cloud/azure/keyvault/content_type_for_secret.rego index 48048d23..1be5757f 100644 --- a/checks/cloud/azure/keyvault/content_type_for_secret.rego +++ b/checks/cloud/azure/keyvault/content_type_for_secret.rego @@ -32,14 +32,18 @@ package builtin.azure.keyvault.azure0015 import rego.v1 +import data.lib.cloud.value + deny contains res if { some vault in input.azure.keyvault.vaults some secret in vault.secrets - not secret_has_content_type(secret) + secret_without_content_type(secret) res := result.new( "Secret does not have a content-type specified.", object.get(secret, "contenttype", secret), ) } -secret_has_content_type(secret) := secret.contenttype.value != "" +secret_without_content_type(secret) if value.is_empty(secret.contenttype) + +secret_without_content_type(secret) if not secret.contenttype diff --git a/checks/cloud/azure/network/retention_policy_set.rego b/checks/cloud/azure/network/retention_policy_set.rego index 3c81d871..67b800ee 100644 --- a/checks/cloud/azure/network/retention_policy_set.rego +++ b/checks/cloud/azure/network/retention_policy_set.rego @@ -36,6 +36,8 @@ import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value + flowlogs := input.azure.network.networkwatcherflowlogs deny contains res if { @@ -54,7 +56,7 @@ deny contains res if { isManaged(flowlog) flowlog.retentionpolicy.enabled.value - flowlog.retentionpolicy.days.value < 90 + value.less_than(flowlog.retentionpolicy.days, 90) res := result.new( "Flow log has a log retention policy of less than 90 days.", metadata.obj_by_path(flowlog, ["retentionpolicy", "days"]), diff --git a/checks/cloud/azure/securitycenter/set_required_contact_details.rego b/checks/cloud/azure/securitycenter/set_required_contact_details.rego index e54e593c..d879df7b 100644 --- a/checks/cloud/azure/securitycenter/set_required_contact_details.rego +++ b/checks/cloud/azure/securitycenter/set_required_contact_details.rego @@ -32,15 +32,18 @@ package builtin.azure.securitycenter.azure0046 import rego.v1 +import data.lib.cloud.value + deny contains res if { some contact in input.azure.securitycenter.contacts isManaged(contact) - - not contact_has_phone(contact) + contact_without_phone(contact) res := result.new( "Security contact does not have a phone number listed.", object.get(contact, "phone", contact), ) } -contact_has_phone(contact) := contact.phone.value != "" +contact_without_phone(contact) if value.is_empty(contact.phone) + +contact_without_phone(contact) if not contact.phone diff --git a/checks/cloud/github/actions/no_plain_text_action_secrets.rego b/checks/cloud/github/actions/no_plain_text_action_secrets.rego index 889e383c..bf8981d5 100644 --- a/checks/cloud/github/actions/no_plain_text_action_secrets.rego +++ b/checks/cloud/github/actions/no_plain_text_action_secrets.rego @@ -32,8 +32,10 @@ package builtin.github.actions.github0002 import rego.v1 +import data.lib.cloud.value + deny contains res if { some secret in input.github.environmentsecrets - secret.plaintextvalue.value != "" + value.is_not_empty(secret.plaintextvalue) res := result.new("Secret has plain text value", secret.plaintextvalue) } diff --git a/checks/cloud/google/compute/disk_encryption_customer_key.rego b/checks/cloud/google/compute/disk_encryption_customer_key.rego index e512fa67..105cee30 100644 --- a/checks/cloud/google/compute/disk_encryption_customer_key.rego +++ b/checks/cloud/google/compute/disk_encryption_customer_key.rego @@ -29,14 +29,17 @@ package builtin.google.compute.google0034 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some disk in input.google.compute.disks - not is_disk_encrypted(disk) + disk_not_encrypted(disk) res := result.new( "Disk is not encrypted with a customer managed key.", metadata.obj_by_path(disk, ["encryption", "kmskeylink"]), ) } -is_disk_encrypted(disk) := disk.encryption.kmskeylink.value != "" +disk_not_encrypted(disk) if value.is_empty(disk.encryption.kmskeylink) + +disk_not_encrypted(disk) if not disk.encryption.kmskeylink diff --git a/checks/cloud/google/compute/no_default_service_account.rego b/checks/cloud/google/compute/no_default_service_account.rego index 5508e7e7..d78c2f79 100644 --- a/checks/cloud/google/compute/no_default_service_account.rego +++ b/checks/cloud/google/compute/no_default_service_account.rego @@ -30,12 +30,9 @@ import rego.v1 deny contains res if { some instance in input.google.compute.instances - service_account := instance.serviceaccount - is_default_service_account(service_account) + instance.serviceaccount.isdefault.value res := result.new( "Instance uses the default service account.", - object.get(service_account, "email", service_account), + instance.serviceaccount.isdefault, ) } - -is_default_service_account(service_account) := service_account.isdefault.value == true diff --git a/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego b/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego index 53678b83..a04bda5c 100644 --- a/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego +++ b/checks/cloud/google/compute/vm_disk_encryption_customer_key.rego @@ -29,6 +29,7 @@ package builtin.google.compute.google0033 import rego.v1 import data.lib.cloud.metadata +import data.lib.cloud.value deny contains res if { some instance in input.google.compute.instances @@ -39,11 +40,13 @@ deny contains res if { some disk in disks - not disk_is_encrypted(disk) + disk_is_not_encrypted(disk) res := result.new( "Instance disk encryption does not use a customer managed key.", metadata.obj_by_path(disk, ["encryption", "kmskeylink"]), ) } -disk_is_encrypted(disk) := disk.encryption.kmskeylink.value != "" +disk_is_not_encrypted(disk) if value.is_empty(disk.encryption.kmskeylink) + +disk_is_not_encrypted(disk) if not disk.encryption.kmskeylink diff --git a/checks/cloud/google/gke/no_legacy_authentication.rego b/checks/cloud/google/gke/no_legacy_authentication.rego index 60dae1f8..ca24d3dd 100644 --- a/checks/cloud/google/gke/no_legacy_authentication.rego +++ b/checks/cloud/google/gke/no_legacy_authentication.rego @@ -32,9 +32,11 @@ package builtin.google.gke.google0064 import rego.v1 +import data.lib.cloud.value + deny contains res if { some cluster in input.google.gke.clusters - cluster.masterauth.clientcertificate.issuecertificate.value == true + cluster.masterauth.clientcertificate.issuecertificate.value res := result.new( "Cluster allows the use of certificates for master authentication.", cluster.masterauth.clientcertificate.issuecertificate, @@ -44,7 +46,7 @@ deny contains res if { deny contains res if { some cluster in input.google.gke.clusters not cluster.masterauth.clientcertificate.issuecertificate.value - cluster.masterauth.username.value != "" + value.is_not_empty(cluster.masterauth.username) res := result.new( "Cluster allows the use of basic auth for master authentication.", cluster.masterauth.username, diff --git a/checks/cloud/google/gke/use_service_account.rego b/checks/cloud/google/gke/use_service_account.rego index 358860fe..835af21b 100644 --- a/checks/cloud/google/gke/use_service_account.rego +++ b/checks/cloud/google/gke/use_service_account.rego @@ -30,22 +30,29 @@ package builtin.google.gke.google0050 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some cluster in input.google.gke.clusters - cluster.removedefaultnodepool.value == false - cluster.nodeconfig.serviceaccount.value == "" + value.is_false(cluster.removedefaultnodepool) + default_account_is_not_overrided(cluster.nodeconfig) res := result.new( "Cluster does not override the default service account.", - cluster.nodeconfig.serviceaccount, + metadata.obj_by_path(cluster, ["nodeconfig", "serviceaccount"]), ) } deny contains res if { some cluster in input.google.gke.clusters some pool in cluster.nodepools - pool.nodeconfig.serviceaccount.value == "" + default_account_is_not_overrided(pool.nodeconfig) res := result.new( "Node pool does not override the default service account.", - pool.nodeconfig.serviceaccount, + metadata.obj_by_path(pool, ["nodeconfig", "serviceaccount"]), ) } + +default_account_is_not_overrided(nodeconfig) if value.is_empty(nodeconfig.serviceaccount) + +default_account_is_not_overrided(nodeconfig) if not nodeconfig.serviceaccount diff --git a/checks/cloud/google/iam/no_conditions_on_workload_identity_pool_provider.rego b/checks/cloud/google/iam/no_conditions_on_workload_identity_pool_provider.rego index 35594d64..e8f47def 100644 --- a/checks/cloud/google/iam/no_conditions_on_workload_identity_pool_provider.rego +++ b/checks/cloud/google/iam/no_conditions_on_workload_identity_pool_provider.rego @@ -30,13 +30,17 @@ package builtin.google.iam.google0068 import rego.v1 +import data.lib.cloud.value + deny contains res if { some provider in input.google.iam.workloadidentitypoolproviders - not has_conditions(provider) + without_conditions(provider) res := result.new( "This workload identity pool provider configuration has no conditions set.", object.get(provider, "attributecondition", provider), ) } -has_conditions(provider) := provider.attributecondition.value != "" +without_conditions(provider) if value.is_empty(provider.attributecondition) + +without_conditions(provider) if not provider.attributecondition diff --git a/checks/cloud/google/sql/enable_pg_temp_file_logging.rego b/checks/cloud/google/sql/enable_pg_temp_file_logging.rego index a923c548..1c0d9da1 100644 --- a/checks/cloud/google/sql/enable_pg_temp_file_logging.rego +++ b/checks/cloud/google/sql/enable_pg_temp_file_logging.rego @@ -30,6 +30,7 @@ package builtin.google.sql.google0014 import rego.v1 +import data.lib.cloud.value import data.lib.google.database deny contains res if { @@ -41,11 +42,11 @@ deny contains res if { } check_log_temp_file_size(logtempfilesize) := msg if { - logtempfilesize.value < 0 + value.less_than(logtempfilesize, 0) msg := "Database instance has temporary file logging disabled." } check_log_temp_file_size(logtempfilesize) := msg if { - logtempfilesize.value > 0 + value.greater_than(logtempfilesize, 0) msg := "Database instance has temporary file logging disabled for files of certain sizes." } diff --git a/checks/cloud/google/sql/encrypt_in_transit_data.rego b/checks/cloud/google/sql/encrypt_in_transit_data.rego index 9a00211c..9846cae3 100644 --- a/checks/cloud/google/sql/encrypt_in_transit_data.rego +++ b/checks/cloud/google/sql/encrypt_in_transit_data.rego @@ -30,6 +30,8 @@ package builtin.google.sql.google0015 import rego.v1 +import data.lib.cloud.value + ssl_mode_trusted_client_certificate_required := "TRUSTED_CLIENT_CERTIFICATE_REQUIRED" deny contains res if { @@ -55,4 +57,4 @@ is_ssl_enforced(ipconf) if { ipconf.requiretls.value == true } -has_ssl_mode(ipconf) if ipconf.sslmode.value != "" +has_ssl_mode(ipconf) if not value.is_empty(ipconf.sslmode) diff --git a/checks/cloud/google/storage/bucket_encryption_customer_key.rego b/checks/cloud/google/storage/bucket_encryption_customer_key.rego index db94d3e7..ba58cd32 100644 --- a/checks/cloud/google/storage/bucket_encryption_customer_key.rego +++ b/checks/cloud/google/storage/bucket_encryption_customer_key.rego @@ -30,9 +30,19 @@ package builtin.google.storage.google0066 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some bucket in input.google.storage.buckets isManaged(bucket) - bucket.encryption.defaultkmskeyname.value == "" - res := result.new("Storage bucket encryption does not use a customer-managed key.", bucket.encryption.defaultkmskeyname) + without_cmk(bucket) + res := result.new( + "Storage bucket encryption does not use a customer-managed key.", + metadata.obj_by_path(bucket, ["encryption", "defaultkmskeyname"]), + ) } + +without_cmk(bucket) if value.is_empty(bucket.encryption.defaultkmskeyname) + +without_cmk(bucket) if not bucket.encryption.defaultkmskeyname diff --git a/checks/cloud/nifcloud/computing/add_description_to_security_group.rego b/checks/cloud/nifcloud/computing/add_description_to_security_group.rego index bf82d7e7..820b7521 100644 --- a/checks/cloud/nifcloud/computing/add_description_to_security_group.rego +++ b/checks/cloud/nifcloud/computing/add_description_to_security_group.rego @@ -34,9 +34,11 @@ package builtin.nifcloud.computing.nifcloud0002 import rego.v1 +import data.lib.cloud.value + deny contains res if { some sg in input.nifcloud.computing.securitygroups - sg.description.value == "" + without_description(sg) res := result.new("Security group does not have a description.", sg.description) } @@ -45,3 +47,7 @@ deny contains res if { sg.description.value == "Managed by Terraform" res := result.new("Security group explicitly uses the default description.", sg.description) } + +without_description(sg) if value.is_empty(sg.description) + +without_description(sg) if not sg.description diff --git a/checks/cloud/nifcloud/computing/add_description_to_security_group_rule.rego b/checks/cloud/nifcloud/computing/add_description_to_security_group_rule.rego index ddf7c5da..55e09830 100644 --- a/checks/cloud/nifcloud/computing/add_description_to_security_group_rule.rego +++ b/checks/cloud/nifcloud/computing/add_description_to_security_group_rule.rego @@ -34,6 +34,9 @@ package builtin.nifcloud.computing.nifcloud0003 import rego.v1 +import data.lib.cloud.metadata +import data.lib.cloud.value + deny contains res if { some sg in input.nifcloud.computing.securitygroups some rule in array.concat( @@ -41,6 +44,13 @@ deny contains res if { object.get(sg, "egressrules", []), ) - rule.description.value == "" - res := result.new("Security group rule does not have a description.", rule.description) + without_description(rule) + res := result.new( + "Security group rule does not have a description.", + metadata.obj_by_path(rule, ["description"]), + ) } + +without_description(rule) if value.is_empty(rule.description) + +without_description(rule) if not rule.description diff --git a/checks/cloud/nifcloud/computing/add_security_group_to_instance.rego b/checks/cloud/nifcloud/computing/add_security_group_to_instance.rego index 7b2bf36a..8524be4a 100644 --- a/checks/cloud/nifcloud/computing/add_security_group_to_instance.rego +++ b/checks/cloud/nifcloud/computing/add_security_group_to_instance.rego @@ -32,8 +32,14 @@ package builtin.nifcloud.computing.nifcloud0004 import rego.v1 +import data.lib.cloud.value + deny contains res if { some instance in input.nifcloud.computing.instances - instance.securitygroup.value == "" + without_sg(instance) res := result.new("Instance does not have a securiy group.", instance.securitygroup) } + +without_sg(instance) if value.is_empty(instance.securitygroup) + +without_sg(instance) if not instance.securitygroup diff --git a/checks/cloud/nifcloud/nas/add_description_to_nas_security_group.rego b/checks/cloud/nifcloud/nas/add_description_to_nas_security_group.rego index 6b6b66a6..1ec72e25 100644 --- a/checks/cloud/nifcloud/nas/add_description_to_nas_security_group.rego +++ b/checks/cloud/nifcloud/nas/add_description_to_nas_security_group.rego @@ -34,9 +34,11 @@ package builtin.nifcloud.nas.nifcloud0015 import rego.v1 +import data.lib.cloud.value + deny contains res if { some sg in input.nifcloud.nas.nassecuritygroups - sg.description.value == "" + without_description(sg) res := result.new("NAS security group does not have a description.", sg.description) } @@ -45,3 +47,7 @@ deny contains res if { sg.description.value == "Managed by Terraform" res := result.new("NAS security group explicitly uses the default description.", sg.description) } + +without_description(sg) if value.is_empty(sg.description) + +without_description(sg) if not sg.description diff --git a/checks/cloud/nifcloud/network/add_security_group_to_router.rego b/checks/cloud/nifcloud/network/add_security_group_to_router.rego index bc7f3850..f8137c2d 100644 --- a/checks/cloud/nifcloud/network/add_security_group_to_router.rego +++ b/checks/cloud/nifcloud/network/add_security_group_to_router.rego @@ -32,8 +32,14 @@ package builtin.nifcloud.network.nifcloud0016 import rego.v1 +import data.lib.cloud.value + deny contains res if { some router in input.nifcloud.network.routers - router.securitygroup.value == "" + without_sg(router) res := result.new("Router does not have a securiy group.", router.securitygroup) } + +without_sg(router) if value.is_empty(router.securitygroup) + +without_sg(router) if not router.securitygroup diff --git a/checks/cloud/nifcloud/network/add_security_group_to_vpn_gateway.rego b/checks/cloud/nifcloud/network/add_security_group_to_vpn_gateway.rego index cc5e0530..1ea8fe7b 100644 --- a/checks/cloud/nifcloud/network/add_security_group_to_vpn_gateway.rego +++ b/checks/cloud/nifcloud/network/add_security_group_to_vpn_gateway.rego @@ -32,8 +32,14 @@ package builtin.nifcloud.network.nifcloud0018 import rego.v1 +import data.lib.cloud.value + deny contains res if { some gateway in input.nifcloud.network.vpngateways - gateway.securitygroup.value == "" + without_sg(gateway) res := result.new("VpnGateway does not have a securiy group.", gateway.securitygroup) } + +without_sg(gateway) if value.is_empty(gateway.securitygroup) + +without_sg(gateway) if not gateway.securitygroup diff --git a/checks/cloud/nifcloud/rdb/add_description_to_db_security_group.rego b/checks/cloud/nifcloud/rdb/add_description_to_db_security_group.rego index 47b07378..760bacb5 100644 --- a/checks/cloud/nifcloud/rdb/add_description_to_db_security_group.rego +++ b/checks/cloud/nifcloud/rdb/add_description_to_db_security_group.rego @@ -34,9 +34,11 @@ package builtin.nifcloud.rdb.nifcloud0012 import rego.v1 +import data.lib.cloud.value + deny contains res if { some sg in input.nifcloud.rdb.dbsecuritygroups - sg.description.value == "" + without_description(sg) res := result.new("DB security group does not have a description.", sg.description) } @@ -45,3 +47,7 @@ deny contains res if { sg.description.value == "Managed by Terraform" res := result.new("DB security group explicitly uses the default description.", sg.description) } + +without_description(sg) if value.is_empty(sg.description) + +without_description(sg) if not sg.description diff --git a/checks/cloud/nifcloud/rdb/specify_backup_retention.rego b/checks/cloud/nifcloud/rdb/specify_backup_retention.rego index 324f1c4a..f579e4d3 100644 --- a/checks/cloud/nifcloud/rdb/specify_backup_retention.rego +++ b/checks/cloud/nifcloud/rdb/specify_backup_retention.rego @@ -30,8 +30,10 @@ package builtin.nifcloud.rdb.nifcloud0009 import rego.v1 +import data.lib.cloud.value + deny contains res if { some db in input.nifcloud.rdb.dbinstances - db.backupretentionperioddays.value < 2 + value.less_than(db.backupretentionperioddays, 2) res := result.new("Instance has very low backup retention period.", db.backupretentionperioddays) } diff --git a/checks/cloud/openstack/compute/no_public_access.rego b/checks/cloud/openstack/compute/no_public_access.rego index a721df8b..248492aa 100644 --- a/checks/cloud/openstack/compute/no_public_access.rego +++ b/checks/cloud/openstack/compute/no_public_access.rego @@ -28,10 +28,12 @@ package builtin.openstack.compute.openstack0002 import rego.v1 +import data.lib.cloud.value + deny contains res if { some rule in input.openstack.compute.firewall.allowrules is_rule_enabled(rule) - rule.destination.value == "" + value.is_empty(rule.destination) res := result.new("Firewall rule does not restrict destination address internally.", rule) } @@ -45,7 +47,7 @@ deny contains res if { deny contains res if { some rule in input.openstack.compute.firewall.allowrules is_rule_enabled(rule) - rule.source.value == "" + value.is_empty(rule.source) res := result.new("Firewall rule does not restrict source address internally.", rule.source) } diff --git a/checks/cloud/openstack/networking/add_description_to_security_group.rego b/checks/cloud/openstack/networking/add_description_to_security_group.rego index 59b50e1f..dc9fe7b1 100644 --- a/checks/cloud/openstack/networking/add_description_to_security_group.rego +++ b/checks/cloud/openstack/networking/add_description_to_security_group.rego @@ -26,8 +26,14 @@ package builtin.openstack.networking.openstack0005 import rego.v1 +import data.lib.cloud.value + deny contains res if { some sg in input.openstack.networking.securitygroups - sg.description.value == "" - res := result.new("Security group rule allows egress to multiple public addresses.", sg.description) + without_description(sg) + res := result.new("Network security group does not have a description.", sg.description) } + +without_description(sg) if value.is_empty(sg.description) + +without_description(sg) if not sg.description diff --git a/lib/cloud/value.rego b/lib/cloud/value.rego new file mode 100644 index 00000000..0a2838a0 --- /dev/null +++ b/lib/cloud/value.rego @@ -0,0 +1,40 @@ +# METADATA +# custom: +# library: true +package lib.cloud.value + +import rego.v1 + +is_unresolvable(val) if val.unresolvable + +# string + +is_empty(val) := is_equal(val, "") + +is_not_empty(val) := is_not_equal(val, "") + +# int + +less_than(val, other) := false if { + is_unresolvable(val) +} else := val.value < other + +greater_than(val, other) := false if { + is_unresolvable(val) +} else := val.value > other + +# bool + +is_true(val) := is_equal(val, true) + +is_false(val) := is_equal(val, false) + +# common + +is_equal(val, raw) := false if { + is_unresolvable(val) +} else := val.value == raw + +is_not_equal(val, raw) := false if { + is_unresolvable(val) +} else := val.value != raw