From c9ceaa159abec435abeced883487673fe67b438f Mon Sep 17 00:00:00 2001 From: Yuping Wei <56525716+yupwei68@users.noreply.github.com> Date: Tue, 17 Mar 2020 07:26:27 +0800 Subject: [PATCH] =?UTF-8?q?`azurerm=5Fsql=5Fdatabase`=20-=20support=20for?= =?UTF-8?q?=20the=20`extended=5Fauditing=5Fpol=E2=80=A6=20(#5049)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to #5036 continuation of #4982 --- .../internal/services/sql/client/client.go | 41 ++-- .../sql/helper/sqlExtendedAuditing.go | 55 +++++ .../services/sql/resource_arm_sql_database.go | 22 ++ .../tests/resource_arm_sql_database_test.go | 216 ++++++++++++++++-- website/docs/r/sql_database.html.markdown | 26 +++ 5 files changed, 325 insertions(+), 35 deletions(-) diff --git a/azurerm/internal/services/sql/client/client.go b/azurerm/internal/services/sql/client/client.go index 7e47528b4cfc..ac421aa58539 100644 --- a/azurerm/internal/services/sql/client/client.go +++ b/azurerm/internal/services/sql/client/client.go @@ -6,15 +6,16 @@ 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 - ExtendedServerBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient + DatabasesClient *sql.DatabasesClient + DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient + ElasticPoolsClient *sql.ElasticPoolsClient + FirewallRulesClient *sql.FirewallRulesClient + FailoverGroupsClient *sql.FailoverGroupsClient + ServersClient *sql.ServersClient + ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient + VirtualNetworkRulesClient *sql.VirtualNetworkRulesClient + ExtendedDatabaseBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient + ExtendedServerBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient } func NewClient(o *common.ClientOptions) *Client { @@ -43,18 +44,22 @@ func NewClient(o *common.ClientOptions) *Client { VirtualNetworkRulesClient := sql.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&VirtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer) + ExtendedDatabaseBlobAuditingPoliciesClient := sql.NewExtendedDatabaseBlobAuditingPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&ExtendedDatabaseBlobAuditingPoliciesClient.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, - ExtendedServerBlobAuditingPoliciesClient: &ExtendedServerBlobAuditingPoliciesClient, + DatabasesClient: &DatabasesClient, + DatabaseThreatDetectionPoliciesClient: &DatabaseThreatDetectionPoliciesClient, + ElasticPoolsClient: &ElasticPoolsClient, + FailoverGroupsClient: &FailoverGroupsClient, + FirewallRulesClient: &FirewallRulesClient, + ServersClient: &ServersClient, + ServerAzureADAdministratorsClient: &ServerAzureADAdministratorsClient, + VirtualNetworkRulesClient: &VirtualNetworkRulesClient, + ExtendedDatabaseBlobAuditingPoliciesClient: &ExtendedDatabaseBlobAuditingPoliciesClient, + ExtendedServerBlobAuditingPoliciesClient: &ExtendedServerBlobAuditingPoliciesClient, } } diff --git a/azurerm/internal/services/sql/helper/sqlExtendedAuditing.go b/azurerm/internal/services/sql/helper/sqlExtendedAuditing.go index b7129a628f9e..5c231d793117 100644 --- a/azurerm/internal/services/sql/helper/sqlExtendedAuditing.go +++ b/azurerm/internal/services/sql/helper/sqlExtendedAuditing.go @@ -96,3 +96,58 @@ func FlattenAzureRmSqlServerBlobAuditingPolicies(extendedServerBlobAuditingPolic }, } } + +func ExpandAzureRmSqlDBBlobAuditingPolicies(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 FlattenAzureRmSqlDBBlobAuditingPolicies(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, + }, + } +} diff --git a/azurerm/internal/services/sql/resource_arm_sql_database.go b/azurerm/internal/services/sql/resource_arm_sql_database.go index 8f0e84d562a9..321431ea6e91 100644 --- a/azurerm/internal/services/sql/resource_arm_sql_database.go +++ b/azurerm/internal/services/sql/resource_arm_sql_database.go @@ -16,6 +16,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" @@ -328,6 +329,8 @@ func resourceArmSqlDatabase() *schema.Resource { Optional: true, }, + "extended_auditing_policy": helper.ExtendedAuditingSchema(), + "tags": tags.Schema(), }, @@ -502,6 +505,14 @@ func resourceArmSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface{} return fmt.Errorf("Error setting database threat detection policy: %+v", err) } + auditingClient := meta.(*clients.Client).Sql.ExtendedDatabaseBlobAuditingPoliciesClient + 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) + } + return resourceArmSqlDatabaseRead(d, meta) } @@ -586,6 +597,17 @@ func resourceArmSqlDatabaseRead(d *schema.ResourceData, meta interface{}) error d.Set("zone_redundant", props.ZoneRedundant) } + auditingClient := meta.(*clients.Client).Sql.ExtendedDatabaseBlobAuditingPoliciesClient + 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) + } + + 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 tags.FlattenAndSet(d, resp.Tags) } diff --git a/azurerm/internal/services/sql/tests/resource_arm_sql_database_test.go b/azurerm/internal/services/sql/tests/resource_arm_sql_database_test.go index 5c16ff1db506..622902a8f0f2 100644 --- a/azurerm/internal/services/sql/tests/resource_arm_sql_database_test.go +++ b/azurerm/internal/services/sql/tests/resource_arm_sql_database_test.go @@ -418,6 +418,76 @@ func TestAccAzureRMSqlDatabase_bacpac(t *testing.T) { }) } +func TestAccAzureRMSqlDatabase_withBlobAuditingPolices(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sql_database", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMSqlDatabaseDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSqlDatabase_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlDatabaseExists(data.ResourceName), + resource.TestCheckNoResourceAttr(data.ResourceName, "extended_auditing_policy.#"), + ), + }, + data.ImportStep("administrator_login_password", "create_mode"), + { + Config: testAccAzureRMSqlDatabase_withBlobAuditingPolices(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlDatabaseExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.#", "1"), + 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", "create_mode"), + { + Config: testAccAzureRMSqlDatabase_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlDatabaseExists(data.ResourceName), + resource.TestCheckNoResourceAttr(data.ResourceName, "extended_auditing_policy.#"), + ), + }, + data.ImportStep("administrator_login_password", "create_mode"), + }, + }) +} + +func TestAccAzureRMSqlDatabase_withBlobAuditingPolicesUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sql_database", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMSqlDatabaseDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSqlDatabase_withBlobAuditingPolices(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlDatabaseExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.#", "1"), + 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", "create_mode"), + { + Config: testAccAzureRMSqlDatabase_withBlobAuditingPolicesUpdated(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlDatabaseExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "extended_auditing_policy.#", "1"), + 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", "create_mode"), + }, + }) +} + func testAccAzureRMSqlDatabase_basic(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -708,31 +778,31 @@ resource "azurerm_resource_group" "test" { resource "azurerm_storage_account" "test" { name = "accsa%d" - resource_group_name = "${azurerm_resource_group.test.name}" - location = "${azurerm_resource_group.test.location}" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location account_tier = "Standard" account_replication_type = "LRS" } resource "azurerm_storage_container" "test" { name = "bacpac" - storage_account_name = "${azurerm_storage_account.test.name}" + storage_account_name = azurerm_storage_account.test.name container_access_type = "private" } resource "azurerm_storage_blob" "test" { name = "test.bacpac" - resource_group_name = "${azurerm_resource_group.test.name}" - storage_account_name = "${azurerm_storage_account.test.name}" - storage_container_name = "${azurerm_storage_container.test.name}" + resource_group_name = azurerm_resource_group.test.name + storage_account_name = azurerm_storage_account.test.name + storage_container_name = azurerm_storage_container.test.name type = "block" source = "testdata/sql_import.bacpac" } resource "azurerm_sql_server" "test" { name = "acctestsqlserver%d" - resource_group_name = "${azurerm_resource_group.test.name}" - location = "${azurerm_resource_group.test.location}" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location version = "12.0" administrator_login = "mradministrator" administrator_login_password = "thisIsDog11" @@ -740,28 +810,28 @@ resource "azurerm_sql_server" "test" { resource "azurerm_sql_firewall_rule" "test" { name = "allowazure" - resource_group_name = "${azurerm_resource_group.test.name}" - server_name = "${azurerm_sql_server.test.name}" + resource_group_name = azurerm_resource_group.test.name + server_name = azurerm_sql_server.test.name start_ip_address = "0.0.0.0" end_ip_address = "0.0.0.0" } resource "azurerm_sql_database" "test" { name = "acctestdb%d" - resource_group_name = "${azurerm_resource_group.test.name}" - server_name = "${azurerm_sql_server.test.name}" - location = "${azurerm_resource_group.test.location}" + resource_group_name = azurerm_resource_group.test.name + server_name = azurerm_sql_server.test.name + location = azurerm_resource_group.test.location edition = "Standard" collation = "SQL_Latin1_General_CP1_CI_AS" max_size_bytes = "1073741824" requested_service_objective_name = "S0" import { - storage_uri = "${azurerm_storage_blob.test.url}" - storage_key = "${azurerm_storage_account.test.primary_access_key}" + storage_uri = azurerm_storage_blob.test.url + storage_key = azurerm_storage_account.test.primary_access_key storage_key_type = "StorageAccessKey" - administrator_login = "${azurerm_sql_server.test.administrator_login}" - administrator_login_password = "${azurerm_sql_server.test.administrator_login_password}" + administrator_login = azurerm_sql_server.test.administrator_login + administrator_login_password = azurerm_sql_server.test.administrator_login_password authentication_type = "SQL" } } @@ -916,3 +986,115 @@ resource "azurerm_sql_database" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, zoneRedundant) } + +func testAccAzureRMSqlDatabase_withBlobAuditingPolices(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_storage_account" "test" { + name = "acctest%[3]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%[3]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" +} + +resource "azurerm_sql_database" "test" { + name = "acctestdb%[1]d" + resource_group_name = azurerm_resource_group.test.name + server_name = azurerm_sql_server.test.name + location = azurerm_resource_group.test.location + edition = "Standard" + collation = "SQL_Latin1_General_CP1_CI_AS" + max_size_bytes = "1073741824" + requested_service_objective_name = "S0" + + 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 + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomIntOfLength(15)) +} + +func testAccAzureRMSqlDatabase_withBlobAuditingPolicesUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_storage_account" "test" { + name = "acctest%[3]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%[3]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" +} + +resource "azurerm_sql_database" "test" { + name = "acctestdb%[1]d" + resource_group_name = azurerm_resource_group.test.name + server_name = azurerm_sql_server.test.name + location = azurerm_resource_group.test.location + edition = "Standard" + collation = "SQL_Latin1_General_CP1_CI_AS" + max_size_bytes = "1073741824" + requested_service_objective_name = "S0" + + 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 = 11 + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomIntOfLength(15)) +} diff --git a/website/docs/r/sql_database.html.markdown b/website/docs/r/sql_database.html.markdown index 2d740c064440..d514a4ed52e9 100644 --- a/website/docs/r/sql_database.html.markdown +++ b/website/docs/r/sql_database.html.markdown @@ -27,12 +27,27 @@ resource "azurerm_sql_server" "example" { administrator_login_password = "4-v3ry-53cr37-p455w0rd" } +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_database" "example" { name = "mysqldatabase" resource_group_name = azurerm_resource_group.example.name location = "West US" server_name = azurerm_sql_server.example.name + 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" } @@ -78,6 +93,8 @@ The following arguments are supported: * `zone_redundant` - (Optional) Whether or not this database is zone redundant, which means the replicas of this database will be spread across multiple availability zones. +* `extended_auditing_policy` - (Optional) A `extended_auditing_policy` block as defined below. + * `tags` - (Optional) A mapping of tags to assign to the resource. `import` supports the following: @@ -103,6 +120,15 @@ The following arguments are supported: * `storage_endpoint` - (Optional) Specifies the blob storage endpoint (e.g. https://MyAccount.blob.core.windows.net). This blob storage will hold all Threat Detection audit logs. Required if `state` is `Enabled`. * `use_server_default` - (Optional) Should the default server policy be used? Defaults to `Disabled`. +--- + +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. +* `retention_in_days` - (Optional) Specifies the number of days to retain logs for in the storage account. + ## Attributes Reference The following attributes are exported: