Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(checks): handle of unresolvable values #279

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
DYNAMIC_REGO_FOLDER=./checks/kubernetes/policies/dynamic
BUNDLE_FILE=bundle.tar.gz
REGISTRY_PORT=5111

.PHONY: test
test:
Expand Down Expand Up @@ -44,9 +46,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 ${REGISTRY_PORT}:5000 --name registry registry:2

stop-registry:
docker stop registry

push-bundle: create-bundle
@REPO=localhost:${REGISTRY_PORT}/trivy-checks:latest ;\
echo "Pushing to repository: $$REPO" ;\
docker run --rm -it --net=host -v $$PWD/${BUNDLE_FILE}:/${BUNDLE_FILE} bitnami/oras:latest push \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need --net=host?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will allow Oras to access the local registry.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my testing, I haven't had the need to allow --net=host.

Run registry:

docker run -it --rm -p 6000:5000 registry

Push image:

oras push localhost:6000/trivy-checks:1 --config /dev/null:application/vnd.cncf.openpolicyagent.config.v1+json  bundle.tar.gz:application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in Makefile oras runs in a container

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's right - I missed that, makes sense.

$$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