diff --git a/pkg/iac/adapters/arm/database/mssql.go b/pkg/iac/adapters/arm/database/mssql.go index b656895a8d..4b545c13e5 100644 --- a/pkg/iac/adapters/arm/database/mssql.go +++ b/pkg/iac/adapters/arm/database/mssql.go @@ -14,18 +14,36 @@ func adaptMSSQLServers(deployment azure2.Deployment) (msSQlServers []database.MS } func adaptMSSQLServer(resource azure2.Resource, deployment azure2.Deployment) database.MSSQLServer { + properties := resource.Properties + administratorLogin := properties.GetMapValue("administratorLogin").AsStringValue("", resource.Metadata) + + // Support for azureadAdministrator block (ARM uses administrators property) + var adAdmins []database.ActiveDirectoryAdministrator + administrators := properties.GetMapValue("administrators") + if administrators.Kind != azure2.KindNull { + login := administrators.GetMapValue("login").AsStringValue("", administrators.GetMetadata()) + if !login.IsEmpty() { + adAdmins = append(adAdmins, database.ActiveDirectoryAdministrator{ + Metadata: administrators.GetMetadata(), + Login: login, + }) + } + } + return database.MSSQLServer{ Metadata: resource.Metadata, Server: database.Server{ Metadata: resource.Metadata, // TODO: this property doesn't exist. - EnableSSLEnforcement: resource.Properties.GetMapValue("sslEnforcement").AsBoolValue(false, resource.Metadata), - MinimumTLSVersion: resource.Properties.GetMapValue("minimalTlsVersion").AsStringValue("TLSEnforcementDisabled", resource.Metadata), - EnablePublicNetworkAccess: resource.Properties.GetMapValue("publicNetworkAccess").AsBoolValue(false, resource.Metadata), + EnableSSLEnforcement: properties.GetMapValue("sslEnforcement").AsBoolValue(false, resource.Metadata), + MinimumTLSVersion: properties.GetMapValue("minimalTlsVersion").AsStringValue("TLSEnforcementDisabled", resource.Metadata), + EnablePublicNetworkAccess: properties.GetMapValue("publicNetworkAccess").AsBoolValue(false, resource.Metadata), FirewallRules: addFirewallRule(resource), }, - ExtendedAuditingPolicies: adaptExtendedAuditingPolicies(resource, deployment), - SecurityAlertPolicies: adaptSecurityAlertPolicies(resource, deployment), + ExtendedAuditingPolicies: adaptExtendedAuditingPolicies(resource, deployment), + SecurityAlertPolicies: adaptSecurityAlertPolicies(resource, deployment), + AdministratorLogin: administratorLogin, + ActiveDirectoryAdministrators: adAdmins, } } diff --git a/pkg/iac/adapters/arm/database/postgresql.go b/pkg/iac/adapters/arm/database/postgresql.go index 155667c65f..f4160aa582 100644 --- a/pkg/iac/adapters/arm/database/postgresql.go +++ b/pkg/iac/adapters/arm/database/postgresql.go @@ -18,16 +18,24 @@ func adaptPostgreSQLServers(deployment azure.Deployment) (databases []database.P } func adaptPostgreSQLServer(resource azure.Resource, deployment azure.Deployment) database.PostgreSQLServer { + properties := resource.Properties + geoRedundantBackup := properties.GetMapValue("storageProfile").GetMapValue("geoRedundantBackup") + geoRedundantBackupEnabled := geoRedundantBackup.AsStringValue("Disabled", resource.Metadata) + + threatDetectionPolicy := adaptThreatDetectionPolicy(resource, deployment) + return database.PostgreSQLServer{ Metadata: resource.Metadata, Server: database.Server{ Metadata: resource.Metadata, - EnableSSLEnforcement: resource.Properties.GetMapValue("sslEnforcement").AsBoolValue(false, resource.Metadata), - MinimumTLSVersion: resource.Properties.GetMapValue("minimalTlsVersion").AsStringValue("TLSEnforcementDisabled", resource.Metadata), - EnablePublicNetworkAccess: resource.Properties.GetMapValue("publicNetworkAccess").AsBoolValue(false, resource.Metadata), + EnableSSLEnforcement: properties.GetMapValue("sslEnforcement").AsBoolValue(false, resource.Metadata), + MinimumTLSVersion: properties.GetMapValue("minimalTlsVersion").AsStringValue("TLSEnforcementDisabled", resource.Metadata), + EnablePublicNetworkAccess: properties.GetMapValue("publicNetworkAccess").AsBoolValue(false, resource.Metadata), FirewallRules: addFirewallRule(resource), }, - Config: adaptPostgreSQLConfiguration(resource, deployment), + Config: adaptPostgreSQLConfiguration(resource, deployment), + GeoRedundantBackupEnabled: iacTypes.Bool(geoRedundantBackupEnabled.EqualTo("Enabled"), geoRedundantBackup.GetMetadata()), + ThreatDetectionPolicy: threatDetectionPolicy, } } @@ -40,25 +48,57 @@ func adaptPostgreSQLConfiguration(resource azure.Resource, deployment azure.Depl LogCheckpoints: iacTypes.BoolDefault(false, resource.Metadata), ConnectionThrottling: iacTypes.BoolDefault(false, resource.Metadata), LogConnections: iacTypes.BoolDefault(false, resource.Metadata), + LogDisconnections: iacTypes.BoolDefault(false, resource.Metadata), } for _, configuration := range deployment.GetResourcesByType("Microsoft.DBforPostgreSQL/servers/configurations") { - if strings.HasPrefix(configuration.Name.AsString(), parent) { - val := configuration.Properties.GetMapValue("value") - if strings.HasSuffix(configuration.Name.AsString(), "log_checkpoints") { - config.LogCheckpoints = val.AsBoolValue(false, configuration.Metadata) - continue - } - if strings.HasSuffix(configuration.Name.AsString(), "log_connections") { - config.LogConnections = val.AsBoolValue(false, configuration.Metadata) - continue - } - if strings.HasSuffix(configuration.Name.AsString(), "connection_throttling") { - config.ConnectionThrottling = val.AsBoolValue(false, configuration.Metadata) - continue - } + if !strings.HasPrefix(configuration.Name.AsString(), parent) { + continue + } + val := configuration.Properties.GetMapValue("value") + if strings.HasSuffix(configuration.Name.AsString(), "log_checkpoints") { + config.LogCheckpoints = val.AsBoolValue(false, configuration.Metadata) + continue + } + if strings.HasSuffix(configuration.Name.AsString(), "log_connections") { + config.LogConnections = val.AsBoolValue(false, configuration.Metadata) + continue + } + if strings.HasSuffix(configuration.Name.AsString(), "connection_throttling") { + config.ConnectionThrottling = val.AsBoolValue(false, configuration.Metadata) + continue + } + if strings.HasSuffix(configuration.Name.AsString(), "log_disconnections") { + config.LogDisconnections = val.AsBoolValue(false, configuration.Metadata) + continue } } return config } + +func adaptThreatDetectionPolicy(resource azure.Resource, deployment azure.Deployment) database.ThreatDetectionPolicy { + // Threat detection policy is configured via Microsoft.DBforPostgreSQL/servers/securityAlertPolicies + // This is a separate child resource, not a property of the server resource + parent := fmt.Sprintf("%s/", resource.Name.AsString()) + + enabled := false + metadata := resource.Metadata + + // Look for security alert policy resources that belong to this server + for _, policy := range deployment.GetResourcesByType("Microsoft.DBforPostgreSQL/servers/securityAlertPolicies") { + if !strings.HasPrefix(policy.Name.AsString(), parent) { + continue + } + // Found the security alert policy for this server + state := policy.Properties.GetMapValue("state").AsStringValue("Disabled", policy.Metadata) + enabled = state.EqualTo("Enabled") + metadata = policy.Properties.GetMapValue("state").GetMetadata() + break + } + + return database.ThreatDetectionPolicy{ + Metadata: metadata, + Enabled: iacTypes.Bool(enabled, metadata), + } +} diff --git a/pkg/iac/adapters/terraform/azure/adapt.go b/pkg/iac/adapters/terraform/azure/adapt.go index bf2fc06317..990537fbde 100644 --- a/pkg/iac/adapters/terraform/azure/adapt.go +++ b/pkg/iac/adapters/terraform/azure/adapt.go @@ -5,6 +5,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/authorization" "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/compute" "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/container" + "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/cosmosdb" "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/database" "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/datafactory" "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/azure/datalake" @@ -24,6 +25,7 @@ func Adapt(modules terraform.Modules) azure.Azure { Authorization: authorization.Adapt(modules), Compute: compute.Adapt(modules), Container: container.Adapt(modules), + CosmosDB: cosmosdb.Adapt(modules), Database: database.Adapt(modules), DataFactory: datafactory.Adapt(modules), DataLake: datalake.Adapt(modules), diff --git a/pkg/iac/adapters/terraform/azure/cosmosdb/adapt.go b/pkg/iac/adapters/terraform/azure/cosmosdb/adapt.go new file mode 100644 index 0000000000..c2997e5ec1 --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/cosmosdb/adapt.go @@ -0,0 +1,46 @@ +package cosmosdb + +import ( + "github.com/zclconf/go-cty/cty" + + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/cosmosdb" + "github.com/aquasecurity/trivy/pkg/iac/terraform" + iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +func Adapt(modules terraform.Modules) cosmosdb.CosmosDB { + return cosmosdb.CosmosDB{ + Accounts: adaptCosmosDBAccounts(modules), + } +} + +func adaptCosmosDBAccounts(modules terraform.Modules) []cosmosdb.Account { + var cosmosDBAccounts []cosmosdb.Account + for _, module := range modules { + for _, resource := range module.GetResourcesByType("azurerm_cosmosdb_account") { + cosmosDBAccounts = append(cosmosDBAccounts, adaptCosmosDBAccount(resource)) + } + } + return cosmosDBAccounts +} + +func adaptCosmosDBAccount(resource *terraform.Block) cosmosdb.Account { + // ip_range_filter is a list of strings in Terraform + ipRangeFilterAttr := resource.GetAttribute("ip_range_filter") + var ipRangeFilterVal []iacTypes.StringValue + if ipRangeFilterAttr.IsNil() { + ipRangeFilterVal = []iacTypes.StringValue{} + } else { + switch ipRangeFilterAttr.Type() { + case cty.String: + ipRangeFilterVal = []iacTypes.StringValue{ipRangeFilterAttr.AsStringValueOrDefault("", resource)} + default: + ipRangeFilterVal = ipRangeFilterAttr.AsStringValues() + } + } + + return cosmosdb.Account{ + Metadata: resource.GetMetadata(), + IPRangeFilter: ipRangeFilterVal, + } +} diff --git a/pkg/iac/adapters/terraform/azure/cosmosdb/adapt_test.go b/pkg/iac/adapters/terraform/azure/cosmosdb/adapt_test.go new file mode 100644 index 0000000000..c9e0a60e8f --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/cosmosdb/adapt_test.go @@ -0,0 +1,238 @@ +package cosmosdb + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform/tftestutil" + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/cosmosdb" + iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +func Test_adaptCosmosDBAccount(t *testing.T) { + tests := []struct { + name string + terraform string + expected cosmosdb.Account + }{ + { + name: "default values", + terraform: ` +resource "azurerm_cosmosdb_account" "example" { +} +`, + expected: cosmosdb.Account{ + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{}, + }, + }, + { + name: "with ip_range_filter single value", + terraform: ` +resource "azurerm_cosmosdb_account" "example" { + ip_range_filter = ["10.0.0.0/16"] +} +`, + expected: cosmosdb.Account{ + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("10.0.0.0/16"), + }, + }, + }, + { + name: "with ip_range_filter multiple values", + terraform: ` +resource "azurerm_cosmosdb_account" "example" { + ip_range_filter = ["10.0.0.0/16", "192.168.1.0/24", "172.16.0.0/12"] +} +`, + expected: cosmosdb.Account{ + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("10.0.0.0/16"), + iacTypes.StringTest("192.168.1.0/24"), + iacTypes.StringTest("172.16.0.0/12"), + }, + }, + }, + { + name: "with ip_range_filter multiple values", + terraform: ` +resource "azurerm_cosmosdb_account" "example" { + ip_range_filter = ["10.0.0.0/8", "172.16.0.0/12"] +} +`, + expected: cosmosdb.Account{ + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("10.0.0.0/8"), + iacTypes.StringTest("172.16.0.0/12"), + }, + }, + }, + { + name: "empty ip_range_filter", + terraform: ` +resource "azurerm_cosmosdb_account" "example" { + ip_range_filter = [] +} +`, + expected: cosmosdb.Account{ + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: nil, // AsStringValues() returns nil for empty lists + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + modules := tftestutil.CreateModulesFromSource(t, test.terraform, ".tf") + adapted := adaptCosmosDBAccount(modules.GetBlocks()[0]) + testutil.AssertDefsecEqual(t, test.expected, adapted) + }) + } +} + +func Test_adaptCosmosDBAccounts(t *testing.T) { + tests := []struct { + name string + terraform string + expected []cosmosdb.Account + }{ + { + name: "single account", + terraform: ` +resource "azurerm_cosmosdb_account" "example1" { +} +`, + expected: []cosmosdb.Account{ + { + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{}, + }, + }, + }, + { + name: "multiple accounts", + terraform: ` +resource "azurerm_cosmosdb_account" "example1" { + ip_range_filter = ["10.0.0.0/16"] +} + +resource "azurerm_cosmosdb_account" "example2" { + ip_range_filter = ["192.168.0.0/16"] +} +`, + expected: []cosmosdb.Account{ + { + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("10.0.0.0/16"), + }, + }, + { + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("192.168.0.0/16"), + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + modules := tftestutil.CreateModulesFromSource(t, test.terraform, ".tf") + adapted := adaptCosmosDBAccounts(modules) + testutil.AssertDefsecEqual(t, test.expected, adapted) + }) + } +} + +func Test_Adapt(t *testing.T) { + tests := []struct { + name string + terraform string + expected cosmosdb.CosmosDB + }{ + { + name: "basic", + terraform: ` +resource "azurerm_cosmosdb_account" "example" { + ip_range_filter = ["10.0.0.0/16"] +} +`, + expected: cosmosdb.CosmosDB{ + Accounts: []cosmosdb.Account{ + { + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("10.0.0.0/16"), + }, + }, + }, + }, + }, + { + name: "multiple accounts", + terraform: ` +resource "azurerm_cosmosdb_account" "example1" { +} + +resource "azurerm_cosmosdb_account" "example2" { + ip_range_filter = ["192.168.0.0/16"] +} +`, + expected: cosmosdb.CosmosDB{ + Accounts: []cosmosdb.Account{ + { + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{}, + }, + { + Metadata: iacTypes.NewTestMetadata(), + IPRangeFilter: []iacTypes.StringValue{ + iacTypes.StringTest("192.168.0.0/16"), + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + modules := tftestutil.CreateModulesFromSource(t, test.terraform, ".tf") + adapted := Adapt(modules) + testutil.AssertDefsecEqual(t, test.expected, adapted) + }) + } +} + +func TestLines(t *testing.T) { + src := ` +resource "azurerm_cosmosdb_account" "example" { + ip_range_filter = ["10.0.0.0/16", "192.168.1.0/24"] +} +` + + modules := tftestutil.CreateModulesFromSource(t, src, ".tf") + adapted := Adapt(modules) + + require.Len(t, adapted.Accounts, 1) + + account := adapted.Accounts[0] + + assert.Equal(t, 2, account.Metadata.Range().GetStartLine()) + assert.Equal(t, 4, account.Metadata.Range().GetEndLine()) + + require.Len(t, account.IPRangeFilter, 2) + assert.Equal(t, 3, account.IPRangeFilter[0].GetMetadata().Range().GetStartLine()) + assert.Equal(t, 3, account.IPRangeFilter[0].GetMetadata().Range().GetEndLine()) + assert.Equal(t, 3, account.IPRangeFilter[1].GetMetadata().Range().GetStartLine()) + assert.Equal(t, 3, account.IPRangeFilter[1].GetMetadata().Range().GetEndLine()) +} diff --git a/pkg/iac/adapters/terraform/azure/database/adapt.go b/pkg/iac/adapters/terraform/azure/database/adapt.go index 7b2f3635a2..5d154be10d 100644 --- a/pkg/iac/adapters/terraform/azure/database/adapt.go +++ b/pkg/iac/adapters/terraform/azure/database/adapt.go @@ -3,435 +3,13 @@ package database import ( "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" "github.com/aquasecurity/trivy/pkg/iac/terraform" - iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" ) func Adapt(modules terraform.Modules) database.Database { - - mssqlAdapter := mssqlAdapter{ - alertPolicyIDs: modules.GetChildResourceIDMapByType("azurerm_mssql_server_security_alert_policy"), - auditingPolicyIDs: modules.GetChildResourceIDMapByType("azurerm_mssql_server_extended_auditing_policy", "azurerm_mssql_database_extended_auditing_policy"), - firewallIDs: modules.GetChildResourceIDMapByType("azurerm_sql_firewall_rule", "azurerm_mssql_firewall_rule"), - } - - mysqlAdapter := mysqlAdapter{ - firewallIDs: modules.GetChildResourceIDMapByType("azurerm_mysql_firewall_rule"), - } - - mariaDBAdapter := mariaDBAdapter{ - firewallIDs: modules.GetChildResourceIDMapByType("azurerm_mariadb_firewall_rule"), - } - - postgresqlAdapter := postgresqlAdapter{ - firewallIDs: modules.GetChildResourceIDMapByType("azurerm_postgresql_firewall_rule"), - } - return database.Database{ - MSSQLServers: mssqlAdapter.adaptMSSQLServers(modules), - MariaDBServers: mariaDBAdapter.adaptMariaDBServers(modules), - MySQLServers: mysqlAdapter.adaptMySQLServers(modules), - PostgreSQLServers: postgresqlAdapter.adaptPostgreSQLServers(modules), - } -} - -type mssqlAdapter struct { - alertPolicyIDs terraform.ResourceIDResolutions - auditingPolicyIDs terraform.ResourceIDResolutions - firewallIDs terraform.ResourceIDResolutions -} - -type mysqlAdapter struct { - firewallIDs terraform.ResourceIDResolutions -} - -type mariaDBAdapter struct { - firewallIDs terraform.ResourceIDResolutions -} - -type postgresqlAdapter struct { - firewallIDs terraform.ResourceIDResolutions -} - -func (a *mssqlAdapter) adaptMSSQLServers(modules terraform.Modules) []database.MSSQLServer { - var mssqlServers []database.MSSQLServer - for _, module := range modules { - for _, resource := range module.GetResourcesByType("azurerm_sql_server") { - mssqlServers = append(mssqlServers, a.adaptMSSQLServer(resource, module)) - } - for _, resource := range module.GetResourcesByType("azurerm_mssql_server") { - mssqlServers = append(mssqlServers, a.adaptMSSQLServer(resource, module)) - } - } - - orphanResources := modules.GetResourceByIDs(a.alertPolicyIDs.Orphans()...) - - if len(orphanResources) > 0 { - orphanage := database.MSSQLServer{ - Metadata: iacTypes.NewUnmanagedMetadata(), - Server: database.Server{ - Metadata: iacTypes.NewUnmanagedMetadata(), - EnableSSLEnforcement: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - MinimumTLSVersion: iacTypes.StringDefault("", iacTypes.NewUnmanagedMetadata()), - EnablePublicNetworkAccess: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - FirewallRules: nil, - }, - ExtendedAuditingPolicies: nil, - SecurityAlertPolicies: nil, - } - for _, policy := range orphanResources { - orphanage.SecurityAlertPolicies = append(orphanage.SecurityAlertPolicies, adaptMSSQLSecurityAlertPolicy(policy)) - } - mssqlServers = append(mssqlServers, orphanage) - - } - - orphanResources = modules.GetResourceByIDs(a.auditingPolicyIDs.Orphans()...) - - if len(orphanResources) > 0 { - orphanage := database.MSSQLServer{ - Metadata: iacTypes.NewUnmanagedMetadata(), - Server: database.Server{ - Metadata: iacTypes.NewUnmanagedMetadata(), - EnableSSLEnforcement: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - MinimumTLSVersion: iacTypes.StringDefault("", iacTypes.NewUnmanagedMetadata()), - EnablePublicNetworkAccess: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - FirewallRules: nil, - }, - } - for _, policy := range orphanResources { - orphanage.ExtendedAuditingPolicies = append(orphanage.ExtendedAuditingPolicies, adaptMSSQLExtendedAuditingPolicy(policy)) - } - mssqlServers = append(mssqlServers, orphanage) - - } - - orphanResources = modules.GetResourceByIDs(a.firewallIDs.Orphans()...) - - if len(orphanResources) > 0 { - orphanage := database.MSSQLServer{ - Metadata: iacTypes.NewUnmanagedMetadata(), - } - for _, policy := range orphanResources { - orphanage.FirewallRules = append(orphanage.FirewallRules, adaptFirewallRule(policy)) - } - mssqlServers = append(mssqlServers, orphanage) - - } - - return mssqlServers -} -func (a *mysqlAdapter) adaptMySQLServers(modules terraform.Modules) []database.MySQLServer { - var mySQLServers []database.MySQLServer - for _, module := range modules { - for _, resource := range module.GetResourcesByType("azurerm_mysql_server") { - mySQLServers = append(mySQLServers, a.adaptMySQLServer(resource, module)) - } - } - - orphanResources := modules.GetResourceByIDs(a.firewallIDs.Orphans()...) - - if len(orphanResources) > 0 { - orphanage := database.MySQLServer{ - Metadata: iacTypes.NewUnmanagedMetadata(), - Server: database.Server{ - Metadata: iacTypes.NewUnmanagedMetadata(), - EnableSSLEnforcement: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - MinimumTLSVersion: iacTypes.StringDefault("", iacTypes.NewUnmanagedMetadata()), - EnablePublicNetworkAccess: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - FirewallRules: nil, - }, - } - for _, policy := range orphanResources { - orphanage.FirewallRules = append(orphanage.FirewallRules, adaptFirewallRule(policy)) - } - mySQLServers = append(mySQLServers, orphanage) - - } - - return mySQLServers -} - -func (a *mariaDBAdapter) adaptMariaDBServers(modules terraform.Modules) []database.MariaDBServer { - var mariaDBServers []database.MariaDBServer - for _, module := range modules { - for _, resource := range module.GetResourcesByType("azurerm_mariadb_server") { - mariaDBServers = append(mariaDBServers, a.adaptMariaDBServer(resource, module)) - } - } - - orphanResources := modules.GetResourceByIDs(a.firewallIDs.Orphans()...) - - if len(orphanResources) > 0 { - orphanage := database.MariaDBServer{ - Metadata: iacTypes.NewUnmanagedMetadata(), - Server: database.Server{ - Metadata: iacTypes.NewUnmanagedMetadata(), - EnableSSLEnforcement: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - MinimumTLSVersion: iacTypes.StringDefault("", iacTypes.NewUnmanagedMetadata()), - EnablePublicNetworkAccess: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - FirewallRules: nil, - }, - } - for _, policy := range orphanResources { - orphanage.FirewallRules = append(orphanage.FirewallRules, adaptFirewallRule(policy)) - } - mariaDBServers = append(mariaDBServers, orphanage) - - } - - return mariaDBServers -} - -func (a *postgresqlAdapter) adaptPostgreSQLServers(modules terraform.Modules) []database.PostgreSQLServer { - var postgreSQLServers []database.PostgreSQLServer - for _, module := range modules { - for _, resource := range module.GetResourcesByType("azurerm_postgresql_server") { - postgreSQLServers = append(postgreSQLServers, a.adaptPostgreSQLServer(resource, module)) - } - } - - orphanResources := modules.GetResourceByIDs(a.firewallIDs.Orphans()...) - - if len(orphanResources) > 0 { - orphanage := database.PostgreSQLServer{ - Metadata: iacTypes.NewUnmanagedMetadata(), - Server: database.Server{ - Metadata: iacTypes.NewUnmanagedMetadata(), - EnableSSLEnforcement: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - MinimumTLSVersion: iacTypes.StringDefault("", iacTypes.NewUnmanagedMetadata()), - EnablePublicNetworkAccess: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - FirewallRules: nil, - }, - Config: database.PostgresSQLConfig{ - Metadata: iacTypes.NewUnmanagedMetadata(), - LogCheckpoints: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - ConnectionThrottling: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - LogConnections: iacTypes.BoolDefault(false, iacTypes.NewUnmanagedMetadata()), - }, - } - for _, policy := range orphanResources { - orphanage.FirewallRules = append(orphanage.FirewallRules, adaptFirewallRule(policy)) - } - postgreSQLServers = append(postgreSQLServers, orphanage) - - } - - return postgreSQLServers -} - -func (a *mssqlAdapter) adaptMSSQLServer(resource *terraform.Block, module *terraform.Module) database.MSSQLServer { - minTLSVersionVal := iacTypes.StringDefault("", resource.GetMetadata()) - publicAccessVal := iacTypes.BoolDefault(true, resource.GetMetadata()) - enableSSLEnforcementVal := iacTypes.BoolDefault(false, resource.GetMetadata()) - - var auditingPolicies []database.ExtendedAuditingPolicy - var alertPolicies []database.SecurityAlertPolicy - var firewallRules []database.FirewallRule - - if resource.TypeLabel() == "azurerm_mssql_server" { - minTLSVersionAttr := resource.GetAttribute("minimum_tls_version") - minTLSVersionVal = minTLSVersionAttr.AsStringValueOrDefault("", resource) - - publicAccessAttr := resource.GetAttribute("public_network_access_enabled") - publicAccessVal = publicAccessAttr.AsBoolValueOrDefault(true, resource) - - } - - alertPolicyBlocks := module.GetReferencingResources(resource, "azurerm_mssql_server_security_alert_policy", "server_name") - for _, alertBlock := range alertPolicyBlocks { - a.alertPolicyIDs.Resolve(alertBlock.ID()) - alertPolicies = append(alertPolicies, adaptMSSQLSecurityAlertPolicy(alertBlock)) - } - - auditingPoliciesBlocks := module.GetReferencingResources(resource, "azurerm_mssql_server_extended_auditing_policy", "server_id") - auditingPoliciesBlocks = append(auditingPoliciesBlocks, resource.GetBlocks("extended_auditing_policy")...) - - databasesRes := module.GetReferencingResources(resource, "azurerm_mssql_database", "server_id") - for _, databaseRes := range databasesRes { - dbAuditingBlocks := module.GetReferencingResources(databaseRes, "azurerm_mssql_database_extended_auditing_policy", "database_id") - auditingPoliciesBlocks = append(auditingPoliciesBlocks, dbAuditingBlocks...) - } - - for _, auditBlock := range auditingPoliciesBlocks { - a.auditingPolicyIDs.Resolve(auditBlock.ID()) - auditingPolicies = append(auditingPolicies, adaptMSSQLExtendedAuditingPolicy(auditBlock)) - } - - firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_sql_firewall_rule", "server_name") - firewallRuleBlocks = append(firewallRuleBlocks, module.GetReferencingResources(resource, "azurerm_mssql_firewall_rule", "server_id")...) - for _, firewallBlock := range firewallRuleBlocks { - a.firewallIDs.Resolve(firewallBlock.ID()) - firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) - } - - return database.MSSQLServer{ - Metadata: resource.GetMetadata(), - Server: database.Server{ - Metadata: resource.GetMetadata(), - EnableSSLEnforcement: enableSSLEnforcementVal, - MinimumTLSVersion: minTLSVersionVal, - EnablePublicNetworkAccess: publicAccessVal, - FirewallRules: firewallRules, - }, - ExtendedAuditingPolicies: auditingPolicies, - SecurityAlertPolicies: alertPolicies, - } -} - -func (a *mysqlAdapter) adaptMySQLServer(resource *terraform.Block, module *terraform.Module) database.MySQLServer { - var firewallRules []database.FirewallRule - - enableSSLEnforcementAttr := resource.GetAttribute("ssl_enforcement_enabled") - enableSSLEnforcementVal := enableSSLEnforcementAttr.AsBoolValueOrDefault(false, resource) - - minTLSVersionAttr := resource.GetAttribute("ssl_minimal_tls_version_enforced") - minTLSVersionVal := minTLSVersionAttr.AsStringValueOrDefault("TLSEnforcementDisabled", resource) - - publicAccessAttr := resource.GetAttribute("public_network_access_enabled") - publicAccessVal := publicAccessAttr.AsBoolValueOrDefault(true, resource) - - firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_mysql_firewall_rule", "server_name") - for _, firewallBlock := range firewallRuleBlocks { - a.firewallIDs.Resolve(firewallBlock.ID()) - firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) - } - - return database.MySQLServer{ - Metadata: resource.GetMetadata(), - Server: database.Server{ - Metadata: resource.GetMetadata(), - EnableSSLEnforcement: enableSSLEnforcementVal, - MinimumTLSVersion: minTLSVersionVal, - EnablePublicNetworkAccess: publicAccessVal, - FirewallRules: firewallRules, - }, - } -} - -func (a *mariaDBAdapter) adaptMariaDBServer(resource *terraform.Block, module *terraform.Module) database.MariaDBServer { - var firewallRules []database.FirewallRule - - enableSSLEnforcementAttr := resource.GetAttribute("ssl_enforcement_enabled") - enableSSLEnforcementVal := enableSSLEnforcementAttr.AsBoolValueOrDefault(false, resource) - - publicAccessAttr := resource.GetAttribute("public_network_access_enabled") - publicAccessVal := publicAccessAttr.AsBoolValueOrDefault(true, resource) - - firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_mariadb_firewall_rule", "server_name") - for _, firewallBlock := range firewallRuleBlocks { - a.firewallIDs.Resolve(firewallBlock.ID()) - firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) - } - - return database.MariaDBServer{ - Metadata: resource.GetMetadata(), - Server: database.Server{ - Metadata: resource.GetMetadata(), - EnableSSLEnforcement: enableSSLEnforcementVal, - MinimumTLSVersion: iacTypes.StringDefault("", resource.GetMetadata()), - EnablePublicNetworkAccess: publicAccessVal, - FirewallRules: firewallRules, - }, - } -} - -func (a *postgresqlAdapter) adaptPostgreSQLServer(resource *terraform.Block, module *terraform.Module) database.PostgreSQLServer { - var firewallRules []database.FirewallRule - - enableSSLEnforcementAttr := resource.GetAttribute("ssl_enforcement_enabled") - enableSSLEnforcementVal := enableSSLEnforcementAttr.AsBoolValueOrDefault(false, resource) - - minTLSVersionAttr := resource.GetAttribute("ssl_minimal_tls_version_enforced") - minTLSVersionVal := minTLSVersionAttr.AsStringValueOrDefault("TLSEnforcementDisabled", resource) - - publicAccessAttr := resource.GetAttribute("public_network_access_enabled") - publicAccessVal := publicAccessAttr.AsBoolValueOrDefault(true, resource) - - firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_postgresql_firewall_rule", "server_name") - for _, firewallBlock := range firewallRuleBlocks { - a.firewallIDs.Resolve(firewallBlock.ID()) - firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) - } - - configBlocks := module.GetReferencingResources(resource, "azurerm_postgresql_configuration", "server_name") - config := adaptPostgreSQLConfig(resource, configBlocks) - - return database.PostgreSQLServer{ - Metadata: resource.GetMetadata(), - Server: database.Server{ - Metadata: resource.GetMetadata(), - EnableSSLEnforcement: enableSSLEnforcementVal, - MinimumTLSVersion: minTLSVersionVal, - EnablePublicNetworkAccess: publicAccessVal, - FirewallRules: firewallRules, - }, - Config: config, - } -} - -func adaptPostgreSQLConfig(resource *terraform.Block, configBlocks []*terraform.Block) database.PostgresSQLConfig { - config := database.PostgresSQLConfig{ - Metadata: resource.GetMetadata(), - LogCheckpoints: iacTypes.BoolDefault(false, resource.GetMetadata()), - ConnectionThrottling: iacTypes.BoolDefault(false, resource.GetMetadata()), - LogConnections: iacTypes.BoolDefault(false, resource.GetMetadata()), - } - - for _, configBlock := range configBlocks { - - nameAttr := configBlock.GetAttribute("name") - valAttr := configBlock.GetAttribute("value") - - if nameAttr.Equals("log_checkpoints") { - config.LogCheckpoints = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) - } - if nameAttr.Equals("connection_throttling") { - config.ConnectionThrottling = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) - } - if nameAttr.Equals("log_connections") { - config.LogConnections = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) - } - } - - return config -} - -func adaptMSSQLSecurityAlertPolicy(resource *terraform.Block) database.SecurityAlertPolicy { - - emailAddressesAttr := resource.GetAttribute("email_addresses") - disabledAlertsAttr := resource.GetAttribute("disabled_alerts") - - emailAccountAdminsAttr := resource.GetAttribute("email_account_admins") - emailAccountAdminsVal := emailAccountAdminsAttr.AsBoolValueOrDefault(false, resource) - - return database.SecurityAlertPolicy{ - Metadata: resource.GetMetadata(), - EmailAddresses: emailAddressesAttr.AsStringValues(), - DisabledAlerts: disabledAlertsAttr.AsStringValues(), - EmailAccountAdmins: emailAccountAdminsVal, - } -} - -func adaptFirewallRule(resource *terraform.Block) database.FirewallRule { - startIPAttr := resource.GetAttribute("start_ip_address") - startIPVal := startIPAttr.AsStringValueOrDefault("", resource) - - endIPAttr := resource.GetAttribute("end_ip_address") - endIPVal := endIPAttr.AsStringValueOrDefault("", resource) - - return database.FirewallRule{ - Metadata: resource.GetMetadata(), - StartIP: startIPVal, - EndIP: endIPVal, - } -} - -func adaptMSSQLExtendedAuditingPolicy(resource *terraform.Block) database.ExtendedAuditingPolicy { - retentionInDaysAttr := resource.GetAttribute("retention_in_days") - retentionInDaysVal := retentionInDaysAttr.AsIntValueOrDefault(0, resource) - - return database.ExtendedAuditingPolicy{ - Metadata: resource.GetMetadata(), - RetentionInDays: retentionInDaysVal, + MSSQLServers: adaptMSSQLServers(modules), + MariaDBServers: adaptMariaDBServers(modules), + MySQLServers: adaptMySQLServers(modules), + PostgreSQLServers: adaptPostgreSQLServers(modules), } } diff --git a/pkg/iac/adapters/terraform/azure/database/adapt_test.go b/pkg/iac/adapters/terraform/azure/database/adapt_test.go index 05dc61173d..d40f38284a 100644 --- a/pkg/iac/adapters/terraform/azure/database/adapt_test.go +++ b/pkg/iac/adapters/terraform/azure/database/adapt_test.go @@ -61,25 +61,86 @@ func Test_Adapt(t *testing.T) { expected: database.Database{ PostgreSQLServers: []database.PostgreSQLServer{ { - Metadata: iacTypes.NewTestMetadata(), Server: database.Server{ - Metadata: iacTypes.NewTestMetadata(), - EnableSSLEnforcement: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - MinimumTLSVersion: iacTypes.String("TLS1_2", iacTypes.NewTestMetadata()), - EnablePublicNetworkAccess: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), FirewallRules: []database.FirewallRule{ { - Metadata: iacTypes.NewTestMetadata(), - StartIP: iacTypes.String("40.112.8.12", iacTypes.NewTestMetadata()), - EndIP: iacTypes.String("40.112.8.12", iacTypes.NewTestMetadata()), + StartIP: iacTypes.StringTest("40.112.8.12"), + EndIP: iacTypes.StringTest("40.112.8.12"), }, }, }, Config: database.PostgresSQLConfig{ - Metadata: iacTypes.NewTestMetadata(), - LogConnections: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - LogCheckpoints: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - ConnectionThrottling: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + LogConnections: iacTypes.BoolTest(true), + LogCheckpoints: iacTypes.BoolTest(true), + ConnectionThrottling: iacTypes.BoolTest(true), + }, + }, + }, + }, + }, + { + name: "postgresql with geo redundant backup and threat detection", + terraform: ` + resource "azurerm_postgresql_server" "example" { + name = "example" + + public_network_access_enabled = true + ssl_enforcement_enabled = true + ssl_minimal_tls_version_enforced = "TLS1_2" + geo_redundant_backup_enabled = true + + threat_detection_policy { + enabled = true + } + } + `, + expected: database.Database{ + PostgreSQLServers: []database.PostgreSQLServer{ + { + Server: database.Server{ + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), + }, + GeoRedundantBackupEnabled: iacTypes.BoolTest(true), + ThreatDetectionPolicy: database.ThreatDetectionPolicy{ + Enabled: iacTypes.BoolTest(true), + }, + }, + }, + }, + }, + { + name: "postgresql with log disconnections", + terraform: ` + resource "azurerm_postgresql_server" "example" { + name = "example" + + public_network_access_enabled = true + ssl_enforcement_enabled = true + ssl_minimal_tls_version_enforced = "TLS1_2" + } + + resource "azurerm_postgresql_configuration" "example" { + name = "log_disconnections" + resource_group_name = azurerm_resource_group.example.name + server_name = azurerm_postgresql_server.example.name + value = "on" + } + `, + expected: database.Database{ + PostgreSQLServers: []database.PostgreSQLServer{ + { + Server: database.Server{ + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), + }, + Config: database.PostgresSQLConfig{ + LogDisconnections: iacTypes.BoolTest(true), }, }, }, @@ -107,17 +168,12 @@ func Test_Adapt(t *testing.T) { expected: database.Database{ MariaDBServers: []database.MariaDBServer{ { - Metadata: iacTypes.NewTestMetadata(), Server: database.Server{ - Metadata: iacTypes.NewTestMetadata(), - EnableSSLEnforcement: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - MinimumTLSVersion: iacTypes.String("", iacTypes.NewTestMetadata()), - EnablePublicNetworkAccess: iacTypes.Bool(false, iacTypes.NewTestMetadata()), + EnableSSLEnforcement: iacTypes.BoolTest(true), FirewallRules: []database.FirewallRule{ { - Metadata: iacTypes.NewTestMetadata(), - StartIP: iacTypes.String("40.112.0.0", iacTypes.NewTestMetadata()), - EndIP: iacTypes.String("40.112.255.255", iacTypes.NewTestMetadata()), + StartIP: iacTypes.StringTest("40.112.0.0"), + EndIP: iacTypes.StringTest("40.112.255.255"), }, }, }, @@ -143,17 +199,227 @@ func Test_Adapt(t *testing.T) { expected: database.Database{ MySQLServers: []database.MySQLServer{ { - Metadata: iacTypes.NewTestMetadata(), Server: database.Server{ - Metadata: iacTypes.NewTestMetadata(), - EnableSSLEnforcement: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - MinimumTLSVersion: iacTypes.String("TLS1_2", iacTypes.NewTestMetadata()), - EnablePublicNetworkAccess: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), FirewallRules: []database.FirewallRule{ { - Metadata: iacTypes.NewTestMetadata(), - StartIP: iacTypes.String("40.112.8.12", iacTypes.NewTestMetadata()), - EndIP: iacTypes.String("40.112.8.12", iacTypes.NewTestMetadata()), + StartIP: iacTypes.StringTest("40.112.8.12"), + EndIP: iacTypes.StringTest("40.112.8.12"), + }, + }, + }, + }, + }, + }, + }, + { + name: "postgresql flexible server", + terraform: ` + resource "azurerm_postgresql_flexible_server" "example" { + name = "example-flexible" + + public_network_access_enabled = true + } + + resource "azurerm_postgresql_flexible_server_configuration" "require_secure_transport" { + name = "require_secure_transport" + server_id = azurerm_postgresql_flexible_server.example.id + value = "ON" + } + + resource "azurerm_postgresql_flexible_server_configuration" "tls_version" { + name = "tls_version" + server_id = azurerm_postgresql_flexible_server.example.id + value = "TLS1_2" + } + + resource "azurerm_postgresql_flexible_server_configuration" "log_connections" { + name = "log_connections" + server_id = azurerm_postgresql_flexible_server.example.id + value = "on" + } + + resource "azurerm_postgresql_flexible_server_configuration" "log_checkpoints" { + name = "log_checkpoints" + server_id = azurerm_postgresql_flexible_server.example.id + value = "on" + } + + resource "azurerm_postgresql_flexible_server_firewall_rule" "example" { + name = "office" + server_id = azurerm_postgresql_flexible_server.example.id + start_ip_address = "40.112.8.12" + end_ip_address = "40.112.8.12" + } +`, + expected: database.Database{ + PostgreSQLServers: []database.PostgreSQLServer{ + { + Server: database.Server{ + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), + FirewallRules: []database.FirewallRule{ + { + StartIP: iacTypes.StringTest("40.112.8.12"), + EndIP: iacTypes.StringTest("40.112.8.12"), + }, + }, + }, + Config: database.PostgresSQLConfig{ + LogConnections: iacTypes.BoolTest(true), + LogCheckpoints: iacTypes.BoolTest(true), + }, + // Threat Detection is not configurable via Terraform for PostgreSQL Flexible Server + // It can only be configured via Azure CLI, so it's marked as unmanaged + ThreatDetectionPolicy: database.ThreatDetectionPolicy{}, + }, + }, + }, + }, + { + name: "postgresql flexible server with configuration resources", + terraform: ` + resource "azurerm_postgresql_flexible_server" "example" { + name = "example-flexible" + + public_network_access_enabled = true + } + + resource "azurerm_postgresql_flexible_server_firewall_rule" "example" { + name = "office" + server_id = azurerm_postgresql_flexible_server.example.id + start_ip_address = "40.112.8.12" + end_ip_address = "40.112.8.12" + } + + resource "azurerm_postgresql_flexible_server_configuration" "require_secure_transport" { + name = "require_secure_transport" + server_id = azurerm_postgresql_flexible_server.example.id + value = "ON" + } + + resource "azurerm_postgresql_flexible_server_configuration" "tls_version" { + name = "tls_version" + server_id = azurerm_postgresql_flexible_server.example.id + value = "TLS1_2" + } + `, + expected: database.Database{ + PostgreSQLServers: []database.PostgreSQLServer{ + { + Server: database.Server{ + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), + FirewallRules: []database.FirewallRule{ + { + StartIP: iacTypes.StringTest("40.112.8.12"), + EndIP: iacTypes.StringTest("40.112.8.12"), + }, + }, + }, + Config: database.PostgresSQLConfig{}, + // Threat Detection is not configurable via Terraform for PostgreSQL Flexible Server + // It can only be configured via Azure CLI, so it's marked as unmanaged + ThreatDetectionPolicy: database.ThreatDetectionPolicy{}, + }, + }, + }, + }, + { + name: "mysql flexible server", + terraform: ` + resource "azurerm_mysql_flexible_server" "example" { + name = "example-flexible" + + public_network_access_enabled = true + } + + resource "azurerm_mysql_flexible_server_firewall_rule" "example" { + name = "office" + server_id = azurerm_mysql_flexible_server.example.id + start_ip_address = "40.112.8.12" + end_ip_address = "40.112.8.12" + } + + resource "azurerm_mysql_flexible_server_configuration" "require_secure_transport" { + name = "require_secure_transport" + server_id = azurerm_mysql_flexible_server.example.id + value = "ON" + } + + resource "azurerm_mysql_flexible_server_configuration" "tls_version" { + name = "tls_version" + server_id = azurerm_mysql_flexible_server.example.id + value = "TLS1_2" + } + + resource "azurerm_mysql_flexible_server_configuration" "interactive_timeout" { + name = "interactive_timeout" + server_id = azurerm_mysql_flexible_server.example.id + value = "600" + } + `, + expected: database.Database{ + MySQLServers: []database.MySQLServer{ + { + Server: database.Server{ + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), + FirewallRules: []database.FirewallRule{ + { + StartIP: iacTypes.StringTest("40.112.8.12"), + EndIP: iacTypes.StringTest("40.112.8.12"), + }, + }, + }, + }, + }, + }, + }, + { + name: "mysql flexible server with configuration resources", + terraform: ` + resource "azurerm_mysql_flexible_server" "example" { + name = "example-flexible" + + public_network_access_enabled = true + } + + resource "azurerm_mysql_flexible_server_firewall_rule" "example" { + name = "office" + server_id = azurerm_mysql_flexible_server.example.id + start_ip_address = "40.112.8.12" + end_ip_address = "40.112.8.12" + } + + resource "azurerm_mysql_flexible_server_configuration" "require_secure_transport" { + name = "require_secure_transport" + server_id = azurerm_mysql_flexible_server.example.id + value = "ON" + } + + resource "azurerm_mysql_flexible_server_configuration" "tls_version" { + name = "tls_version" + server_id = azurerm_mysql_flexible_server.example.id + value = "TLS1_2" + } + `, + expected: database.Database{ + MySQLServers: []database.MySQLServer{ + { + Server: database.Server{ + EnableSSLEnforcement: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest("TLS1_2"), + EnablePublicNetworkAccess: iacTypes.BoolTest(true), + FirewallRules: []database.FirewallRule{ + { + StartIP: iacTypes.StringTest("40.112.8.12"), + EndIP: iacTypes.StringTest("40.112.8.12"), }, }, }, @@ -198,37 +464,30 @@ func Test_Adapt(t *testing.T) { expected: database.Database{ MSSQLServers: []database.MSSQLServer{ { - Metadata: iacTypes.NewTestMetadata(), Server: database.Server{ - Metadata: iacTypes.NewTestMetadata(), - MinimumTLSVersion: iacTypes.String("1.2", iacTypes.NewTestMetadata()), - EnablePublicNetworkAccess: iacTypes.Bool(false, iacTypes.NewTestMetadata()), - EnableSSLEnforcement: iacTypes.Bool(false, iacTypes.NewTestMetadata()), + MinimumTLSVersion: iacTypes.StringTest("1.2"), FirewallRules: []database.FirewallRule{ { - Metadata: iacTypes.NewTestMetadata(), - StartIP: iacTypes.String("10.0.17.62", iacTypes.NewTestMetadata()), - EndIP: iacTypes.String("10.0.17.62", iacTypes.NewTestMetadata()), + StartIP: iacTypes.StringTest("10.0.17.62"), + EndIP: iacTypes.StringTest("10.0.17.62"), }, }, }, ExtendedAuditingPolicies: []database.ExtendedAuditingPolicy{ { - Metadata: iacTypes.NewTestMetadata(), - RetentionInDays: iacTypes.Int(6, iacTypes.NewTestMetadata()), + RetentionInDays: iacTypes.IntTest(6), }, }, SecurityAlertPolicies: []database.SecurityAlertPolicy{ { - Metadata: iacTypes.NewTestMetadata(), EmailAddresses: []iacTypes.StringValue{ - iacTypes.String("example@example.com", iacTypes.NewTestMetadata()), + iacTypes.StringTest("example@example.com"), }, DisabledAlerts: []iacTypes.StringValue{ - iacTypes.String("Sql_Injection", iacTypes.NewTestMetadata()), - iacTypes.String("Data_Exfiltration", iacTypes.NewTestMetadata()), + iacTypes.StringTest("Sql_Injection"), + iacTypes.StringTest("Data_Exfiltration"), }, - EmailAccountAdmins: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + EmailAccountAdmins: iacTypes.BoolTest(true), }, }, }, diff --git a/pkg/iac/adapters/terraform/azure/database/common.go b/pkg/iac/adapters/terraform/azure/database/common.go new file mode 100644 index 0000000000..d63482e12f --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/database/common.go @@ -0,0 +1,47 @@ +package database + +import ( + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" + "github.com/aquasecurity/trivy/pkg/iac/terraform" + iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +// serverParameters represents server configuration parameters that are common +// to both MySQL and PostgreSQL flexible servers in Azure. +type serverParameters struct { + requireSecureTransport iacTypes.BoolValue + tlsVersion iacTypes.StringValue +} + +// parseServerParameters parses a list of server configurations to extract +// server parameters for MySQL and PostgreSQL flexible servers. +func parseServerParameters(configs []*terraform.Block, resourceMetadata iacTypes.Metadata) serverParameters { + // https://learn.microsoft.com/en-us/azure/mysql/flexible-server/overview#enterprise-grade-security-compliance-and-privacy + params := serverParameters{ + requireSecureTransport: iacTypes.BoolDefault(true, resourceMetadata), + tlsVersion: iacTypes.StringDefault("TLS1.2", resourceMetadata), + } + + for _, config := range configs { + nameAttr := config.GetAttribute("name") + valAttr := config.GetAttribute("value") + switch { + case nameAttr.Equals("require_secure_transport"): + params.requireSecureTransport, _ = iacTypes.BoolFromCtyValue(valAttr.Value(), valAttr.GetMetadata()) + case nameAttr.Equals("tls_version"): + params.tlsVersion = valAttr.AsStringValueOrDefault("TLS1_2", config) + } + } + + return params +} + +func adaptFirewallRule(resource *terraform.Block) database.FirewallRule { + return database.FirewallRule{ + Metadata: resource.GetMetadata(), + StartIP: resource.GetAttribute("start_ip_address"). + AsStringValueOrDefault("", resource), + EndIP: resource.GetAttribute("end_ip_address"). + AsStringValueOrDefault("", resource), + } +} diff --git a/pkg/iac/adapters/terraform/azure/database/mariadb.go b/pkg/iac/adapters/terraform/azure/database/mariadb.go new file mode 100644 index 0000000000..bdf813e18f --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/database/mariadb.go @@ -0,0 +1,39 @@ +package database + +import ( + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" + "github.com/aquasecurity/trivy/pkg/iac/terraform" + iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +func adaptMariaDBServers(modules terraform.Modules) []database.MariaDBServer { + var mariaDBServers []database.MariaDBServer + for _, module := range modules { + for _, resource := range module.GetResourcesByType("azurerm_mariadb_server") { + mariaDBServers = append(mariaDBServers, adaptMariaDBServer(resource, module)) + } + } + + return mariaDBServers +} + +func adaptMariaDBServer(resource *terraform.Block, module *terraform.Module) database.MariaDBServer { + var firewallRules []database.FirewallRule + firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_mariadb_firewall_rule", "server_name") + for _, firewallBlock := range firewallRuleBlocks { + firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) + } + + return database.MariaDBServer{ + Metadata: resource.GetMetadata(), + Server: database.Server{ + Metadata: resource.GetMetadata(), + EnableSSLEnforcement: resource.GetAttribute("ssl_enforcement_enabled"). + AsBoolValueOrDefault(false, resource), + MinimumTLSVersion: iacTypes.StringDefault("", resource.GetMetadata()), + EnablePublicNetworkAccess: resource.GetAttribute("public_network_access_enabled"). + AsBoolValueOrDefault(true, resource), + FirewallRules: firewallRules, + }, + } +} diff --git a/pkg/iac/adapters/terraform/azure/database/mssql.go b/pkg/iac/adapters/terraform/azure/database/mssql.go new file mode 100644 index 0000000000..eee4fba58a --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/database/mssql.go @@ -0,0 +1,118 @@ +package database + +import ( + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" + "github.com/aquasecurity/trivy/pkg/iac/terraform" + iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +func adaptMSSQLServers(modules terraform.Modules) []database.MSSQLServer { + var mssqlServers []database.MSSQLServer + for _, module := range modules { + for _, resource := range module.GetResourcesByType("azurerm_sql_server", "azurerm_mssql_server") { + mssqlServers = append(mssqlServers, adaptMSSQLServer(resource, module)) + } + } + return mssqlServers +} + +func adaptMSSQLServer(resource *terraform.Block, module *terraform.Module) database.MSSQLServer { + minTLSVersionVal := iacTypes.StringDefault("", resource.GetMetadata()) + publicAccessVal := iacTypes.BoolDefault(true, resource.GetMetadata()) + enableSSLEnforcementVal := iacTypes.BoolDefault(false, resource.GetMetadata()) + + if resource.TypeLabel() == "azurerm_mssql_server" { + minTLSVersionAttr := resource.GetAttribute("minimum_tls_version") + minTLSVersionVal = minTLSVersionAttr.AsStringValueOrDefault("1.2", resource) + publicAccessAttr := resource.GetAttribute("public_network_access_enabled") + publicAccessVal = publicAccessAttr.AsBoolValueOrDefault(true, resource) + } + + var alertPolicies []database.SecurityAlertPolicy + alertPolicyBlocks := module.GetReferencingResources(resource, "azurerm_mssql_server_security_alert_policy", "server_name") + for _, alertBlock := range alertPolicyBlocks { + alertPolicies = append(alertPolicies, adaptMSSQLSecurityAlertPolicy(alertBlock)) + } + + auditingPoliciesBlocks := module.GetReferencingResources(resource, "azurerm_mssql_server_extended_auditing_policy", "server_id") + auditingPoliciesBlocks = append(auditingPoliciesBlocks, resource.GetBlocks("extended_auditing_policy")...) + + databasesRes := module.GetReferencingResources(resource, "azurerm_mssql_database", "server_id") + for _, databaseRes := range databasesRes { + dbAuditingBlocks := module.GetReferencingResources(databaseRes, "azurerm_mssql_database_extended_auditing_policy", "database_id") + auditingPoliciesBlocks = append(auditingPoliciesBlocks, dbAuditingBlocks...) + } + + var auditingPolicies []database.ExtendedAuditingPolicy + for _, auditBlock := range auditingPoliciesBlocks { + auditingPolicies = append(auditingPolicies, adaptMSSQLExtendedAuditingPolicy(auditBlock)) + } + + var firewallRules []database.FirewallRule + firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_sql_firewall_rule", "server_name") + firewallRuleBlocks = append(firewallRuleBlocks, module.GetReferencingResources(resource, "azurerm_mssql_firewall_rule", "server_id")...) + for _, firewallBlock := range firewallRuleBlocks { + firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) + } + + // Support for deprecated azuread_administrator block (backward compatibility) + var adAdmins []database.ActiveDirectoryAdministrator + azureadAdminBlock := resource.GetBlock("azuread_administrator") + if azureadAdminBlock.IsNotNil() { + adAdmins = append(adAdmins, adaptAzureADAdministratorBlock(azureadAdminBlock)) + } + + // Support for azurerm_sql_active_directory_administrator resource (preferred method) + adAdminBlocks := module.GetReferencingResources(resource, "azurerm_sql_active_directory_administrator", "server_name") + for _, adAdminBlock := range adAdminBlocks { + adAdmins = append(adAdmins, adaptActiveDirectoryAdministrator(adAdminBlock)) + } + + return database.MSSQLServer{ + Metadata: resource.GetMetadata(), + Server: database.Server{ + Metadata: resource.GetMetadata(), + EnableSSLEnforcement: enableSSLEnforcementVal, + MinimumTLSVersion: minTLSVersionVal, + EnablePublicNetworkAccess: publicAccessVal, + FirewallRules: firewallRules, + }, + ExtendedAuditingPolicies: auditingPolicies, + SecurityAlertPolicies: alertPolicies, + AdministratorLogin: resource.GetAttribute("administrator_login").AsStringValueOrDefault("", resource), + ActiveDirectoryAdministrators: adAdmins, + } +} + +func adaptMSSQLSecurityAlertPolicy(resource *terraform.Block) database.SecurityAlertPolicy { + return database.SecurityAlertPolicy{ + Metadata: resource.GetMetadata(), + EmailAddresses: resource.GetAttribute("email_addresses").AsStringValues(), + DisabledAlerts: resource.GetAttribute("disabled_alerts").AsStringValues(), + EmailAccountAdmins: resource.GetAttribute("email_account_admins"). + AsBoolValueOrDefault(false, resource), + } +} + +func adaptMSSQLExtendedAuditingPolicy(resource *terraform.Block) database.ExtendedAuditingPolicy { + return database.ExtendedAuditingPolicy{ + Metadata: resource.GetMetadata(), + RetentionInDays: resource.GetAttribute("retention_in_days").AsIntValueOrDefault(0, resource), + } +} + +func adaptActiveDirectoryAdministrator(resource *terraform.Block) database.ActiveDirectoryAdministrator { + return database.ActiveDirectoryAdministrator{ + Metadata: resource.GetMetadata(), + Login: resource.GetAttribute("login").AsStringValueOrDefault("", resource), + } +} + +func adaptAzureADAdministratorBlock(block *terraform.Block) database.ActiveDirectoryAdministrator { + return database.ActiveDirectoryAdministrator{ + Metadata: block.GetMetadata(), + // The azuread_administrator block uses login_username attribute + Login: block.GetFirstAttributeOf("login_username", "login"). + AsStringValueOrDefault("", block), + } +} diff --git a/pkg/iac/adapters/terraform/azure/database/mysql.go b/pkg/iac/adapters/terraform/azure/database/mysql.go new file mode 100644 index 0000000000..21e79750b1 --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/database/mysql.go @@ -0,0 +1,72 @@ +package database + +import ( + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" + "github.com/aquasecurity/trivy/pkg/iac/terraform" +) + +func adaptMySQLServers(modules terraform.Modules) []database.MySQLServer { + var mySQLServers []database.MySQLServer + for _, module := range modules { + // Support legacy azurerm_mysql_server + for _, resource := range module.GetResourcesByType("azurerm_mysql_server") { + mySQLServers = append(mySQLServers, adaptMySQLServer(resource, module)) + } + // Support new azurerm_mysql_flexible_server + for _, resource := range module.GetResourcesByType("azurerm_mysql_flexible_server") { + mySQLServers = append(mySQLServers, adaptMySQLFlexibleServer(resource, module)) + } + } + return mySQLServers +} + +func adaptMySQLServer(resource *terraform.Block, module *terraform.Module) database.MySQLServer { + var firewallRules []database.FirewallRule + firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_mysql_firewall_rule", "server_name") + for _, firewallBlock := range firewallRuleBlocks { + firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) + } + + return database.MySQLServer{ + Metadata: resource.GetMetadata(), + Server: database.Server{ + Metadata: resource.GetMetadata(), + EnableSSLEnforcement: resource.GetAttribute("ssl_enforcement_enabled"). + AsBoolValueOrDefault(false, resource), + MinimumTLSVersion: resource.GetAttribute("ssl_minimal_tls_version_enforced"). + AsStringValueOrDefault("TLS1_2", resource), + EnablePublicNetworkAccess: resource.GetAttribute("public_network_access_enabled"). + AsBoolValueOrDefault(true, resource), + FirewallRules: firewallRules, + }, + } +} + +func adaptMySQLFlexibleServer(resource *terraform.Block, module *terraform.Module) database.MySQLServer { + var firewallRules []database.FirewallRule + + // Flexible server firewall rules use server_id instead of server_name + firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_mysql_flexible_server_firewall_rule", "server_id") + for _, firewallBlock := range firewallRuleBlocks { + firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) + } + + // MySQL Flexible Server configurations (new standalone resource) + // TLS settings are configured through azurerm_mysql_flexible_server_configuration resources + // Each configuration resource manages a single parameter specified in the name attribute + // By default, the server enforces secure connections using TLS 1.2 + configBlocks := module.GetReferencingResources(resource, "azurerm_mysql_flexible_server_configuration", "server_id") + params := parseServerParameters(configBlocks, resource.GetMetadata()) + + return database.MySQLServer{ + Metadata: resource.GetMetadata(), + Server: database.Server{ + Metadata: resource.GetMetadata(), + EnableSSLEnforcement: params.requireSecureTransport, + MinimumTLSVersion: params.tlsVersion, + EnablePublicNetworkAccess: resource.GetAttribute("public_network_access_enabled"). + AsBoolValueOrDefault(true, resource), + FirewallRules: firewallRules, + }, + } +} diff --git a/pkg/iac/adapters/terraform/azure/database/postgresql.go b/pkg/iac/adapters/terraform/azure/database/postgresql.go new file mode 100644 index 0000000000..556309ff40 --- /dev/null +++ b/pkg/iac/adapters/terraform/azure/database/postgresql.go @@ -0,0 +1,141 @@ +package database + +import ( + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" + "github.com/aquasecurity/trivy/pkg/iac/terraform" + iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" +) + +func adaptPostgreSQLServers(modules terraform.Modules) []database.PostgreSQLServer { + var postgreSQLServers []database.PostgreSQLServer + for _, module := range modules { + // Support legacy azurerm_postgresql_server + for _, resource := range module.GetResourcesByType("azurerm_postgresql_server") { + postgreSQLServers = append(postgreSQLServers, adaptPostgreSQLServer(resource, module)) + } + // Support new azurerm_postgresql_flexible_server + for _, resource := range module.GetResourcesByType("azurerm_postgresql_flexible_server") { + postgreSQLServers = append(postgreSQLServers, adaptPostgreSQLFlexibleServer(resource, module)) + } + } + + return postgreSQLServers +} + +func adaptPostgreSQLServer(resource *terraform.Block, module *terraform.Module) database.PostgreSQLServer { + var firewallRules []database.FirewallRule + firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_postgresql_firewall_rule", "server_name") + for _, firewallBlock := range firewallRuleBlocks { + firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) + } + + configs := module.GetReferencingResources(resource, "azurerm_postgresql_configuration", "server_name") + config := adaptPostgreSQLConfig(resource, configs) + return database.PostgreSQLServer{ + Metadata: resource.GetMetadata(), + Server: database.Server{ + Metadata: resource.GetMetadata(), + EnableSSLEnforcement: resource.GetAttribute("ssl_enforcement_enabled"). + AsBoolValueOrDefault(false, resource), + MinimumTLSVersion: resource.GetAttribute("ssl_minimal_tls_version_enforced"). + AsStringValueOrDefault("TLS1_2", resource), + EnablePublicNetworkAccess: resource.GetAttribute("public_network_access_enabled"). + AsBoolValueOrDefault(true, resource), + FirewallRules: firewallRules, + }, + Config: config, + GeoRedundantBackupEnabled: resource.GetAttribute("geo_redundant_backup_enabled"). + AsBoolValueOrDefault(false, resource), + ThreatDetectionPolicy: adaptThreatDetectionPolicy(resource, resource.GetMetadata()), + } +} + +func adaptPostgreSQLFlexibleServer(resource *terraform.Block, module *terraform.Module) database.PostgreSQLServer { + var firewallRules []database.FirewallRule + + firewallRuleBlocks := module.GetReferencingResources(resource, "azurerm_postgresql_flexible_server_firewall_rule", "server_id") + for _, firewallBlock := range firewallRuleBlocks { + firewallRules = append(firewallRules, adaptFirewallRule(firewallBlock)) + } + + // PostgreSQL Flexible Server configurations (new standalone resource) + // TLS settings are configured through azurerm_postgresql_flexible_server_configuration resources + // Each configuration resource manages a single parameter specified in the name attribute + // By default, the server enforces secure connections using TLS 1.2 + // Flexible server configurations use server_id instead of server_name + configBlocks := module.GetReferencingResources(resource, "azurerm_postgresql_flexible_server_configuration", "server_id") + config := adaptPostgreSQLConfig(resource, configBlocks) + params := parseServerParameters(configBlocks, resource.GetMetadata()) + + return database.PostgreSQLServer{ + Metadata: resource.GetMetadata(), + Server: database.Server{ + Metadata: resource.GetMetadata(), + EnableSSLEnforcement: params.requireSecureTransport, + MinimumTLSVersion: params.tlsVersion, + EnablePublicNetworkAccess: resource.GetAttribute("public_network_access_enabled"). + AsBoolValueOrDefault(true, resource), + FirewallRules: firewallRules, + }, + Config: config, + GeoRedundantBackupEnabled: resource.GetAttribute("geo_redundant_backup_enabled"). + AsBoolValueOrDefault(false, resource), + + // Threat Detection is not configurable via Terraform for PostgreSQL Flexible Server + // It can only be configured via Azure CLI, so we mark it as unmanaged to avoid false positives + ThreatDetectionPolicy: database.ThreatDetectionPolicy{ + Metadata: iacTypes.NewUnmanagedMetadata(), + }, + } +} + +func adaptPostgreSQLConfig(resource *terraform.Block, configBlocks []*terraform.Block) database.PostgresSQLConfig { + var defaultMetadata iacTypes.Metadata + if resource != nil { + defaultMetadata = resource.GetMetadata() + } else { + defaultMetadata = iacTypes.NewUnmanagedMetadata() + } + + config := database.PostgresSQLConfig{ + Metadata: defaultMetadata, + LogCheckpoints: iacTypes.BoolDefault(false, defaultMetadata), + ConnectionThrottling: iacTypes.BoolDefault(false, defaultMetadata), + LogConnections: iacTypes.BoolDefault(false, defaultMetadata), + LogDisconnections: iacTypes.BoolDefault(false, defaultMetadata), + } + + for _, configBlock := range configBlocks { + + nameAttr := configBlock.GetAttribute("name") + valAttr := configBlock.GetAttribute("value") + + switch { + case nameAttr.Equals("log_checkpoints"): + config.LogCheckpoints = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) + case nameAttr.Equals("connection_throttling"): + config.ConnectionThrottling = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) + case nameAttr.Equals("log_connections"): + config.LogConnections = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) + case nameAttr.Equals("log_disconnections"): + config.LogDisconnections = iacTypes.Bool(valAttr.Equals("on"), valAttr.GetMetadata()) + } + } + + return config +} + +func adaptThreatDetectionPolicy(resource *terraform.Block, defaultMetadata iacTypes.Metadata) database.ThreatDetectionPolicy { + block := resource.GetBlock("threat_detection_policy") + if block.IsNil() { + return database.ThreatDetectionPolicy{ + Metadata: defaultMetadata, + Enabled: iacTypes.BoolDefault(false, defaultMetadata), + } + } + + return database.ThreatDetectionPolicy{ + Metadata: block.GetMetadata(), + Enabled: block.GetAttribute("enabled").AsBoolValueOrDefault(false, block), + } +} diff --git a/pkg/iac/providers/azure/azure.go b/pkg/iac/providers/azure/azure.go index 07774647a4..dc89e6d62e 100755 --- a/pkg/iac/providers/azure/azure.go +++ b/pkg/iac/providers/azure/azure.go @@ -5,6 +5,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/providers/azure/authorization" "github.com/aquasecurity/trivy/pkg/iac/providers/azure/compute" "github.com/aquasecurity/trivy/pkg/iac/providers/azure/container" + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/cosmosdb" "github.com/aquasecurity/trivy/pkg/iac/providers/azure/database" "github.com/aquasecurity/trivy/pkg/iac/providers/azure/datafactory" "github.com/aquasecurity/trivy/pkg/iac/providers/azure/datalake" @@ -21,6 +22,7 @@ type Azure struct { Authorization authorization.Authorization Compute compute.Compute Container container.Container + CosmosDB cosmosdb.CosmosDB Database database.Database DataFactory datafactory.DataFactory DataLake datalake.DataLake diff --git a/pkg/iac/providers/azure/cosmosdb/cosmosdb.go b/pkg/iac/providers/azure/cosmosdb/cosmosdb.go new file mode 100644 index 0000000000..aaba8c5a6f --- /dev/null +++ b/pkg/iac/providers/azure/cosmosdb/cosmosdb.go @@ -0,0 +1,12 @@ +package cosmosdb + +import iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" + +type CosmosDB struct { + Accounts []Account +} + +type Account struct { + Metadata iacTypes.Metadata + IPRangeFilter []iacTypes.StringValue +} diff --git a/pkg/iac/providers/azure/database/database.go b/pkg/iac/providers/azure/database/database.go index 34ac63d8f1..b3a705a3b5 100755 --- a/pkg/iac/providers/azure/database/database.go +++ b/pkg/iac/providers/azure/database/database.go @@ -24,7 +24,9 @@ type MySQLServer struct { type PostgreSQLServer struct { Metadata iacTypes.Metadata Server - Config PostgresSQLConfig + Config PostgresSQLConfig + GeoRedundantBackupEnabled iacTypes.BoolValue + ThreatDetectionPolicy ThreatDetectionPolicy } type PostgresSQLConfig struct { @@ -32,6 +34,7 @@ type PostgresSQLConfig struct { LogCheckpoints iacTypes.BoolValue ConnectionThrottling iacTypes.BoolValue LogConnections iacTypes.BoolValue + LogDisconnections iacTypes.BoolValue } type Server struct { @@ -45,8 +48,10 @@ type Server struct { type MSSQLServer struct { Metadata iacTypes.Metadata Server - ExtendedAuditingPolicies []ExtendedAuditingPolicy - SecurityAlertPolicies []SecurityAlertPolicy + ExtendedAuditingPolicies []ExtendedAuditingPolicy + SecurityAlertPolicies []SecurityAlertPolicy + AdministratorLogin iacTypes.StringValue + ActiveDirectoryAdministrators []ActiveDirectoryAdministrator } type SecurityAlertPolicy struct { @@ -66,3 +71,13 @@ type FirewallRule struct { StartIP iacTypes.StringValue EndIP iacTypes.StringValue } + +type ThreatDetectionPolicy struct { + Metadata iacTypes.Metadata + Enabled iacTypes.BoolValue +} + +type ActiveDirectoryAdministrator struct { + Metadata iacTypes.Metadata + Login iacTypes.StringValue +} diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index ff484adcf0..5369f4c653 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -4443,6 +4443,10 @@ "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.container.Container" }, + "cosmosdb": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.cosmosdb.CosmosDB" + }, "database": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.Database" @@ -4936,6 +4940,47 @@ } } }, + "github.com.aquasecurity.trivy.pkg.iac.providers.azure.cosmosdb.Account": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "iprangefilter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + } + } + } + }, + "github.com.aquasecurity.trivy.pkg.iac.providers.azure.cosmosdb.CosmosDB": { + "type": "object", + "properties": { + "accounts": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.cosmosdb.Account" + } + } + } + }, + "github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.ActiveDirectoryAdministrator": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "login": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + } + } + }, "github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.Database": { "type": "object", "properties": { @@ -5006,6 +5051,17 @@ "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" }, + "activedirectoryadministrators": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.ActiveDirectoryAdministrator" + } + }, + "administratorlogin": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, "extendedauditingpolicies": { "type": "array", "items": { @@ -5063,9 +5119,17 @@ "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.PostgresSQLConfig" }, + "georedundantbackupenabled": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" + }, "server": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.Server" + }, + "threatdetectionpolicy": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.ThreatDetectionPolicy" } } }, @@ -5087,6 +5151,10 @@ "logconnections": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" + }, + "logdisconnections": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" } } }, @@ -5145,6 +5213,19 @@ } } }, + "github.com.aquasecurity.trivy.pkg.iac.providers.azure.database.ThreatDetectionPolicy": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "enabled": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" + } + } + }, "github.com.aquasecurity.trivy.pkg.iac.providers.azure.datafactory.DataFactory": { "type": "object", "properties": { diff --git a/pkg/iac/types/bool.go b/pkg/iac/types/bool.go index b2bc6e4ece..175df0904e 100755 --- a/pkg/iac/types/bool.go +++ b/pkg/iac/types/bool.go @@ -127,9 +127,9 @@ func ctyToBool(val cty.Value) (bool, bool) { return val.True(), true case cty.String: switch strings.ToLower(val.AsString()) { - case "true", "yes", "y", "1": + case "true", "yes", "y", "1", "on": return true, true - case "false", "no", "n", "0": + case "false", "no", "n", "0", "off": return false, true } case cty.Number: