Skip to content

Commit

Permalink
Fix azurerm_sql_database blob auditing error under online secondary…
Browse files Browse the repository at this point in the history
… create mode (#6402)
  • Loading branch information
yupwei68 committed Apr 26, 2020
1 parent ec8406a commit ca6c4b2
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 14 deletions.
7 changes: 6 additions & 1 deletion azurerm/internal/services/mssql/client/client.go
Expand Up @@ -8,6 +8,7 @@ import (

type Client struct {
DatabasesClient *sql.DatabasesClient
DatabaseExtendedBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient
DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient
ElasticPoolsClient *sql.ElasticPoolsClient
DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient
Expand All @@ -21,6 +22,9 @@ func NewClient(o *common.ClientOptions) *Client {
databasesClient := sql.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&databasesClient.Client, o.ResourceManagerAuthorizer)

databaseExtendedBlobAuditingPoliciesClient := sql.NewExtendedDatabaseBlobAuditingPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&databaseExtendedBlobAuditingPoliciesClient.Client, o.ResourceManagerAuthorizer)

databaseThreatDetectionPoliciesClient := sql.NewDatabaseThreatDetectionPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&databaseThreatDetectionPoliciesClient.Client, o.ResourceManagerAuthorizer)

Expand All @@ -43,7 +47,8 @@ func NewClient(o *common.ClientOptions) *Client {
o.ConfigureClient(&sqlVirtualMachinesClient.Client, o.ResourceManagerAuthorizer)

return &Client{
DatabasesClient: &databasesClient,
DatabasesClient: &databasesClient,
DatabaseExtendedBlobAuditingPoliciesClient: &databaseExtendedBlobAuditingPoliciesClient,
DatabaseThreatDetectionPoliciesClient: &databaseThreatDetectionPoliciesClient,
DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient,
ElasticPoolsClient: &elasticPoolsClient,
Expand Down
98 changes: 98 additions & 0 deletions azurerm/internal/services/mssql/helper/sql_extended_auditing.go
@@ -0,0 +1,98 @@
package helper

import (
"github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func ExtendedAuditingSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"storage_account_access_key": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"storage_endpoint": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.IsURLWithHTTPS,
},

"storage_account_access_key_is_secondary": {
Type: schema.TypeBool,
Optional: true,
},

"retention_in_days": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 3285),
},
},
},
}
}

func ExpandAzureRmMsSqlDBBlobAuditingPolicies(input []interface{}) *sql.ExtendedDatabaseBlobAuditingPolicyProperties {
if len(input) == 0 {
return &sql.ExtendedDatabaseBlobAuditingPolicyProperties{
State: sql.BlobAuditingPolicyStateDisabled,
}
}
dbBlobAuditingPolicies := input[0].(map[string]interface{})

ExtendedDatabaseBlobAuditingPolicyProperties := sql.ExtendedDatabaseBlobAuditingPolicyProperties{
State: sql.BlobAuditingPolicyStateEnabled,
StorageAccountAccessKey: utils.String(dbBlobAuditingPolicies["storage_account_access_key"].(string)),
StorageEndpoint: utils.String(dbBlobAuditingPolicies["storage_endpoint"].(string)),
}
if v, ok := dbBlobAuditingPolicies["storage_account_access_key_is_secondary"]; ok {
ExtendedDatabaseBlobAuditingPolicyProperties.IsStorageSecondaryKeyInUse = utils.Bool(v.(bool))
}
if v, ok := dbBlobAuditingPolicies["retention_in_days"]; ok {
ExtendedDatabaseBlobAuditingPolicyProperties.RetentionDays = utils.Int32(int32(v.(int)))
}

return &ExtendedDatabaseBlobAuditingPolicyProperties
}

func FlattenAzureRmMsSqlDBBlobAuditingPolicies(extendedDatabaseBlobAuditingPolicy *sql.ExtendedDatabaseBlobAuditingPolicy, d *schema.ResourceData) []interface{} {
if extendedDatabaseBlobAuditingPolicy == nil || extendedDatabaseBlobAuditingPolicy.State == sql.BlobAuditingPolicyStateDisabled {
return []interface{}{}
}
var storageAccessKey, storageEndpoint string
// storage_account_access_key will not be returned, so we transfer the schema value
if v, ok := d.GetOk("extended_auditing_policy.0.storage_account_access_key"); ok {
storageAccessKey = v.(string)
}

if extendedDatabaseBlobAuditingPolicy.StorageEndpoint != nil {
storageEndpoint = *extendedDatabaseBlobAuditingPolicy.StorageEndpoint
}
var secondKeyInUse bool
if extendedDatabaseBlobAuditingPolicy.IsStorageSecondaryKeyInUse != nil {
secondKeyInUse = *extendedDatabaseBlobAuditingPolicy.IsStorageSecondaryKeyInUse
}
var retentionDays int32
if extendedDatabaseBlobAuditingPolicy.RetentionDays != nil {
retentionDays = *extendedDatabaseBlobAuditingPolicy.RetentionDays
}

return []interface{}{
map[string]interface{}{
"storage_account_access_key": storageAccessKey,
"storage_endpoint": storageEndpoint,
"storage_account_access_key_is_secondary": secondKeyInUse,
"retention_in_days": retentionDays,
},
}
}
38 changes: 33 additions & 5 deletions azurerm/internal/services/mssql/resource_arm_mssql_database.go
Expand Up @@ -17,6 +17,7 @@ import (
azValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/helper"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
Expand Down Expand Up @@ -99,6 +100,8 @@ func resourceArmMsSqlDatabase() *schema.Resource {
ValidateFunc: validate.MsSqlElasticPoolID,
},

"extended_auditing_policy": helper.ExtendedAuditingSchema(),

"license_type": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -270,6 +273,7 @@ func resourceArmMsSqlDatabase() *schema.Resource {

func resourceArmMsSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).MSSQL.DatabasesClient
auditingClient := meta.(*clients.Client).MSSQL.DatabaseExtendedBlobAuditingPoliciesClient
serverClient := meta.(*clients.Client).MSSQL.ServersClient
threatClient := meta.(*clients.Client).MSSQL.DatabaseThreatDetectionPoliciesClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
Expand Down Expand Up @@ -321,11 +325,15 @@ func resourceArmMsSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}

if v, ok := d.GetOk("create_mode"); ok {
if _, ok := d.GetOk("creation_source_database_id"); (v.(string) == string(sql.CreateModeCopy) || v.(string) == string(sql.CreateModePointInTimeRestore) || v.(string) == string(sql.CreateModeRestore) || v.(string) == string(sql.CreateModeSecondary)) && !ok {
return fmt.Errorf("'creation_source_database_id' is required for create_mode %s", v.(string))
}
params.DatabaseProperties.CreateMode = sql.CreateMode(v.(string))
createMode, ok := d.GetOk("create_mode")
if _, dbok := d.GetOk("creation_source_database_id"); ok && (createMode.(string) == string(sql.CreateModeCopy) || createMode.(string) == string(sql.CreateModePointInTimeRestore) || createMode.(string) == string(sql.CreateModeRestore) || createMode.(string) == string(sql.CreateModeSecondary)) && !dbok {
return fmt.Errorf("'creation_source_database_id' is required for create_mode %s", createMode.(string))
}
params.DatabaseProperties.CreateMode = sql.CreateMode(createMode.(string))

auditingPolicies := d.Get("extended_auditing_policy").([]interface{})
if (createMode == string(sql.CreateModeOnlineSecondary) || createMode == string(sql.Secondary)) && len(auditingPolicies) > 0 {
return fmt.Errorf("could not configure auditing policies on SQL Database %q (Resource Group %q, Server %q) in secondary create mode", name, serverId.ResourceGroup, serverId.Name)
}

if v, ok := d.GetOk("max_size_gb"); ok {
Expand Down Expand Up @@ -382,12 +390,22 @@ func resourceArmMsSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface
return fmt.Errorf("setting database threat detection policy: %+v", err)
}

if createMode != string(sql.CreateModeOnlineSecondary) && createMode != string(sql.CreateModeSecondary) {
auditingProps := sql.ExtendedDatabaseBlobAuditingPolicy{
ExtendedDatabaseBlobAuditingPolicyProperties: helper.ExpandAzureRmMsSqlDBBlobAuditingPolicies(auditingPolicies),
}
if _, err = auditingClient.CreateOrUpdate(ctx, serverId.ResourceGroup, serverId.Name, name, auditingProps); err != nil {
return fmt.Errorf("failure in issuing create/update request for SQL Database %q Blob Auditing Policies(SQL Server %q/ Resource Group %q): %+v", name, serverId.Name, serverId.ResourceGroup, err)
}
}

return resourceArmMsSqlDatabaseRead(d, meta)
}

func resourceArmMsSqlDatabaseRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).MSSQL.DatabasesClient
threatClient := meta.(*clients.Client).MSSQL.DatabaseThreatDetectionPoliciesClient
auditingClient := meta.(*clients.Client).MSSQL.DatabaseExtendedBlobAuditingPoliciesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

Expand Down Expand Up @@ -441,6 +459,16 @@ func resourceArmMsSqlDatabaseRead(d *schema.ResourceData, meta interface{}) erro
}
}

auditingResp, err := auditingClient.Get(ctx, id.ResourceGroup, id.MsSqlServer, id.Name)
if err != nil {
return fmt.Errorf("failure in reading SQL Database %q: %v Blob Auditing Policies", id.Name, err)
}

flattenBlobAuditing := helper.FlattenAzureRmMsSqlDBBlobAuditingPolicies(&auditingResp, d)
if err := d.Set("extended_auditing_policy", flattenBlobAuditing); err != nil {
return fmt.Errorf("failure in setting `extended_auditing_policy`: %+v", err)
}

return tags.FlattenAndSet(d, resp.Tags)
}

Expand Down
Expand Up @@ -327,6 +327,46 @@ func TestAccAzureRMMsSqlDatabase_threatDetectionPolicy(t *testing.T) {
})
}

func TestAccAzureRMSqlDatabase_withBlobAuditingPolices(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_mssql_database", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
CheckDestroy: testCheckAzureRMMsSqlDatabaseDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMMsSqlDatabase_basic(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMMsSqlDatabaseExists(data.ResourceName),
),
},
data.ImportStep(),
{
Config: testAccAzureRMMsSqlDatabase_withBlobAuditingPolices(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMMsSqlDatabaseExists(data.ResourceName),
),
},
data.ImportStep("extended_auditing_policy.0.storage_account_access_key"),
{
Config: testAccAzureRMMsSqlDatabase_withBlobAuditingPolicesUpdated(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMMsSqlDatabaseExists(data.ResourceName),
),
},
data.ImportStep("extended_auditing_policy.0.storage_account_access_key"),
{
Config: testAccAzureRMMsSqlDatabase_basic(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMMsSqlDatabaseExists(data.ResourceName),
),
},
data.ImportStep(),
},
})
}

func testCheckAzureRMMsSqlDatabaseExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
client := acceptance.AzureProvider.Meta().(*clients.Client).MSSQL.DatabasesClient
Expand Down Expand Up @@ -698,3 +738,71 @@ resource "azurerm_mssql_database" "test" {
}
`, template, data.RandomInteger, state)
}

func testAccAzureRMMsSqlDatabase_withBlobAuditingPolices(data acceptance.TestData) string {
template := testAccAzureRMMsSqlDatabase_template(data)
return fmt.Sprintf(`
%s
resource "azurerm_storage_account" "test" {
name = "acctest%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_account" "test2" {
name = "acctest2%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_mssql_database" "test" {
name = "acctest-db-%[3]d"
server_id = azurerm_sql_server.test.id
extended_auditing_policy {
storage_endpoint = azurerm_storage_account.test.primary_blob_endpoint
storage_account_access_key = azurerm_storage_account.test.primary_access_key
storage_account_access_key_is_secondary = true
retention_in_days = 6
}
}
`, template, data.RandomIntOfLength(15), data.RandomInteger)
}

func testAccAzureRMMsSqlDatabase_withBlobAuditingPolicesUpdated(data acceptance.TestData) string {
template := testAccAzureRMMsSqlDatabase_template(data)
return fmt.Sprintf(`
%s
resource "azurerm_storage_account" "test" {
name = "acctest%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_account" "test2" {
name = "acctest2%[2]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_mssql_database" "test" {
name = "acctest-db-%[3]d"
server_id = azurerm_sql_server.test.id
extended_auditing_policy {
storage_endpoint = azurerm_storage_account.test2.primary_blob_endpoint
storage_account_access_key = azurerm_storage_account.test2.primary_access_key
storage_account_access_key_is_secondary = false
retention_in_days = 3
}
}
`, template, data.RandomIntOfLength(15), data.RandomInteger)
}
24 changes: 16 additions & 8 deletions azurerm/internal/services/sql/resource_arm_sql_database.go
Expand Up @@ -365,6 +365,12 @@ func resourceArmSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface{}
resourceGroup := d.Get("resource_group_name").(string)
location := azure.NormalizeLocation(d.Get("location").(string))
createMode := d.Get("create_mode").(string)
auditingPolicies := d.Get("extended_auditing_policy").([]interface{})

if createMode == string(sql.CreateModeOnlineSecondary) && len(auditingPolicies) > 0 {
return fmt.Errorf("could not configure auditing policies on SQL Database %q (Resource Group %q, Server %q) in online secondary create mode", name, resourceGroup, serverName)
}

zoneRedundant := d.Get("zone_redundant").(bool)
t := d.Get("tags").(map[string]interface{})

Expand Down Expand Up @@ -500,12 +506,14 @@ func resourceArmSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface{}
return fmt.Errorf("Error setting database threat detection policy: %+v", err)
}

auditingClient := meta.(*clients.Client).Sql.DatabaseExtendedBlobAuditingPoliciesClient
auditingProps := sql.ExtendedDatabaseBlobAuditingPolicy{
ExtendedDatabaseBlobAuditingPolicyProperties: helper.ExpandAzureRmSqlDBBlobAuditingPolicies(d.Get("extended_auditing_policy").([]interface{})),
}
if _, err = auditingClient.CreateOrUpdate(ctx, resourceGroup, serverName, name, auditingProps); err != nil {
return fmt.Errorf("Error issuing create/update request for SQL Database %q Blob Auditing Policies(SQL Server %q/ Resource Group %q): %+v", name, serverName, resourceGroup, err)
if createMode != string(sql.CreateModeOnlineSecondary) {
auditingClient := meta.(*clients.Client).Sql.DatabaseExtendedBlobAuditingPoliciesClient
auditingProps := sql.ExtendedDatabaseBlobAuditingPolicy{
ExtendedDatabaseBlobAuditingPolicyProperties: helper.ExpandAzureRmSqlDBBlobAuditingPolicies(auditingPolicies),
}
if _, err = auditingClient.CreateOrUpdate(ctx, resourceGroup, serverName, name, auditingProps); err != nil {
return fmt.Errorf("failure in issuing create/update request for SQL Database %q Blob Auditing Policies(SQL Server %q/ Resource Group %q): %+v", name, serverName, resourceGroup, err)
}
}

return resourceArmSqlDatabaseRead(d, meta)
Expand Down Expand Up @@ -594,12 +602,12 @@ func resourceArmSqlDatabaseRead(d *schema.ResourceData, meta interface{}) error
auditingClient := meta.(*clients.Client).Sql.DatabaseExtendedBlobAuditingPoliciesClient
auditingResp, err := auditingClient.Get(ctx, resourceGroup, serverName, name)
if err != nil {
return fmt.Errorf("Error reading SQL Database %q: %v Blob Auditing Policies", name, err)
return fmt.Errorf("failure in reading SQL Database %q: %v Blob Auditing Policies", name, err)
}

flattenBlobAuditing := helper.FlattenAzureRmSqlDBBlobAuditingPolicies(&auditingResp, d)
if err := d.Set("extended_auditing_policy", flattenBlobAuditing); err != nil {
return fmt.Errorf("Error setting `extended_auditing_policy`: %+v", err)
return fmt.Errorf("failure in setting `extended_auditing_policy`: %+v", err)
}

return tags.FlattenAndSet(d, resp.Tags)
Expand Down

0 comments on commit ca6c4b2

Please sign in to comment.