Repository: clouditor/clouditor
Pull request #516 (2022-02-15 16:28:50)

Tie-in of metric configuration with Rego evaluation
This PR ties in the metric configuration with the Repo evaluation. It introduces a new interfaces called `MetricConfigurationSource`, which is expected by the `RunEvidence` function. 

This interface can be used to retrieve a metric configuration for a particular metric (and target service). Currently, only the default cloud target service is used, as not every micro-service is aware of the target cloud service (yet). Currently, the assessment service implements this interfaces and fetches the metric configurations from the orchestrator (and caches them). 

In the future, we need a proper way to evict that cache based on an event (such as the configuration of a target cloud service changed).

codecov[bot]: # [Codecov](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) Report
> Merging [#516](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (07b3f74) into [main](https://codecov.io/gh/clouditor/clouditor/commit/58835a75c55ff88c723b9541ed135243f574a571?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (58835a7) will **decrease** coverage by `0.00%`.
> The diff coverage is `80.64%`.

[![Impacted file tree graph](https://codecov.io/gh/clouditor/clouditor/pull/516/graphs/tree.svg?width=650&height=150&src=pr&token=syrXsw5LTX&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)

```diff
@@            Coverage Diff             @@
##             main     #516      +/-   ##
==========================================
- Coverage   80.36%   80.35%   -0.01%     
==========================================
  Files          49       49              
  Lines        4568     4581      +13     
==========================================
+ Hits         3671     3681      +10     
- Misses        720      723       +3     
  Partials      177      177              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `80.35% <80.64%> (-0.01%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) | Coverage Δ | |
|---|---|---|
| [policies/policies.go](https://codecov.io/gh/clouditor/clouditor/pull/516/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-cG9saWNpZXMvcG9saWNpZXMuZ28=) | `68.65% <76.92%> (+1.42%)` | :arrow_up: |
| [service/assessment/assessment.go](https://codecov.io/gh/clouditor/clouditor/pull/516/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9hc3Nlc3NtZW50L2Fzc2Vzc21lbnQuZ28=) | `90.82% <100.00%> (-0.08%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor). Last update [58835a7...07b3f74](https://codecov.io/gh/clouditor/clouditor/pull/516?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor).


Patch:
diff --git a/api/orchestrator/orchestrator.proto b/api/orchestrator/orchestrator.proto
index ebc8a5bd..014abd73 100644
--- a/api/orchestrator/orchestrator.proto
+++ b/api/orchestrator/orchestrator.proto
@@ -193,7 +193,7 @@ service Orchestrator {
     };
   }
 
-  // Lists all a metric configurations (target value and operator) for a specific service and metric ID
+  // Lists all a metric configurations (target value and operator) for a specific service ID
   rpc ListMetricConfigurations(ListMetricConfigurationRequest)
       returns (ListMetricConfigurationResponse) {
     option (google.api.http) = {
diff --git a/go.mod b/go.mod
index 49b4e6ff..46ebc36f 100644
--- a/go.mod
+++ b/go.mod
@@ -17,6 +17,7 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/s3 v1.24.0
 	github.com/aws/aws-sdk-go-v2/service/sts v1.14.0
 	github.com/aws/smithy-go v1.10.0
+	github.com/fatih/camelcase v1.0.0
 	github.com/go-co-op/gocron v1.12.0
 	github.com/golang-jwt/jwt/v4 v4.3.0
 	github.com/google/uuid v1.3.0
@@ -24,6 +25,7 @@ require (
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0
 	github.com/jinzhu/copier v0.3.4
 	github.com/logrusorgru/aurora/v3 v3.0.0
+	github.com/mitchellh/mapstructure v1.4.3
 	github.com/open-policy-agent/opa v0.37.1
 	github.com/sirupsen/logrus v1.8.1
 	github.com/spf13/cobra v1.3.0
@@ -102,7 +104,6 @@ require (
 	github.com/magiconair/properties v1.8.5 // indirect
 	github.com/mattn/go-sqlite3 v1.14.9 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
-	github.com/mitchellh/mapstructure v1.4.3 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/pelletier/go-toml v1.9.4 // indirect
diff --git a/go.sum b/go.sum
index c882d9fa..036f5a16 100644
--- a/go.sum
+++ b/go.sum
@@ -213,6 +213,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
 github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
 github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
+github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
diff --git a/policies/bundles/AnomalyDetectionEnabled/metric.rego b/policies/bundles/AnomalyDetectionEnabled/metric.rego
index 524d1636..22b82b91 100644
--- a/policies/bundles/AnomalyDetectionEnabled/metric.rego
+++ b/policies/bundles/AnomalyDetectionEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.anomaly_detection_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/AnomalyDetectionOutput/metric.rego b/policies/bundles/AnomalyDetectionOutput/metric.rego
index 0db53f01..74b37ba4 100644
--- a/policies/bundles/AnomalyDetectionOutput/metric.rego
+++ b/policies/bundles/AnomalyDetectionOutput/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.anomaly_detection_output
+
+import data.clouditor.isIn
 
 default applicable = false
 
diff --git a/policies/bundles/AnonymousAuthentication/metric.rego b/policies/bundles/AnonymousAuthentication/metric.rego
index 0e4e79bf..de45a8e2 100644
--- a/policies/bundles/AnonymousAuthentication/metric.rego
+++ b/policies/bundles/AnonymousAuthentication/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.anonymous_authentication
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/AtRestEncryptionAlgorithm/metric.rego b/policies/bundles/AtRestEncryptionAlgorithm/metric.rego
index fb350ea2..0997b509 100644
--- a/policies/bundles/AtRestEncryptionAlgorithm/metric.rego
+++ b/policies/bundles/AtRestEncryptionAlgorithm/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.at_rest_encryption_algorithm
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/AtRestEncryptionEnabled/metric.rego b/policies/bundles/AtRestEncryptionEnabled/metric.rego
index c2350963..cb6df799 100644
--- a/policies/bundles/AtRestEncryptionEnabled/metric.rego
+++ b/policies/bundles/AtRestEncryptionEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.at_rest_encryption_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/AutomaticUpdatesEnabled/metric.rego b/policies/bundles/AutomaticUpdatesEnabled/metric.rego
index ad202323..5834f1a5 100644
--- a/policies/bundles/AutomaticUpdatesEnabled/metric.rego
+++ b/policies/bundles/AutomaticUpdatesEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.automatic_updates_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/AutomaticUpdatesInterval/metric.rego b/policies/bundles/AutomaticUpdatesInterval/metric.rego
index b6383738..486c1fff 100644
--- a/policies/bundles/AutomaticUpdatesInterval/metric.rego
+++ b/policies/bundles/AutomaticUpdatesInterval/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.automatic_updates_interval
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/AutomaticUpdatesSecurityOnly/metric.rego b/policies/bundles/AutomaticUpdatesSecurityOnly/metric.rego
index 9543b43e..ffcd086d 100644
--- a/policies/bundles/AutomaticUpdatesSecurityOnly/metric.rego
+++ b/policies/bundles/AutomaticUpdatesSecurityOnly/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.automatic_updates_security_only
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/BootLoggingEnabled/metric.rego b/policies/bundles/BootLoggingEnabled/metric.rego
index ad4809e1..cd253370 100644
--- a/policies/bundles/BootLoggingEnabled/metric.rego
+++ b/policies/bundles/BootLoggingEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.boot_logging_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/BootLoggingOutput/metric.rego b/policies/bundles/BootLoggingOutput/metric.rego
index fda0f977..05007b31 100644
--- a/policies/bundles/BootLoggingOutput/metric.rego
+++ b/policies/bundles/BootLoggingOutput/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.boot_logging_output
+
+import data.clouditor.isIn
 
 default applicable = false
 
diff --git a/policies/bundles/BootLoggingRetention/metric.rego b/policies/bundles/BootLoggingRetention/metric.rego
index 50c89f1c..2e38feb6 100644
--- a/policies/bundles/BootLoggingRetention/metric.rego
+++ b/policies/bundles/BootLoggingRetention/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.boot_logging_retention
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/BroadAssignments/metric.rego b/policies/bundles/BroadAssignments/metric.rego
index 9c3a1ff7..f91d2eb0 100644
--- a/policies/bundles/BroadAssignments/metric.rego
+++ b/policies/bundles/BroadAssignments/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.broad_assignments
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/CustomerKeyEncryption/metric.rego b/policies/bundles/CustomerKeyEncryption/metric.rego
index 195b97b2..314ff1a8 100644
--- a/policies/bundles/CustomerKeyEncryption/metric.rego
+++ b/policies/bundles/CustomerKeyEncryption/metric.rego
@@ -1,4 +1,4 @@
-package clouditor
+package clouditor.metrics.customer_key_encryption
 
 default applicable = false
 
diff --git a/policies/bundles/L3FirewallEnabled/metric.rego b/policies/bundles/L3FirewallEnabled/metric.rego
index df826e56..b0196a30 100644
--- a/policies/bundles/L3FirewallEnabled/metric.rego
+++ b/policies/bundles/L3FirewallEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.l_3_firewall_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/L3FirewallRestrictedPorts/metric.rego b/policies/bundles/L3FirewallRestrictedPorts/metric.rego
index 7f477f1e..399e3495 100644
--- a/policies/bundles/L3FirewallRestrictedPorts/metric.rego
+++ b/policies/bundles/L3FirewallRestrictedPorts/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.l_3_firewall_restricted_ports
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/MalwareProtectionEnabled/metric.rego b/policies/bundles/MalwareProtectionEnabled/metric.rego
index a9c623c7..71e77296 100644
--- a/policies/bundles/MalwareProtectionEnabled/metric.rego
+++ b/policies/bundles/MalwareProtectionEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.malware_protection_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/MalwareProtectionOutput/metric.rego b/policies/bundles/MalwareProtectionOutput/metric.rego
index fe6b5b5b..7393a5e4 100644
--- a/policies/bundles/MalwareProtectionOutput/metric.rego
+++ b/policies/bundles/MalwareProtectionOutput/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.malware_protection_output
+
+import data.clouditor.isIn
 
 default applicable = false
 
diff --git a/policies/bundles/MixedDuties/metric.rego b/policies/bundles/MixedDuties/metric.rego
index 154a6944..3ac1e76f 100644
--- a/policies/bundles/MixedDuties/metric.rego
+++ b/policies/bundles/MixedDuties/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.mixed_duties
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/MutualAuthentication/metric.rego b/policies/bundles/MutualAuthentication/metric.rego
index 266b5deb..08a3a803 100644
--- a/policies/bundles/MutualAuthentication/metric.rego
+++ b/policies/bundles/MutualAuthentication/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.mutual_authentication
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/OSLoggingEnabled/metric.rego b/policies/bundles/OSLoggingEnabled/metric.rego
index 711ffb35..a88cbfe8 100644
--- a/policies/bundles/OSLoggingEnabled/metric.rego
+++ b/policies/bundles/OSLoggingEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.os_logging_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/OSLoggingOutput/metric.rego b/policies/bundles/OSLoggingOutput/metric.rego
index b20bb503..663f73bf 100644
--- a/policies/bundles/OSLoggingOutput/metric.rego
+++ b/policies/bundles/OSLoggingOutput/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.os_logging_output
+
+import data.clouditor.isIn
 
 default applicable = false
 
diff --git a/policies/bundles/OSLoggingRetention/metric.rego b/policies/bundles/OSLoggingRetention/metric.rego
index 606a1e0f..7de5b593 100644
--- a/policies/bundles/OSLoggingRetention/metric.rego
+++ b/policies/bundles/OSLoggingRetention/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.os_logging_retention
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/RuntimeVersion/metric.rego b/policies/bundles/RuntimeVersion/metric.rego
index ad32845c..88b814d1 100644
--- a/policies/bundles/RuntimeVersion/metric.rego
+++ b/policies/bundles/RuntimeVersion/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.runtime_version
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/SingleSignOnEnabled/metric.rego b/policies/bundles/SingleSignOnEnabled/metric.rego
index 1189af03..eeabf983 100644
--- a/policies/bundles/SingleSignOnEnabled/metric.rego
+++ b/policies/bundles/SingleSignOnEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.single_sign_on_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/bundles/TLSVersion/metric.rego b/policies/bundles/TLSVersion/metric.rego
index 6c02699d..09d16609 100644
--- a/policies/bundles/TLSVersion/metric.rego
+++ b/policies/bundles/TLSVersion/metric.rego
@@ -1,4 +1,7 @@
-package clouditor
+package clouditor.metrics.tls_version
+
+import data.clouditor.compare
+import data.clouditor.isIn
 
 default compliant = false
 
diff --git a/policies/bundles/TransportEncryptionAlgorithm/input.json b/policies/bundles/TransportEncryptionAlgorithm/input.json
new file mode 100644
index 00000000..1e69e76c
--- /dev/null
+++ b/policies/bundles/TransportEncryptionAlgorithm/input.json
@@ -0,0 +1,14 @@
+{
+    "name": "/object",
+    "id": "someObject",
+    "type": [
+        "ObjectStorage"
+    ],
+    "httpEndpoint": {
+        "url": "clouditor.io",
+        "transportEncryption": {
+            "enabled": true,
+            "algorithm": "TLS"
+        }
+    }
+}
\ No newline at end of file
diff --git a/policies/bundles/TransportEncryptionAlgorithm/metric.rego b/policies/bundles/TransportEncryptionAlgorithm/metric.rego
index a4c5e3be..93f56703 100644
--- a/policies/bundles/TransportEncryptionAlgorithm/metric.rego
+++ b/policies/bundles/TransportEncryptionAlgorithm/metric.rego
@@ -1,11 +1,12 @@
-package clouditor
+package clouditor.metrics.transport_encryption_algorithm
+
+import data.clouditor.compare
+import input.httpEndpoint as endpoint
 
 default compliant = false
 
 default applicable = false
 
-endpoint := input.httpEndpoint
-
 applicable {
 	endpoint
 }
diff --git a/policies/bundles/TransportEncryptionEnabled/metric.rego b/policies/bundles/TransportEncryptionEnabled/metric.rego
index 1b26633f..91df0818 100644
--- a/policies/bundles/TransportEncryptionEnabled/metric.rego
+++ b/policies/bundles/TransportEncryptionEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.transport_encryption_enabled
+
+import data.clouditor.compare
 
 default compliant = false
 
diff --git a/policies/bundles/TransportEncryptionEnforced/metric.rego b/policies/bundles/TransportEncryptionEnforced/metric.rego
index e63f485b..516e541b 100644
--- a/policies/bundles/TransportEncryptionEnforced/metric.rego
+++ b/policies/bundles/TransportEncryptionEnforced/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.transport_encryption_enforced
+
+import data.clouditor.compare
 
 default compliant = false
 
diff --git a/policies/bundles/WebApplicationFirewallEnabled/metric.rego b/policies/bundles/WebApplicationFirewallEnabled/metric.rego
index bd5cf62c..22f18972 100644
--- a/policies/bundles/WebApplicationFirewallEnabled/metric.rego
+++ b/policies/bundles/WebApplicationFirewallEnabled/metric.rego
@@ -1,4 +1,6 @@
-package clouditor
+package clouditor.metrics.web_application_firewall_enabled
+
+import data.clouditor.compare
 
 default applicable = false
 
diff --git a/policies/policies.go b/policies/policies.go
index 182a8722..0bcf3ac9 100644
--- a/policies/policies.go
+++ b/policies/policies.go
@@ -27,12 +27,14 @@ package policies
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"os"
 	"strings"
 
+	"clouditor.io/clouditor/api/assessment"
 	"clouditor.io/clouditor/api/evidence"
+	"github.com/fatih/camelcase"
+	"github.com/mitchellh/mapstructure"
 	"github.com/open-policy-agent/opa/rego"
 	"github.com/open-policy-agent/opa/storage"
 	"github.com/open-policy-agent/opa/storage/inmem"
@@ -41,8 +43,21 @@ import (
 // applicableMetrics stores a list of applicable metrics per resourceType
 var applicableMetrics = make(map[string][]string)
 
-func RunEvidence(evidence *evidence.Evidence) ([]map[string]interface{}, error) {
-	data := make([]map[string]interface{}, 0)
+type Result struct {
+	Applicable  bool
+	Compliant   bool
+	TargetValue interface{} `mapstructure:"target_value"`
+	Operator    string
+	MetricId    string
+}
+
+// MetricConfigurationSource can be used to retrieve a metric configuration for a particular metric (and target service)
+type MetricConfigurationSource interface {
+	MetricConfiguration(metric string) (*assessment.MetricConfiguration, error)
+}
+
+func RunEvidence(evidence *evidence.Evidence, holder MetricConfigurationSource) ([]*Result, error) {
+	data := make([]*Result, 0)
 	var baseDir string = "."
 
 	var m = evidence.Resource.GetStructValue().AsMap()
@@ -74,7 +89,7 @@ func RunEvidence(evidence *evidence.Evidence) ([]map[string]interface{}, error)
 		}
 
 		for _, fileInfo := range files {
-			runMap, err := RunMap(baseDir, fileInfo.Name(), m)
+			runMap, err := RunMap(baseDir, fileInfo.Name(), m, holder)
 			if err != nil {
 				return nil, err
 			}
@@ -82,19 +97,19 @@ func RunEvidence(evidence *evidence.Evidence) ([]map[string]interface{}, error)
 			if runMap != nil {
 				metricId := fileInfo.Name()
 				applicableMetrics[key] = append(applicableMetrics[key], metricId)
-				runMap["metricId"] = metricId
+				runMap.MetricId = metricId
 
 				data = append(data, runMap)
 			}
 		}
 	} else {
 		for _, metric := range applicableMetrics[key] {
-			runMap, err := RunMap(baseDir, metric, m)
+			runMap, err := RunMap(baseDir, metric, m, holder)
 			if err != nil {
 				return nil, err
 			}
 
-			runMap["metricId"] = metric
+			runMap.MetricId = metric
 			data = append(data, runMap)
 		}
 	}
@@ -102,24 +117,29 @@ func RunEvidence(evidence *evidence.Evidence) ([]map[string]interface{}, error)
 	return data, nil
 }
 
-func RunMap(baseDir string, metric string, m map[string]interface{}) (data map[string]interface{}, err error) {
+func RunMap(baseDir string, metric string, m map[string]interface{}, holder MetricConfigurationSource) (result *Result, err error) {
 	var (
-		ok   bool
-		tx   storage.Transaction
-		file *os.File
+		tx storage.Transaction
 	)
 
 	// Create paths for bundle directory and utility functions file
 	bundle := fmt.Sprintf("%s/policies/bundles/%s/", baseDir, metric)
 	operators := fmt.Sprintf("%s/policies/operators.rego", baseDir)
 
-	// Load from data
-	file, err = os.Open(bundle + "data.json")
+	config, err := holder.MetricConfiguration(metric)
 	if err != nil {
-		return nil, fmt.Errorf("could not open: %w", err)
+		return nil, fmt.Errorf("could not fetch metric configuration: %w", err)
 	}
 
-	store := inmem.NewFromReader(file)
+	c := map[string]interface{}{
+		"target_value": config.TargetValue.AsInterface(),
+		"operator":     config.Operator,
+	}
+
+	// Convert camelCase metric in under_score_style for package name
+	metric = strings.ToLower(strings.Join(camelcase.Split(metric), "_"))
+
+	store := inmem.NewFromObject(c)
 	ctx := context.Background()
 
 	tx, err = store.NewTransaction(ctx, storage.WriteParams)
@@ -128,7 +148,13 @@ func RunMap(baseDir string, metric string, m map[string]interface{}) (data map[s
 	}
 
 	r, err := rego.New(
-		rego.Query("data.clouditor"),
+		rego.Query(fmt.Sprintf(`x = {
+			"applicable": data.clouditor.metrics.%s.applicable, 
+			"compliant": data.clouditor.metrics.%s.compliant, 
+			"operator": data.clouditor.operator,
+			"target_value": data.clouditor.target_value,
+		}`, metric, metric)),
+		rego.Package("clouditor.metrics"),
 		rego.Store(store),
 		rego.Transaction(tx),
 		rego.Input(m),
@@ -153,12 +179,21 @@ func RunMap(baseDir string, metric string, m map[string]interface{}) (data map[s
 		return nil, fmt.Errorf("could not evaluate rego policy: %w", err)
 	}
 
-	if data, ok = results[0].Expressions[0].Value.(map[string]interface{}); !ok {
-		return nil, errors.New("expected data is not a map[string]interface{}")
-	} else if data["applicable"] == false {
+	if len(results) == 0 {
+		return nil, fmt.Errorf("no results. probably the package name of the metric is wrong")
+	}
+
+	result = new(Result)
+	err = mapstructure.Decode(results[0].Bindings["x"], result)
+
+	if err != nil {
+		return nil, fmt.Errorf("expected data is not a map[string]interface{}: %w", err)
+	}
+
+	if !result.Applicable {
 		return nil, nil
 	} else {
-		return data, nil
+		return result, nil
 	}
 }
 
diff --git a/service/assessment/assessment.go b/service/assessment/assessment.go
index 74d6455b..f760955b 100644
--- a/service/assessment/assessment.go
+++ b/service/assessment/assessment.go
@@ -31,12 +31,15 @@ import (
 	"fmt"
 	"io"
 	"sync"
+	"time"
 
 	"clouditor.io/clouditor/api"
 	"clouditor.io/clouditor/api/assessment"
 	"clouditor.io/clouditor/api/evidence"
 	"clouditor.io/clouditor/api/orchestrator"
 	"clouditor.io/clouditor/policies"
+	service_orchestrator "clouditor.io/clouditor/service/orchestrator"
+
 	"github.com/google/uuid"
 	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
@@ -53,6 +56,16 @@ func init() {
 	log = logrus.WithField("component", "assessment")
 }
 
+const (
+	// EvictionTime is the time after which an entry in the metric configuration is invalid
+	EvictionTime = time.Hour * 1
+)
+
+type cachedConfiguration struct {
+	cachedAt time.Time
+	*assessment.MetricConfiguration
+}
+
 // Service is an implementation of the Clouditor Assessment service. It should not be used directly,
 // but rather the NewService constructor should be used. It implements the AssessmentServer interface.
 type Service struct {
@@ -65,6 +78,7 @@ type Service struct {
 
 	// orchestratorStream sends ARs to the Orchestrator
 	orchestratorStream  orchestrator.Orchestrator_StoreAssessmentResultsClient
+	orchestratorClient  orchestrator.OrchestratorClient
 	orchestratorAddress string
 
 	// resultHooks is a list of hook functions that can be used if one wants to be
@@ -76,6 +90,10 @@ type Service struct {
 	// Currently, results are just stored as a map (=in-memory). In the future, we will use a DB.
 	results map[string]*assessment.AssessmentResult
 
+	// cachedConfigurations holds cached metric configurations for faster access with key being the corresponding
+	// metric name
+	cachedConfigurations map[string]cachedConfiguration
+
 	authorizer api.Authorizer
 }
 
@@ -117,6 +135,7 @@ func NewService(opts ...ServiceOption) *Service {
 		results:              make(map[string]*assessment.AssessmentResult),
 		evidenceStoreAddress: DefaultEvidenceStoreAddress,
 		orchestratorAddress:  DefaultOrchestratorAddress,
+		cachedConfigurations: make(map[string]cachedConfiguration),
 	}
 
 	// Apply any options
@@ -203,10 +222,10 @@ func (s *Service) AssessEvidences(stream assessment.Assessment_AssessEvidencesSe
 
 // handleEvidence is the helper method for the actual assessment used by AssessEvidence and AssessEvidences
 func (s *Service) handleEvidence(evidence *evidence.Evidence, resourceId string) (err error) {
-	log.Infof("Running evidence %s (%s) collected by %s at %v", evidence.Id, resourceId, evidence.ToolId, evidence.Timestamp)
+	log.Infof("Evaluating evidence %s (%s) collected by %s at %v", evidence.Id, resourceId, evidence.ToolId, evidence.Timestamp)
 	log.Debugf("Evidence: %+v", evidence)
 
-	evaluations, err := policies.RunEvidence(evidence)
+	evaluations, err := policies.RunEvidence(evidence, s)
 	if err != nil {
 		newError := fmt.Errorf("could not evaluate evidence: %w", err)
 		log.Errorf(newError.Error())
@@ -223,14 +242,11 @@ func (s *Service) handleEvidence(evidence *evidence.Evidence, resourceId string)
 	}
 
 	for i, data := range evaluations {
-		metricId := data["metricId"].(string)
+		metricId := data.MetricId
 
-		log.Infof("Evaluated evidence with metric '%v' as %v", metricId, data["compliant"])
+		log.Infof("Evaluated evidence with metric '%v' as %v", metricId, data.Compliant)
 
-		// Get output values of Rego evaluation. If they are not given, the zero value is used
-		operator, _ := data["operator"].(string)
-		targetValue := data["target_value"]
-		compliant, _ := data["compliant"].(bool)
+		targetValue := data.TargetValue
 
 		convertedTargetValue, err := convertTargetValue(targetValue)
 		if err != nil {
@@ -243,9 +259,9 @@ func (s *Service) handleEvidence(evidence *evidence.Evidence, resourceId string)
 			MetricId:  metricId,
 			MetricConfiguration: &assessment.MetricConfiguration{
 				TargetValue: convertedTargetValue,
-				Operator:    operator,
+				Operator:    data.Operator,
 			},
-			Compliant:             compliant,
+			Compliant:             data.Compliant,
 			EvidenceId:            evidence.Id,
 			ResourceId:            resourceId,
 			NonComplianceComments: "No comments so far",
@@ -341,7 +357,9 @@ func (s *Service) sendToEvidenceStore(e *evidence.Evidence) error {
 			return fmt.Errorf("could not initialize stream to Evidence Store: %v", err)
 		}
 	}
+
 	log.Infof("Sending evidence (%v) to Evidence Store", e.Id)
+
 	err := s.evidenceStoreStream.Send(&evidence.StoreEvidenceRequest{Evidence: e})
 	if err != nil {
 		return err
@@ -361,27 +379,74 @@ func (s *Service) initOrchestratorStream(additionalOpts ...grpc.DialOption) erro
 		return fmt.Errorf("could not connect to orchestrator service: %w", err)
 	}
 
-	orchestratorClient := orchestrator.NewOrchestratorClient(conn)
-	s.orchestratorStream, err = orchestratorClient.StoreAssessmentResults(context.Background())
+	s.orchestratorClient = orchestrator.NewOrchestratorClient(conn)
+	s.orchestratorStream, err = s.orchestratorClient.StoreAssessmentResults(context.Background())
 	if err != nil {
 		return fmt.Errorf("could not set up stream for storing assessment results: %w", err)
 	}
+
 	log.Infof("Connected to Orchestrator")
+
 	return nil
 }
 
 // sendToOrchestrator sends the assessment result to the Orchestrator
 func (s *Service) sendToOrchestrator(result *assessment.AssessmentResult) error {
-	if s.orchestratorStream == nil {
+	if s.orchestratorStream == nil || s.orchestratorClient == nil {
 		err := s.initOrchestratorStream()
 		if err != nil {
 			return fmt.Errorf("could not initialize stream to Orchestrator: %v", err)
 		}
 	}
+
 	log.Infof("Sending assessment result (%v) to Orchestrator", result.Id)
+
 	err := s.orchestratorStream.Send(result)
 	if err != nil {
 		return err
 	}
+
 	return nil
 }
+
+// MetricConfiguration implements MetricConfigurationSource by getting the corresponding metric configuration for the
+// default target cloud service
+func (s *Service) MetricConfiguration(metric string) (config *assessment.MetricConfiguration, err error) {
+	var (
+		ok    bool
+		cache cachedConfiguration
+	)
+
+	// Lazy init of connection
+	if s.orchestratorStream == nil || s.orchestratorClient == nil {
+		err = s.initOrchestratorStream()
+		if err != nil {
+			return nil, fmt.Errorf("could not initialize connection to orchestrator: %v", err)
+		}
+	}
+
+	// Retrieve our cached entry
+	cache, ok = s.cachedConfigurations[metric]
+
+	// Check if entry is not there or is expired
+	if !ok || cache.cachedAt.After(time.Now().Add(EvictionTime)) {
+		config, err = s.orchestratorClient.GetMetricConfiguration(context.Background(), &orchestrator.GetMetricConfigurationRequest{
+			ServiceId: service_orchestrator.DefaultTargetCloudServiceId,
+			MetricId:  metric,
+		})
+
+		if err != nil {
+			return nil, fmt.Errorf("could not retrieve metric configuration for %s: %w", metric, err)
+		}
+
+		cache = cachedConfiguration{
+			cachedAt:            time.Now(),
+			MetricConfiguration: config,
+		}
+
+		// Update the metric configuration
+		s.cachedConfigurations[metric] = cache
+	}
+
+	return cache.MetricConfiguration, nil
+}
diff --git a/service/orchestrator/metrics.json b/service/orchestrator/metrics.json
index 35db15d1..d4ebb850 100644
--- a/service/orchestrator/metrics.json
+++ b/service/orchestrator/metrics.json
@@ -129,6 +129,9 @@
       "CKM-02.2"
     ]
   },
+  {
+    "id": "TransportEncryptionEnforced"
+  },
   {
     "id": "WebApplicationFirewallEnabled"
   }
diff --git a/service/orchestrator/orchestrator.go b/service/orchestrator/orchestrator.go
index 7894b090..4ce37fe8 100644
--- a/service/orchestrator/orchestrator.go
+++ b/service/orchestrator/orchestrator.go
@@ -241,7 +241,6 @@ func (s *Service) StoreAssessmentResults(stream orchestrator.Orchestrator_StoreA
 			return err
 		}
 	}
-
 }
 
 // ListAssessmentResults is a method implementation of the orchestrator interface


Test patch:
diff --git a/policies/policies_test.go b/policies/policies_test.go
index 77f48786..b0cb4052 100644
--- a/policies/policies_test.go
+++ b/policies/policies_test.go
@@ -26,11 +26,15 @@
 package policies
 
 import (
+	"fmt"
+	"io/ioutil"
 	"os"
 	"testing"
 
 	"clouditor.io/clouditor/voc"
+	"google.golang.org/protobuf/encoding/protojson"
 
+	"clouditor.io/clouditor/api/assessment"
 	"clouditor.io/clouditor/api/evidence"
 	"github.com/stretchr/testify/assert"
 )
@@ -61,9 +65,13 @@ func TestRunEvidence(t *testing.T) {
 		resource   voc.IsCloudResource
 		evidenceID string
 	}
+	type args struct {
+		source MetricConfigurationSource
+	}
 	tests := []struct {
 		name       string
 		fields     fields
+		args       args
 		applicable bool
 		compliant  bool
 		wantErr    bool
@@ -104,6 +112,7 @@ func TestRunEvidence(t *testing.T) {
 				},
 				evidenceID: mockObjStorage1EvidenceID,
 			},
+			args:       args{source: &mockMetricConfigurationSource{t: t}},
 			applicable: true,
 			compliant:  true,
 			wantErr:    false,
@@ -140,6 +149,7 @@ func TestRunEvidence(t *testing.T) {
 				},
 				evidenceID: mockObjStorage2EvidenceID,
 			},
+			args:       args{source: &mockMetricConfigurationSource{t: t}},
 			applicable: true,
 			compliant:  false,
 			wantErr:    false,
@@ -180,6 +190,7 @@ func TestRunEvidence(t *testing.T) {
 				},
 				evidenceID: mockObjStorage2EvidenceID,
 			},
+			args:       args{source: &mockMetricConfigurationSource{t: t}},
 			applicable: true,
 			compliant:  false,
 			wantErr:    false,
@@ -212,6 +223,7 @@ func TestRunEvidence(t *testing.T) {
 				},
 				evidenceID: mockVM1EvidenceID,
 			},
+			args:       args{source: &mockMetricConfigurationSource{t: t}},
 			applicable: true,
 			compliant:  true,
 			wantErr:    false,
@@ -244,6 +256,7 @@ func TestRunEvidence(t *testing.T) {
 				},
 				evidenceID: mockVM2EvidenceID,
 			},
+			args:       args{source: &mockMetricConfigurationSource{t: t}},
 			applicable: true,
 			compliant:  false,
 			wantErr:    false,
@@ -256,16 +269,37 @@ func TestRunEvidence(t *testing.T) {
 			results, err := RunEvidence(&evidence.Evidence{
 				Id:       tt.fields.evidenceID,
 				Resource: resource,
-			})
+			}, tt.args.source)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("RunEvidence() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
 			assert.NotEmpty(t, results)
 			for _, result := range results {
-				assert.Equal(t, tt.applicable, result["applicable"].(bool))
-				assert.Equal(t, tt.compliant, result["compliant"].(bool))
+				assert.Equal(t, tt.applicable, result.Applicable)
+				assert.Equal(t, tt.compliant, result.Compliant)
 			}
 		})
 	}
 }
+
+type mockMetricConfigurationSource struct {
+	t *testing.T
+}
+
+func (m *mockMetricConfigurationSource) MetricConfiguration(metric string) (*assessment.MetricConfiguration, error) {
+	// Fetch the metric configuration directly from our file
+
+	bundle := fmt.Sprintf("policies/bundles/%s/data.json", metric)
+	file, err := os.OpenFile(bundle, os.O_RDONLY, 0600)
+	assert.NoError(m.t, err)
+
+	b, err := ioutil.ReadAll(file)
+	assert.NoError(m.t, err)
+
+	var config assessment.MetricConfiguration
+	err = protojson.Unmarshal(b, &config)
+	assert.NoError(m.t, err)
+
+	return &config, nil
+}
diff --git a/service/assessment/assessment_test.go b/service/assessment/assessment_test.go
index 405ab66e..f5074466 100644
--- a/service/assessment/assessment_test.go
+++ b/service/assessment/assessment_test.go
@@ -40,6 +40,7 @@ import (
 	"clouditor.io/clouditor/api/assessment"
 	"clouditor.io/clouditor/api/evidence"
 	"clouditor.io/clouditor/voc"
+
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
@@ -85,6 +86,7 @@ func TestNewService(t *testing.T) {
 				results:              make(map[string]*assessment.AssessmentResult),
 				evidenceStoreAddress: "localhost:9090",
 				orchestratorAddress:  "localhost:9090",
+				cachedConfigurations: make(map[string]cachedConfiguration),
 			},
 		},
 		{
@@ -99,6 +101,7 @@ func TestNewService(t *testing.T) {
 				results:              make(map[string]*assessment.AssessmentResult),
 				evidenceStoreAddress: "localhost:9091",
 				orchestratorAddress:  "localhost:9092",
+				cachedConfigurations: make(map[string]cachedConfiguration),
 			},
 		},
 	}
@@ -292,6 +295,7 @@ func TestAssessEvidences(t *testing.T) {
 			s := Service{
 				resultHooks:                   tt.fields.ResultHooks,
 				results:                       tt.fields.results,
+				cachedConfigurations:          make(map[string]cachedConfiguration),
 				UnimplementedAssessmentServer: tt.fields.UnimplementedAssessmentServer,
 			}
 			if tt.fields.hasRPCConnection {
@@ -693,7 +697,6 @@ func TestHandleEvidence(t *testing.T) {
 			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
 				assert.Error(t, err)
 				// Check if error message contains "empty" (list of types)
-				assert.Contains(t, err.Error(), "Orchestrator")
 				assert.Contains(t, err.Error(), "Unavailable desc")
 				return true
 			},