Skip to content

Commit

Permalink
fix(checks): handle of unresolvable values
Browse files Browse the repository at this point in the history
Signed-off-by: Nikita Pivkin <[email protected]>
  • Loading branch information
nikpivkin committed Oct 22, 2024
1 parent e9a668e commit 8e5c630
Show file tree
Hide file tree
Showing 80 changed files with 646 additions and 188 deletions.
21 changes: 18 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
DYNAMIC_REGO_FOLDER=./checks/kubernetes/policies/dynamic
BUNDLE_FILE=bundle.tar.gz

.PHONY: test
test:
Expand Down Expand Up @@ -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
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"
11 changes: 7 additions & 4 deletions checks/cloud/aws/apigateway/enable_access_logging.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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"]),
Expand All @@ -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
7 changes: 6 additions & 1 deletion checks/cloud/aws/apigateway/enable_cache.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
7 changes: 6 additions & 1 deletion checks/cloud/aws/apigateway/enable_cache_encryption.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
7 changes: 6 additions & 1 deletion checks/cloud/aws/apigateway/enable_tracing.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 10 additions & 4 deletions checks/cloud/aws/apigateway/no_public_access.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 6 additions & 5 deletions checks/cloud/aws/athena/enable_at_rest_encryption.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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"]),
Expand All @@ -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
7 changes: 5 additions & 2 deletions checks/cloud/aws/cloudfront/enable_logging.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 6 additions & 2 deletions checks/cloud/aws/cloudfront/enable_waf.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 5 additions & 2 deletions checks/cloud/aws/cloudtrail/encryption_customer_key.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 5 additions & 2 deletions checks/cloud/aws/cloudwatch/log_group_customer_key.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 7 additions & 0 deletions checks/cloud/aws/documentdb/enable_log_export.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
}
5 changes: 5 additions & 0 deletions checks/cloud/aws/documentdb/enable_log_export_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
9 changes: 6 additions & 3 deletions checks/cloud/aws/documentdb/encryption_customer_key.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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"]),
Expand All @@ -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
15 changes: 13 additions & 2 deletions checks/cloud/aws/dynamodb/enable_at_rest_encryption.rego
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit 8e5c630

Please sign in to comment.