Skip to content

Commit ea2dc58

Browse files
yagreutnikpivkin
andauthored
feat(misconf): Update Azure network schema for new checks (#9791)
Signed-off-by: nikpivkin <[email protected]> Co-authored-by: Nikita Pivkin <[email protected]>
1 parent c6d95d7 commit ea2dc58

File tree

13 files changed

+423
-285
lines changed

13 files changed

+423
-285
lines changed

pkg/iac/adapters/arm/compute/adapt.go

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package compute
22

33
import (
44
"github.com/aquasecurity/trivy/pkg/iac/providers/azure/compute"
5+
"github.com/aquasecurity/trivy/pkg/iac/providers/azure/network"
56
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure"
67
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
78
)
@@ -93,25 +94,6 @@ func adaptLinuxVirtualMachine(resource azure.Resource) compute.LinuxVirtualMachi
9394

9495
}
9596

96-
func extractNetworkInterfaces(networkProfile azure.Value, metadata iacTypes.Metadata) []compute.NetworkInterface {
97-
var networkInterfaces []compute.NetworkInterface
98-
99-
nicsArray := networkProfile.GetMapValue("networkInterfaces").AsList()
100-
for _, nic := range nicsArray {
101-
nicID := nic.GetMapValue("id").AsStringValue("", metadata)
102-
if nicID.Value() != "" {
103-
// Create a minimal NetworkInterface object with the ID information
104-
// In ARM templates, we don't have direct access to subnet details like in Terraform
105-
networkInterface := compute.NetworkInterface{
106-
Metadata: nicID.GetMetadata(),
107-
SubnetID: iacTypes.StringDefault("", nicID.GetMetadata()),
108-
SecurityGroups: nil,
109-
HasPublicIP: iacTypes.BoolDefault(false, nicID.GetMetadata()),
110-
PublicIPAddress: iacTypes.StringDefault("", nicID.GetMetadata()),
111-
}
112-
networkInterfaces = append(networkInterfaces, networkInterface)
113-
}
114-
}
115-
116-
return networkInterfaces
97+
func extractNetworkInterfaces(_ azure.Value, _ iacTypes.Metadata) []network.NetworkInterface {
98+
return nil
11799
}

pkg/iac/adapters/arm/compute/adapt_test.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,6 @@ func TestAdapt(t *testing.T) {
116116
LinuxVirtualMachines: []compute.LinuxVirtualMachine{{
117117
VirtualMachine: compute.VirtualMachine{
118118
CustomData: types.StringTest("test"),
119-
NetworkInterfaces: []compute.NetworkInterface{
120-
{
121-
Metadata: types.NewTestMetadata(),
122-
SubnetID: types.StringTest(""),
123-
SecurityGroups: nil,
124-
HasPublicIP: types.BoolTest(false),
125-
PublicIPAddress: types.StringTest(""),
126-
},
127-
{
128-
Metadata: types.NewTestMetadata(),
129-
SubnetID: types.StringTest(""),
130-
SecurityGroups: nil,
131-
HasPublicIP: types.BoolTest(false),
132-
PublicIPAddress: types.StringTest(""),
133-
},
134-
},
135119
},
136120
OSProfileLinuxConfig: compute.OSProfileLinuxConfig{
137121
DisablePasswordAuthentication: types.BoolTest(false),
@@ -140,22 +124,6 @@ func TestAdapt(t *testing.T) {
140124
WindowsVirtualMachines: []compute.WindowsVirtualMachine{{
141125
VirtualMachine: compute.VirtualMachine{
142126
CustomData: types.StringTest("test"),
143-
NetworkInterfaces: []compute.NetworkInterface{
144-
{
145-
Metadata: types.NewTestMetadata(),
146-
SubnetID: types.StringTest(""),
147-
SecurityGroups: nil,
148-
HasPublicIP: types.BoolTest(false),
149-
PublicIPAddress: types.StringTest(""),
150-
},
151-
{
152-
Metadata: types.NewTestMetadata(),
153-
SubnetID: types.StringTest(""),
154-
SecurityGroups: nil,
155-
HasPublicIP: types.BoolTest(false),
156-
PublicIPAddress: types.StringTest(""),
157-
},
158-
},
159127
},
160128
}},
161129
},

pkg/iac/adapters/arm/network/adapt.go

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func Adapt(deployment azure.Deployment) network.Network {
1515
return network.Network{
1616
SecurityGroups: adaptSecurityGroups(deployment),
1717
NetworkWatcherFlowLogs: adaptNetworkWatcherFlowLogs(deployment),
18+
NetworkInterfaces: adaptNetworkInterfaces(deployment),
1819
}
1920
}
2021

@@ -42,7 +43,9 @@ func adaptSecurityGroupRules(deployment azure.Deployment) (rules []network.Secur
4243

4344
func adaptSecurityGroupRule(resource azure.Resource) network.SecurityGroupRule {
4445
sourceAddressPrefixes := resource.Properties.GetMapValue("sourceAddressPrefixes").AsStringValuesList("")
45-
sourceAddressPrefixes = append(sourceAddressPrefixes, resource.Properties.GetMapValue("sourceAddressPrefix").AsStringValue("", resource.Metadata))
46+
if prefix := resource.Properties.GetMapValue("sourceAddressPrefix").AsStringValue("", resource.Metadata); prefix.IsNotEmpty() {
47+
sourceAddressPrefixes = append(sourceAddressPrefixes, prefix)
48+
}
4649

4750
var sourcePortRanges []common.PortRange
4851
for _, portRange := range resource.Properties.GetMapValue("sourcePortRanges").AsList() {
@@ -56,7 +59,9 @@ func adaptSecurityGroupRule(resource azure.Resource) network.SecurityGroupRule {
5659
}
5760

5861
destinationAddressPrefixes := resource.Properties.GetMapValue("destinationAddressPrefixes").AsStringValuesList("")
59-
destinationAddressPrefixes = append(destinationAddressPrefixes, resource.Properties.GetMapValue("destinationAddressPrefix").AsStringValue("", resource.Metadata))
62+
if prefix := resource.Properties.GetMapValue("destinationAddressPrefix").AsStringValue("", resource.Metadata); prefix.IsNotEmpty() {
63+
destinationAddressPrefixes = append(destinationAddressPrefixes, prefix)
64+
}
6065

6166
var destinationPortRanges []common.PortRange
6267
for _, portRange := range resource.Properties.GetMapValue("destinationPortRanges").AsList() {
@@ -99,12 +104,57 @@ func adaptNetworkWatcherFlowLogs(deployment azure.Deployment) (flowLogs []networ
99104
}
100105

101106
func adaptNetworkWatcherFlowLog(resource azure.Resource) network.NetworkWatcherFlowLog {
107+
enabled := resource.Properties.GetMapValue("enabled").AsBoolValue(false, resource.Metadata)
108+
retentionPolicy := resource.Properties.GetMapValue("retentionPolicy")
109+
102110
return network.NetworkWatcherFlowLog{
103111
Metadata: resource.Metadata,
112+
Enabled: enabled,
104113
RetentionPolicy: network.RetentionPolicy{
105114
Metadata: resource.Metadata,
106-
Enabled: resource.Properties.GetMapValue("retentionPolicy").GetMapValue("enabled").AsBoolValue(false, resource.Metadata),
107-
Days: resource.Properties.GetMapValue("retentionPolicy").GetMapValue("days").AsIntValue(0, resource.Metadata),
115+
Enabled: retentionPolicy.GetMapValue("enabled").AsBoolValue(false, resource.Metadata),
116+
Days: retentionPolicy.GetMapValue("days").AsIntValue(0, resource.Metadata),
108117
},
109118
}
110119
}
120+
121+
func adaptNetworkInterfaces(deployment azure.Deployment) []network.NetworkInterface {
122+
var networkInterfaces []network.NetworkInterface
123+
for _, resource := range deployment.GetResourcesByType("Microsoft.Network/networkInterfaces") {
124+
networkInterfaces = append(networkInterfaces, adaptNetworkInterface(resource, deployment))
125+
}
126+
return networkInterfaces
127+
}
128+
129+
func adaptNetworkInterface(resource azure.Resource, _ azure.Deployment) network.NetworkInterface {
130+
ni := network.NetworkInterface{
131+
Metadata: resource.Metadata,
132+
EnableIPForwarding: resource.Properties.GetMapValue("enableIPForwarding").AsBoolValue(false, resource.Metadata),
133+
HasPublicIP: iacTypes.BoolDefault(false, resource.Metadata),
134+
PublicIPAddress: iacTypes.StringDefault("", resource.Metadata),
135+
SubnetID: iacTypes.StringDefault("", resource.Metadata),
136+
}
137+
138+
ipConfigs := resource.Properties.GetMapValue("ipConfigurations").AsList()
139+
ni.IPConfigurations = make([]network.IPConfiguration, 0, len(ipConfigs))
140+
141+
for _, ipConfig := range ipConfigs {
142+
if ipConfig.IsNull() {
143+
continue
144+
}
145+
ipConfigProps := ipConfig.GetMapValue("properties")
146+
ni.IPConfigurations = append(ni.IPConfigurations, network.IPConfiguration{
147+
Metadata: resource.Metadata,
148+
PublicIPAddress: ipConfigProps.GetMapValue("publicIPAddress").
149+
GetMapValue("id").AsStringValue("", resource.Metadata),
150+
SubnetID: ipConfigProps.GetMapValue("subnet").
151+
GetMapValue("id").AsStringValue("", resource.Metadata),
152+
Primary: ipConfigProps.GetMapValue("primary").AsBoolValue(false, resource.Metadata),
153+
})
154+
}
155+
ni.Setup()
156+
157+
// Note: SecurityGroups are not resolved for ARM templates as related resource search
158+
// is not yet implemented for ARM (parser cannot evaluate expressions/references)
159+
return ni
160+
}

pkg/iac/adapters/arm/network/adapt_test.go

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,10 @@ func TestAdapt(t *testing.T) {
3535
}`,
3636
expected: network.Network{
3737
NetworkWatcherFlowLogs: []network.NetworkWatcherFlowLog{{
38-
RetentionPolicy: network.RetentionPolicy{
39-
Days: types.IntTest(0),
40-
Enabled: types.BoolTest(false),
41-
},
38+
RetentionPolicy: network.RetentionPolicy{},
4239
}},
4340
SecurityGroups: []network.SecurityGroup{{
44-
Rules: []network.SecurityGroupRule{{
45-
DestinationAddresses: []types.StringValue{types.StringTest("")},
46-
SourceAddresses: []types.StringValue{types.StringTest("")},
47-
}},
41+
Rules: []network.SecurityGroupRule{{}},
4842
}},
4943
},
5044
},
@@ -147,6 +141,71 @@ func TestAdapt(t *testing.T) {
147141
}},
148142
},
149143
},
144+
{
145+
name: "network interface with ip configurations",
146+
source: `{
147+
"resources": [
148+
{
149+
"type": "Microsoft.Network/networkInterfaces",
150+
"properties": {
151+
"enableIPForwarding": true,
152+
"ipConfigurations": [
153+
{
154+
"name": "primary-ip",
155+
"properties": {
156+
"primary": true,
157+
"subnet": {
158+
"id": "/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet-primary"
159+
},
160+
"publicIPAddress": {
161+
"id": "/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip-primary"
162+
}
163+
}
164+
},
165+
{
166+
"name": "secondary-ip",
167+
"properties": {
168+
"primary": false,
169+
"subnet": {
170+
"id": "/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet-secondary"
171+
}
172+
}
173+
}
174+
]
175+
}
176+
}
177+
]
178+
}`,
179+
expected: network.Network{
180+
NetworkInterfaces: []network.NetworkInterface{
181+
{
182+
EnableIPForwarding: types.BoolTest(true),
183+
184+
// backward compatibility — filled from primary config
185+
SubnetID: types.StringTest("/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet-primary"),
186+
HasPublicIP: types.BoolTest(true),
187+
PublicIPAddress: types.StringTest("/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip-primary"),
188+
189+
IPConfigurations: []network.IPConfiguration{
190+
{
191+
Primary: types.BoolTest(true),
192+
SubnetID: types.StringTest(
193+
"/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet-primary",
194+
),
195+
HasPublicIP: types.BoolTest(true),
196+
PublicIPAddress: types.StringTest("/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/publicIPAddresses/pip-primary"),
197+
},
198+
{
199+
Primary: types.BoolTest(false),
200+
SubnetID: types.StringTest("/subscriptions/abc/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet-secondary"),
201+
HasPublicIP: types.BoolTest(false),
202+
PublicIPAddress: types.StringTest(""),
203+
},
204+
},
205+
},
206+
},
207+
},
208+
},
150209
}
151210

152211
for _, tt := range tests {

pkg/iac/adapters/terraform/azure/appservice/adapt.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package appservice
22

33
import (
4-
"github.com/samber/lo"
5-
64
"github.com/aquasecurity/trivy/pkg/iac/providers/azure/appservice"
75
"github.com/aquasecurity/trivy/pkg/iac/terraform"
6+
"github.com/aquasecurity/trivy/pkg/iac/types"
87
)
98

109
func Adapt(modules terraform.Modules) appservice.AppService {
@@ -31,30 +30,42 @@ func adaptFunctionApps(modules terraform.Modules) []appservice.FunctionApp {
3130
}
3231

3332
func adaptService(resource *terraform.Block) appservice.Service {
34-
siteBlock := resource.GetBlock("site_config")
35-
identityBlock := resource.GetBlock("identity")
36-
authBlock := resource.GetBlock("auth_settings")
37-
return appservice.Service{
33+
service := appservice.Service{
3834
Metadata: resource.GetMetadata(),
3935
EnableClientCert: resource.GetAttribute("client_cert_enabled").AsBoolValueOrDefault(false, resource),
4036
HTTPSOnly: resource.GetAttribute("https_only").AsBoolValueOrDefault(false, resource),
41-
Identity: appservice.Identity{
42-
Metadata: lo.TernaryF(identityBlock.IsNil(), resource.GetMetadata, identityBlock.GetMetadata),
43-
Type: identityBlock.GetAttribute("type").AsStringValueOrDefault("", identityBlock),
37+
Site: appservice.Site{
38+
Metadata: resource.GetMetadata(),
39+
MinimumTLSVersion: types.StringDefault("1.2", resource.GetMetadata()),
4440
},
45-
Authentication: appservice.Authentication{
46-
Metadata: lo.TernaryF(identityBlock.IsNil(), resource.GetMetadata, authBlock.GetMetadata),
41+
}
42+
43+
if identityBlock := resource.GetBlock("identity"); identityBlock.IsNotNil() {
44+
service.Identity = appservice.Identity{
45+
Metadata: identityBlock.GetMetadata(),
46+
Type: identityBlock.GetAttribute("type").AsStringValueOrDefault("", identityBlock),
47+
}
48+
}
49+
50+
if authBlock := resource.GetBlock("auth_settings"); authBlock.IsNotNil() {
51+
service.Authentication = appservice.Authentication{
52+
Metadata: authBlock.GetMetadata(),
4753
Enabled: authBlock.GetAttribute("enabled").AsBoolValueOrDefault(false, authBlock),
48-
},
49-
Site: appservice.Site{
50-
Metadata: lo.TernaryF(identityBlock.IsNil(), resource.GetMetadata, siteBlock.GetMetadata),
54+
}
55+
}
56+
57+
if siteBlock := resource.GetBlock("site_config"); siteBlock.IsNotNil() {
58+
service.Site = appservice.Site{
59+
Metadata: siteBlock.GetMetadata(),
5160
EnableHTTP2: siteBlock.GetAttribute("http2_enabled").AsBoolValueOrDefault(false, siteBlock),
5261
MinimumTLSVersion: siteBlock.GetAttribute("min_tls_version").AsStringValueOrDefault("1.2", siteBlock),
5362
PHPVersion: siteBlock.GetAttribute("php_version").AsStringValueOrDefault("", siteBlock),
5463
PythonVersion: siteBlock.GetAttribute("python_version").AsStringValueOrDefault("", siteBlock),
5564
FTPSState: siteBlock.GetAttribute("ftps_state").AsStringValueOrDefault("", siteBlock),
56-
},
65+
}
5766
}
67+
68+
return service
5869
}
5970

6071
func adaptFunctionApp(resource *terraform.Block) appservice.FunctionApp {

0 commit comments

Comments
 (0)