Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_sql_server - support for the extended_auditing_policy property #5036

Merged
merged 32 commits into from Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 21 additions & 16 deletions azurerm/internal/services/sql/client/client.go
Expand Up @@ -6,14 +6,15 @@ import (
)

type Client struct {
DatabasesClient *sql.DatabasesClient
DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient
ElasticPoolsClient *sql.ElasticPoolsClient
FirewallRulesClient *sql.FirewallRulesClient
FailoverGroupsClient *sql.FailoverGroupsClient
ServersClient *sql.ServersClient
ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient
VirtualNetworkRulesClient *sql.VirtualNetworkRulesClient
DatabasesClient *sql.DatabasesClient
DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient
ElasticPoolsClient *sql.ElasticPoolsClient
FirewallRulesClient *sql.FirewallRulesClient
FailoverGroupsClient *sql.FailoverGroupsClient
ServersClient *sql.ServersClient
ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient
VirtualNetworkRulesClient *sql.VirtualNetworkRulesClient
ExtendedServerBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand Down Expand Up @@ -42,14 +43,18 @@ func NewClient(o *common.ClientOptions) *Client {
VirtualNetworkRulesClient := sql.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&VirtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer)

ExtendedServerBlobAuditingPoliciesClient := sql.NewExtendedServerBlobAuditingPoliciesClient(o.SubscriptionId)
o.ConfigureClient(&ExtendedServerBlobAuditingPoliciesClient.Client, o.ResourceManagerAuthorizer)

return &Client{
DatabasesClient: &DatabasesClient,
DatabaseThreatDetectionPoliciesClient: &DatabaseThreatDetectionPoliciesClient,
ElasticPoolsClient: &ElasticPoolsClient,
FailoverGroupsClient: &FailoverGroupsClient,
FirewallRulesClient: &FirewallRulesClient,
ServersClient: &ServersClient,
ServerAzureADAdministratorsClient: &ServerAzureADAdministratorsClient,
VirtualNetworkRulesClient: &VirtualNetworkRulesClient,
DatabasesClient: &DatabasesClient,
DatabaseThreatDetectionPoliciesClient: &DatabaseThreatDetectionPoliciesClient,
ElasticPoolsClient: &ElasticPoolsClient,
FailoverGroupsClient: &FailoverGroupsClient,
FirewallRulesClient: &FirewallRulesClient,
ServersClient: &ServersClient,
ServerAzureADAdministratorsClient: &ServerAzureADAdministratorsClient,
VirtualNetworkRulesClient: &VirtualNetworkRulesClient,
ExtendedServerBlobAuditingPoliciesClient: &ExtendedServerBlobAuditingPoliciesClient,
}
}
98 changes: 98 additions & 0 deletions azurerm/internal/services/sql/helper/sqlExtendedAuditing.go
@@ -0,0 +1,98 @@
package helper

import (
"github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2017-03-01-preview/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 ExpandAzureRmSqlServerBlobAuditingPolicies(input []interface{}) *sql.ExtendedServerBlobAuditingPolicyProperties {
if len(input) == 0 {
return &sql.ExtendedServerBlobAuditingPolicyProperties{
State: sql.BlobAuditingPolicyStateDisabled,
}
}
serverBlobAuditingPolicies := input[0].(map[string]interface{})

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

return &ExtendedServerBlobAuditingPolicyProperties
}

func FlattenAzureRmSqlServerBlobAuditingPolicies(extendedServerBlobAuditingPolicy *sql.ExtendedServerBlobAuditingPolicy, d *schema.ResourceData) []interface{} {
if extendedServerBlobAuditingPolicy == nil || extendedServerBlobAuditingPolicy.State == sql.BlobAuditingPolicyStateDisabled {
return []interface{}{}
}
var storageEndpoint, storageAccessKey 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 extendedServerBlobAuditingPolicy.StorageEndpoint != nil {
storageEndpoint = *extendedServerBlobAuditingPolicy.StorageEndpoint
}

var secondKeyInUse bool
if extendedServerBlobAuditingPolicy.IsStorageSecondaryKeyInUse != nil {
secondKeyInUse = *extendedServerBlobAuditingPolicy.IsStorageSecondaryKeyInUse
}
var retentionDays int32
if extendedServerBlobAuditingPolicy.RetentionDays != nil {
retentionDays = *extendedServerBlobAuditingPolicy.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,
},
}
}
22 changes: 22 additions & 0 deletions azurerm/internal/services/sql/resource_arm_sql_server.go
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"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/sql/helper"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
Expand Down Expand Up @@ -100,6 +101,8 @@ func resourceArmSqlServer() *schema.Resource {
},
},

"extended_auditing_policy": helper.ExtendedAuditingSchema(),

"tags": tags.Schema(),
},
}
Expand Down Expand Up @@ -171,6 +174,14 @@ func resourceArmSqlServerCreateUpdate(d *schema.ResourceData, meta interface{})

d.SetId(*resp.ID)

auditingClient := meta.(*clients.Client).Sql.ExtendedServerBlobAuditingPoliciesClient
auditingProps := sql.ExtendedServerBlobAuditingPolicy{
ExtendedServerBlobAuditingPolicyProperties: helper.ExpandAzureRmSqlServerBlobAuditingPolicies(d.Get("extended_auditing_policy").([]interface{})),
}
if _, err = auditingClient.CreateOrUpdate(ctx, resGroup, name, auditingProps); err != nil {
return fmt.Errorf("Error issuing create/update request for SQL Server %q Blob Auditing Policies(Resource Group %q): %+v", name, resGroup, err)
}

return resourceArmSqlServerRead(d, meta)
}

Expand Down Expand Up @@ -214,6 +225,17 @@ func resourceArmSqlServerRead(d *schema.ResourceData, meta interface{}) error {
d.Set("fully_qualified_domain_name", serverProperties.FullyQualifiedDomainName)
}

auditingClient := meta.(*clients.Client).Sql.ExtendedServerBlobAuditingPoliciesClient
auditingResp, err := auditingClient.Get(ctx, resGroup, name)
if err != nil {
return fmt.Errorf("Error reading SQL Server %s Blob Auditing Policies: %v ", name, err)
}

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

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

Expand Down
120 changes: 120 additions & 0 deletions azurerm/internal/services/sql/tests/resource_arm_sql_server_test.go
Expand Up @@ -171,6 +171,36 @@ func TestAccAzureRMSqlServer_updateWithIdentityAdded(t *testing.T) {
})
}

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
CheckDestroy: testCheckAzureRMSqlServerDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMSqlServer_withBlobAuditingPolices(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMSqlServerExists(data.ResourceName),
resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.0.storage_account_access_key_is_secondary", "true"),
resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.0.retention_in_days", "6"),
),
},
data.ImportStep("administrator_login_password", "extended_auditing_policy.0.storage_account_access_key"),
{
Config: testAccAzureRMSqlServer_withBlobAuditingPolicesUpdated(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMSqlServerExists(data.ResourceName),
resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.0.storage_account_access_key_is_secondary", "false"),
resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.0.retention_in_days", "11"),
),
},
data.ImportStep("administrator_login_password", "extended_auditing_policy.0.storage_account_access_key"),
},
})
}

func testCheckAzureRMSqlServerExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acceptance.AzureProvider.Meta().(*clients.Client).Sql.ServersClient
Expand Down Expand Up @@ -366,3 +396,93 @@ resource "azurerm_sql_server" "test" {
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func testAccAzureRMSqlServer_withBlobAuditingPolices(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
yupwei68 marked this conversation as resolved.
Show resolved Hide resolved
name = "acctestRG-sql-%[1]d"
location = "%[2]s"
}

resource "azurerm_storage_account" "test" {
name = "acctest%[1]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%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}

resource "azurerm_sql_server" "test" {
name = "acctestsqlserver%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
version = "12.0"
administrator_login = "mradministrator"
administrator_login_password = "thisIsDog11"

extended_auditing_policy {
storage_account_access_key = azurerm_storage_account.test.primary_access_key
storage_endpoint = azurerm_storage_account.test.primary_blob_endpoint
storage_account_access_key_is_secondary = true
retention_in_days = 6
}
}
`, data.RandomIntOfLength(15), data.Locations.Primary)
}

func testAccAzureRMSqlServer_withBlobAuditingPolicesUpdated(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
yupwei68 marked this conversation as resolved.
Show resolved Hide resolved
name = "acctestRG-sql-%[1]d"
location = "%[2]s"
}

resource "azurerm_storage_account" "test" {
name = "acctest%[1]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%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}

resource "azurerm_sql_server" "test" {
name = "acctestsqlserver%[1]d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
version = "12.0"
administrator_login = "mradministrator"
administrator_login_password = "thisIsDog11"

extended_auditing_policy {
storage_account_access_key = azurerm_storage_account.test2.primary_access_key
storage_endpoint = azurerm_storage_account.test2.primary_blob_endpoint
storage_account_access_key_is_secondary = false
retention_in_days = 11
}
}
`, data.RandomIntOfLength(15), data.Locations.Primary)
}
2 changes: 1 addition & 1 deletion go.sum
Expand Up @@ -463,4 +463,4 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
31 changes: 30 additions & 1 deletion website/docs/r/sql_server.html.markdown
Expand Up @@ -22,6 +22,14 @@ resource "azurerm_resource_group" "example" {
location = "West US"
}

resource "azurerm_storage_account" "example" {
name = "examplesa"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
}

resource "azurerm_sql_server" "example" {
name = "mysqlserver"
resource_group_name = azurerm_resource_group.example.name
Expand All @@ -30,6 +38,13 @@ resource "azurerm_sql_server" "example" {
administrator_login = "mradministrator"
administrator_login_password = "thisIsDog11"

extended_auditing_policy {
storage_endpoint = azurerm_storage_account.example.primary_blob_endpoint
storage_account_access_key = azurerm_storage_account.example.primary_access_key
storage_account_access_key_is_secondary = true
retention_in_days = 6
}

tags = {
environment = "production"
}
Expand All @@ -53,6 +68,8 @@ The following arguments are supported:

* `identity` - (Optional) An `identity` block as defined below.

* `extended_auditing_policy` - (Optional) A `extended_auditing_policy` block as defined below.

* `tags` - (Optional) A mapping of tags to assign to the resource.

---
Expand Down Expand Up @@ -80,7 +97,19 @@ The following attributes are exported:

-> You can access the Principal ID via `${azurerm_sql_server.example.identity.0.principal_id}` and the Tenant ID via `${azurerm_sql_server.example.identity.0.tenant_id}`

## Timeouts
---

A `extended_auditing_policy` block supports the following:

* `storage_account_access_key` - (Required) Specifies the access key to use for the auditing storage account.

* `storage_endpoint` - (Required) Specifies the blob storage endpoint (e.g. https://MyAccount.blob.core.windows.net).

* `storage_account_access_key_is_secondary` - (Optional) Specifies whether `storage_account_access_key` value is the storage's secondary key.
Comment on lines +106 to +108
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we order these alphabetically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't need to put required fields in advance? We just order all required and optional fields alphabetically, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHoops missed the optional, yes typically alphabetically, but sometimes i'll order for aesthetics ie storage_endpoint -> storage_account_access_key -> storage_account_access_key_is_secondary


* `retention_in_days` - (Optional) Specifies the number of days to retain logs for in the storage account.

### Timeouts

The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions:

Expand Down