Repository: clouditor/clouditor
Pull request #1119 (2023-05-22 10:55:17)

Include raw discovery traffic in raw property of an evidence
This PR adds the resource object from the Cloud Provider as a json string to the evidence raw field.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) Report
> Merging [#1119](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (efeae56) into [main](https://app.codecov.io/gh/clouditor/clouditor/commit/381315f725fbf8db9d88e5c7afee9412937705d2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (381315f) will **decrease** coverage by `0.15%`.
> The diff coverage is `58.33%`.

```diff
@@            Coverage Diff             @@
##             main    #1119      +/-   ##
==========================================
- Coverage   83.66%   83.51%   -0.15%     
==========================================
  Files          92       92              
  Lines        8508     8577      +69     
==========================================
+ Hits         7118     7163      +45     
- Misses       1051     1067      +16     
- Partials      339      347       +8     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `83.51% <58.33%> (-0.15%)` | :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://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) | Coverage Δ | |
|---|---|---|
| [service/discovery/azure/compute.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXp1cmUvY29tcHV0ZS5nbw==) | `89.39% <40.00%> (-1.86%)` | :arrow_down: |
| [service/discovery/azure/network.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXp1cmUvbmV0d29yay5nbw==) | `85.82% <40.00%> (-2.97%)` | :arrow_down: |
| [service/discovery/azure/storage.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXp1cmUvc3RvcmFnZS5nbw==) | `83.67% <40.00%> (-2.00%)` | :arrow_down: |
| [voc/voc.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-dm9jL3ZvYy5nbw==) | `69.09% <72.72%> (+0.90%)` | :arrow_up: |
| [api/discovery/discovery.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-YXBpL2Rpc2NvdmVyeS9kaXNjb3ZlcnkuZ28=) | `100.00% <100.00%> (ø)` | |
| [service/discovery/aws/compute.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXdzL2NvbXB1dGUuZ28=) | `94.82% <100.00%> (+0.02%)` | :arrow_up: |
| [service/discovery/aws/storage.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXdzL3N0b3JhZ2UuZ28=) | `85.99% <100.00%> (+0.13%)` | :arrow_up: |
| [service/discovery/discovery.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvZGlzY292ZXJ5Lmdv) | `88.67% <100.00%> (+0.17%)` | :arrow_up: |
| [service/discovery/k8s/compute.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvazhzL2NvbXB1dGUuZ28=) | `90.66% <100.00%> (+0.25%)` | :arrow_up: |
| [service/discovery/k8s/network.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvazhzL25ldHdvcmsuZ28=) | `90.38% <100.00%> (+0.18%)` | :arrow_up: |
| ... and [1 more](https://app.codecov.io/gh/clouditor/clouditor/pull/1119?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) | |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/clouditor/clouditor/pull/1119/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)



Patch:
diff --git a/api/discovery/discovery.go b/api/discovery/discovery.go
index 0051aa26..edd3ba48 100644
--- a/api/discovery/discovery.go
+++ b/api/discovery/discovery.go
@@ -30,6 +30,11 @@ import (
 
 	"clouditor.io/clouditor/internal/util"
 	"clouditor.io/clouditor/voc"
+	"github.com/sirupsen/logrus"
+)
+
+var (
+	log *logrus.Entry
 )
 
 // DefaultCloudServiceID is the default service ID. Currently, our discoverers have no way to differentiate between different
@@ -52,7 +57,12 @@ type Authorizer interface {
 }
 
 // NewResource creates a new voc resource.
-func NewResource(d Discoverer, ID voc.ResourceID, name string, creationTime *time.Time, location voc.GeoLocation, labels map[string]string, typ []string) *voc.Resource {
+func NewResource(d Discoverer, ID voc.ResourceID, name string, creationTime *time.Time, location voc.GeoLocation, labels map[string]string, typ []string, raw ...interface{}) *voc.Resource {
+	rawString, err := voc.ToStringInterface(raw)
+	if err != nil {
+		log.Errorf("%v: %v", voc.ErrConvertingStructToString, err)
+	}
+
 	return &voc.Resource{
 		ID:           ID,
 		ServiceID:    d.CloudServiceID(),
@@ -61,5 +71,6 @@ func NewResource(d Discoverer, ID voc.ResourceID, name string, creationTime *tim
 		GeoLocation:  location,
 		Type:         typ,
 		Labels:       labels,
+		Raw:          rawString,
 	}
 }
diff --git a/service/discovery/aws/compute.go b/service/discovery/aws/compute.go
index f4a80600..4d3c403f 100644
--- a/service/discovery/aws/compute.go
+++ b/service/discovery/aws/compute.go
@@ -94,7 +94,7 @@ func (*computeDiscovery) Name() string {
 }
 
 // List is the method implementation defined in the discovery.Discoverer interface
-func (d computeDiscovery) List() (resources []voc.IsCloudResource, err error) {
+func (d *computeDiscovery) List() (resources []voc.IsCloudResource, err error) {
 	log.Infof("Collecting evidences in %s", d.Name())
 
 	// Even though technically volumes are "storage", they are part of the EC2 API and therefore discovered here
@@ -169,6 +169,7 @@ func (d *computeDiscovery) discoverVolumes() ([]*voc.BlockStorage, error) {
 					},
 					d.labels(volume.Tags),
 					voc.BlockStorageType,
+					&res.Volumes[i],
 				),
 				AtRestEncryption: atRest,
 			},
@@ -191,17 +192,18 @@ func (d *computeDiscovery) discoverNetworkInterfaces() ([]voc.NetworkInterface,
 
 		ifcs = append(ifcs, voc.NetworkInterface{
 			Networking: &voc.Networking{
-				Resource: &voc.Resource{
-					ID:           d.arnify("network-interface", ifc.NetworkInterfaceId),
-					ServiceID:    discovery.DefaultCloudServiceID,
-					Name:         d.nameOrID(ifc.TagSet, ifc.NetworkInterfaceId),
-					CreationTime: 0,
-					Type:         []string{"NetworkInterface", "Networking", "Resource"},
-					GeoLocation: voc.GeoLocation{
+				Resource: discovery.NewResource(
+					d,
+					d.arnify("network-interface", ifc.NetworkInterfaceId),
+					d.nameOrID(ifc.TagSet, ifc.NetworkInterfaceId),
+					nil,
+					voc.GeoLocation{
 						Region: d.awsConfig.cfg.Region,
 					},
-					Labels: d.labels(ifc.TagSet),
-				},
+					d.labels(ifc.TagSet),
+					[]string{"NetworkInterface", "Networking", "Resource"},
+					&res.NetworkInterfaces[i],
+				),
 			},
 		})
 	}
@@ -220,17 +222,19 @@ func (d *computeDiscovery) discoverVirtualMachines() ([]*voc.VirtualMachine, err
 		for i := range reservation.Instances {
 			vm := &reservation.Instances[i]
 			computeResource := &voc.Compute{
-				Resource: &voc.Resource{
-					ID:           d.arnify("instance", vm.InstanceId),
-					ServiceID:    discovery.DefaultCloudServiceID,
-					Name:         d.getNameOfVM(vm),
-					CreationTime: 0,
-					Type:         []string{"VirtualMachine", "Compute", "Resource"},
-					GeoLocation: voc.GeoLocation{
+				Resource: discovery.NewResource(
+					d,
+					d.arnify("instance", vm.InstanceId),
+					d.getNameOfVM(vm),
+					nil,
+					voc.GeoLocation{
 						Region: d.awsConfig.cfg.Region,
 					},
-					Labels: d.labels(vm.Tags),
-				},
+					d.labels(vm.Tags),
+					[]string{"VirtualMachine", "Compute", "Resource"},
+					&reservation,
+				),
+
 				NetworkInterfaces: d.getNetworkInterfacesOfVM(vm),
 			}
 
@@ -269,20 +273,24 @@ func (d *computeDiscovery) discoverFunctions() (resources []*voc.Function, err e
 
 // mapFunctionResources iterates functionConfigurations and returns a list of corresponding FunctionResources
 func (d *computeDiscovery) mapFunctionResources(functions []typesLambda.FunctionConfiguration) (resources []*voc.Function) {
+	// TODO(all): Labels are missing
 	for i := range functions {
 		function := &functions[i]
+
 		resources = append(resources, &voc.Function{
 			Compute: &voc.Compute{
-				Resource: &voc.Resource{
-					ID:           voc.ResourceID(aws.ToString(function.FunctionArn)),
-					ServiceID:    discovery.DefaultCloudServiceID,
-					Name:         aws.ToString(function.FunctionName),
-					CreationTime: 0,
-					Type:         []string{"Function", "Compute", "Resource"},
-					GeoLocation: voc.GeoLocation{
+				Resource: discovery.NewResource(
+					d,
+					voc.ResourceID(aws.ToString(function.FunctionArn)),
+					aws.ToString(function.FunctionName),
+					nil,
+					voc.GeoLocation{
 						Region: d.awsConfig.cfg.Region,
 					},
-				},
+					nil,
+					voc.FunctionType,
+					&functions[i],
+				),
 			}})
 	}
 	return
@@ -372,7 +380,7 @@ func (*computeDiscovery) labels(tags []typesEC2.Tag) (labels map[string]string)
 }
 
 // addARNToVolume generates the ARN of a volumne instance
-func (d computeDiscovery) arnify(typ string, ID *string) voc.ResourceID {
+func (d *computeDiscovery) arnify(typ string, ID *string) voc.ResourceID {
 	return voc.ResourceID("arn:aws:ec2:" +
 		d.awsConfig.cfg.Region + ":" +
 		aws.ToString(d.awsConfig.accountID) +
diff --git a/service/discovery/aws/storage.go b/service/discovery/aws/storage.go
index e32321d3..df84b744 100644
--- a/service/discovery/aws/storage.go
+++ b/service/discovery/aws/storage.go
@@ -58,6 +58,7 @@ type bucket struct {
 	creationTime time.Time
 	endpoint     string
 	region       string
+	raw          []interface{}
 }
 
 // S3API describes the S3 api interface which is implemented by the official AWS storageAPI and mock clients in tests
@@ -111,8 +112,12 @@ func (*awsS3Discovery) Name() string {
 
 // List is the method implementation defined in the discovery.Discoverer interface
 func (d *awsS3Discovery) List() (resources []voc.IsCloudResource, err error) {
-	var encryptionAtRest voc.IsAtRestEncryption
-	var encryptionAtTransmit *voc.TransportEncryption
+	var (
+		encryptionAtRest    voc.IsAtRestEncryption
+		encryptionAtTransit *voc.TransportEncryption
+		rawBucketEncOutput  *s3.GetBucketEncryptionOutput
+		rawBucketTranspEnc  *s3.GetBucketPolicyOutput
+	)
 
 	log.Infof("Collecting evidences in %s", d.Name())
 	var buckets []bucket
@@ -120,12 +125,13 @@ func (d *awsS3Discovery) List() (resources []voc.IsCloudResource, err error) {
 	if err != nil {
 		return
 	}
+
 	for _, b := range buckets {
-		encryptionAtRest, err = d.getEncryptionAtRest(&b)
+		encryptionAtRest, rawBucketEncOutput, err = d.getEncryptionAtRest(&b)
 		if err != nil {
 			return
 		}
-		encryptionAtTransmit, err = d.getTransportEncryption(b.name)
+		encryptionAtTransit, rawBucketTranspEnc, err = d.getTransportEncryption(b.name)
 		if err != nil {
 			return
 		}
@@ -142,7 +148,8 @@ func (d *awsS3Discovery) List() (resources []voc.IsCloudResource, err error) {
 							Region: b.region,
 						},
 						nil,
-						voc.ObjectStorageType),
+						voc.ObjectStorageType,
+						&b, &rawBucketEncOutput, &rawBucketTranspEnc, &b.raw),
 					AtRestEncryption: encryptionAtRest,
 				},
 			},
@@ -159,14 +166,15 @@ func (d *awsS3Discovery) List() (resources []voc.IsCloudResource, err error) {
 								voc.GeoLocation{Region: b.region},
 								nil,
 								voc.ObjectStorageServiceType,
+								&b, &rawBucketEncOutput, &rawBucketTranspEnc, &b.raw,
 							),
 						},
-						TransportEncryption: encryptionAtTransmit,
+						TransportEncryption: encryptionAtTransit,
 					},
 				},
 				HttpEndpoint: &voc.HttpEndpoint{
 					Url:                 b.endpoint,
-					TransportEncryption: encryptionAtTransmit,
+					TransportEncryption: encryptionAtTransit,
 				},
 			})
 	}
@@ -200,10 +208,15 @@ func (d *awsS3Discovery) getBuckets() (buckets []bucket, err error) {
 	}
 	var region string
 	for _, b := range resp.Buckets {
-		region, err = d.getRegion(aws.ToString(b.Name))
+		var (
+			rawRegion *s3.GetBucketLocationOutput
+		)
+
+		region, rawRegion, err = d.getRegion(aws.ToString(b.Name))
 		if err != nil {
 			return
 		}
+
 		// Currently only buckets are retrieved that are in the region of the users specified region in the config. Since getBucketPolicy throws error if bucket region differs
 		// TODO(lebogg): Retrieve all buckets (just remove if) and fix issues with other methods, e.g. getBucketPolicy
 		if region == d.awsConfig.cfg.Region {
@@ -213,6 +226,7 @@ func (d *awsS3Discovery) getBuckets() (buckets []bucket, err error) {
 				creationTime: aws.ToTime(b.CreationDate),
 				region:       region,
 				endpoint:     "https://" + aws.ToString(b.Name) + ".s3." + region + ".amazonaws.com",
+				raw:          []interface{}{b, rawRegion},
 			})
 		}
 	}
@@ -220,12 +234,11 @@ func (d *awsS3Discovery) getBuckets() (buckets []bucket, err error) {
 }
 
 // getEncryptionAtRest gets the bucket's encryption configuration
-func (d *awsS3Discovery) getEncryptionAtRest(bucket *bucket) (e voc.IsAtRestEncryption, err error) {
+func (d *awsS3Discovery) getEncryptionAtRest(bucket *bucket) (e voc.IsAtRestEncryption, resp *s3.GetBucketEncryptionOutput, err error) {
 	input := s3.GetBucketEncryptionInput{
 		Bucket:              aws.String(bucket.name),
 		ExpectedBucketOwner: nil,
 	}
-	var resp *s3.GetBucketEncryptionOutput
 
 	resp, err = d.storageAPI.GetBucketEncryption(context.TODO(), &input)
 	if err != nil {
@@ -269,7 +282,7 @@ func (d *awsS3Discovery) getEncryptionAtRest(bucket *bucket) (e voc.IsAtRestEncr
 // "confirm that your bucket policies explicitly deny access to HTTP requests"
 // https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/
 // getTransportEncryption loops over all statements in the bucket policy and checks if one statement denies https only == false
-func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEncryption, error) {
+func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEncryption, *s3.GetBucketPolicyOutput, error) {
 	input := s3.GetBucketPolicyInput{
 		Bucket:              aws.String(bucket),
 		ExpectedBucketOwner: nil,
@@ -292,13 +305,13 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 					Enabled:    true,
 					TlsVersion: "TLS1.2",
 					Algorithm:  "TLS",
-				}, nil
+				}, resp, nil
 			}
 			// Any other error is a connection error with AWS : Format err and return it
 			err = formatError(ae)
 		}
 		// return any error (but according to doc: "All service API response errors implement the smithy.APIError")
-		return nil, err
+		return nil, resp, err
 	}
 
 	// Case 2: bucket policy -> check if https only is set
@@ -306,7 +319,7 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 	var policy BucketPolicy
 	err = json.Unmarshal([]byte(aws.ToString(resp.Policy)), &policy)
 	if err != nil {
-		return nil, fmt.Errorf("error occurred while unmarshalling the bucket policy: %v", err)
+		return nil, resp, fmt.Errorf("error occurred while unmarshalling the bucket policy: %v", err)
 	}
 	// one statement has set https only -> default encryption is set
 	for _, statement := range policy.Statement {
@@ -317,7 +330,7 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 					Enabled:    true,
 					TlsVersion: "TLS1.2",
 					Algorithm:  "TLS",
-				}, nil
+				}, resp, nil
 			}
 		}
 		if actions, ok := statement.Action.([]string); ok {
@@ -328,7 +341,7 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 						Enabled:    true,
 						TlsVersion: "TLS1.2",
 						Algorithm:  "TLS",
-					}, nil
+					}, resp, nil
 				}
 			}
 		}
@@ -338,16 +351,15 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 		Enabled:    true,
 		TlsVersion: "TLS1.2",
 		Algorithm:  "TLS",
-	}, nil
+	}, resp, nil
 
 }
 
 // getRegion returns the region where the bucket resides
-func (d *awsS3Discovery) getRegion(bucket string) (region string, err error) {
+func (d *awsS3Discovery) getRegion(bucket string) (region string, resp *s3.GetBucketLocationOutput, err error) {
 	input := s3.GetBucketLocationInput{
 		Bucket: aws.String(bucket),
 	}
-	var resp *s3.GetBucketLocationOutput
 	resp, err = d.storageAPI.GetBucketLocation(context.TODO(), &input)
 	if err != nil {
 		var oe *smithy.OperationError
diff --git a/service/discovery/azure/azure.go b/service/discovery/azure/azure.go
index c0c312a6..2ba69bdc 100644
--- a/service/discovery/azure/azure.go
+++ b/service/discovery/azure/azure.go
@@ -345,11 +345,15 @@ func (d *azureDiscovery) discoverBackupVaults() error {
 }
 
 func (d *azureDiscovery) handleInstances(vault *armdataprotection.BackupVaultResource, instance *armdataprotection.BackupInstanceResource) (resource voc.IsCloudResource, err error) {
-
 	if vault == nil || instance == nil {
 		return nil, ErrVaultInstanceIsEmpty
 	}
 
+	raw, err := voc.ToStringInterface([]interface{}{instance, vault})
+	if err != nil {
+		log.Error(err)
+	}
+
 	if *instance.Properties.DataSourceInfo.DatasourceType == "Microsoft.Storage/storageAccounts/blobServices" {
 		resource = &voc.ObjectStorage{
 			Storage: &voc.Storage{
@@ -363,6 +367,7 @@ func (d *azureDiscovery) handleInstances(vault *armdataprotection.BackupVaultRes
 					Labels:    nil,
 					ServiceID: d.csID,
 					Type:      voc.ObjectStorageType,
+					Raw:       raw,
 				},
 			},
 		}
@@ -379,6 +384,7 @@ func (d *azureDiscovery) handleInstances(vault *armdataprotection.BackupVaultRes
 						Region: *vault.Location,
 					},
 					Labels: nil,
+					Raw:    raw,
 				},
 			},
 		}
diff --git a/service/discovery/azure/compute.go b/service/discovery/azure/compute.go
index aa706cf4..e81322ad 100644
--- a/service/discovery/azure/compute.go
+++ b/service/discovery/azure/compute.go
@@ -188,6 +188,7 @@ func (d *azureComputeDiscovery) handleFunction(function *armappservice.Site) voc
 				},
 				labels(function.Tags),
 				voc.FunctionType,
+				function,
 			),
 			NetworkInterfaces: []voc.ResourceID{},
 		},
@@ -282,6 +283,7 @@ func (d *azureComputeDiscovery) handleVirtualMachines(vm *armcompute.VirtualMach
 				},
 				labels(vm.Tags),
 				voc.VirtualMachineType,
+				vm,
 			),
 			NetworkInterfaces: []voc.ResourceID{},
 		},
@@ -429,18 +431,22 @@ func (d *azureComputeDiscovery) discoverBlockStorages() ([]voc.IsCloudResource,
 }
 
 func (d *azureComputeDiscovery) handleBlockStorage(disk *armcompute.Disk) (*voc.BlockStorage, error) {
-	var backups []*voc.Backup
+	var (
+		rawKeyUrl *armcompute.DiskEncryptionSet
+		backups   []*voc.Backup
+	)
 
 	// If a mandatory field is empty, the whole disk is empty
 	if disk == nil || disk.ID == nil {
 		return nil, fmt.Errorf("disk is nil")
 	}
 
-	enc, err := d.blockStorageAtRestEncryption(disk)
+	enc, rawKeyUrl, err := d.blockStorageAtRestEncryption(disk)
 	if err != nil {
 		return nil, fmt.Errorf("could not get block storage properties for the atRestEncryption: %w", err)
 	}
 
+	// Get voc.Backup
 	if d.backupMap[DataSourceTypeDisc] != nil && d.backupMap[DataSourceTypeDisc].backup[util.Deref(disk.ID)] != nil {
 		backups = d.backupMap[DataSourceTypeDisc].backup[util.Deref(disk.ID)]
 	}
@@ -456,6 +462,7 @@ func (d *azureComputeDiscovery) handleBlockStorage(disk *armcompute.Disk) (*voc.
 				},
 				labels(disk.Tags),
 				voc.BlockStorageType,
+				disk, rawKeyUrl,
 			),
 			AtRestEncryption: enc,
 			Backups:          backups,
@@ -465,18 +472,18 @@ func (d *azureComputeDiscovery) handleBlockStorage(disk *armcompute.Disk) (*voc.
 
 // blockStorageAtRestEncryption takes encryption properties of an armcompute.Disk and converts it into our respective
 // ontology object.
-func (d *azureComputeDiscovery) blockStorageAtRestEncryption(disk *armcompute.Disk) (enc voc.IsAtRestEncryption, err error) {
+func (d *azureComputeDiscovery) blockStorageAtRestEncryption(disk *armcompute.Disk) (enc voc.IsAtRestEncryption, rawKeyUrl *armcompute.DiskEncryptionSet, err error) {
 	var (
 		diskEncryptionSetID string
 		keyUrl              string
 	)
 
 	if disk == nil {
-		return enc, errors.New("disk is empty")
+		return enc, nil, errors.New("disk is empty")
 	}
 
 	if disk.Properties.Encryption.Type == nil {
-		return enc, errors.New("error getting atRestEncryption properties of blockStorage")
+		return enc, nil, errors.New("error getting atRestEncryption properties of blockStorage")
 	} else if util.Deref(disk.Properties.Encryption.Type) == armcompute.EncryptionTypeEncryptionAtRestWithPlatformKey {
 		enc = &voc.ManagedKeyEncryption{AtRestEncryption: &voc.AtRestEncryption{
 			Algorithm: "AES256",
@@ -485,9 +492,9 @@ func (d *azureComputeDiscovery) blockStorageAtRestEncryption(disk *armcompute.Di
 	} else if util.Deref(disk.Properties.Encryption.Type) == armcompute.EncryptionTypeEncryptionAtRestWithCustomerKey {
 		diskEncryptionSetID = util.Deref(disk.Properties.Encryption.DiskEncryptionSetID)
 
-		keyUrl, err = d.keyURL(diskEncryptionSetID)
+		keyUrl, rawKeyUrl, err = d.keyURL(diskEncryptionSetID)
 		if err != nil {
-			return nil, fmt.Errorf("could not get keyVaultID: %w", err)
+			return nil, nil, fmt.Errorf("could not get keyVaultID: %w", err)
 		}
 
 		enc = &voc.CustomerKeyEncryption{
@@ -499,32 +506,32 @@ func (d *azureComputeDiscovery) blockStorageAtRestEncryption(disk *armcompute.Di
 		}
 	}
 
-	return enc, nil
+	return enc, rawKeyUrl, nil
 }
 
-func (d *azureComputeDiscovery) keyURL(diskEncryptionSetID string) (string, error) {
+func (d *azureComputeDiscovery) keyURL(diskEncryptionSetID string) (string, *armcompute.DiskEncryptionSet, error) {
 	if diskEncryptionSetID == "" {
-		return "", ErrMissingDiskEncryptionSetID
+		return "", nil, ErrMissingDiskEncryptionSetID
 	}
 
 	if err := d.initDiskEncryptonSetClient(); err != nil {
-		return "", err
+		return "", nil, err
 	}
 
 	// Get disk encryption set
 	kv, err := d.clients.diskEncSetClient.Get(context.TODO(), resourceGroupName(diskEncryptionSetID), diskEncryptionSetName(diskEncryptionSetID), &armcompute.DiskEncryptionSetsClientGetOptions{})
 	if err != nil {
 		err = fmt.Errorf("could not get key vault: %w", err)
-		return "", err
+		return "", nil, err
 	}
 
 	keyURL := kv.DiskEncryptionSet.Properties.ActiveKey.KeyURL
 
 	if keyURL == nil {
-		return "", fmt.Errorf("could not get keyURL")
+		return "", nil, fmt.Errorf("could not get keyURL")
 	}
 
-	return util.Deref(keyURL), nil
+	return util.Deref(keyURL), &kv.DiskEncryptionSet, nil
 }
 
 // initFunctionsClient creates the client if not already exists
diff --git a/service/discovery/azure/network.go b/service/discovery/azure/network.go
index 50d8ce09..f72d816f 100644
--- a/service/discovery/azure/network.go
+++ b/service/discovery/azure/network.go
@@ -215,6 +215,7 @@ func (d *azureNetworkDiscovery) handleLoadBalancer(lb *armnetwork.LoadBalancer)
 					},
 					labels(lb.Tags),
 					voc.LoadBalancerType,
+					lb,
 				),
 			},
 			Ips:   publicIPAddressFromLoadBalancer(lb),
@@ -239,6 +240,7 @@ func (d *azureNetworkDiscovery) handleApplicationGateway(ag *armnetwork.Applicat
 					voc.GeoLocation{Region: util.Deref(ag.Location)},
 					labels(ag.Tags),
 					voc.LoadBalancerType,
+					ag,
 				),
 			},
 		},
@@ -261,6 +263,7 @@ func (d *azureNetworkDiscovery) handleNetworkInterfaces(ni *armnetwork.Interface
 				},
 				labels(ni.Tags),
 				voc.NetworkInterfaceType,
+				ni,
 			),
 		},
 		AccessRestriction: &voc.L3Firewall{
diff --git a/service/discovery/azure/storage.go b/service/discovery/azure/storage.go
index 814fc0c9..967f8433 100644
--- a/service/discovery/azure/storage.go
+++ b/service/discovery/azure/storage.go
@@ -248,7 +248,9 @@ func (d *azureStorageDiscovery) discoverObjectStorages(account *armstorage.Accou
 }
 
 func (d *azureStorageDiscovery) handleStorageAccount(account *armstorage.Account, storagesList []voc.IsCloudResource) (*voc.ObjectStorageService, error) {
-	var storageResourceIDs []voc.ResourceID
+	var (
+		storageResourceIDs []voc.ResourceID
+	)
 
 	if account == nil {
 		return nil, ErrEmptyStorageAccount
@@ -282,6 +284,7 @@ func (d *azureStorageDiscovery) handleStorageAccount(account *armstorage.Account
 						},
 						labels(account.Tags),
 						voc.ObjectStorageServiceType,
+						account,
 					),
 				},
 				TransportEncryption: te,
@@ -311,11 +314,13 @@ func (d *azureStorageDiscovery) handleFileStorage(account *armstorage.Account, f
 		return nil, fmt.Errorf("fileshare is nil")
 	}
 
+	// Get atRestEncryptionEnabled
 	enc, err := storageAtRestEncryption(account)
 	if err != nil {
 		return nil, fmt.Errorf("could not get file storage properties for the atRestEncryption: %w", err)
 	}
 
+	// Get monitoringLogDataEnabled and securityAlertsEnabled
 	if d.defenderProperties[DefenderStorageType] != nil {
 		monitoringLogDataEnabled = d.defenderProperties[DefenderVirtualMachineType].monitoringLogDataEnabled
 		securityAlertsEnabled = d.defenderProperties[DefenderVirtualMachineType].securityAlertsEnabled
@@ -335,6 +340,7 @@ func (d *azureStorageDiscovery) handleFileStorage(account *armstorage.Account, f
 				// The storage account labels the file storage belongs to
 				labels(account.Tags),
 				voc.FileStorageType,
+				account, fileshare,
 			),
 			ResourceLogging: &voc.ResourceLogging{
 				Logging: &voc.Logging{
@@ -353,6 +359,7 @@ func (d *azureStorageDiscovery) handleObjectStorage(account *armstorage.Account,
 		monitoringLogDataEnabled bool
 		securityAlertsEnabled    bool
 	)
+
 	if account == nil {
 		return nil, ErrEmptyStorageAccount
 	}
@@ -390,6 +397,7 @@ func (d *azureStorageDiscovery) handleObjectStorage(account *armstorage.Account,
 				// The storage account labels the object storage belongs to
 				labels(account.Tags),
 				voc.ObjectStorageType,
+				account, container,
 			),
 			AtRestEncryption: enc,
 			Immutability: &voc.Immutability{
diff --git a/service/discovery/discovery.go b/service/discovery/discovery.go
index 7c476e8b..540e2975 100644
--- a/service/discovery/discovery.go
+++ b/service/discovery/discovery.go
@@ -36,6 +36,7 @@ import (
 	"clouditor.io/clouditor/api/assessment"
 	"clouditor.io/clouditor/api/discovery"
 	"clouditor.io/clouditor/api/evidence"
+	"clouditor.io/clouditor/internal/util"
 	"clouditor.io/clouditor/persistence"
 	"clouditor.io/clouditor/persistence/inmemory"
 	"clouditor.io/clouditor/service"
@@ -377,8 +378,8 @@ func (svc *Service) StartDiscovery(discoverer discovery.Discoverer) {
 			Id:             uuid.New().String(),
 			CloudServiceId: resource.GetServiceID(),
 			Timestamp:      timestamppb.Now(),
+			Raw:            util.Ref(resource.GetRaw()),
 			ToolId:         discovery.EvidenceCollectorToolId,
-			Raw:            nil,
 			Resource:       v,
 		}
 
diff --git a/service/discovery/k8s/compute.go b/service/discovery/k8s/compute.go
index b96eee51..e71cac34 100644
--- a/service/discovery/k8s/compute.go
+++ b/service/discovery/k8s/compute.go
@@ -50,7 +50,7 @@ func (*k8sComputeDiscovery) Description() string {
 	return "Discover Kubernetes compute resources."
 }
 
-func (d k8sComputeDiscovery) List() ([]voc.IsCloudResource, error) {
+func (d *k8sComputeDiscovery) List() ([]voc.IsCloudResource, error) {
 	var list []voc.IsCloudResource
 
 	// Get pods
@@ -89,6 +89,7 @@ func (d *k8sComputeDiscovery) handlePod(pod *v1.Pod) *voc.Container {
 				voc.GeoLocation{},
 				pod.Labels,
 				voc.ContainerType,
+				pod,
 			),
 		},
 	}
@@ -119,6 +120,7 @@ func (d *k8sComputeDiscovery) handlePodVolume(pod *v1.Pod) []voc.IsCloudResource
 				voc.GeoLocation{},
 				nil, // anatheka: As I understand it, there are no labels for the volume here, we have to get that from the related storage directly. But we could take the pod labels to which the volume is assigned. I think that makes more sense.
 				voc.BlockStorageType,
+				pod, &vol,
 			),
 			AtRestEncryption: &voc.AtRestEncryption{}, // Not able to get the AtRestEncryption information, that must be retrieved directly from the storage
 		}
diff --git a/service/discovery/k8s/network.go b/service/discovery/k8s/network.go
index 36457c46..1d394ec3 100644
--- a/service/discovery/k8s/network.go
+++ b/service/discovery/k8s/network.go
@@ -85,7 +85,9 @@ func (d *k8sNetworkDiscovery) List() ([]voc.IsCloudResource, error) {
 }
 
 func (d *k8sNetworkDiscovery) handleService(service *corev1.Service) voc.IsNetwork {
-	var ports []uint16
+	var (
+		ports []uint16
+	)
 
 	for _, v := range service.Spec.Ports {
 		ports = append(ports, uint16(v.Port))
@@ -101,6 +103,7 @@ func (d *k8sNetworkDiscovery) handleService(service *corev1.Service) voc.IsNetwo
 				voc.GeoLocation{},
 				service.Labels,
 				voc.NetworkServiceType,
+				service,
 			),
 		},
 
@@ -125,6 +128,7 @@ func (d *k8sNetworkDiscovery) handleIngress(ingress *v1.Ingress) voc.IsNetwork {
 					voc.GeoLocation{},
 					ingress.Labels,
 					voc.LoadBalancerType,
+					ingress,
 				),
 			},
 			Ips:   nil, // TODO (oxisto): fill out IPs
diff --git a/service/discovery/k8s/storage.go b/service/discovery/k8s/storage.go
index 0e7496d4..d7098564 100644
--- a/service/discovery/k8s/storage.go
+++ b/service/discovery/k8s/storage.go
@@ -50,8 +50,8 @@ func (*k8sStorageDiscovery) Description() string {
 	return "Discover Kubernetes storage resources."
 }
 
-func (d k8sStorageDiscovery) List() ([]voc.IsCloudResource, error) {
-	list := []voc.IsCloudResource{}
+func (d *k8sStorageDiscovery) List() ([]voc.IsCloudResource, error) {
+	var list []voc.IsCloudResource
 
 	// Get persistent volumes
 	// Note: Volumes exist in the context of a pod and cannot be created on its own, PersistentVolumes are first class objects with its own lifecycle.
@@ -86,6 +86,7 @@ func (d *k8sStorageDiscovery) handlePV(pv *v1.PersistentVolume) voc.IsCloudResou
 			voc.GeoLocation{},
 			pv.Labels,
 			voc.BlockStorageType,
+			pv,
 		),
 		AtRestEncryption: &voc.AtRestEncryption{},
 	}
diff --git a/service/orchestrator/cloud_service.go b/service/orchestrator/cloud_service.go
index fc2df7a6..c4fdcb09 100644
--- a/service/orchestrator/cloud_service.go
+++ b/service/orchestrator/cloud_service.go
@@ -225,7 +225,7 @@ func (s *Service) CreateDefaultTargetCloudService() (service *orchestrator.Cloud
 			log.Infof("Created new default target cloud service: %s", service.Id)
 		}
 	} else {
-		log.Infof("Cloud services already exist.")
+		log.Infof("Default target cloud service already exist.")
 	}
 
 	return
diff --git a/service/orchestrator/metrics.go b/service/orchestrator/metrics.go
index e15e2e72..43317cf9 100644
--- a/service/orchestrator/metrics.go
+++ b/service/orchestrator/metrics.go
@@ -94,7 +94,8 @@ func (svc *Service) loadMetrics() (err error) {
 
 	}
 
-	return
+	// Here we have return nil, as the previous errors are only a warning and not a real error for the calling function.
+	return nil
 }
 
 // prepareMetric takes care of the heavy lifting of loading the default implementation and configuration of a particular
diff --git a/voc/file_storage_service.go b/voc/file_storage_service.go
new file mode 100644
index 00000000..9875eafb
--- /dev/null
+++ b/voc/file_storage_service.go
@@ -0,0 +1,36 @@
+// Auto-generated code by owl2java (https://github.com/clouditor/cloud-property-graph)
+
+// Copyright 2023 Fraunhofer AISEC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//           $$\                           $$\ $$\   $$\
+//           $$ |                          $$ |\__|  $$ |
+//  $$$$$$$\ $$ | $$$$$$\  $$\   $$\  $$$$$$$ |$$\ $$$$$$\    $$$$$$\   $$$$$$\
+// $$  _____|$$ |$$  __$$\ $$ |  $$ |$$  __$$ |$$ |\_$$  _|  $$  __$$\ $$  __$$\
+// $$ /      $$ |$$ /  $$ |$$ |  $$ |$$ /  $$ |$$ |  $$ |    $$ /  $$ |$$ | \__|
+// $$ |      $$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |$$\ $$ |  $$ |$$ |
+// \$$$$$$\  $$ |\$$$$$   |\$$$$$   |\$$$$$$  |$$ |  \$$$   |\$$$$$   |$$ |
+//  \_______|\__| \______/  \______/  \_______|\__|   \____/  \______/ \__|
+//
+// This file is part of Clouditor Community Edition.
+
+package voc
+
+var FileStorageServiceType = []string{"FileStorageService", "StorageService", "NetworkService", "Networking", "Resource"}
+
+// FileStorageService is an entity in our Cloud ontology. An file storage service represents the network service that is used to access a list of file storage shares. The storage itself is modelled as a FileStorage. The service has an http endpoint.
+type FileStorageService struct {
+	*StorageService
+	HttpEndpoint *HttpEndpoint `json:"httpEndpoint"`
+}
diff --git a/voc/voc.go b/voc/voc.go
index 9a25ddba..e7b8b6e1 100644
--- a/voc/voc.go
+++ b/voc/voc.go
@@ -29,12 +29,18 @@ package voc
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
+	"reflect"
 	"time"
 
 	"google.golang.org/protobuf/types/known/structpb"
 )
 
+var (
+	ErrConvertingStructToString = errors.New("error converting struct to string")
+)
+
 type IsCloudResource interface {
 	GetID() ResourceID
 	GetServiceID() string
@@ -43,6 +49,7 @@ type IsCloudResource interface {
 	GetType() []string
 	HasType(string) bool
 	GetCreationTime() *time.Time
+	GetRaw() string
 	Related() []string
 }
 
@@ -64,6 +71,7 @@ type Resource struct {
 	Type        []string          `json:"type"`
 	GeoLocation GeoLocation       `json:"geoLocation"`
 	Labels      map[string]string `json:"labels"`
+	Raw         string            `json:"raw"`
 }
 
 func (r *Resource) GetID() ResourceID {
@@ -98,6 +106,10 @@ func (r *Resource) HasType(resourceType string) (ok bool) {
 	return
 }
 
+func (r *Resource) GetRaw() string {
+	return r.Raw
+}
+
 func (r *Resource) GetCreationTime() *time.Time {
 	t := time.Unix(r.CreationTime, 0)
 	return &t
@@ -107,6 +119,30 @@ func (*Resource) Related() []string {
 	return []string{}
 }
 
+// ToStringInterface returns a string representation of the input
+func ToStringInterface(r []interface{}) (s string, err error) {
+	var (
+		b          []byte
+		rawInfoMap = make(map[string][]interface{})
+	)
+
+	if r == nil {
+		return "", nil
+	}
+
+	for i := range r {
+		typ := reflect.TypeOf(r[i]).String()
+
+		rawInfoMap[typ] = append(rawInfoMap[typ], r[i])
+	}
+
+	if b, err = json.Marshal(rawInfoMap); err != nil {
+		return "", fmt.Errorf("JSON marshal failed: %w", err)
+	}
+
+	return string(b), nil
+}
+
 func ToStruct(r IsCloudResource) (s *structpb.Value, err error) {
 	var b []byte
 


Test patch:
diff --git a/cli/commands/resource/resource_test.go b/cli/commands/resource/resource_test.go
index d8e50905..6ff86b22 100644
--- a/cli/commands/resource/resource_test.go
+++ b/cli/commands/resource/resource_test.go
@@ -183,6 +183,13 @@ func (mockIsCloudResource) GetCreationTime() *time.Time {
 	return nil
 }
 
+func (mockIsCloudResource) GetRaw() string {
+	return ""
+}
+
+func (mockIsCloudResource) SetRaw(_ string) {
+}
+
 func (mockIsCloudResource) Related() []string {
 	return []string{}
 }
diff --git a/cli/commands/service/discovery/discovery_test.go b/cli/commands/service/discovery/discovery_test.go
index ab979579..9b00742b 100644
--- a/cli/commands/service/discovery/discovery_test.go
+++ b/cli/commands/service/discovery/discovery_test.go
@@ -200,6 +200,13 @@ func (mockIsCloudResource) GetCreationTime() *time.Time {
 	return nil
 }
 
+func (mockIsCloudResource) GetRaw() string {
+	return ""
+}
+
+func (mockIsCloudResource) SetRaw(_ string) {
+}
+
 func (mockIsCloudResource) Related() []string {
 	return []string{}
 }
diff --git a/service/assessment/assessment_test.go b/service/assessment/assessment_test.go
index ba1a26c5..479e701d 100644
--- a/service/assessment/assessment_test.go
+++ b/service/assessment/assessment_test.go
@@ -952,11 +952,13 @@ func TestService_HandleEvidence(t *testing.T) {
 				s.evidenceStore.Opts = []grpc.DialOption{grpc.WithContextDialer(bufConnDialer)}
 			} else {
 				s.evidenceStore.Opts = []grpc.DialOption{grpc.WithContextDialer(nil)}
+				s.evidenceStore.Target = ""
 			}
 			if tt.fields.hasOrchestratorStream {
 				s.orchestrator.Opts = []grpc.DialOption{grpc.WithContextDialer(bufConnDialer)}
 			} else {
 				s.orchestrator.Opts = []grpc.DialOption{grpc.WithContextDialer(nil)}
+				s.orchestrator.Target = ""
 			}
 
 			// Two tests: 1st) wantErr function. 2nd) if wantErr false then check if the results are valid
diff --git a/service/discovery/aws/compute_test.go b/service/discovery/aws/compute_test.go
index ebdea4a9..e166c6c5 100644
--- a/service/discovery/aws/compute_test.go
+++ b/service/discovery/aws/compute_test.go
@@ -384,6 +384,7 @@ func TestComputeDiscovery_discoverFunctions(t *testing.T) {
 		functionAPI       LambdaAPI
 		isDiscovering     bool
 		awsConfig         *Client
+		csID              string
 	}
 	mockClient := &Client{
 		cfg: aws.Config{
@@ -403,19 +404,21 @@ func TestComputeDiscovery_discoverFunctions(t *testing.T) {
 			fields{
 				functionAPI: mockLambdaAPI{},
 				awsConfig:   mockClient,
+				csID:        testdata.MockCloudServiceID1,
 			},
 			//args: args{client: mockClient},
 			[]*voc.Function{
 				{Compute: &voc.Compute{
 					Resource: &voc.Resource{
 						ID:           mockFunction1ID,
-						ServiceID:    discovery.DefaultCloudServiceID,
+						ServiceID:    testdata.MockCloudServiceID1,
 						Name:         mockFunction1,
 						CreationTime: int64(0),
 						Type:         []string{"Function", "Compute", "Resource"},
 						GeoLocation: voc.GeoLocation{
 							Region: mockFunction1Region,
 						},
+						Raw: "{\"*types.FunctionConfiguration\":[{\"Architectures\":null,\"CodeSha256\":null,\"CodeSize\":0,\"DeadLetterConfig\":null,\"Description\":null,\"Environment\":null,\"EphemeralStorage\":null,\"FileSystemConfigs\":null,\"FunctionArn\":\"arn:aws:lambda:eu-central-1:123456789:function:mock-function:1\",\"FunctionName\":\"MockFunction1\",\"Handler\":null,\"ImageConfigResponse\":null,\"KMSKeyArn\":null,\"LastModified\":\"2012-11-01T22:08:41.0+00:00\",\"LastUpdateStatus\":\"\",\"LastUpdateStatusReason\":null,\"LastUpdateStatusReasonCode\":\"\",\"Layers\":null,\"MasterArn\":null,\"MemorySize\":null,\"PackageType\":\"\",\"RevisionId\":null,\"Role\":null,\"Runtime\":\"\",\"RuntimeVersionConfig\":null,\"SigningJobArn\":null,\"SigningProfileVersionArn\":null,\"SnapStart\":null,\"State\":\"\",\"StateReason\":null,\"StateReasonCode\":\"\",\"Timeout\":null,\"TracingConfig\":null,\"Version\":null,\"VpcConfig\":null}]}",
 					},
 				}},
 			},
@@ -437,6 +440,7 @@ func TestComputeDiscovery_discoverFunctions(t *testing.T) {
 				functionAPI:       tt.fields.functionAPI,
 				isDiscovering:     tt.fields.isDiscovering,
 				awsConfig:         tt.fields.awsConfig,
+				csID:              tt.fields.csID,
 			}
 			got, err := d.discoverFunctions()
 			if (err != nil) != tt.wantErr {
diff --git a/service/discovery/aws/storage_test.go b/service/discovery/aws/storage_test.go
index 58ecd7d5..cf5996ed 100644
--- a/service/discovery/aws/storage_test.go
+++ b/service/discovery/aws/storage_test.go
@@ -335,9 +335,10 @@ func TestAwsS3Discovery_getBuckets(t *testing.T) {
 // TestGetEncryptionAtRest tests the getEncryptionAtRest method
 func TestAwsS3Discovery_getEncryptionAtRest(t *testing.T) {
 	var (
-		encryptionAtRest   voc.IsAtRestEncryption
-		managedEncryption  *voc.ManagedKeyEncryption
-		customerEncryption *voc.CustomerKeyEncryption
+		encryptionAtRest    voc.IsAtRestEncryption
+		managedEncryption   *voc.ManagedKeyEncryption
+		customerEncryption  *voc.CustomerKeyEncryption
+		rawEncryptionAtRest *s3.GetBucketEncryptionOutput
 
 		ok            bool
 		err           error
@@ -354,45 +355,51 @@ func TestAwsS3Discovery_getEncryptionAtRest(t *testing.T) {
 	}
 
 	// First case: SSE-S3 encryption
-	encryptionAtRest, err = d.getEncryptionAtRest(&bucket{name: mockBucket1})
+	encryptionAtRest, rawEncryptionAtRest, err = d.getEncryptionAtRest(&bucket{name: mockBucket1})
 	assert.NoError(t, err)
 	managedEncryption, ok = encryptionAtRest.(*voc.ManagedKeyEncryption)
 	assert.True(t, ok)
 	assert.True(t, managedEncryption.Enabled)
 	assert.Equal(t, "AES256", managedEncryption.Algorithm)
+	assert.NotEmpty(t, rawEncryptionAtRest)
 
 	// Second case: SSE-KMS encryption
-	encryptionAtRest, err = d.getEncryptionAtRest(&bucket{name: mockBucket2, region: mockBucket2Region})
+	encryptionAtRest, rawEncryptionAtRest, err = d.getEncryptionAtRest(&bucket{name: mockBucket2, region: mockBucket2Region})
 	customerEncryption, ok = encryptionAtRest.(*voc.CustomerKeyEncryption)
 	assert.True(t, ok)
 	assert.NoError(t, err)
 	assert.True(t, customerEncryption.Enabled)
 	assert.Equal(t, "", customerEncryption.Algorithm)
 	assert.Equal(t, "arn:aws:kms:"+mockBucket2Region+":"+mockAccountID+":key/"+mockBucket2KeyId, customerEncryption.KeyUrl)
+	assert.NotEmpty(t, rawEncryptionAtRest)
 
 	// Third case: No encryption
-	encryptionAtRest, err = d.getEncryptionAtRest(&bucket{name: "mockbucket3"})
+	encryptionAtRest, rawEncryptionAtRest, err = d.getEncryptionAtRest(&bucket{name: "mockbucket3"})
 	assert.NoError(t, err)
 	assert.False(t, encryptionAtRest.IsEnabled())
+	assert.Empty(t, rawEncryptionAtRest)
 
 	// 4th case: Connection error
 	d = awsS3Discovery{
 		storageAPI:    mockS3APIWitHErrors{},
 		isDiscovering: false,
 	}
-	_, err = d.getEncryptionAtRest(&bucket{name: "mockbucket4"})
+	_, _, err = d.getEncryptionAtRest(&bucket{name: "mockbucket4"})
 	assert.Error(t, err)
 }
 
 // TestGetTransportEncryption tests the getTransportEncryption method
 func TestAwsS3Discovery_getTransportEncryption(t *testing.T) {
+	var rawBucketPolicy *s3.GetBucketPolicyOutput
+
 	// Case 1: Connection error
 	d := awsS3Discovery{
 		storageAPI:    mockS3APIWitHErrors{},
 		isDiscovering: false,
 	}
-	_, err := d.getTransportEncryption("")
+	_, rawBucketPolicy, err := d.getTransportEncryption("")
 	assert.Error(t, err)
+	assert.Empty(t, rawBucketPolicy)
 
 	d = awsS3Discovery{
 		storageAPI:    mockS3APINew{},
@@ -400,31 +407,34 @@ func TestAwsS3Discovery_getTransportEncryption(t *testing.T) {
 	}
 
 	// Case 2: Enforced
-	encryptionAtTransit, err := d.getTransportEncryption(mockBucket1)
+	encryptionAtTransit, rawBucketPolicy, err := d.getTransportEncryption(mockBucket1)
 	assert.NoError(t, err)
 	assert.True(t, encryptionAtTransit.Enabled)
 	assert.Equal(t, "TLS1.2", encryptionAtTransit.TlsVersion)
 	assert.True(t, encryptionAtTransit.Enforced)
+	assert.NotEmpty(t, rawBucketPolicy)
 
 	// Case 3: JSON failure
-	encryptionAtTransit, err = d.getTransportEncryption(mockBucket2)
+	encryptionAtTransit, rawBucketPolicy, err = d.getTransportEncryption(mockBucket2)
 	assert.Error(t, err)
 	assert.Nil(t, encryptionAtTransit)
+	assert.NotEmpty(t, rawBucketPolicy)
 
 	// Case 4: Not enforced
-	encryptionAtTransit, err = d.getTransportEncryption(mockBucket3)
+	encryptionAtTransit, rawBucketPolicy, err = d.getTransportEncryption(mockBucket3)
 	assert.NoError(t, err)
 	assert.True(t, encryptionAtTransit.Enabled)
 	assert.Equal(t, "TLS1.2", encryptionAtTransit.TlsVersion)
 	assert.False(t, encryptionAtTransit.Enforced)
+	assert.NotEmpty(t, rawBucketPolicy)
 
 	// Case 5: No bucket policy == not enforced
-	encryptionAtTransit, err = d.getTransportEncryption("")
+	encryptionAtTransit, rawBucketPolicy, err = d.getTransportEncryption("")
 	assert.NoError(t, err)
 	assert.True(t, encryptionAtTransit.Enabled)
 	assert.Equal(t, "TLS1.2", encryptionAtTransit.TlsVersion)
 	assert.False(t, encryptionAtTransit.Enforced)
-
+	assert.Empty(t, rawBucketPolicy)
 }
 
 // TestGetRegion tests the getRegion method
@@ -433,16 +443,19 @@ func TestAwsS3Discovery_getRegion(t *testing.T) {
 		storageAPI:    mockS3APINew{},
 		isDiscovering: false,
 	}
-	actualRegion, err := d.getRegion(mockBucket1)
+	actualRegion, rawRegion, err := d.getRegion(mockBucket1)
 	assert.NoError(t, err)
+	assert.NotEmpty(t, rawRegion)
 	assert.Equal(t, mockBucket1Region, actualRegion)
 
-	actualRegion, err = d.getRegion(mockBucket2)
+	actualRegion, rawRegion, err = d.getRegion(mockBucket2)
 	assert.NoError(t, err)
+	assert.NotEmpty(t, rawRegion)
 	assert.Equal(t, mockBucket2Region, actualRegion)
 
 	// Error case
-	_, err = d.getRegion("mockbucketNotAvailable")
+	_, rawRegion, err = d.getRegion("mockbucketNotAvailable")
+	assert.Empty(t, rawRegion)
 	assert.Error(t, err)
 
 }
@@ -489,6 +502,8 @@ func TestAwsS3Discovery_List(t *testing.T) {
 	assert.Equal(t, expectedResourceNames[0], resources[0].GetName())
 	log.Println("Testing type of resource", 1)
 	assert.True(t, resources[0].HasType("ObjectStorage"))
+	expectedRaw := "{\"**s3.GetBucketEncryptionOutput\":[{\"ServerSideEncryptionConfiguration\":{\"Rules\":[{\"ApplyServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\",\"KMSMasterKeyID\":null},\"BucketKeyEnabled\":false}]},\"ResultMetadata\":{}}],\"**s3.GetBucketPolicyOutput\":[{\"Policy\":\"{\\\"id\\\":\\\"Mock BucketPolicy ID 1234\\\",\\\"Version\\\":\\\"2012-10-17\\\",\\\"Statement\\\":[{\\\"Action\\\":\\\"s3:*\\\",\\\"Effect\\\":\\\"Deny\\\",\\\"Resource\\\":\\\"*\\\",\\\"Condition\\\":{\\\"aws:SecureTransport\\\":false}}]}\",\"ResultMetadata\":{}}],\"*[]interface {}\":[[{\"CreationDate\":\"2012-11-01T22:08:41Z\",\"Name\":\"mockbucket1\"},{\"LocationConstraint\":\"eu-central-1\",\"ResultMetadata\":{}}]],\"*aws.bucket\":[{}]}"
+	assert.Equal(t, expectedRaw, resources[0].GetRaw())
 
 	// Check second element: voc.ObjectStorageService
 	log.Println("Testing name for resource (bucket)", 2)
diff --git a/service/discovery/azure/azure_test.go b/service/discovery/azure/azure_test.go
index 49917e9a..ae007854 100644
--- a/service/discovery/azure/azure_test.go
+++ b/service/discovery/azure/azure_test.go
@@ -849,6 +849,7 @@ func Test_azureDiscovery_handleInstances(t *testing.T) {
 						CreationTime: 0,
 						Type:         voc.ObjectStorageType,
 						Labels:       nil,
+						Raw:          "{\"*armdataprotection.BackupInstanceResource\":[{\"properties\":{\"dataSourceInfo\":{\"datasourceType\":\"Microsoft.Storage/storageAccounts/blobServices\"}},\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1/backupInstances/account1-account1-22222222-2222-2222-2222-222222222222\",\"name\":\"account1-account1-22222222-2222-2222-2222-222222222222\"}],\"*armdataprotection.BackupVaultResource\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1\",\"location\":\"westeurope\",\"name\":\"backupAccount1\"}]}",
 					},
 				},
 			},
@@ -887,6 +888,7 @@ func Test_azureDiscovery_handleInstances(t *testing.T) {
 						CreationTime: 0,
 						Type:         voc.BlockStorageType,
 						Labels:       nil,
+						Raw:          "{\"*armdataprotection.BackupInstanceResource\":[{\"properties\":{\"dataSourceInfo\":{\"datasourceType\":\"Microsoft.Compute/disks\"}},\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1/backupInstances/disk1-disk1-22222222-2222-2222-2222-222222222222\",\"name\":\"disk1-disk1-22222222-2222-2222-2222-222222222222\"}],\"*armdataprotection.BackupVaultResource\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1\",\"location\":\"westeurope\",\"name\":\"backupAccount1\"}]}",
 					},
 				},
 			},
diff --git a/service/discovery/azure/compute_test.go b/service/discovery/azure/compute_test.go
index a6d83758..bbfe378d 100644
--- a/service/discovery/azure/compute_test.go
+++ b/service/discovery/azure/compute_test.go
@@ -631,6 +631,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							},
 							Labels: map[string]string{},
 							Type:   voc.BlockStorageType,
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/disks/disk1\",\"location\":\"eastus\",\"name\":\"disk1\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"\",\"type\":\"EncryptionAtRestWithPlatformKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[null]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -664,6 +665,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							},
 							Labels: map[string]string{},
 							Type:   voc.BlockStorageType,
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/disks/disk2\",\"location\":\"eastus\",\"name\":\"disk2\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/diskEncryptionSets/encryptionkeyvault1\",\"type\":\"EncryptionAtRestWithCustomerKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/diskEncryptionSets/encryption-keyvault1\",\"location\":\"germanywestcentral\",\"name\":\"encryptionkeyvault1\",\"properties\":{\"activeKey\":{\"keyUrl\":\"https://keyvault1.vault.azure.net/keys/customer-key/6273gdb374jz789hjm17819283748382\",\"sourceVault\":{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.KeyVault/vaults/keyvault1\"}}},\"type\":\"Microsoft.Compute/diskEncryptionSets\"}]}",
 						},
 						AtRestEncryption: &voc.CustomerKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -687,6 +689,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							},
 							Labels: map[string]string{},
 							Type:   voc.BlockStorageType,
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res2/providers/Microsoft.Compute/disks/disk3\",\"location\":\"eastus\",\"name\":\"disk3\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"\",\"type\":\"EncryptionAtRestWithPlatformKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[null]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -708,6 +711,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "westeurope",
 							},
+							Raw: "{\"*armdataprotection.BackupInstanceResource\":[{\"properties\":{\"dataSourceInfo\":{\"resourceID\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/disks/disk1\",\"datasourceType\":\"Microsoft.Compute/disks\"},\"policyInfo\":{\"policyId\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1/backupPolicies/backupPolicyDisk\"}},\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1/backupInstances/disk1-disk1-22222222-2222-2222-2222-222222222222\",\"name\":\"disk1-disk1-22222222-2222-2222-2222-222222222222\"}],\"*armdataprotection.BackupVaultResource\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1\",\"location\":\"westeurope\",\"name\":\"backupAccount1\"}]}",
 						},
 					},
 				},
@@ -723,6 +727,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm1\",\"location\":\"eastus\",\"name\":\"vm1\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://logstoragevm1.blob.core.windows.net/\"}},\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"123\"},{\"id\":\"234\"}]},\"osProfile\":{\"linuxConfiguration\":{\"patchSettings\":{\"patchMode\":\"AutomaticByPlatform\"}}},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_1\"}},{\"managedDisk\":{\"id\":\"data_disk_2\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{"123", "234"},
 					},
@@ -765,6 +770,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm2\",\"location\":\"eastus\",\"name\":\"vm2\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true}},\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"987\"},{\"id\":\"654\"}]},\"osProfile\":{\"windowsConfiguration\":{\"patchSettings\":{\"patchMode\":\"AutomaticByOS\"}}},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_2\"}},{\"managedDisk\":{\"id\":\"data_disk_3\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}}}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{"987", "654"},
 					},
@@ -807,6 +813,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm3\",\"location\":\"eastus\",\"name\":\"vm3\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{}}}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{},
 					},
@@ -852,6 +859,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "West Europe",
 							},
+							Raw: "{\"*armappservice.Site\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Web/sites/function1\",\"location\":\"West Europe\",\"name\":\"function1\",\"properties\":{\"siteConfig\":{\"linuxFxVersion\":\"PYTHON|3.8\"}},\"tags\":{\"testKey1\":\"testTag1\",\"testKey2\":\"testTag2\"}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{},
 					},
@@ -880,6 +888,7 @@ func Test_azureComputeDiscovery_List(t *testing.T) {
 							},
 							Labels: map[string]string{},
 							Type:   voc.BlockStorageType,
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res2/providers/Microsoft.Compute/disks/disk3\",\"location\":\"eastus\",\"name\":\"disk3\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"\",\"type\":\"EncryptionAtRestWithPlatformKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[null]}",
 						},
 						Backups: nil,
 						AtRestEncryption: &voc.ManagedKeyEncryption{
@@ -953,6 +962,7 @@ func Test_azureComputeDiscovery_discoverFunctions(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "West Europe",
 							},
+							Raw: "{\"*armappservice.Site\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Web/sites/function1\",\"location\":\"West Europe\",\"name\":\"function1\",\"properties\":{\"siteConfig\":{\"linuxFxVersion\":\"PYTHON|3.8\"}},\"tags\":{\"testKey1\":\"testTag1\",\"testKey2\":\"testTag2\"}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{},
 					},
@@ -1048,6 +1058,7 @@ func Test_azureComputeDiscovery_handleFunction(t *testing.T) {
 						GeoLocation: voc.GeoLocation{
 							Region: "West Europe",
 						},
+						Raw: "{\"*armappservice.Site\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Web/sites/function1\",\"location\":\"West Europe\",\"name\":\"function1\",\"properties\":{\"siteConfig\":{\"linuxFxVersion\":\"PYTHON|3.8\"}},\"tags\":{\"testKey1\":\"testTag1\",\"testKey2\":\"testTag2\"}}]}",
 					},
 					NetworkInterfaces: []voc.ResourceID{},
 				},
@@ -1106,6 +1117,7 @@ func Test_azureComputeDiscovery_discoverVirtualMachines(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm1\",\"location\":\"eastus\",\"name\":\"vm1\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://logstoragevm1.blob.core.windows.net/\"}},\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"123\"},{\"id\":\"234\"}]},\"osProfile\":{\"linuxConfiguration\":{\"patchSettings\":{\"patchMode\":\"AutomaticByPlatform\"}}},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_1\"}},{\"managedDisk\":{\"id\":\"data_disk_2\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{"123", "234"},
 					},
@@ -1148,6 +1160,7 @@ func Test_azureComputeDiscovery_discoverVirtualMachines(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm2\",\"location\":\"eastus\",\"name\":\"vm2\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true}},\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"987\"},{\"id\":\"654\"}]},\"osProfile\":{\"windowsConfiguration\":{\"patchSettings\":{\"patchMode\":\"AutomaticByOS\"}}},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_2\"}},{\"managedDisk\":{\"id\":\"data_disk_3\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}}}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{"987", "654"},
 					},
@@ -1190,6 +1203,7 @@ func Test_azureComputeDiscovery_discoverVirtualMachines(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm3\",\"location\":\"eastus\",\"name\":\"vm3\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{}}}}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{},
 					},
@@ -1342,6 +1356,7 @@ func Test_azureComputeDiscovery_handleVirtualMachines(t *testing.T) {
 						GeoLocation: voc.GeoLocation{
 							Region: "eastus",
 						},
+						Raw: "{\"*armcompute.VirtualMachine\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm1\",\"location\":\"eastus\",\"name\":\"vm1\",\"properties\":{\"diagnosticsProfile\":{\"bootDiagnostics\":{\"enabled\":true,\"storageUri\":\"https://logstoragevm1.blob.core.windows.net/\"}},\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"123\"},{\"id\":\"234\"}]},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_1\"}},{\"managedDisk\":{\"id\":\"data_disk_2\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}},\"timeCreated\":\"2017-05-24T13:28:53.004540398Z\"}}]}",
 					},
 					NetworkInterfaces: []voc.ResourceID{"123", "234"},
 				},
@@ -1615,6 +1630,7 @@ func Test_azureComputeDiscovery_discoverBlockStorage(t *testing.T) {
 							},
 							Type:   []string{"BlockStorage", "Storage", "Resource"},
 							Labels: map[string]string{},
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/disks/disk1\",\"location\":\"eastus\",\"name\":\"disk1\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"\",\"type\":\"EncryptionAtRestWithPlatformKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[null]}",
 						},
 
 						AtRestEncryption: &voc.ManagedKeyEncryption{
@@ -1637,6 +1653,7 @@ func Test_azureComputeDiscovery_discoverBlockStorage(t *testing.T) {
 							},
 							Type:   []string{"BlockStorage", "Storage", "Resource"},
 							Labels: map[string]string{},
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/disks/disk2\",\"location\":\"eastus\",\"name\":\"disk2\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/diskEncryptionSets/encryptionkeyvault1\",\"type\":\"EncryptionAtRestWithCustomerKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/diskEncryptionSets/encryption-keyvault1\",\"location\":\"germanywestcentral\",\"name\":\"encryptionkeyvault1\",\"properties\":{\"activeKey\":{\"keyUrl\":\"https://keyvault1.vault.azure.net/keys/customer-key/6273gdb374jz789hjm17819283748382\",\"sourceVault\":{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.KeyVault/vaults/keyvault1\"}}},\"type\":\"Microsoft.Compute/diskEncryptionSets\"}]}",
 						},
 						AtRestEncryption: &voc.CustomerKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -1659,6 +1676,7 @@ func Test_azureComputeDiscovery_discoverBlockStorage(t *testing.T) {
 							},
 							Labels: map[string]string{},
 							Type:   voc.BlockStorageType,
+							Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res2/providers/Microsoft.Compute/disks/disk3\",\"location\":\"eastus\",\"name\":\"disk3\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"\",\"type\":\"EncryptionAtRestWithPlatformKey\"},\"timeCreated\":\"2017-05-24T13:28:53.4540398Z\"},\"type\":\"Microsoft.Compute/disks\"}],\"*armcompute.DiskEncryptionSet\":[null]}",
 						},
 
 						AtRestEncryption: &voc.ManagedKeyEncryption{
@@ -1786,6 +1804,7 @@ func Test_azureComputeDiscovery_handleBlockStorage(t *testing.T) {
 							Region: "eastus",
 						},
 						Labels: map[string]string{},
+						Raw:    "{\"*armcompute.Disk\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/disks/disk1\",\"location\":\"eastus\",\"name\":\"disk1\",\"properties\":{\"encryption\":{\"diskEncryptionSetId\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/diskEncryptionSets/encryptionkeyvault1\",\"type\":\"EncryptionAtRestWithCustomerKey\"},\"timeCreated\":\"2017-05-24T13:28:53.004540398Z\"}}],\"*armcompute.DiskEncryptionSet\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/diskEncryptionSets/encryption-keyvault1\",\"location\":\"germanywestcentral\",\"name\":\"encryptionkeyvault1\",\"properties\":{\"activeKey\":{\"keyUrl\":\"https://keyvault1.vault.azure.net/keys/customer-key/6273gdb374jz789hjm17819283748382\",\"sourceVault\":{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.KeyVault/vaults/keyvault1\"}}},\"type\":\"Microsoft.Compute/diskEncryptionSets\"}]}",
 					},
 
 					AtRestEncryption: &voc.CustomerKeyEncryption{
@@ -1899,7 +1918,7 @@ func Test_azureComputeDiscovery_blockStorageAtRestEncryption(t *testing.T) {
 			d := &azureComputeDiscovery{
 				azureDiscovery: tt.fields.azureDiscovery,
 			}
-			got, err := d.blockStorageAtRestEncryption(tt.args.disk)
+			got, _, err := d.blockStorageAtRestEncryption(tt.args.disk)
 			if !tt.wantErr(t, err) {
 				return
 			}
@@ -1973,7 +1992,7 @@ func Test_azureComputeDiscovery_keyURL(t *testing.T) {
 			d := &azureComputeDiscovery{
 				azureDiscovery: tt.fields.azureDiscovery,
 			}
-			got, err := d.keyURL(tt.args.diskEncryptionSetID)
+			got, _, err := d.keyURL(tt.args.diskEncryptionSetID)
 			if !tt.wantErr(t, err, fmt.Sprintf("keyURL(%v)", tt.args.diskEncryptionSetID)) {
 				return
 			}
diff --git a/service/discovery/azure/network_test.go b/service/discovery/azure/network_test.go
index 489318ef..6ad4b5f2 100644
--- a/service/discovery/azure/network_test.go
+++ b/service/discovery/azure/network_test.go
@@ -294,6 +294,7 @@ func Test_azureNetworkDiscovery_List(t *testing.T) {
 							},
 							Type:   voc.NetworkInterfaceType,
 							Labels: map[string]string{},
+							Raw:    "{\"*armnetwork.Interface\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkInterfaces/iface1\",\"location\":\"eastus\",\"name\":\"iface1\",\"properties\":{\"networkSecurityGroup\":{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkSecurityGroups/nsg1\",\"location\":\"eastus\",\"name\":\"nsg1\",\"properties\":{\"securityRules\":[{\"properties\":{\"access\":\"Deny\",\"sourcePortRange\":\"*\"}},{\"properties\":{\"access\":\"Deny\",\"sourcePortRange\":\"*\"}}]}}}}]}",
 						},
 					},
 					AccessRestriction: &voc.L3Firewall{
@@ -312,6 +313,7 @@ func Test_azureNetworkDiscovery_List(t *testing.T) {
 								},
 								Type:   voc.LoadBalancerType,
 								Labels: map[string]string{},
+								Raw:    "{\"*armnetwork.LoadBalancer\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/loadBalancers/lb1\",\"location\":\"eastus\",\"name\":\"lb1\",\"properties\":{\"frontendIPConfigurations\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/loadBalancers/lb1/frontendIPConfigurations/b9cb3645-25d0-4288-910a-020563f63b1c\",\"name\":\"b9cb3645-25d0-4288-910a-020563f63b1c\",\"properties\":{\"publicIPAddress\":{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/publicIPAddresses/test-b9cb3645-25d0-4288-910a-020563f63b1c\",\"properties\":{\"ipAddress\":\"111.222.333.444\"}}}}],\"loadBalancingRules\":[{\"properties\":{\"frontendPort\":1234}},{\"properties\":{\"frontendPort\":5678}}]}}]}",
 							},
 						},
 						Ips:   []string{"111.222.333.444"},
@@ -331,6 +333,7 @@ func Test_azureNetworkDiscovery_List(t *testing.T) {
 								},
 								Type:   voc.LoadBalancerType,
 								Labels: map[string]string{},
+								Raw:    "{\"*armnetwork.LoadBalancer\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/loadBalancers/lb2\",\"location\":\"eastus\",\"name\":\"lb2\",\"properties\":{\"frontendIPConfigurations\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/loadBalancers/lb1/frontendIPConfigurations/b9cb3645-25d0-4288-910a-020563f63b1c\",\"name\":\"b9cb3645-25d0-4288-910a-020563f63b1c\",\"properties\":{}}],\"loadBalancingRules\":[{\"properties\":{\"frontendPort\":1234}},{\"properties\":{\"frontendPort\":5678}}]}}]}",
 							},
 						},
 						Ports: []uint16{1234, 5678},
@@ -350,6 +353,7 @@ func Test_azureNetworkDiscovery_List(t *testing.T) {
 								},
 								Type:   voc.LoadBalancerType,
 								Labels: map[string]string{},
+								Raw:    "{\"*armnetwork.LoadBalancer\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/loadBalancers/lb3\",\"location\":\"eastus\",\"name\":\"lb3\",\"properties\":{\"frontendIPConfigurations\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/loadBalancers/lb1/frontendIPConfigurations/b9cb3645-25d0-4288-910a-020563f63b1c\",\"name\":\"b9cb3645-25d0-4288-910a-020563f63b1c\",\"properties\":{\"publicIPAddress\":{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/publicIPAddresses/test-b9cb3645-25d0-4288-910a-020563f63b1d\"}}}],\"loadBalancingRules\":[{\"properties\":{\"frontendPort\":1234}},{\"properties\":{\"frontendPort\":5678}}]}}]}",
 							},
 						},
 						Ports: []uint16{1234, 5678},
@@ -369,6 +373,7 @@ func Test_azureNetworkDiscovery_List(t *testing.T) {
 								},
 								Type:   voc.LoadBalancerType,
 								Labels: map[string]string{},
+								Raw:    "{\"*armnetwork.ApplicationGateway\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/applicationGateways/appgw1\",\"location\":\"eastus\",\"name\":\"appgw1\",\"properties\":{\"webApplicationFirewallConfiguration\":{\"enabled\":true}}}]}",
 							},
 						},
 					},
diff --git a/service/discovery/azure/storage_test.go b/service/discovery/azure/storage_test.go
index 4501b56b..b2cb5022 100644
--- a/service/discovery/azure/storage_test.go
+++ b/service/discovery/azure/storage_test.go
@@ -436,6 +436,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\",\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/blobServices/default/containers/container1\",\"name\":\"container1\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"Container\"},\"type\":\"Microsoft.Storage/storageAccounts/blobServices/containers\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -477,6 +478,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\",\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/blobServices/default/containers/container2\",\"name\":\"container2\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"Container\"},\"type\":\"Microsoft.Storage/storageAccounts/blobServices/containers\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -517,6 +519,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\",\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}],\"*armstorage.FileShareItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/fileServices/default/shares/fileshare1\",\"name\":\"fileshare1\",\"type\":\"Microsoft.Storage/storageAccounts/fileServices/shares\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -544,6 +547,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\",\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}],\"*armstorage.FileShareItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/fileServices/default/shares/fileshare2\",\"name\":\"fileshare2\",\"type\":\"Microsoft.Storage/storageAccounts/fileServices/shares\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -580,6 +584,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 									GeoLocation: voc.GeoLocation{
 										Region: "eastus",
 									},
+									Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\",\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}]}",
 								},
 							},
 							TransportEncryption: &voc.TransportEncryption{
@@ -612,6 +617,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account2\",\"location\":\"eastus\",\"name\":\"account2\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Keyvault\",\"keyvaultproperties\":{\"keyvaulturi\":\"https://testvault.vault.azure.net/keys/testkey/123456\"},\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account2/blobServices/default/containers/container3\",\"name\":\"container3\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"None\"},\"type\":\"Microsoft.Storage/storageAccounts/blobServices/containers\"}]}",
 						},
 						AtRestEncryption: &voc.CustomerKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -643,6 +649,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account2\",\"location\":\"eastus\",\"name\":\"account2\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Keyvault\",\"keyvaultproperties\":{\"keyvaulturi\":\"https://testvault.vault.azure.net/keys/testkey/123456\"},\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account2/blobServices/default/containers/container4\",\"name\":\"container4\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"None\"},\"type\":\"Microsoft.Storage/storageAccounts/blobServices/containers\"}]}",
 						},
 						AtRestEncryption: &voc.CustomerKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -680,6 +687,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 									GeoLocation: voc.GeoLocation{
 										Region: "eastus",
 									},
+									Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account2\",\"location\":\"eastus\",\"name\":\"account2\",\"properties\":{\"allowBlobPublicAccess\":false,\"creationTime\":\"2017-05-24T13:28:53.4540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Keyvault\",\"keyvaultproperties\":{\"keyvaulturi\":\"https://testvault.vault.azure.net/keys/testkey/123456\"},\"services\":{\"blob\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"},\"file\":{\"enabled\":true,\"keyType\":\"Account\",\"lastEnabledTime\":\"2019-12-11T20:49:31.703614Z\"}}},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net/\",\"file\":\"https://account1.file.core.windows.net/\"},\"supportsHttpsTrafficOnly\":true}}]}",
 								},
 							},
 							TransportEncryption: &voc.TransportEncryption{
@@ -711,6 +719,7 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "westeurope",
 							},
+							Raw: "{\"*armdataprotection.BackupInstanceResource\":[{\"properties\":{\"dataSourceInfo\":{\"resourceID\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"datasourceType\":\"Microsoft.Storage/storageAccounts/blobServices\"},\"policyInfo\":{\"policyId\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1/backupPolicies/backupPolicyContainer\"}},\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1/backupInstances/account1-account1-22222222-2222-2222-2222-222222222222\",\"name\":\"account1-account1-22222222-2222-2222-2222-222222222222\"}],\"*armdataprotection.BackupVaultResource\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/res1/providers/Microsoft.DataProtection/backupVaults/backupAccount1\",\"location\":\"westeurope\",\"name\":\"backupAccount1\"}]}",
 						},
 					},
 				},
@@ -1067,6 +1076,7 @@ func Test_handleFileStorage(t *testing.T) {
 						},
 						Labels: map[string]string{},
 						Type:   voc.FileStorageType,
+						Raw:    "{\"*armstorage.Account\":[{\"location\":\"eastus\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"}}}],\"*armstorage.FileShareItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/fileServices/default/shares/fileshare1\",\"name\":\"fileShare1\"}]}",
 					},
 					AtRestEncryption: &voc.ManagedKeyEncryption{
 						AtRestEncryption: &voc.AtRestEncryption{
@@ -1197,6 +1207,7 @@ func Test_azureStorageDiscovery_handleStorageAccount(t *testing.T) {
 									Region: accountRegion,
 								},
 								Labels: map[string]string{},
+								Raw:    "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"},\"minimumTlsVersion\":\"TLS1_2\",\"primaryEndpoints\":{\"blob\":\"https://account1.blob.core.windows.net\"},\"supportsHttpsTrafficOnly\":true}}]}",
 							},
 						},
 						TransportEncryption: &voc.TransportEncryption{
@@ -1329,6 +1340,7 @@ func Test_handleObjectStorage(t *testing.T) {
 						},
 						Labels: map[string]string{},
 						Type:   voc.ObjectStorageType,
+						Raw:    "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"}}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/blobServices/default/containers/container1\",\"name\":\"container1\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"None\"}}]}",
 					},
 					AtRestEncryption: &voc.ManagedKeyEncryption{
 						AtRestEncryption: &voc.AtRestEncryption{
@@ -1432,6 +1444,7 @@ func Test_azureStorageDiscovery_discoverFileStorages(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"}}}],\"*armstorage.FileShareItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/fileServices/default/shares/fileshare1\",\"name\":\"fileshare1\",\"type\":\"Microsoft.Storage/storageAccounts/fileServices/shares\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -1459,6 +1472,7 @@ func Test_azureStorageDiscovery_discoverFileStorages(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"}}}],\"*armstorage.FileShareItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/fileServices/default/shares/fileshare2\",\"name\":\"fileshare2\",\"type\":\"Microsoft.Storage/storageAccounts/fileServices/shares\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -1563,6 +1577,7 @@ func Test_azureStorageDiscovery_discoverObjectStorages(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"}}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/blobServices/default/containers/container1\",\"name\":\"container1\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"Container\"},\"type\":\"Microsoft.Storage/storageAccounts/blobServices/containers\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
@@ -1592,6 +1607,7 @@ func Test_azureStorageDiscovery_discoverObjectStorages(t *testing.T) {
 							GeoLocation: voc.GeoLocation{
 								Region: "eastus",
 							},
+							Raw: "{\"*armstorage.Account\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1\",\"location\":\"eastus\",\"name\":\"account1\",\"properties\":{\"creationTime\":\"2017-05-24T13:28:53.004540398Z\",\"encryption\":{\"keySource\":\"Microsoft.Storage\"}}}],\"*armstorage.ListContainerItem\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Storage/storageAccounts/account1/blobServices/default/containers/container2\",\"name\":\"container2\",\"properties\":{\"hasImmutabilityPolicy\":false,\"publicAccess\":\"Container\"},\"type\":\"Microsoft.Storage/storageAccounts/blobServices/containers\"}]}",
 						},
 						AtRestEncryption: &voc.ManagedKeyEncryption{
 							AtRestEncryption: &voc.AtRestEncryption{
diff --git a/service/discovery/discovery_test.go b/service/discovery/discovery_test.go
index 0a5323ae..c69aaf8d 100644
--- a/service/discovery/discovery_test.go
+++ b/service/discovery/discovery_test.go
@@ -487,9 +487,9 @@ type mockDiscoverer struct {
 	csID     string
 }
 
-func (mockDiscoverer) Name() string { return "just mocking" }
+func (*mockDiscoverer) Name() string { return "just mocking" }
 
-func (m mockDiscoverer) List() ([]voc.IsCloudResource, error) {
+func (m *mockDiscoverer) List() ([]voc.IsCloudResource, error) {
 	switch m.testCase {
 	case 0:
 		return nil, fmt.Errorf("mock error in List()")
@@ -499,10 +499,11 @@ func (m mockDiscoverer) List() ([]voc.IsCloudResource, error) {
 		return []voc.IsCloudResource{
 			&voc.ObjectStorage{
 				Storage: &voc.Storage{
-					Resource: discovery.NewResource(&m,
+					Resource: discovery.NewResource(m,
 						"some-id",
 						"some-name", nil, voc.GeoLocation{}, nil,
-						[]string{"ObjectStorage", "Storage", "Resource"}),
+						[]string{"ObjectStorage", "Storage", "Resource"},
+						map[string][]interface{}{"raw": {"raw"}}),
 				},
 			},
 			&voc.ObjectStorageService{
@@ -510,10 +511,11 @@ func (m mockDiscoverer) List() ([]voc.IsCloudResource, error) {
 					Storage: []voc.ResourceID{"some-id"},
 					NetworkService: &voc.NetworkService{
 						Networking: &voc.Networking{
-							Resource: discovery.NewResource(&m,
+							Resource: discovery.NewResource(m,
 								"some-storage-account-id",
 								"some-storage-account-name", nil, voc.GeoLocation{}, nil,
-								[]string{"StorageService", "NetworkService", "Networking", "Resource"}),
+								[]string{"StorageService", "NetworkService", "Networking", "Resource"},
+								map[string][]interface{}{"raw": {"raw"}}),
 						},
 					},
 				},
@@ -654,6 +656,13 @@ func (mockIsCloudResource) GetCreationTime() *time.Time {
 	return nil
 }
 
+func (mockIsCloudResource) GetRaw() string {
+	return ""
+}
+
+func (mockIsCloudResource) SetRaw(_ string) {
+}
+
 func (mockIsCloudResource) Related() []string {
 	return []string{}
 }
diff --git a/service/discovery/k8s/compute_test.go b/service/discovery/k8s/compute_test.go
index 898e351d..1935011b 100644
--- a/service/discovery/k8s/compute_test.go
+++ b/service/discovery/k8s/compute_test.go
@@ -27,18 +27,62 @@ package k8s
 
 import (
 	"context"
+	"reflect"
 	"testing"
 
+	"clouditor.io/clouditor/api/discovery"
 	"clouditor.io/clouditor/internal/testdata"
 	"clouditor.io/clouditor/voc"
-
 	"github.com/stretchr/testify/assert"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/fake"
 )
 
-func TestListPods(t *testing.T) {
+func TestNewKubernetesComputeDiscovery(t *testing.T) {
+	type args struct {
+		intf           kubernetes.Interface
+		cloudServiceID string
+	}
+	tests := []struct {
+		name string
+		args args
+		want discovery.Discoverer
+	}{
+		{
+			name: "empty input",
+			want: &k8sComputeDiscovery{
+				k8sDiscovery: k8sDiscovery{},
+			},
+		},
+		{
+			name: "Happy path",
+			args: args{
+				intf:           &fake.Clientset{},
+				cloudServiceID: testdata.MockCloudServiceID1,
+			},
+			want: &k8sComputeDiscovery{
+				k8sDiscovery: k8sDiscovery{
+					intf: &fake.Clientset{},
+					csID: testdata.MockCloudServiceID1,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewKubernetesComputeDiscovery(tt.args.intf, tt.args.cloudServiceID)
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewKubernetesComputeDiscovery() = %v, want %v", got, tt.want)
+			}
+
+			assert.Equal(t, "Kubernetes Compute", got.Name())
+		})
+	}
+}
+
+func Test_k8sComputeDiscovery_List(t *testing.T) {
 	var (
 		volumeName      = "my-volume"
 		diskName        = "my-disk"
@@ -76,55 +120,96 @@ func TestListPods(t *testing.T) {
 		t.Fatalf("error injecting pod add: %v", err)
 	}
 
-	d := NewKubernetesComputeDiscovery(client, testdata.MockCloudServiceID1)
+	type fields struct {
+		discovery discovery.Discoverer
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		want    assert.ValueAssertionFunc
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name: "Happy path",
+			fields: fields{
+				NewKubernetesComputeDiscovery(client, testdata.MockCloudServiceID1),
+			},
+			want: func(tt assert.TestingT, i1 interface{}, i2 ...interface{}) bool {
+				cloudResource, ok := i1.([]voc.IsCloudResource)
+				if !assert.True(tt, ok) {
+					return false
+				}
+				container, ok := cloudResource[0].(*voc.Container)
+				if !assert.True(tt, ok) {
+					return false
+				}
+				// Create expected voc.Container
+				expectedContainer := &voc.Container{
+					Compute: &voc.Compute{
+						Resource: &voc.Resource{
+							ID:        voc.ResourceID(podID),
+							ServiceID: testdata.MockCloudServiceID1,
+							Name:      podName,
+							Type:      []string{"Container", "Compute", "Resource"},
+							Labels:    podLabel,
+							Raw:       "",
+						},
+						NetworkInterfaces: []voc.ResourceID{
+							voc.ResourceID(podNamespace),
+						},
+					},
+				}
+
+				// Delete creation time
+				assert.NotNil(t, container.CreationTime)
+				container.CreationTime = 0
+
+				// Delete raw. We have to delete it, because of the creation time included in the raw field.
+				assert.NotNil(t, container.Raw)
+				container.Raw = ""
 
-	list, err := d.List()
+				assert.True(t, ok)
+				assert.Equal(t, expectedContainer, container)
 
-	assert.NoError(t, err)
-	assert.NotNil(t, list)
+				// Check volume
+				volume, ok := cloudResource[1].(*voc.BlockStorage)
+				// Create expected voc.BlockStorage
+				expectedVolume := &voc.BlockStorage{
+					Storage: &voc.Storage{
+						Resource: &voc.Resource{
+							ID:           voc.ResourceID(volumeName),
+							ServiceID:    testdata.MockCloudServiceID1,
+							Name:         volumeName,
+							CreationTime: 0,
+							Type:         []string{"BlockStorage", "Storage", "Resource"},
+							GeoLocation: voc.GeoLocation{
+								Region: "",
+							},
+						},
+						AtRestEncryption: &voc.AtRestEncryption{},
+					},
+				}
 
-	// Check container
-	container, ok := list[0].(*voc.Container)
+				// Delete raw. We have to delete it, because of the creation time included in the raw field.
+				assert.NotNil(t, volume.Raw)
+				volume.Raw = ""
 
-	// Create expected voc.Container
-	expectedContainer := &voc.Container{
-		Compute: &voc.Compute{
-			Resource: &voc.Resource{
-				ID:           voc.ResourceID(podID),
-				ServiceID:    testdata.MockCloudServiceID1,
-				Name:         podName,
-				CreationTime: podCreationTime.Unix(),
-				Type:         []string{"Container", "Compute", "Resource"},
-				Labels:       podLabel,
-			},
-			NetworkInterfaces: []voc.ResourceID{
-				voc.ResourceID(podNamespace),
+				assert.True(t, ok)
+				return assert.Equal(t, expectedVolume, volume)
 			},
+			wantErr: assert.NoError,
 		},
 	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := tt.fields.discovery
 
-	assert.True(t, ok)
-	assert.Equal(t, expectedContainer, container)
-
-	// Check volume
-	volume, ok := list[1].(*voc.BlockStorage)
-	// Create expected voc.BlockStorage
-	expectedVolume := &voc.BlockStorage{
-		Storage: &voc.Storage{
-			Resource: &voc.Resource{
-				ID:           voc.ResourceID(volumeName),
-				ServiceID:    testdata.MockCloudServiceID1,
-				Name:         volumeName,
-				CreationTime: 0,
-				Type:         []string{"BlockStorage", "Storage", "Resource"},
-				GeoLocation: voc.GeoLocation{
-					Region: "",
-				},
-			},
-			AtRestEncryption: &voc.AtRestEncryption{},
-		},
-	}
+			got, err := d.List()
+			tt.wantErr(t, err)
 
-	assert.True(t, ok)
-	assert.Equal(t, expectedVolume, volume)
+			if tt.want != nil {
+				tt.want(t, got)
+			}
+		})
+	}
 }
diff --git a/service/discovery/k8s/network_test.go b/service/discovery/k8s/network_test.go
index e9bd5868..a72aaccb 100644
--- a/service/discovery/k8s/network_test.go
+++ b/service/discovery/k8s/network_test.go
@@ -27,8 +27,10 @@ package k8s
 
 import (
 	"context"
+	"reflect"
 	"testing"
 
+	"clouditor.io/clouditor/api/discovery"
 	"clouditor.io/clouditor/internal/testdata"
 	"clouditor.io/clouditor/voc"
 
@@ -36,9 +38,52 @@ import (
 	v1 "k8s.io/api/core/v1"
 	networkingv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/fake"
 )
 
+func TestNewKubernetesNetworkDiscovery(t *testing.T) {
+	type args struct {
+		intf           kubernetes.Interface
+		cloudServiceID string
+	}
+	tests := []struct {
+		name string
+		args args
+		want discovery.Discoverer
+	}{
+		{
+			name: "empty input",
+			want: &k8sNetworkDiscovery{
+				k8sDiscovery: k8sDiscovery{},
+			},
+		},
+		{
+			name: "Happy path",
+			args: args{
+				intf:           &fake.Clientset{},
+				cloudServiceID: testdata.MockCloudServiceID1,
+			},
+			want: &k8sNetworkDiscovery{
+				k8sDiscovery: k8sDiscovery{
+					intf: &fake.Clientset{},
+					csID: testdata.MockCloudServiceID1,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewKubernetesNetworkDiscovery(tt.args.intf, tt.args.cloudServiceID)
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewKubernetesNetworkDiscovery() = %v, want %v", got, tt.want)
+			}
+
+			assert.Equal(t, "Kubernetes Network", got.Name())
+		})
+	}
+}
+
 func TestListIngresses(t *testing.T) {
 	client := fake.NewSimpleClientset()
 
diff --git a/service/discovery/k8s/storage_test.go b/service/discovery/k8s/storage_test.go
index 87259b49..ac498b9e 100644
--- a/service/discovery/k8s/storage_test.go
+++ b/service/discovery/k8s/storage_test.go
@@ -27,8 +27,10 @@ package k8s
 
 import (
 	"context"
+	"reflect"
 	"testing"
 
+	"clouditor.io/clouditor/api/discovery"
 	"clouditor.io/clouditor/internal/testdata"
 	"clouditor.io/clouditor/voc"
 
@@ -36,9 +38,52 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/fake"
 )
 
+func TestNewKubernetesStorageDiscovery(t *testing.T) {
+	type args struct {
+		intf           kubernetes.Interface
+		cloudServiceID string
+	}
+	tests := []struct {
+		name string
+		args args
+		want discovery.Discoverer
+	}{
+		{
+			name: "empty input",
+			want: &k8sStorageDiscovery{
+				k8sDiscovery: k8sDiscovery{},
+			},
+		},
+		{
+			name: "Happy path",
+			args: args{
+				intf:           &fake.Clientset{},
+				cloudServiceID: testdata.MockCloudServiceID1,
+			},
+			want: &k8sStorageDiscovery{
+				k8sDiscovery: k8sDiscovery{
+					intf: &fake.Clientset{},
+					csID: testdata.MockCloudServiceID1,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewKubernetesStorageDiscovery(tt.args.intf, tt.args.cloudServiceID)
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("NewKubernetesStorageDiscovery() = %v, want %v", got, tt.want)
+			}
+
+			assert.Equal(t, "Kubernetes Storage", got.Name())
+		})
+	}
+}
+
 func Test_k8sStorageDiscovery_List(t *testing.T) {
 
 	var (
@@ -100,6 +145,10 @@ func Test_k8sStorageDiscovery_List(t *testing.T) {
 		},
 	}
 
+	// Delete raw. We have to delete it, because of the creation time included in the raw field.
+	assert.NotNil(t, volume.Raw)
+	volume.Raw = ""
+
 	assert.True(t, ok)
 	assert.Equal(t, expectedVolume, volume)
 }
diff --git a/service/orchestrator/metrics_test.go b/service/orchestrator/metrics_test.go
index e43d43eb..1c4d1fcb 100644
--- a/service/orchestrator/metrics_test.go
+++ b/service/orchestrator/metrics_test.go
@@ -75,16 +75,6 @@ func TestService_loadMetrics(t *testing.T) {
 				return assert.ErrorIs(t, err, os.ErrNotExist)
 			},
 		},
-		{
-			name: "storage error",
-			fields: fields{
-				metricsFile: "metrics.json",
-				storage:     &testutil.StorageWithError{SaveErr: ErrSomeError},
-			},
-			wantErr: func(tt assert.TestingT, err error, i ...interface{}) bool {
-				return assert.ErrorIs(t, err, ErrSomeError)
-			},
-		},
 		{
 			name: "custom loading function with error",
 			fields: fields{
diff --git a/voc/voc_test.go b/voc/voc_test.go
index 7cad4f63..375f7ccf 100644
--- a/voc/voc_test.go
+++ b/voc/voc_test.go
@@ -29,8 +29,15 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"google.golang.org/protobuf/types/known/structpb"
 )
 
+type test struct {
+	A int    `json:"a"`
+	B string `json:"b"`
+	C bool   `json:"c"`
+}
+
 func TestAuthenticityInterface(t *testing.T) {
 	tests := []struct {
 		isAuthenticity IsAuthenticity
@@ -92,3 +99,84 @@ func TestAuthorizationInterface(t *testing.T) {
 		})
 	}
 }
+
+func TestToStringInterface(t *testing.T) {
+	var tmp = []interface{}{}
+
+	s, err := ToStringInterface(tmp)
+	assert.NoError(t, err)
+	assert.Equal(t, "{}", s)
+
+	tmp = append(tmp, test{
+		A: 200,
+		B: "TestStruct",
+		C: false,
+	})
+	s, err = ToStringInterface(tmp)
+	assert.NoError(t, err)
+	assert.Equal(t, "{\"voc.test\":[{\"a\":200,\"b\":\"TestStruct\",\"c\":false}]}", s)
+}
+
+func TestToStruct(t *testing.T) {
+	type args struct {
+		r IsCloudResource
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantS   *structpb.Value
+		wantErr assert.ErrorAssertionFunc
+	}{
+		{
+			name:    "Empty input",
+			args:    args{},
+			wantS:   nil,
+			wantErr: assert.NoError,
+		},
+		{
+			name: "Happy path",
+			args: args{
+				r: &Resource{
+					ID:   "my-resource-id",
+					Name: "my-resource-name",
+					Type: ObjectStorageType,
+				},
+			},
+			wantS: &structpb.Value{
+				Kind: &structpb.Value_StructValue{
+					StructValue: &structpb.Struct{
+						Fields: map[string]*structpb.Value{
+							"creationTime": structpb.NewNumberValue(0),
+							"geoLocation": structpb.NewStructValue(&structpb.Struct{
+								Fields: map[string]*structpb.Value{
+									"region": structpb.NewStringValue(""),
+								}}),
+							"id":        structpb.NewStringValue("my-resource-id"),
+							"labels":    structpb.NewNullValue(),
+							"name":      structpb.NewStringValue("my-resource-name"),
+							"raw":       structpb.NewStringValue(""),
+							"serviceId": structpb.NewStringValue(""),
+							"type": structpb.NewListValue(&structpb.ListValue{Values: []*structpb.Value{
+								structpb.NewStringValue("ObjectStorage"),
+								structpb.NewStringValue("Storage"),
+								structpb.NewStringValue("Resource"),
+							}}),
+						},
+					},
+				},
+			},
+			wantErr: assert.NoError,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			gotS, err := ToStruct(tt.args.r)
+
+			tt.wantErr(t, err)
+
+			if tt.wantErr != nil {
+				assert.Equal(t, tt.wantS.String(), gotS.String())
+			}
+		})
+	}
+}