feat(misconf): support for azurerm_*_web_app (#9944)

Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
Nikita Pivkin
2026-01-15 01:43:04 +06:00
committed by GitHub
parent 51f5412ba7
commit 37b5da895b
6 changed files with 164 additions and 20 deletions

View File

@@ -3,6 +3,7 @@ package appservice
import (
"github.com/aquasecurity/trivy/pkg/iac/providers/azure/appservice"
"github.com/aquasecurity/trivy/pkg/iac/scanners/azure"
"github.com/aquasecurity/trivy/pkg/iac/types"
)
func Adapt(deployment azure.Deployment) appservice.AppService {
@@ -44,6 +45,7 @@ func adaptService(resource azure.Resource) appservice.Service {
siteConfig := props.GetMapValue("siteConfig")
return appservice.Service{
Metadata: resource.Metadata,
Resource: types.String("Microsoft.Web/sites", resource.Metadata),
EnableClientCert: props.GetMapValue("clientCertEnabled").AsBoolValue(false, props.GetMetadata()),
HTTPSOnly: props.GetMapValue("httpsOnly").AsBoolValue(false, props.GetMetadata()),
Identity: appservice.Identity{

View File

@@ -25,7 +25,9 @@ func TestAdapt(t *testing.T) {
]
}`,
expected: appservice.AppService{
Services: []appservice.Service{{}},
Services: []appservice.Service{{
Resource: types.StringTest("Microsoft.Web/sites"),
}},
FunctionApps: []appservice.FunctionApp{{}},
},
},
@@ -58,6 +60,7 @@ func TestAdapt(t *testing.T) {
}`,
expected: appservice.AppService{
Services: []appservice.Service{{
Resource: types.StringTest("Microsoft.Web/sites"),
EnableClientCert: types.BoolTest(true),
HTTPSOnly: types.BoolTest(true),
Identity: appservice.Identity{

View File

@@ -18,12 +18,17 @@ func adaptServices(modules terraform.Modules) []appservice.Service {
for _, resource := range modules.GetResourcesByType("azurerm_app_service") {
services = append(services, adaptService(resource))
}
for _, resource := range modules.GetResourcesByType("azurerm_linux_web_app", "azurerm_windows_web_app") {
services = append(services, adaptWebApp(resource))
}
return services
}
func adaptFunctionApps(modules terraform.Modules) []appservice.FunctionApp {
var functionApps []appservice.FunctionApp
for _, resource := range modules.GetResourcesByType("azurerm_function_app") {
for _, resource := range modules.GetResourcesByType(
"azurerm_function_app", "azurerm_linux_function_app", "azurerm_windows_function_app",
) {
functionApps = append(functionApps, adaptFunctionApp(resource))
}
return functionApps
@@ -32,6 +37,7 @@ func adaptFunctionApps(modules terraform.Modules) []appservice.FunctionApp {
func adaptService(resource *terraform.Block) appservice.Service {
service := appservice.Service{
Metadata: resource.GetMetadata(),
Resource: types.String(resource.TypeLabel(), resource.GetMetadata()),
EnableClientCert: resource.GetAttribute("client_cert_enabled").AsBoolValueOrDefault(false, resource),
HTTPSOnly: resource.GetAttribute("https_only").AsBoolValueOrDefault(false, resource),
Site: appservice.Site{
@@ -74,3 +80,53 @@ func adaptFunctionApp(resource *terraform.Block) appservice.FunctionApp {
HTTPSOnly: resource.GetAttribute("https_only").AsBoolValueOrDefault(false, resource),
}
}
func adaptWebApp(resource *terraform.Block) appservice.Service {
service := appservice.Service{
Metadata: resource.GetMetadata(),
Resource: types.String(resource.TypeLabel(), resource.GetMetadata()),
EnableClientCert: resource.GetAttribute("client_certificate_enabled").AsBoolValueOrDefault(false, resource),
HTTPSOnly: resource.GetAttribute("https_only").AsBoolValueOrDefault(false, resource),
Site: appservice.Site{
Metadata: resource.GetMetadata(),
FTPSState: types.StringDefault("Disabled", resource.GetMetadata()),
MinimumTLSVersion: types.StringDefault("1.2", resource.GetMetadata()),
},
}
if identityBlock := resource.GetBlock("identity"); identityBlock.IsNotNil() {
service.Identity = appservice.Identity{
Metadata: identityBlock.GetMetadata(),
Type: identityBlock.GetAttribute("type").AsStringValueOrDefault("", identityBlock),
}
}
if authBlock := resource.GetBlock("auth_settings"); authBlock.IsNotNil() {
service.Authentication = appservice.Authentication{
Metadata: authBlock.GetMetadata(),
Enabled: authBlock.GetAttribute("enabled").AsBoolValueOrDefault(false, authBlock),
}
}
if siteBlock := resource.GetBlock("site_config"); siteBlock.IsNotNil() {
service.Site = appservice.Site{
Metadata: siteBlock.GetMetadata(),
EnableHTTP2: siteBlock.GetAttribute("http2_enabled").AsBoolValueOrDefault(false, siteBlock),
MinimumTLSVersion: siteBlock.GetAttribute("minimum_tls_version").AsStringValueOrDefault("1.2", siteBlock),
FTPSState: siteBlock.GetAttribute("ftps_state").AsStringValueOrDefault("Disabled", siteBlock),
}
if appStack := siteBlock.GetBlock("application_stack"); appStack.IsNotNil() {
switch resource.TypeLabel() {
case "azurerm_linux_web_app":
service.Site.PHPVersion = appStack.GetAttribute("php_version").AsStringValueOrDefault("", appStack)
service.Site.PythonVersion = appStack.GetAttribute("python_version").AsStringValueOrDefault("", appStack)
case "azurerm_windows_web_app":
// azurerm_windows_web_app does not support configuring the python version
appStack := siteBlock.GetBlock("application_stack")
service.Site.PHPVersion = appStack.GetAttribute("php_version").AsStringValueOrDefault("", appStack)
}
}
}
return service
}

View File

@@ -16,7 +16,7 @@ func Test_adaptService(t *testing.T) {
tests := []struct {
name string
terraform string
expected appservice.Service
expected appservice.AppService
}{
{
name: "configured",
@@ -39,18 +39,21 @@ func Test_adaptService(t *testing.T) {
}
}
`,
expected: appservice.Service{
EnableClientCert: iacTypes.BoolTest(true),
Identity: appservice.Identity{
Type: iacTypes.StringTest("UserAssigned"),
},
Authentication: appservice.Authentication{
Enabled: iacTypes.BoolTest(true),
},
Site: appservice.Site{
EnableHTTP2: iacTypes.BoolTest(true),
MinimumTLSVersion: iacTypes.StringTest("1.0"),
},
expected: appservice.AppService{
Services: []appservice.Service{{
Resource: iacTypes.StringTest("azurerm_app_service"),
EnableClientCert: iacTypes.BoolTest(true),
Identity: appservice.Identity{
Type: iacTypes.StringTest("UserAssigned"),
},
Authentication: appservice.Authentication{
Enabled: iacTypes.BoolTest(true),
},
Site: appservice.Site{
EnableHTTP2: iacTypes.BoolTest(true),
MinimumTLSVersion: iacTypes.StringTest("1.0"),
},
}},
},
},
{
@@ -59,10 +62,73 @@ func Test_adaptService(t *testing.T) {
resource "azurerm_app_service" "my_example" {
}
`,
expected: appservice.Service{
Site: appservice.Site{
MinimumTLSVersion: iacTypes.StringTest("1.2"),
},
expected: appservice.AppService{
Services: []appservice.Service{{
Resource: iacTypes.StringTest("azurerm_app_service"),
Site: appservice.Site{
MinimumTLSVersion: iacTypes.StringTest("1.2"),
},
}},
},
},
{
name: "empty azurerm_windows_web_app",
terraform: `resource "azurerm_windows_web_app" "example" {
name = "example"
}`,
expected: appservice.AppService{
Services: []appservice.Service{{
Resource: iacTypes.StringTest("azurerm_windows_web_app"),
Site: appservice.Site{
MinimumTLSVersion: iacTypes.StringTest("1.2"),
FTPSState: iacTypes.StringTest("Disabled"),
},
}},
},
},
{
name: "complete azurerm_windows_web_app",
terraform: `resource "azurerm_windows_web_app" "example" {
https_only = true
client_certificate_enabled = true
identity {
type = "SystemAssigned"
}
auth_settings {
enabled = true
}
site_config {
http2_enabled = true
minimum_tls_version = "1.3"
ftps_state = "FtpsOnly"
application_stack {
php_version = "7.4"
}
}
}
`,
expected: appservice.AppService{
Services: []appservice.Service{{
Resource: iacTypes.StringTest("azurerm_windows_web_app"),
HTTPSOnly: iacTypes.BoolTest(true),
EnableClientCert: iacTypes.BoolTest(true),
Identity: appservice.Identity{
Type: iacTypes.StringTest("SystemAssigned"),
},
Authentication: appservice.Authentication{
Enabled: iacTypes.BoolTest(true),
},
Site: appservice.Site{
EnableHTTP2: iacTypes.BoolTest(true),
MinimumTLSVersion: iacTypes.StringTest("1.3"),
FTPSState: iacTypes.StringTest("FtpsOnly"),
PHPVersion: iacTypes.StringTest("7.4"),
},
}},
},
},
}
@@ -70,7 +136,7 @@ func Test_adaptService(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
modules := tftestutil.CreateModulesFromSource(t, test.terraform, ".tf")
adapted := adaptService(modules.GetBlocks()[0])
adapted := Adapt(modules)
testutil.AssertDefsecEqual(t, test.expected, adapted)
})
}
@@ -104,6 +170,18 @@ func Test_adaptFunctionApp(t *testing.T) {
HTTPSOnly: iacTypes.BoolTest(false),
},
},
{
name: "os-specific resource",
terraform: `
resource "azurerm_windows_function_app" "my_example" {
name = "test-azure-functions"
https_only = true
}
`,
expected: appservice.FunctionApp{
HTTPSOnly: iacTypes.BoolTest(true),
},
},
}
for _, test := range tests {

View File

@@ -21,6 +21,7 @@ type Authentication struct {
type Service struct {
Metadata iacTypes.Metadata
Resource iacTypes.StringValue
EnableClientCert iacTypes.BoolValue
HTTPSOnly iacTypes.BoolValue
Identity Identity

View File

@@ -4566,6 +4566,10 @@
"type": "object",
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Identity"
},
"platform": {
"type": "object",
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue"
},
"site": {
"type": "object",
"$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.appservice.Site"