From d7011d7d2a495016159fb9913868fa70bde22a48 Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 30 Apr 2020 13:27:42 -0700 Subject: [PATCH 1/8] azurerm_postgres_server - support for security_alert_policy --- ..._arm_mssql_server_security_alert_policy.go | 2 + ...mssql_server_security_alert_policy_test.go | 4 +- .../services/postgres/client/client.go | 25 ++- .../resource_arm_postgresql_server.go | 200 +++++++++++++++++- .../resource_arm_postgresql_server_test.go | 81 ++++++- 5 files changed, 284 insertions(+), 28 deletions(-) diff --git a/azurerm/internal/services/mssql/resource_arm_mssql_server_security_alert_policy.go b/azurerm/internal/services/mssql/resource_arm_mssql_server_security_alert_policy.go index bb8ce87b0277..4f2e9fc649fe 100644 --- a/azurerm/internal/services/mssql/resource_arm_mssql_server_security_alert_policy.go +++ b/azurerm/internal/services/mssql/resource_arm_mssql_server_security_alert_policy.go @@ -14,6 +14,8 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) +// todo 3.0 - this may want to be put into the mssql_server resource now that it exists. + func resourceArmMssqlServerSecurityAlertPolicy() *schema.Resource { return &schema.Resource{ Create: resourceArmMssqlServerSecurityAlertPolicyCreateUpdate, diff --git a/azurerm/internal/services/mssql/tests/resource_arm_mssql_server_security_alert_policy_test.go b/azurerm/internal/services/mssql/tests/resource_arm_mssql_server_security_alert_policy_test.go index 53a8304b7144..a2c063ec9e3d 100644 --- a/azurerm/internal/services/mssql/tests/resource_arm_mssql_server_security_alert_policy_test.go +++ b/azurerm/internal/services/mssql/tests/resource_arm_mssql_server_security_alert_policy_test.go @@ -184,9 +184,9 @@ resource "azurerm_sql_server" "test" { resource "azurerm_storage_account" "test" { name = "accsa%d" resource_group_name = azurerm_resource_group.test.name - location = "%s" + location = azurerm_resource_group.test.location account_tier = "Standard" account_replication_type = "GRS" } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.Locations.Primary) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } diff --git a/azurerm/internal/services/postgres/client/client.go b/azurerm/internal/services/postgres/client/client.go index 50975fc5276c..0dd71d9cc304 100644 --- a/azurerm/internal/services/postgres/client/client.go +++ b/azurerm/internal/services/postgres/client/client.go @@ -6,11 +6,12 @@ import ( ) type Client struct { - ConfigurationsClient *postgresql.ConfigurationsClient - DatabasesClient *postgresql.DatabasesClient - FirewallRulesClient *postgresql.FirewallRulesClient - ServersClient *postgresql.ServersClient - VirtualNetworkRulesClient *postgresql.VirtualNetworkRulesClient + ConfigurationsClient *postgresql.ConfigurationsClient + DatabasesClient *postgresql.DatabasesClient + FirewallRulesClient *postgresql.FirewallRulesClient + ServersClient *postgresql.ServersClient + ServerSecurityAlertPoliciesClient *postgresql.ServerSecurityAlertPoliciesClient + VirtualNetworkRulesClient *postgresql.VirtualNetworkRulesClient } func NewClient(o *common.ClientOptions) *Client { @@ -26,14 +27,18 @@ func NewClient(o *common.ClientOptions) *Client { serversClient := postgresql.NewServersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&serversClient.Client, o.ResourceManagerAuthorizer) + serverSecurityAlertPoliciesClient := postgresql.NewServerSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&serverSecurityAlertPoliciesClient.Client, o.ResourceManagerAuthorizer) + virtualNetworkRulesClient := postgresql.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&virtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer) return &Client{ - ConfigurationsClient: &configurationsClient, - DatabasesClient: &databasesClient, - FirewallRulesClient: &firewallRulesClient, - ServersClient: &serversClient, - VirtualNetworkRulesClient: &virtualNetworkRulesClient, + ConfigurationsClient: &configurationsClient, + DatabasesClient: &databasesClient, + FirewallRulesClient: &firewallRulesClient, + ServersClient: &serversClient, + ServerSecurityAlertPoliciesClient: &serverSecurityAlertPoliciesClient, + VirtualNetworkRulesClient: &virtualNetworkRulesClient, } } diff --git a/azurerm/internal/services/postgres/resource_arm_postgresql_server.go b/azurerm/internal/services/postgres/resource_arm_postgresql_server.go index 7f8cc2c45208..aa54419b642c 100644 --- a/azurerm/internal/services/postgres/resource_arm_postgresql_server.go +++ b/azurerm/internal/services/postgres/resource_arm_postgresql_server.go @@ -277,6 +277,77 @@ func resourceArmPostgreSQLServer() *schema.Resource { DiffSuppressFunc: suppress.CaseDifference, }, + // computed as when not set the API returns an empty zeroed out struct + "security_alert_policy": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "disabled_alerts": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Set: schema.HashString, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + "Sql_Injection", + "Sql_Injection_Vulnerability", + "Access_Anomaly", + "Data_Exfiltration", + "Unsafe_Action", + }, false), + }, + }, + + "email_account_admins": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "email_addresses": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + // todo email validation in code + }, + Set: schema.HashString, + }, + + "retention_days": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "storage_account_access_key": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "storage_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "fqdn": { Type: schema.TypeString, Computed: true, @@ -289,6 +360,7 @@ func resourceArmPostgreSQLServer() *schema.Resource { func resourceArmPostgreSQLServerCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Postgres.ServersClient + securityClient := meta.(*clients.Client).Postgres.ServerSecurityAlertPoliciesClient ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -339,7 +411,7 @@ func resourceArmPostgreSQLServerCreate(d *schema.ResourceData, meta interface{}) ssl = postgresql.SslEnforcementEnumDisabled } - storage := expandAzureRmPostgreSQLStorageProfile(d) + storage := expandPostgreSQLStorageProfile(d) var props postgresql.BasicServerPropertiesForCreate switch mode { @@ -440,11 +512,26 @@ func resourceArmPostgreSQLServerCreate(d *schema.ResourceData, meta interface{}) d.SetId(*read.ID) + if v, ok := d.GetOk("security_alert_policy"); ok { + alert := expandSecurityAlertPolicy(v) + if alert != nil { + future, err := securityClient.CreateOrUpdate(ctx, resourceGroup, name, *alert) + if err != nil { + return fmt.Errorf("error updataing postgres server security alert policy: %v", err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("error waiting for creation/update of postgrest server security alert policy (server %q, resource group %q): %+v", name, resourceGroup, err) + } + } + } + return resourceArmPostgreSQLServerRead(d, meta) } func resourceArmPostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Postgres.ServersClient + securityClient := meta.(*clients.Client).Postgres.ServerSecurityAlertPoliciesClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -478,7 +565,7 @@ func resourceArmPostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) AdministratorLoginPassword: utils.String(d.Get("administrator_login_password").(string)), PublicNetworkAccess: publicAccess, SslEnforcement: ssl, - StorageProfile: expandAzureRmPostgreSQLStorageProfile(d), + StorageProfile: expandPostgreSQLStorageProfile(d), Version: postgresql.ServerVersion(d.Get("version").(string)), }, Sku: sku, @@ -494,21 +581,26 @@ func resourceArmPostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("waiting for update of PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - read, err := client.Get(ctx, id.ResourceGroup, id.Name) - if err != nil { - return fmt.Errorf("retrieving PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - if read.ID == nil { - return fmt.Errorf("Cannot read PostgreSQL Server %s (resource group %s) ID", id.Name, id.ResourceGroup) - } + if v, ok := d.GetOk("security_alert_policy"); ok { + alert := expandSecurityAlertPolicy(v) + if alert != nil { + future, err := securityClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, *alert) + if err != nil { + return fmt.Errorf("error updataing mssql server security alert policy: %v", err) + } - d.SetId(*read.ID) + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("error waiting for creation/update of postgrest server security alert policy (server %q, resource group %q): %+v", id.Name, id.ResourceGroup, err) + } + } + } return resourceArmPostgreSQLServerRead(d, meta) } func resourceArmPostgreSQLServerRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Postgres.ServersClient + securityClient := meta.(*clients.Client).Postgres.ServerSecurityAlertPoliciesClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -563,6 +655,19 @@ func resourceArmPostgreSQLServerRead(d *schema.ResourceData, meta interface{}) e // Computed d.Set("fqdn", props.FullyQualifiedDomainName) } + + secResp, err := securityClient.Get(ctx, id.ResourceGroup, id.Name) + if err != nil && !utils.ResponseWasNotFound(secResp.Response) { + return fmt.Errorf("error making read request to postgres server security alert policy: %+v", err) + } + + if !utils.ResponseWasNotFound(secResp.Response) { + block := flattenSecurityAlertPolicy(secResp.SecurityAlertPolicyProperties, d.Get("security_alert_policy.0.storage_account_access_key").(string)) + if err := d.Set("security_alert_policy", block); err != nil { + return fmt.Errorf("setting `security_alert_policy`: %+v", err) + } + } + return tags.FlattenAndSet(d, resp.Tags) } @@ -627,7 +732,7 @@ func expandServerSkuName(skuName string) (*postgresql.Sku, error) { }, nil } -func expandAzureRmPostgreSQLStorageProfile(d *schema.ResourceData) *postgresql.StorageProfile { +func expandPostgreSQLStorageProfile(d *schema.ResourceData) *postgresql.StorageProfile { storage := postgresql.StorageProfile{} if v, ok := d.GetOk("storage_profile"); ok { storageprofile := v.([]interface{})[0].(map[string]interface{}) @@ -682,3 +787,76 @@ func flattenPostgreSQLStorageProfile(resp *postgresql.StorageProfile) []interfac return []interface{}{values} } + +func expandSecurityAlertPolicy(i interface{}) *postgresql.ServerSecurityAlertPolicy { + slice := i.([]interface{}) + if len(slice) == 0 { + return nil + } + + block := slice[0].(map[string]interface{}) + + state := postgresql.ServerSecurityAlertPolicyStateEnabled + if !block["enabled"].(bool) { + state = postgresql.ServerSecurityAlertPolicyStateDisabled + } + + props := &postgresql.SecurityAlertPolicyProperties{ + State: state, + } + + if v, ok := block["disabled_alerts"]; ok { + props.DisabledAlerts = utils.ExpandStringSlice(v.(*schema.Set).List()) + } + + if v, ok := block["email_addresses"]; ok { + props.EmailAddresses = utils.ExpandStringSlice(v.(*schema.Set).List()) + } + + if v, ok := block["email_account_admins"]; ok { + props.EmailAccountAdmins = utils.Bool(v.(bool)) + } + + if v, ok := block["retention_days"]; ok { + props.RetentionDays = utils.Int32(int32(v.(int))) + } + + if v, ok := block["storage_account_access_key"]; ok { + props.StorageAccountAccessKey = utils.String(v.(string)) + } + + if v, ok := block["storage_endpoint"]; ok { + props.StorageEndpoint = utils.String(v.(string)) + } + + return &postgresql.ServerSecurityAlertPolicy{ + SecurityAlertPolicyProperties: props, + } +} + +func flattenSecurityAlertPolicy(props *postgresql.SecurityAlertPolicyProperties, accessKey string) interface{} { + if props == nil { + return nil + } + + block := map[string]interface{}{} + + block["enabled"] = props.State == postgresql.ServerSecurityAlertPolicyStateEnabled + + block["disabled_alerts"] = utils.FlattenStringSlice(props.DisabledAlerts) + block["disabled_alerts"] = utils.FlattenStringSlice(props.EmailAddresses) + + if v := props.EmailAccountAdmins; v != nil { + block["email_account_admins"] = *v + } + if v := props.RetentionDays; v != nil { + block["retention_days"] = *v + } + if v := props.StorageEndpoint; v != nil { + block["storage_endpoint"] = *v + } + + block["storage_account_access_key"] = accessKey + + return []interface{}{block} +} diff --git a/azurerm/internal/services/postgres/tests/resource_arm_postgresql_server_test.go b/azurerm/internal/services/postgres/tests/resource_arm_postgresql_server_test.go index f0d93a0a0d0d..0b31e9d3c7b2 100644 --- a/azurerm/internal/services/postgres/tests/resource_arm_postgresql_server_test.go +++ b/azurerm/internal/services/postgres/tests/resource_arm_postgresql_server_test.go @@ -225,6 +225,13 @@ func TestAccAzureRMPostgreSQLServer_updated(t *testing.T) { ), }, data.ImportStep("administrator_login_password"), + { + Config: testAccAzureRMPostgreSQLServer_complete2(data, "9.6"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPostgreSQLServerExists(data.ResourceName), + ), + }, + data.ImportStep("administrator_login_password"), { Config: testAccAzureRMPostgreSQLServer_basic(data, "9.6"), Check: resource.ComposeTestCheckFunc( @@ -553,12 +560,12 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-psql-%d" - location = "%s" + name = "acctestRG-psql-%[1]d" + location = "%[2]s" } resource "azurerm_postgresql_server" "test" { - name = "acctest-psql-server-%d" + name = "acctest-psql-server-%[1]d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name @@ -566,7 +573,7 @@ resource "azurerm_postgresql_server" "test" { administrator_login_password = "H@Sh1CoR3!updated" sku_name = "GP_Gen5_4" - version = "%s" + version = "%[3]s" storage_mb = 640000 backup_retention_days = 7 @@ -577,8 +584,72 @@ resource "azurerm_postgresql_server" "test" { public_network_access_enabled = false ssl_enforcement_enabled = true ssl_minimal_tls_version_enforced = "TLS1_2" + + security_alert_policy { + enabled = true + disabled_alerts = ["Sql_Injection", "Data_Exfiltration"] + email_account_admins = true + email_addresses = ["kt@example.com", "admin@example.com"] + + retention_days = 7 + } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, version) +`, data.RandomInteger, data.Locations.Primary, version) +} + +func testAccAzureRMPostgreSQLServer_complete2(data acceptance.TestData, version string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-psql-%[1]d" + location = "%[2]s" +} + +resource "azurerm_storage_account" "test" { + name = "accsa%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "GRS" +} + +resource "azurerm_postgresql_server" "test" { + name = "acctest-psql-server-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + administrator_login = "acctestun" + administrator_login_password = "H@Sh1CoR3!updated" + + sku_name = "GP_Gen5_4" + version = "%[3]s" + storage_mb = 640000 + + backup_retention_days = 14 + geo_redundant_backup_enabled = false + auto_grow_enabled = false + + infrastructure_encryption_enabled = false + public_network_access_enabled = true + ssl_enforcement_enabled = false + ssl_minimal_tls_version_enforced = "TLS1_1" + + security_alert_policy { + enabled = true + disabled_alerts = ["Sql_Injection"] + email_account_admins = true + email_addresses = ["kt@example.com"] + + retention_days = 7 + + storage_endpoint = azurerm_storage_account.test.primary_blob_endpoint + storage_account_access_key = azurerm_storage_account.test.primary_access_key + } +} +`, data.RandomInteger, data.Locations.Primary, version) } func testAccAzureRMPostgreSQLServer_sku(data acceptance.TestData, version, sku string) string { From b10a0003d96ac599ec8936d32caea194979dedce Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 7 May 2020 08:31:23 -0700 Subject: [PATCH 2/8] terrafmt --- .../tests/postgresql_server_resource_test.go | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go b/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go index 0b31e9d3c7b2..7b27711b0137 100644 --- a/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go +++ b/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go @@ -586,12 +586,12 @@ resource "azurerm_postgresql_server" "test" { ssl_minimal_tls_version_enforced = "TLS1_2" security_alert_policy { - enabled = true - disabled_alerts = ["Sql_Injection", "Data_Exfiltration"] - email_account_admins = true - email_addresses = ["kt@example.com", "admin@example.com"] + enabled = true + disabled_alerts = ["Sql_Injection", "Data_Exfiltration"] + email_account_admins = true + email_addresses = ["kt@example.com", "admin@example.com"] - retention_days = 7 + retention_days = 7 } } `, data.RandomInteger, data.Locations.Primary, version) @@ -638,15 +638,15 @@ resource "azurerm_postgresql_server" "test" { ssl_minimal_tls_version_enforced = "TLS1_1" security_alert_policy { - enabled = true - disabled_alerts = ["Sql_Injection"] - email_account_admins = true - email_addresses = ["kt@example.com"] + enabled = true + disabled_alerts = ["Sql_Injection"] + email_account_admins = true + email_addresses = ["kt@example.com"] - retention_days = 7 + retention_days = 7 - storage_endpoint = azurerm_storage_account.test.primary_blob_endpoint - storage_account_access_key = azurerm_storage_account.test.primary_access_key + storage_endpoint = azurerm_storage_account.test.primary_blob_endpoint + storage_account_access_key = azurerm_storage_account.test.primary_access_key } } `, data.RandomInteger, data.Locations.Primary, version) From 85e284ae9193566dd73f710364a7b2eb5cda324b Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 7 May 2020 11:53:33 -0700 Subject: [PATCH 3/8] stash --- .../postgres/postgresql_server_resource.go | 6 ------ .../tests/postgresql_server_resource_test.go | 2 +- .../docs/r/postgresql_server.html.markdown | 21 +++++++++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/azurerm/internal/services/postgres/postgresql_server_resource.go b/azurerm/internal/services/postgres/postgresql_server_resource.go index aa54419b642c..4435de4c4d63 100644 --- a/azurerm/internal/services/postgres/postgresql_server_resource.go +++ b/azurerm/internal/services/postgres/postgresql_server_resource.go @@ -281,20 +281,17 @@ func resourceArmPostgreSQLServer() *schema.Resource { "security_alert_policy": { Type: schema.TypeList, Optional: true, - Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "enabled": { Type: schema.TypeBool, Optional: true, - Computed: true, }, "disabled_alerts": { Type: schema.TypeSet, Optional: true, - Computed: true, Set: schema.HashString, Elem: &schema.Schema{ Type: schema.TypeString, @@ -311,13 +308,11 @@ func resourceArmPostgreSQLServer() *schema.Resource { "email_account_admins": { Type: schema.TypeBool, Optional: true, - Computed: true, }, "email_addresses": { Type: schema.TypeSet, Optional: true, - Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, // todo email validation in code @@ -328,7 +323,6 @@ func resourceArmPostgreSQLServer() *schema.Resource { "retention_days": { Type: schema.TypeInt, Optional: true, - Computed: true, ValidateFunc: validation.IntAtLeast(0), }, diff --git a/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go b/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go index 7b27711b0137..2bc1d08ecb58 100644 --- a/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go +++ b/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go @@ -508,7 +508,7 @@ resource "azurerm_postgresql_server" "import" { sku_name = azurerm_postgresql_server.test.sku_name version = azurerm_postgresql_server.test.version - storage_mb = azurerm_postgresql_server.test.storage_profile.storage_mb + storage_mb = azurerm_postgresql_server.test.storage_mb ssl_enforcement_enabled = azurerm_postgresql_server.test.ssl_enforcement_enabled } diff --git a/website/docs/r/postgresql_server.html.markdown b/website/docs/r/postgresql_server.html.markdown index 904841049d53..21f5f2bfa7d0 100644 --- a/website/docs/r/postgresql_server.html.markdown +++ b/website/docs/r/postgresql_server.html.markdown @@ -85,8 +85,29 @@ The following arguments are supported: * `storage_mb` - (Optional) Max storage allowed for a server. Possible values are between `5120` MB(5GB) and `1048576` MB(1TB) for the Basic SKU and between `5120` MB(5GB) and `4194304` MB(4TB) for General Purpose/Memory Optimized SKUs. For more information see the [product documentation](https://docs.microsoft.com/en-us/rest/api/postgresql/servers/create#StorageProfile). +* `threat_detection_policy` - (Optional) Threat detection policy configuration. The `threat_detection_policy` block supports fields documented below. + * `tags` - (Optional) A mapping of tags to assign to the resource. +--- + +a `threat_detection_policy` block supports the following: + +* `enabled` - (Required) Is the policy enabled? + +* `disabled_alerts` - (Optional) Specifies a list of alerts which should be disabled. Possible values include `Access_Anomaly`, `Sql_Injection` and `Sql_Injection_Vulnerability`. + +* `email_account_admins` - (Optional) Should the account administrators be emailed when this alert is triggered? + +* `email_addresses` - (Optional) A list of email addresses which alerts should be sent to. + +* `retention_days` - (Optional) Specifies the number of days to keep in the Threat Detection audit logs. + +* `storage_account_access_key` - (Optional) Specifies the identifier key of the Threat Detection audit storage account. Required if `state` is `Enabled`. + +* `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`. + + ## Attributes Reference The following attributes are exported: From 14ce238e0add0a38e958a0db8ffdc731c2400a7b Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 7 May 2020 15:20:09 -0700 Subject: [PATCH 4/8] stash --- .../postgres/postgresql_server_resource.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/postgres/postgresql_server_resource.go b/azurerm/internal/services/postgres/postgresql_server_resource.go index 4435de4c4d63..95ef10f5ea25 100644 --- a/azurerm/internal/services/postgres/postgresql_server_resource.go +++ b/azurerm/internal/services/postgres/postgresql_server_resource.go @@ -815,11 +815,11 @@ func expandSecurityAlertPolicy(i interface{}) *postgresql.ServerSecurityAlertPol props.RetentionDays = utils.Int32(int32(v.(int))) } - if v, ok := block["storage_account_access_key"]; ok { + if v, ok := block["storage_account_access_key"]; ok && v.(string) != "" { props.StorageAccountAccessKey = utils.String(v.(string)) } - if v, ok := block["storage_endpoint"]; ok { + if v, ok := block["storage_endpoint"]; ok && v.(string) != "" { props.StorageEndpoint = utils.String(v.(string)) } @@ -833,6 +833,19 @@ func flattenSecurityAlertPolicy(props *postgresql.SecurityAlertPolicyProperties, return nil } + // if they have no been set an empty struct is returned - so ignore it + /*if props.StorageAccountAccessKey == "" && props.StorageEndpoint == "" + + cy.#: "1" => "0" + security_alert_policy.0.disabled_alerts.#: "1" => "" + security_alert_policy.0.disabled_alerts.0: "" => "" + security_alert_policy.0.email_account_admins: "false" => "" + security_alert_policy.0.email_addresses.#: "0" => "" + security_alert_policy.0.enabled: "false" => "" + security_alert_policy.0.retention_days: "0" => "" + security_alert_policy.0.storage_account_access_key: "" => "" + security_alert_policy.0.storage_endpoint: "" => ""*/ + block := map[string]interface{}{} block["enabled"] = props.State == postgresql.ServerSecurityAlertPolicyStateEnabled From 660049459af6cb091616534565e4eb0039003e0d Mon Sep 17 00:00:00 2001 From: kt Date: Wed, 13 May 2020 21:09:12 -0700 Subject: [PATCH 5/8] fix test --- .../postgres/postgresql_server_resource.go | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/azurerm/internal/services/postgres/postgresql_server_resource.go b/azurerm/internal/services/postgres/postgresql_server_resource.go index 95ef10f5ea25..18e2db690607 100644 --- a/azurerm/internal/services/postgres/postgresql_server_resource.go +++ b/azurerm/internal/services/postgres/postgresql_server_resource.go @@ -833,25 +833,23 @@ func flattenSecurityAlertPolicy(props *postgresql.SecurityAlertPolicyProperties, return nil } - // if they have no been set an empty struct is returned - so ignore it - /*if props.StorageAccountAccessKey == "" && props.StorageEndpoint == "" - - cy.#: "1" => "0" - security_alert_policy.0.disabled_alerts.#: "1" => "" - security_alert_policy.0.disabled_alerts.0: "" => "" - security_alert_policy.0.email_account_admins: "false" => "" - security_alert_policy.0.email_addresses.#: "0" => "" - security_alert_policy.0.enabled: "false" => "" - security_alert_policy.0.retention_days: "0" => "" - security_alert_policy.0.storage_account_access_key: "" => "" - security_alert_policy.0.storage_endpoint: "" => ""*/ + // check if its an empty block as in its never been set before + if props.DisabledAlerts != nil && len(*props.DisabledAlerts) == 1 && (*props.DisabledAlerts)[0] == "" && + props.EmailAddresses != nil && len(*props.EmailAddresses) == 1 && (*props.EmailAddresses)[0] == "" && + props.StorageAccountAccessKey != nil && *props.StorageAccountAccessKey == "" && + props.StorageEndpoint != nil && *props.StorageEndpoint == "" && + props.RetentionDays != nil && *props.RetentionDays == 0 && + props.EmailAccountAdmins != nil && !*props.EmailAccountAdmins && + props.State == postgresql.ServerSecurityAlertPolicyStateDisabled { + return nil + } block := map[string]interface{}{} block["enabled"] = props.State == postgresql.ServerSecurityAlertPolicyStateEnabled block["disabled_alerts"] = utils.FlattenStringSlice(props.DisabledAlerts) - block["disabled_alerts"] = utils.FlattenStringSlice(props.EmailAddresses) + block["email_addresses"] = utils.FlattenStringSlice(props.EmailAddresses) if v := props.EmailAccountAdmins; v != nil { block["email_account_admins"] = *v From 7e2a19988d7dacf69e0a76899d6228eb6f9ce879 Mon Sep 17 00:00:00 2001 From: kt Date: Wed, 13 May 2020 21:26:41 -0700 Subject: [PATCH 6/8] update property name to reflect portal and docs --- .../postgres/postgresql_server_resource.go | 15 +++++++-------- .../tests/postgresql_server_resource_test.go | 4 ++-- website/docs/r/postgresql_server.html.markdown | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/azurerm/internal/services/postgres/postgresql_server_resource.go b/azurerm/internal/services/postgres/postgresql_server_resource.go index 18e2db690607..9cfd766d8198 100644 --- a/azurerm/internal/services/postgres/postgresql_server_resource.go +++ b/azurerm/internal/services/postgres/postgresql_server_resource.go @@ -276,9 +276,8 @@ func resourceArmPostgreSQLServer() *schema.Resource { }, true), DiffSuppressFunc: suppress.CaseDifference, }, - - // computed as when not set the API returns an empty zeroed out struct - "security_alert_policy": { + + "threat_detection_policy": { Type: schema.TypeList, Optional: true, MaxItems: 1, @@ -506,7 +505,7 @@ func resourceArmPostgreSQLServerCreate(d *schema.ResourceData, meta interface{}) d.SetId(*read.ID) - if v, ok := d.GetOk("security_alert_policy"); ok { + if v, ok := d.GetOk("threat_detection_policy"); ok { alert := expandSecurityAlertPolicy(v) if alert != nil { future, err := securityClient.CreateOrUpdate(ctx, resourceGroup, name, *alert) @@ -575,7 +574,7 @@ func resourceArmPostgreSQLServerUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("waiting for update of PostgreSQL Server %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - if v, ok := d.GetOk("security_alert_policy"); ok { + if v, ok := d.GetOk("threat_detection_policy"); ok { alert := expandSecurityAlertPolicy(v) if alert != nil { future, err := securityClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, *alert) @@ -656,9 +655,9 @@ func resourceArmPostgreSQLServerRead(d *schema.ResourceData, meta interface{}) e } if !utils.ResponseWasNotFound(secResp.Response) { - block := flattenSecurityAlertPolicy(secResp.SecurityAlertPolicyProperties, d.Get("security_alert_policy.0.storage_account_access_key").(string)) - if err := d.Set("security_alert_policy", block); err != nil { - return fmt.Errorf("setting `security_alert_policy`: %+v", err) + block := flattenSecurityAlertPolicy(secResp.SecurityAlertPolicyProperties, d.Get("threat_detection_policy.0.storage_account_access_key").(string)) + if err := d.Set("threat_detection_policy", block); err != nil { + return fmt.Errorf("setting `threat_detection_policy`: %+v", err) } } diff --git a/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go b/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go index 2bc1d08ecb58..5e5954245470 100644 --- a/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go +++ b/azurerm/internal/services/postgres/tests/postgresql_server_resource_test.go @@ -585,7 +585,7 @@ resource "azurerm_postgresql_server" "test" { ssl_enforcement_enabled = true ssl_minimal_tls_version_enforced = "TLS1_2" - security_alert_policy { + threat_detection_policy { enabled = true disabled_alerts = ["Sql_Injection", "Data_Exfiltration"] email_account_admins = true @@ -637,7 +637,7 @@ resource "azurerm_postgresql_server" "test" { ssl_enforcement_enabled = false ssl_minimal_tls_version_enforced = "TLS1_1" - security_alert_policy { + threat_detection_policy { enabled = true disabled_alerts = ["Sql_Injection"] email_account_admins = true diff --git a/website/docs/r/postgresql_server.html.markdown b/website/docs/r/postgresql_server.html.markdown index 1983bbc7f3c9..194e9500679f 100644 --- a/website/docs/r/postgresql_server.html.markdown +++ b/website/docs/r/postgresql_server.html.markdown @@ -87,7 +87,7 @@ The following arguments are supported: * `storage_mb` - (Optional) Max storage allowed for a server. Possible values are between `5120` MB(5GB) and `1048576` MB(1TB) for the Basic SKU and between `5120` MB(5GB) and `4194304` MB(4TB) for General Purpose/Memory Optimized SKUs. For more information see the [product documentation](https://docs.microsoft.com/en-us/rest/api/postgresql/servers/create#StorageProfile). -* `threat_detection_policy` - (Optional) Threat detection policy configuration. The `threat_detection_policy` block supports fields documented below. +* `threat_detection_policy` - (Optional) Threat detection policy configuration, known in the API as Server Security Alerts Policy. The `threat_detection_policy` block supports fields documented below. * `tags` - (Optional) A mapping of tags to assign to the resource. From 740286b6415ba2b293e22300f257efa0fbac7e33 Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 14 May 2020 12:31:37 -0700 Subject: [PATCH 7/8] make fmt --- .../internal/services/postgres/postgresql_server_resource.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/postgres/postgresql_server_resource.go b/azurerm/internal/services/postgres/postgresql_server_resource.go index 9cfd766d8198..68831a6d08e1 100644 --- a/azurerm/internal/services/postgres/postgresql_server_resource.go +++ b/azurerm/internal/services/postgres/postgresql_server_resource.go @@ -276,7 +276,7 @@ func resourceArmPostgreSQLServer() *schema.Resource { }, true), DiffSuppressFunc: suppress.CaseDifference, }, - + "threat_detection_policy": { Type: schema.TypeList, Optional: true, From 7c45db3b74dfc096145674bc841645c825de9bda Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 14 May 2020 13:02:10 -0700 Subject: [PATCH 8/8] Update postgresql_server.html.markdown --- website/docs/r/postgresql_server.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/postgresql_server.html.markdown b/website/docs/r/postgresql_server.html.markdown index 194e9500679f..25fe6491314c 100644 --- a/website/docs/r/postgresql_server.html.markdown +++ b/website/docs/r/postgresql_server.html.markdown @@ -105,9 +105,9 @@ a `threat_detection_policy` block supports the following: * `retention_days` - (Optional) Specifies the number of days to keep in the Threat Detection audit logs. -* `storage_account_access_key` - (Optional) Specifies the identifier key of the Threat Detection audit storage account. Required if `state` is `Enabled`. +* `storage_account_access_key` - (Optional) Specifies the identifier key of the Threat Detection audit storage account. -* `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`. +* `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. ## Attributes Reference