Repository: clouditor/clouditor
Pull request #1155 (2023-07-09 20:49:56)

Fix networking discovery

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/clouditor/clouditor/pull/1155?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) Report
> Merging [#1155](https://app.codecov.io/gh/clouditor/clouditor/pull/1155?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (68d0997) into [main](https://app.codecov.io/gh/clouditor/clouditor/commit/25d0ebe8d389b1f9a36b51e88d863204fb1e9b42?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (25d0ebe) will **decrease** coverage by `0.06%`.
> The diff coverage is `68.00%`.

```diff
@@            Coverage Diff             @@
##             main    #1155      +/-   ##
==========================================
- Coverage   83.80%   83.75%   -0.06%     
==========================================
  Files          93       93              
  Lines        8826     8846      +20     
==========================================
+ Hits         7397     7409      +12     
- Misses       1094     1100       +6     
- Partials      335      337       +2     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `83.75% <68.00%> (-0.06%)` | :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/1155?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) | Coverage Δ | |
|---|---|---|
| [service/discovery/azure/azure.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1155?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXp1cmUvYXp1cmUuZ28=) | `86.50% <ø> (ø)` | |
| [service/discovery/azure/network.go](https://app.codecov.io/gh/clouditor/clouditor/pull/1155?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9kaXNjb3ZlcnkvYXp1cmUvbmV0d29yay5nbw==) | `86.66% <68.00%> (-2.27%)` | :arrow_down: |



Patch:
diff --git a/api/discovery/discovery.go b/api/discovery/discovery.go
index edd3ba48..9a14341a 100644
--- a/api/discovery/discovery.go
+++ b/api/discovery/discovery.go
@@ -37,11 +37,13 @@ var (
 	log *logrus.Entry
 )
 
-// DefaultCloudServiceID is the default service ID. Currently, our discoverers have no way to differentiate between different
-// services, but we need this feature in the future. This serves as a default to already prepare the necessary
-// structures for this feature.
-const DefaultCloudServiceID = "00000000-0000-0000-0000-000000000000"
-const EvidenceCollectorToolId = "Clouditor Evidences Collection"
+const (
+	// DefaultCloudServiceID is the default service ID. Currently, our discoverers have no way to differentiate between different
+	// services, but we need this feature in the future. This serves as a default to already prepare the necessary
+	// structures for this feature.
+	DefaultCloudServiceID   = "00000000-0000-0000-0000-000000000000"
+	EvidenceCollectorToolId = "Clouditor Evidences Collection"
+)
 
 // Discoverer is a part of the discovery service that takes care of the actual discovering and translation into
 // vocabulary objects.
diff --git a/internal/constants/constants.go b/internal/constants/constants.go
index 7f18605b..4e933bb4 100644
--- a/internal/constants/constants.go
+++ b/internal/constants/constants.go
@@ -27,7 +27,10 @@ package constants
 
 const (
 	TLS    = "TLS"
-	AES    = "AES"
+	TLS1_0 = "TLS1_0"
+	TLS1_1 = "TLS1_1"
 	TLS1_2 = "TLS1_2"
+
+	AES    = "AES"
 	AES256 = "AES256"
 )
diff --git a/policies/bundles/BootLoggingOutput/data.json b/policies/bundles/BootLoggingOutput/data.json
index e7a8ff6c..32d9e538 100644
--- a/policies/bundles/BootLoggingOutput/data.json
+++ b/policies/bundles/BootLoggingOutput/data.json
@@ -1,4 +1,4 @@
 {
-  "operator" : "isIn",
-  "target_value" : ["SomeResourceId1","SomeResourceId2"]
+  "operator" : ">",
+  "target_value" : 0
 }
\ No newline at end of file
diff --git a/policies/bundles/BootLoggingOutput/metric.rego b/policies/bundles/BootLoggingOutput/metric.rego
index 961c7c61..553a5041 100644
--- a/policies/bundles/BootLoggingOutput/metric.rego
+++ b/policies/bundles/BootLoggingOutput/metric.rego
@@ -14,5 +14,5 @@ applicable {
 }
 
 compliant {
-	compare(data.operator, data.target_value, logging.loggingService)
+	compare(data.operator, data.target_value, count(logging.loggingService))
 }
diff --git a/policies/bundles/L3FirewallEnabled/metric.rego b/policies/bundles/L3FirewallEnabled/metric.rego
index d520cad7..46c2afb0 100644
--- a/policies/bundles/L3FirewallEnabled/metric.rego
+++ b/policies/bundles/L3FirewallEnabled/metric.rego
@@ -6,7 +6,7 @@ default applicable = false
 
 default compliant = false
 
-enabled := input.l3Firewall.enabled
+enabled := input.accessRestriction.enabled
 
 applicable {
 	enabled != null
diff --git a/policies/bundles/L3FirewallRestrictedPorts/metric.rego b/policies/bundles/L3FirewallRestrictedPorts/metric.rego
index 36c25477..88a2cf34 100644
--- a/policies/bundles/L3FirewallRestrictedPorts/metric.rego
+++ b/policies/bundles/L3FirewallRestrictedPorts/metric.rego
@@ -6,7 +6,7 @@ default applicable = false
 
 default compliant = false
 
-restrictedPorts := input.l3Firewall.restrictedPorts
+restrictedPorts := input.accessRestriction.restrictedPorts
 
 applicable {
 	restrictedPorts != null
diff --git a/policies/bundles/OSLoggingOutput/data.json b/policies/bundles/OSLoggingOutput/data.json
index e7a8ff6c..32d9e538 100644
--- a/policies/bundles/OSLoggingOutput/data.json
+++ b/policies/bundles/OSLoggingOutput/data.json
@@ -1,4 +1,4 @@
 {
-  "operator" : "isIn",
-  "target_value" : ["SomeResourceId1","SomeResourceId2"]
+  "operator" : ">",
+  "target_value" : 0
 }
\ No newline at end of file
diff --git a/policies/bundles/OSLoggingOutput/metric.rego b/policies/bundles/OSLoggingOutput/metric.rego
index 8c0192cf..4e6008d3 100644
--- a/policies/bundles/OSLoggingOutput/metric.rego
+++ b/policies/bundles/OSLoggingOutput/metric.rego
@@ -1,6 +1,7 @@
 package clouditor.metrics.os_logging_output
 
 import data.clouditor.compare
+import input.oSLogging as logging
 
 default applicable = false
 
@@ -8,12 +9,10 @@ default compliant = false
 
 metricConfiguration := data.target_value
 
-output := input.oSLogging.loggingService
-
 applicable {
-	output != null
+	logging
 }
 
 compliant {
-	compare(data.operator, data.target_value, output)
+	compare(data.operator, data.target_value, count(logging.loggingService))
 }
diff --git a/policies/bundles/TransportEncryptionProtocol/data.json b/policies/bundles/TransportEncryptionProtocol/data.json
index 26c8f684..443792c1 100644
--- a/policies/bundles/TransportEncryptionProtocol/data.json
+++ b/policies/bundles/TransportEncryptionProtocol/data.json
@@ -1,4 +1,4 @@
 {
   "operator" : "==",
-  "target_value" : "TLS 1.3"
+  "target_value" : "TLS1_2"
 }
\ No newline at end of file
diff --git a/policies/bundles/TransportEncryptionProtocol/input.json b/policies/bundles/TransportEncryptionProtocol/input.json
index 1e69e76c..ddc1c7cb 100644
--- a/policies/bundles/TransportEncryptionProtocol/input.json
+++ b/policies/bundles/TransportEncryptionProtocol/input.json
@@ -8,7 +8,8 @@
         "url": "clouditor.io",
         "transportEncryption": {
             "enabled": true,
-            "algorithm": "TLS"
+            "algorithm": "TLS",
+            "tlsVersion": "TLS1_2"
         }
     }
 }
\ No newline at end of file
diff --git a/policies/bundles/TransportEncryptionProtocol/metric.rego b/policies/bundles/TransportEncryptionProtocol/metric.rego
index 5aeea20c..66966156 100644
--- a/policies/bundles/TransportEncryptionProtocol/metric.rego
+++ b/policies/bundles/TransportEncryptionProtocol/metric.rego
@@ -12,5 +12,5 @@ applicable {
 }
 
 compliant {
-	compare(data.operator, data.target_value, enc.algorithm)
+	compare(data.operator, data.target_value, enc.tlsVersion)
 }
diff --git a/service/discovery/aws/storage.go b/service/discovery/aws/storage.go
index df84b744..57a24949 100644
--- a/service/discovery/aws/storage.go
+++ b/service/discovery/aws/storage.go
@@ -37,6 +37,7 @@ import (
 	"github.com/aws/aws-sdk-go-v2/service/s3/types"
 
 	"clouditor.io/clouditor/api/discovery"
+	"clouditor.io/clouditor/internal/constants"
 	"clouditor.io/clouditor/voc"
 	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/service/s3"
@@ -303,8 +304,8 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 				return &voc.TransportEncryption{
 					Enforced:   false,
 					Enabled:    true,
-					TlsVersion: "TLS1.2",
-					Algorithm:  "TLS",
+					TlsVersion: constants.TLS1_2,
+					Algorithm:  constants.TLS,
 				}, resp, nil
 			}
 			// Any other error is a connection error with AWS : Format err and return it
@@ -328,8 +329,8 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 				return &voc.TransportEncryption{
 					Enforced:   true,
 					Enabled:    true,
-					TlsVersion: "TLS1.2",
-					Algorithm:  "TLS",
+					TlsVersion: constants.TLS1_2,
+					Algorithm:  constants.TLS,
 				}, resp, nil
 			}
 		}
@@ -339,8 +340,8 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 					return &voc.TransportEncryption{
 						Enforced:   true,
 						Enabled:    true,
-						TlsVersion: "TLS1.2",
-						Algorithm:  "TLS",
+						TlsVersion: constants.TLS1_2,
+						Algorithm:  constants.TLS,
 					}, resp, nil
 				}
 			}
@@ -349,8 +350,8 @@ func (d *awsS3Discovery) getTransportEncryption(bucket string) (*voc.TransportEn
 	return &voc.TransportEncryption{
 		Enforced:   false,
 		Enabled:    true,
-		TlsVersion: "TLS1.2",
-		Algorithm:  "TLS",
+		TlsVersion: constants.TLS1_2,
+		Algorithm:  constants.TLS,
 	}, resp, nil
 
 }
diff --git a/service/discovery/azure/azure.go b/service/discovery/azure/azure.go
index ff80258a..3f13c28f 100644
--- a/service/discovery/azure/azure.go
+++ b/service/discovery/azure/azure.go
@@ -137,9 +137,10 @@ type clients struct {
 	accountsClient      *armstorage.AccountsClient
 
 	// Network
-	networkInterfacesClient  *armnetwork.InterfacesClient
-	loadBalancerClient       *armnetwork.LoadBalancersClient
-	applicationGatewayClient *armnetwork.ApplicationGatewaysClient
+	networkInterfacesClient     *armnetwork.InterfacesClient
+	loadBalancerClient          *armnetwork.LoadBalancersClient
+	applicationGatewayClient    *armnetwork.ApplicationGatewaysClient
+	networkSecurityGroupsClient *armnetwork.SecurityGroupsClient
 
 	// AppService
 	sitesClient *armappservice.WebAppsClient
diff --git a/service/discovery/azure/compute.go b/service/discovery/azure/compute.go
index 42482407..23dabb58 100644
--- a/service/discovery/azure/compute.go
+++ b/service/discovery/azure/compute.go
@@ -448,8 +448,7 @@ func automaticUpdates(vm *armcompute.VirtualMachine) (automaticUpdates *voc.Auto
 	// Check if Linux configuration is available
 	if vm.Properties.OSProfile.LinuxConfiguration != nil &&
 		vm.Properties.OSProfile.LinuxConfiguration.PatchSettings != nil {
-		if util.Deref(vm.Properties.OSProfile.LinuxConfiguration.PatchSettings.PatchMode) == armcompute.LinuxVMGuestPatchModeAutomaticByPlatform ||
-			util.Deref(vm.Properties.OSProfile.LinuxConfiguration.PatchSettings.PatchMode) == armcompute.LinuxVMGuestPatchModeImageDefault {
+		if util.Deref(vm.Properties.OSProfile.LinuxConfiguration.PatchSettings.PatchMode) == armcompute.LinuxVMGuestPatchModeAutomaticByPlatform {
 			automaticUpdates.Enabled = true
 			automaticUpdates.Interval = Duration30Days
 			return
@@ -459,8 +458,8 @@ func automaticUpdates(vm *armcompute.VirtualMachine) (automaticUpdates *voc.Auto
 	// Check if Windows configuration is available
 	if vm.Properties.OSProfile.WindowsConfiguration != nil &&
 		vm.Properties.OSProfile.WindowsConfiguration.PatchSettings != nil {
-		if util.Deref(vm.Properties.OSProfile.WindowsConfiguration.PatchSettings.PatchMode) == armcompute.WindowsVMGuestPatchModeAutomaticByOS ||
-			util.Deref(vm.Properties.OSProfile.WindowsConfiguration.PatchSettings.PatchMode) == armcompute.WindowsVMGuestPatchModeAutomaticByPlatform {
+		if util.Deref(vm.Properties.OSProfile.WindowsConfiguration.PatchSettings.PatchMode) == armcompute.WindowsVMGuestPatchModeAutomaticByOS && *vm.Properties.OSProfile.WindowsConfiguration.EnableAutomaticUpdates ||
+			util.Deref(vm.Properties.OSProfile.WindowsConfiguration.PatchSettings.PatchMode) == armcompute.WindowsVMGuestPatchModeAutomaticByPlatform && *vm.Properties.OSProfile.WindowsConfiguration.EnableAutomaticUpdates {
 			automaticUpdates.Enabled = true
 			automaticUpdates.Interval = Duration30Days
 			return
diff --git a/service/discovery/azure/network.go b/service/discovery/azure/network.go
index f72d816f..aaadf624 100644
--- a/service/discovery/azure/network.go
+++ b/service/discovery/azure/network.go
@@ -26,7 +26,9 @@
 package azure
 
 import (
+	"context"
 	"fmt"
+	"strings"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
 
@@ -267,7 +269,7 @@ func (d *azureNetworkDiscovery) handleNetworkInterfaces(ni *armnetwork.Interface
 			),
 		},
 		AccessRestriction: &voc.L3Firewall{
-			Enabled: nsgFirewallEnabled(ni),
+			Enabled: d.nsgFirewallEnabled(ni),
 			// Inbound: ,
 			// RestrictedPorts: ,
 		},
@@ -275,9 +277,26 @@ func (d *azureNetworkDiscovery) handleNetworkInterfaces(ni *armnetwork.Interface
 }
 
 // nsgFirewallEnabled checks if network security group (NSG) rules are configured. A NSG is a firewall that operates at OSI layers 3 and 4 to filter ingress and egress traffic. (https://learn.microsoft.com/en-us/azure/firewall/firewall-faq#what-is-the-difference-between-network-security-groups--nsgs--and-azure-firewall, Last access: 05/02/2023)
-func nsgFirewallEnabled(ni *armnetwork.Interface) bool {
-	if ni != nil && ni.Properties != nil && ni.Properties.NetworkSecurityGroup != nil && ni.Properties.NetworkSecurityGroup.Properties != nil && ni.Properties.NetworkSecurityGroup.Properties.SecurityRules != nil && len(ni.Properties.NetworkSecurityGroup.Properties.SecurityRules) >= 1 {
-		return true
+func (d *azureNetworkDiscovery) nsgFirewallEnabled(ni *armnetwork.Interface) bool {
+	// initialize network interfaces client
+	if err := d.initNetworkSecurityGroupClient(); err != nil {
+		log.Error(err)
+		return false
+	}
+
+	if ni != nil && ni.Properties != nil && ni.Properties.NetworkSecurityGroup != nil {
+		vmNsg := ni.Properties.NetworkSecurityGroup
+		nsg, err := d.clients.networkSecurityGroupsClient.Get(context.Background(), resourceGroupName(*vmNsg.ID), getName(*vmNsg.ID), &armnetwork.SecurityGroupsClientGetOptions{})
+		if err != nil {
+			log.Errorf("error getting network security group: %v", err)
+			return false
+		}
+
+		// TODO(all): We have to check more than len(securityRules) > 0. But what is a good check?
+		if len(nsg.SecurityGroup.Properties.SecurityRules) > 0 {
+			return true
+		}
+
 	}
 
 	return false
@@ -368,6 +387,14 @@ func publicIPAddressFromLoadBalancer(lb *armnetwork.LoadBalancer) []string {
 	return publicIPAddresses
 }
 
+// getName returns the resource group name of a given Azure ID
+func getName(id string) string {
+	if id == "" {
+		return ""
+	}
+	return strings.Split(id, "/")[8]
+}
+
 // initNetworkInterfacesClient creates the client if not already exists
 func (d *azureNetworkDiscovery) initNetworkInterfacesClient() (err error) {
 	d.clients.networkInterfacesClient, err = initClient(d.clients.networkInterfacesClient, d.azureDiscovery, armnetwork.NewInterfacesClient)
@@ -385,3 +412,9 @@ func (d *azureNetworkDiscovery) initApplicationGatewayClient() (err error) {
 	d.clients.applicationGatewayClient, err = initClient(d.clients.applicationGatewayClient, d.azureDiscovery, armnetwork.NewApplicationGatewaysClient)
 	return
 }
+
+// initNetworkSecurityGroupClient creates the client if not already exists
+func (d *azureNetworkDiscovery) initNetworkSecurityGroupClient() (err error) {
+	d.clients.networkSecurityGroupsClient, err = initClient(d.clients.networkSecurityGroupsClient, d.azureDiscovery, armnetwork.NewSecurityGroupsClient)
+	return
+}
diff --git a/service/discovery/azure/storage.go b/service/discovery/azure/storage.go
index 967f8433..e04e8433 100644
--- a/service/discovery/azure/storage.go
+++ b/service/discovery/azure/storage.go
@@ -32,6 +32,7 @@ import (
 	"strings"
 
 	"clouditor.io/clouditor/api/discovery"
+	"clouditor.io/clouditor/internal/constants"
 	"clouditor.io/clouditor/internal/util"
 	"clouditor.io/clouditor/voc"
 
@@ -267,7 +268,7 @@ func (d *azureStorageDiscovery) handleStorageAccount(account *armstorage.Account
 		Enforced:   util.Deref(account.Properties.EnableHTTPSTrafficOnly),
 		Enabled:    true, // cannot be disabled
 		TlsVersion: string(util.Deref(account.Properties.MinimumTLSVersion)),
-		Algorithm:  "TLS",
+		Algorithm:  constants.TLS,
 	}
 
 	storageService := &voc.ObjectStorageService{


Test patch:
diff --git a/service/discovery/aws/storage_test.go b/service/discovery/aws/storage_test.go
index cf5996ed..81c5c9cb 100644
--- a/service/discovery/aws/storage_test.go
+++ b/service/discovery/aws/storage_test.go
@@ -34,6 +34,7 @@ import (
 	"testing"
 	"time"
 
+	"clouditor.io/clouditor/internal/constants"
 	"clouditor.io/clouditor/voc"
 
 	"github.com/aws/aws-sdk-go-v2/aws"
@@ -410,7 +411,7 @@ func TestAwsS3Discovery_getTransportEncryption(t *testing.T) {
 	encryptionAtTransit, rawBucketPolicy, err := d.getTransportEncryption(mockBucket1)
 	assert.NoError(t, err)
 	assert.True(t, encryptionAtTransit.Enabled)
-	assert.Equal(t, "TLS1.2", encryptionAtTransit.TlsVersion)
+	assert.Equal(t, constants.TLS1_2, encryptionAtTransit.TlsVersion)
 	assert.True(t, encryptionAtTransit.Enforced)
 	assert.NotEmpty(t, rawBucketPolicy)
 
@@ -424,7 +425,7 @@ func TestAwsS3Discovery_getTransportEncryption(t *testing.T) {
 	encryptionAtTransit, rawBucketPolicy, err = d.getTransportEncryption(mockBucket3)
 	assert.NoError(t, err)
 	assert.True(t, encryptionAtTransit.Enabled)
-	assert.Equal(t, "TLS1.2", encryptionAtTransit.TlsVersion)
+	assert.Equal(t, constants.TLS1_2, encryptionAtTransit.TlsVersion)
 	assert.False(t, encryptionAtTransit.Enforced)
 	assert.NotEmpty(t, rawBucketPolicy)
 
@@ -432,7 +433,7 @@ func TestAwsS3Discovery_getTransportEncryption(t *testing.T) {
 	encryptionAtTransit, rawBucketPolicy, err = d.getTransportEncryption("")
 	assert.NoError(t, err)
 	assert.True(t, encryptionAtTransit.Enabled)
-	assert.Equal(t, "TLS1.2", encryptionAtTransit.TlsVersion)
+	assert.Equal(t, constants.TLS1_2, encryptionAtTransit.TlsVersion)
 	assert.False(t, encryptionAtTransit.Enforced)
 	assert.Empty(t, rawBucketPolicy)
 }
diff --git a/service/discovery/azure/compute_test.go b/service/discovery/azure/compute_test.go
index bd26979a..63eca6df 100644
--- a/service/discovery/azure/compute_test.go
+++ b/service/discovery/azure/compute_test.go
@@ -147,6 +147,7 @@ func (m mockComputeSender) Do(req *http.Request) (res *http.Response, err error)
 								"patchSettings": map[string]interface{}{
 									"patchMode": "AutomaticByOS",
 								},
+								"enableAutomaticUpdates": true,
 							},
 						},
 						"diagnosticsProfile": map[string]interface{}{
@@ -808,7 +809,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\"}}}},\"resources\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm2/extensions/OmsAgentForLinux\"}]}]}",
+							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\":{\"enableAutomaticUpdates\":true,\"patchSettings\":{\"patchMode\":\"AutomaticByOS\"}}},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_2\"}},{\"managedDisk\":{\"id\":\"data_disk_3\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}}},\"resources\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm2/extensions/OmsAgentForLinux\"}]}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{"987", "654"},
 					},
@@ -1306,7 +1307,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\"}}}},\"resources\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm2/extensions/OmsAgentForLinux\"}]}]}",
+							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\":{\"enableAutomaticUpdates\":true,\"patchSettings\":{\"patchMode\":\"AutomaticByOS\"}}},\"storageProfile\":{\"dataDisks\":[{\"managedDisk\":{\"id\":\"data_disk_2\"}},{\"managedDisk\":{\"id\":\"data_disk_3\"}}],\"osDisk\":{\"managedDisk\":{\"id\":\"os_test_disk\"}}}},\"resources\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Compute/virtualMachines/vm2/extensions/OmsAgentForLinux\"}]}]}",
 						},
 						NetworkInterfaces: []voc.ResourceID{"987", "654"},
 					},
@@ -2314,6 +2315,7 @@ func Test_automaticUpdatesEnabled(t *testing.T) {
 								PatchSettings: &armcompute.PatchSettings{
 									PatchMode: util.Ref(armcompute.WindowsVMGuestPatchModeAutomaticByOS),
 								},
+								EnableAutomaticUpdates: util.Ref(true),
 							},
 						},
 					},
@@ -2393,6 +2395,7 @@ func Test_automaticUpdates(t *testing.T) {
 								PatchSettings: &armcompute.PatchSettings{
 									PatchMode: util.Ref(armcompute.WindowsVMGuestPatchModeAutomaticByPlatform),
 								},
+								EnableAutomaticUpdates: util.Ref(true),
 							},
 						},
 					},
diff --git a/service/discovery/azure/network_test.go b/service/discovery/azure/network_test.go
index 6ad4b5f2..cf483a2c 100644
--- a/service/discovery/azure/network_test.go
+++ b/service/discovery/azure/network_test.go
@@ -59,24 +59,7 @@ func (m mockNetworkSender) Do(req *http.Request) (res *http.Response, err error)
 					"properties": map[string]interface{}{
 						"networkSecurityGroup": map[string]interface{}{
 							"id":       "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkSecurityGroups/nsg1",
-							"name":     "nsg1",
 							"location": "eastus",
-							"properties": map[string]interface{}{
-								"securityRules": []map[string]interface{}{ // Important: These properties must the same as for the path "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkSecurityGroups/nsg1"
-									{
-										"properties": map[string]interface{}{
-											"access":          "Deny",
-											"sourcePortRange": "*",
-										},
-									},
-									{
-										"properties": map[string]interface{}{
-											"access":          "Deny",
-											"sourcePortRange": "*",
-										},
-									},
-								},
-							},
 						},
 					},
 				},
@@ -294,7 +277,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\":\"*\"}}]}}}}]}",
+							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\"}}}]}",
 						},
 					},
 					AccessRestriction: &voc.L3Firewall{
@@ -727,32 +710,51 @@ func Test_azureNetworkDiscovery_discoverApplicationGateway(t *testing.T) {
 }
 
 func Test_nsgFirewallEnabled(t *testing.T) {
+	type fields struct {
+		azureDiscovery *azureDiscovery
+	}
 	type args struct {
 		ni *armnetwork.Interface
 	}
 	tests := []struct {
-		name string
-		args args
-		want bool
+		name   string
+		fields fields
+		args   args
+		want   bool
 	}{
 		{
 			name: "Empty input",
+			fields: fields{
+				azureDiscovery: NewMockAzureDiscovery(newMockNetworkSender()),
+			},
 			args: args{},
 			want: false,
+		}, {
+			name: "Error getting nsg",
+			fields: fields{
+				azureDiscovery: NewMockAzureDiscovery(newMockNetworkSender()),
+			},
+			args: args{
+				ni: &armnetwork.Interface{
+					Properties: &armnetwork.InterfacePropertiesFormat{
+						NetworkSecurityGroup: &armnetwork.SecurityGroup{
+							ID: util.Ref("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkInterfaces/false"),
+						},
+					},
+				},
+			},
+			want: false,
 		},
 		{
 			name: "Happy path",
+			fields: fields{
+				azureDiscovery: NewMockAzureDiscovery(newMockNetworkSender()),
+			},
 			args: args{
 				ni: &armnetwork.Interface{
 					Properties: &armnetwork.InterfacePropertiesFormat{
 						NetworkSecurityGroup: &armnetwork.SecurityGroup{
-							Properties: &armnetwork.SecurityGroupPropertiesFormat{
-								SecurityRules: []*armnetwork.SecurityRule{
-									{
-										ID: util.Ref("test security rule"),
-									},
-								},
-							},
+							ID: util.Ref("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkInterfaces/nsg1"),
 						},
 					},
 				},
@@ -761,10 +763,44 @@ func Test_nsgFirewallEnabled(t *testing.T) {
 		},
 	}
 	for _, tt := range tests {
+		d := &azureNetworkDiscovery{
+			azureDiscovery: tt.fields.azureDiscovery,
+		}
 		t.Run(tt.name, func(t *testing.T) {
-			if got := nsgFirewallEnabled(tt.args.ni); got != tt.want {
+			if got := d.nsgFirewallEnabled(tt.args.ni); got != tt.want {
 				t.Errorf("nsgFirewallEnabled() = %v, want %v", got, tt.want)
 			}
 		})
 	}
 }
+
+func Test_getIDName(t *testing.T) {
+	type args struct {
+		id string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "Missing input",
+			args: args{},
+			want: "",
+		},
+		{
+			name: "Happy path",
+			args: args{
+				id: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/res1/providers/Microsoft.Network/networkInterfaces/nsg1",
+			},
+			want: "nsg1",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := getName(tt.args.id); got != tt.want {
+				t.Errorf("getIDName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/service/discovery/azure/storage_test.go b/service/discovery/azure/storage_test.go
index b2cb5022..b7a20e5e 100644
--- a/service/discovery/azure/storage_test.go
+++ b/service/discovery/azure/storage_test.go
@@ -590,8 +590,8 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							TransportEncryption: &voc.TransportEncryption{
 								Enforced:   true,
 								Enabled:    true,
-								TlsVersion: "TLS1_2",
-								Algorithm:  "TLS",
+								TlsVersion: constants.TLS1_2,
+								Algorithm:  constants.TLS,
 							},
 						},
 					},
@@ -600,8 +600,8 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 						TransportEncryption: &voc.TransportEncryption{
 							Enforced:   true,
 							Enabled:    true,
-							TlsVersion: "TLS1_2",
-							Algorithm:  "TLS",
+							TlsVersion: constants.TLS1_2,
+							Algorithm:  constants.TLS,
 						},
 					},
 				},
@@ -693,8 +693,8 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 							TransportEncryption: &voc.TransportEncryption{
 								Enforced:   true,
 								Enabled:    true,
-								TlsVersion: "TLS1_2",
-								Algorithm:  "TLS",
+								TlsVersion: constants.TLS1_2,
+								Algorithm:  constants.TLS,
 							},
 						},
 					},
@@ -703,8 +703,8 @@ func Test_azureStorageDiscovery_List(t *testing.T) {
 						TransportEncryption: &voc.TransportEncryption{
 							Enforced:   true,
 							Enabled:    true,
-							TlsVersion: "TLS1_2",
-							Algorithm:  "TLS",
+							TlsVersion: constants.TLS1_2,
+							Algorithm:  constants.TLS,
 						},
 					},
 				},
@@ -1213,8 +1213,8 @@ func Test_azureStorageDiscovery_handleStorageAccount(t *testing.T) {
 						TransportEncryption: &voc.TransportEncryption{
 							Enforced:   true,
 							Enabled:    true,
-							TlsVersion: "TLS1_2",
-							Algorithm:  "TLS",
+							TlsVersion: constants.TLS1_2,
+							Algorithm:  constants.TLS,
 						},
 					},
 				},
@@ -1223,8 +1223,8 @@ func Test_azureStorageDiscovery_handleStorageAccount(t *testing.T) {
 					TransportEncryption: &voc.TransportEncryption{
 						Enforced:   true,
 						Enabled:    true,
-						TlsVersion: "TLS1_2",
-						Algorithm:  "TLS",
+						TlsVersion: constants.TLS1_2,
+						Algorithm:  constants.TLS,
 					},
 				},
 			},