From 3be186012fc4eaad0bec8e9ed7194aea2d26cbdc Mon Sep 17 00:00:00 2001 From: kt Date: Wed, 10 Oct 2018 18:13:16 -0700 Subject: [PATCH 1/5] new resource secduriyt workspace --- azurerm/config.go | 9 +- azurerm/provider.go | 1 + .../resource_arm_securitycenter_contact.go | 17 +- ...esource_arm_securitycenter_contact_test.go | 34 +++- ...arm_securitycenter_subscription_pricing.go | 3 +- .../resource_arm_securitycenter_workspace.go | 168 ++++++++++++++++++ ...ource_arm_securitycenter_workspace_test.go | 163 +++++++++++++++++ 7 files changed, 374 insertions(+), 21 deletions(-) create mode 100644 azurerm/resource_arm_securitycenter_workspace.go create mode 100644 azurerm/resource_arm_securitycenter_workspace_test.go diff --git a/azurerm/config.go b/azurerm/config.go index 1f905f5ec002..a0e4e355838e 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -254,8 +254,9 @@ type ArmClient struct { searchServicesClient search.ServicesClient // Security Centre - securityCenterPricingClient security.PricingsClient - securityCenterContactsClient security.ContactsClient + securityCenterPricingClient security.PricingsClient + securityCenterContactsClient security.ContactsClient + securityCenterWorkspaceClient security.WorkspaceSettingsClient // ServiceBus serviceBusQueuesClient servicebus.QueuesClient @@ -1030,6 +1031,10 @@ func (c *ArmClient) registerSecurityCenterClients(endpoint, subscriptionId, ascL securityCenterContactsClient := security.NewContactsClientWithBaseURI(endpoint, subscriptionId, ascLocation) c.configureClient(&securityCenterContactsClient.Client, auth) c.securityCenterContactsClient = securityCenterContactsClient + + securityCenterWorkspaceClient := security.NewWorkspaceSettingsClientWithBaseURI(endpoint, subscriptionId, ascLocation) + c.configureClient(&securityCenterWorkspaceClient.Client, auth) + c.securityCenterWorkspaceClient = securityCenterWorkspaceClient } func (c *ArmClient) registerServiceBusClients(endpoint, subscriptionId string, auth autorest.Authorizer) { diff --git a/azurerm/provider.go b/azurerm/provider.go index eb52799831b4..4a76e7e07691 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -245,6 +245,7 @@ func Provider() terraform.ResourceProvider { "azurerm_search_service": resourceArmSearchService(), "azurerm_securitycenter_subscription_pricing": resourceArmSecurityCenterSubscriptionPricing(), "azurerm_securitycenter_contact": resourceArmSecurityCenterContact(), + "azurerm_securitycenter_workspace": resourceArmSecurityCenterWorkspace(), "azurerm_servicebus_namespace": resourceArmServiceBusNamespace(), "azurerm_servicebus_namespace_authorization_rule": resourceArmServiceBusNamespaceAuthorizationRule(), "azurerm_servicebus_queue": resourceArmServiceBusQueue(), diff --git a/azurerm/resource_arm_securitycenter_contact.go b/azurerm/resource_arm_securitycenter_contact.go index 092f7cd13ca7..0a4492a75928 100644 --- a/azurerm/resource_arm_securitycenter_contact.go +++ b/azurerm/resource_arm_securitycenter_contact.go @@ -2,11 +2,9 @@ package azurerm import ( "fmt" - "log" - "strings" - "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/2017-08-01-preview/security" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" + "log" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" @@ -81,8 +79,7 @@ func resourceArmSecurityCenterContactCreateUpdate(d *schema.ResourceData, meta i } if d.IsNewResource() { - _, err := client.Create(ctx, "default1", contact) - if err != nil { + if _, err := client.Create(ctx, "default1", contact); err != nil { return fmt.Errorf("Error creating Security Center Contact: %+v", err) } @@ -96,8 +93,7 @@ func resourceArmSecurityCenterContactCreateUpdate(d *schema.ResourceData, meta i d.SetId(*resp.ID) } else { - _, err := client.Update(ctx, "default1", contact) - if err != nil { + if _, err := client.Update(ctx, "default1", contact); err != nil { return fmt.Errorf("Error updating Security Center Contact: %+v", err) } } @@ -109,12 +105,7 @@ func resourceArmSecurityCenterContactRead(d *schema.ResourceData, meta interface client := meta.(*ArmClient).securityCenterContactsClient ctx := meta.(*ArmClient).StopContext - //id is in format of `/subscriptions/20ff7fc3-e762-44dd-bd96-b71116dcdc23/providers/Microsoft.Security/securityContacts/john` - //parseAzureResourceID doesn't support id without a resource group - bits := strings.Split(d.Id(), "/") - name := bits[len(bits)-1] - - resp, err := client.Get(ctx, name) + resp, err := client.Get(ctx, "default1") if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[DEBUG] Security Center Subscription Contact was not found: %v", err) diff --git a/azurerm/resource_arm_securitycenter_contact_test.go b/azurerm/resource_arm_securitycenter_contact_test.go index cfba6f9eb705..1188dcdd0f65 100644 --- a/azurerm/resource_arm_securitycenter_contact_test.go +++ b/azurerm/resource_arm_securitycenter_contact_test.go @@ -13,8 +13,9 @@ func TestAccAzureRMSecurityCenterContact_basic(t *testing.T) { resourceName := "azurerm_securitycenter_contact.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSecurityCenterContactDestroy, Steps: []resource.TestStep{ { Config: testAccAzureRMSecurityCenterContact_template("email1@example.com", "+1-555-555-5555", true, true), @@ -39,8 +40,9 @@ func TestAccAzureRMSecurityCenterContact_update(t *testing.T) { resourceName := "azurerm_securitycenter_contact.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSecurityCenterContactDestroy, Steps: []resource.TestStep{ { Config: testAccAzureRMSecurityCenterContact_template("email1@example.com", "+1-555-555-5555", true, true), @@ -96,6 +98,30 @@ func testCheckAzureRMSecurityCenterContactExists(name string) resource.TestCheck } } +func testCheckAzureRMSecurityCenterContactDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).securityCenterContactsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, res := range s.RootModule().Resources { + if res.Type != "azurerm_securitycenter_contact" { + continue + } + + resp, err := client.Get(ctx, "default1") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + return fmt.Errorf("security center worspace contact still exists") + } + + return nil +} + func testAccAzureRMSecurityCenterContact_template(email, phone string, notifications, adminAlerts bool) string { return fmt.Sprintf(` resource "azurerm_securitycenter_contact" "test" { diff --git a/azurerm/resource_arm_securitycenter_subscription_pricing.go b/azurerm/resource_arm_securitycenter_subscription_pricing.go index 6899f3787dd6..d200a4ab762a 100644 --- a/azurerm/resource_arm_securitycenter_subscription_pricing.go +++ b/azurerm/resource_arm_securitycenter_subscription_pricing.go @@ -49,8 +49,7 @@ func resourceArmSecurityCenterSubscriptionPricingCreateUpdate(d *schema.Resource }, } - _, err := client.UpdateSubscriptionPricing(ctx, "default", pricing) - if err != nil { + if _, err := client.UpdateSubscriptionPricing(ctx, "default", pricing); err != nil { return fmt.Errorf("Error creating/updating Security Center Subscription pricing: %+v", err) } diff --git a/azurerm/resource_arm_securitycenter_workspace.go b/azurerm/resource_arm_securitycenter_workspace.go new file mode 100644 index 000000000000..bb849d7ba725 --- /dev/null +++ b/azurerm/resource_arm_securitycenter_workspace.go @@ -0,0 +1,168 @@ +package azurerm + +import ( + "fmt" + "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/2017-08-01-preview/security" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "log" + "time" +) + +//only valid name is default +// Message="Invalid workspace settings name 'kttest' , only default is allowed " +func resourceArmSecurityCenterWorkspace() *schema.Resource { + return &schema.Resource{ + Create: resourceArmSecurityCenterWorkspaceCreateUpdate, + Read: resourceArmSecurityCenterWorkspaceRead, + Update: resourceArmSecurityCenterWorkspaceCreateUpdate, + Delete: resourceArmSecurityCenterWorkspaceDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "scope": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: validation.NoZeroValues, + }, + + "workspace_id": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: azure.ValidateResourceID, + }, + }, + } +} + +func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).securityCenterWorkspaceClient + ctx := meta.(*ArmClient).StopContext + + contact := security.WorkspaceSetting{ + WorkspaceSettingProperties: &security.WorkspaceSettingProperties{ + Scope: utils.String(d.Get("scope").(string)), + WorkspaceID: utils.String(d.Get("workspace_id").(string)), + }, + } + + if d.IsNewResource() { + _, err := client.Create(ctx, "default", contact) + if err != nil { + return fmt.Errorf("Error creating Security Center Workspace: %+v", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"Waiting"}, + Target: []string{"Populated"}, + Timeout: 60 * time.Minute, + MinTimeout: 30 * time.Second, + Refresh: func() (interface{}, string, error) { + + resp, err := client.Get(ctx, "default") + if err != nil { + return resp, "Error", fmt.Errorf("Error reading Security Center Workspace: %+v", err) + } + + if properties := resp.WorkspaceSettingProperties; properties != nil { + if properties.WorkspaceID != nil && *properties.WorkspaceID != "" { + return resp, "Populated", nil + } + } + + return resp, "Waiting", nil + }, + } + + resp, err := stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting: %+v", err) + } + + d.SetId(*resp.(security.WorkspaceSetting).ID) + + } else { + _, err := client.Update(ctx, "default", contact) + if err != nil { + return fmt.Errorf("Error updating Security Center Workspace: %+v", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"Waiting"}, + Target: []string{"Populated"}, + Timeout: 60 * time.Minute, + MinTimeout: 30 * time.Second, + Refresh: func() (interface{}, string, error) { + + resp, err := client.Get(ctx, "default") + if err != nil { + return resp, "Error", fmt.Errorf("Error reading Security Center Workspace: %+v", err) + } + + if properties := resp.WorkspaceSettingProperties; properties != nil { + if properties.WorkspaceID != nil && *properties.WorkspaceID != "" { + return resp, "Populated", nil + } + } + + return resp, "Waiting", nil + }, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting: %+v", err) + } + } + + return resourceArmSecurityCenterWorkspaceRead(d, meta) +} + +func resourceArmSecurityCenterWorkspaceRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).securityCenterWorkspaceClient + ctx := meta.(*ArmClient).StopContext + + resp, err := client.Get(ctx, "default") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Security Center Subscription Workspace was not found: %v", err) + d.SetId("") + return nil + } + + return fmt.Errorf("Error reading Security Center Workspace: %+v", err) + } + + if properties := resp.WorkspaceSettingProperties; properties != nil { + d.Set("scope", properties.Scope) + d.Set("workspace_id", properties.WorkspaceID) + } + + return nil +} + +func resourceArmSecurityCenterWorkspaceDelete(_ *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).securityCenterWorkspaceClient + ctx := meta.(*ArmClient).StopContext + + resp, err := client.Delete(ctx, "default") + if err != nil { + if utils.ResponseWasNotFound(resp) { + log.Printf("[DEBUG] Security Center Subscription Workspace was not found: %v", err) + return nil + } + + return fmt.Errorf("Error deleting Security Center Workspace: %+v", err) + } + + return nil +} diff --git a/azurerm/resource_arm_securitycenter_workspace_test.go b/azurerm/resource_arm_securitycenter_workspace_test.go new file mode 100644 index 000000000000..acb5d108f71c --- /dev/null +++ b/azurerm/resource_arm_securitycenter_workspace_test.go @@ -0,0 +1,163 @@ +package azurerm + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/acctest" + "os" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { + resourceName := "azurerm_securitycenter_workspace.test" + ri := acctest.RandInt() + + scope := fmt.Sprintf("/subscriptions/%s", os.Getenv("ARM_SUBSCRIPTION_ID")) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSecurityCenterWorkspaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSecurityCenterWorkspace_basic(ri, testLocation(), scope), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSecurityCenterWorkspaceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "scope", scope), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMSecurityCenterWorkspace_update(t *testing.T) { + resourceName := "azurerm_securitycenter_workspace.test" + ri := acctest.RandInt() + + scope := fmt.Sprintf("/subscriptions/%s", os.Getenv("ARM_SUBSCRIPTION_ID")) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSecurityCenterWorkspace_basic(ri, testLocation(), scope), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSecurityCenterWorkspaceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "scope", scope), + ), + }, + { + Config: testAccAzureRMSecurityCenterWorkspace_differentWorkspace(ri, testLocation(), scope), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSecurityCenterWorkspaceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "scope", scope), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMSecurityCenterWorkspaceExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).securityCenterWorkspaceClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + contactName := rs.Primary.Attributes["workspaceSettings"] + + resp, err := client.Get(ctx, contactName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Security Center Subscription Workspace %q was not found: %+v", contactName, err) + } + + return fmt.Errorf("Bad: GetWorkspace: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMSecurityCenterWorkspaceDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).securityCenterWorkspaceClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, res := range s.RootModule().Resources { + if res.Type != "azurerm_securitycenter_workspace" { + continue + } + + resp, err := client.Get(ctx, "default") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + return fmt.Errorf("security center worspace settings still exists") + } + + return nil +} + +func testAccAzureRMSecurityCenterWorkspace_basic(rInt int, location, scope string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_log_analytics_workspace" "test1" { + name = "acctest-%[1]d-1" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "PerGB2018" +} + +resource "azurerm_securitycenter_workspace" "test" { + scope = "%[3]s" + workspace_id = "${azurerm_log_analytics_workspace.test1.id}" +} +`, rInt, location, scope) +} + +func testAccAzureRMSecurityCenterWorkspace_differentWorkspace(rInt int, location, scope string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_log_analytics_workspace" "test2" { + name = "acctest-%[1]d-2" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "PerGB2018" +} + +resource "azurerm_securitycenter_workspace" "test" { + scope = "%[3]s" + workspace_id = "${azurerm_log_analytics_workspace.test2.id}" +} +`, rInt, location, scope) +} From 0ccb7103a41f57c84da380fbad79513a4fbc5e3f Mon Sep 17 00:00:00 2001 From: kt Date: Fri, 12 Oct 2018 19:41:34 -0700 Subject: [PATCH 2/5] Update resource and add docs --- azurerm/provider.go | 2 +- ...resource_arm_security_center_workspace.go} | 105 +++++++----------- ...rce_arm_security_center_workspace_test.go} | 12 +- website/azurerm.erb | 9 +- .../docs/r/security_center_workspace.markdown | 53 +++++++++ 5 files changed, 107 insertions(+), 74 deletions(-) rename azurerm/{resource_arm_securitycenter_workspace.go => resource_arm_security_center_workspace.go} (58%) rename azurerm/{resource_arm_securitycenter_workspace_test.go => resource_arm_security_center_workspace_test.go} (92%) create mode 100644 website/docs/r/security_center_workspace.markdown diff --git a/azurerm/provider.go b/azurerm/provider.go index c5ad9ffeae35..f90807849760 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -245,7 +245,7 @@ func Provider() terraform.ResourceProvider { "azurerm_search_service": resourceArmSearchService(), "azurerm_security_center_subscription_pricing": resourceArmSecurityCenterSubscriptionPricing(), "azurerm_security_center_contact": resourceArmSecurityCenterContact(), - "azurerm_securitycenter_workspace": resourceArmSecurityCenterWorkspace(), + "azurerm_security_center_workspace": resourceArmSecurityCenterWorkspace(), "azurerm_servicebus_namespace": resourceArmServiceBusNamespace(), "azurerm_servicebus_namespace_authorization_rule": resourceArmServiceBusNamespaceAuthorizationRule(), "azurerm_servicebus_queue": resourceArmServiceBusQueue(), diff --git a/azurerm/resource_arm_securitycenter_workspace.go b/azurerm/resource_arm_security_center_workspace.go similarity index 58% rename from azurerm/resource_arm_securitycenter_workspace.go rename to azurerm/resource_arm_security_center_workspace.go index bb849d7ba725..f9253ec80121 100644 --- a/azurerm/resource_arm_securitycenter_workspace.go +++ b/azurerm/resource_arm_security_center_workspace.go @@ -7,7 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" "log" "time" @@ -15,6 +14,8 @@ import ( //only valid name is default // Message="Invalid workspace settings name 'kttest' , only default is allowed " +const resourceArmSecurityCenterWorkspaceName = "default" + func resourceArmSecurityCenterWorkspace() *schema.Resource { return &schema.Resource{ Create: resourceArmSecurityCenterWorkspaceCreateUpdate, @@ -28,17 +29,15 @@ func resourceArmSecurityCenterWorkspace() *schema.Resource { Schema: map[string]*schema.Schema{ "scope": { - Type: schema.TypeString, - Required: true, - DiffSuppressFunc: suppress.CaseDifference, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, }, "workspace_id": { - Type: schema.TypeString, - Required: true, - DiffSuppressFunc: suppress.CaseDifference, - ValidateFunc: azure.ValidateResourceID, + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, }, }, } @@ -48,6 +47,8 @@ func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta client := meta.(*ArmClient).securityCenterWorkspaceClient ctx := meta.(*ArmClient).StopContext + name := resourceArmSecurityCenterWorkspaceName + contact := security.WorkspaceSetting{ WorkspaceSettingProperties: &security.WorkspaceSettingProperties{ Scope: utils.String(d.Get("scope").(string)), @@ -56,72 +57,46 @@ func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta } if d.IsNewResource() { - _, err := client.Create(ctx, "default", contact) + _, err := client.Create(ctx, name, contact) if err != nil { return fmt.Errorf("Error creating Security Center Workspace: %+v", err) } - - stateConf := &resource.StateChangeConf{ - Pending: []string{"Waiting"}, - Target: []string{"Populated"}, - Timeout: 60 * time.Minute, - MinTimeout: 30 * time.Second, - Refresh: func() (interface{}, string, error) { - - resp, err := client.Get(ctx, "default") - if err != nil { - return resp, "Error", fmt.Errorf("Error reading Security Center Workspace: %+v", err) - } - - if properties := resp.WorkspaceSettingProperties; properties != nil { - if properties.WorkspaceID != nil && *properties.WorkspaceID != "" { - return resp, "Populated", nil - } - } - - return resp, "Waiting", nil - }, - } - - resp, err := stateConf.WaitForState() - if err != nil { - return fmt.Errorf("Error waiting: %+v", err) - } - - d.SetId(*resp.(security.WorkspaceSetting).ID) - } else { - _, err := client.Update(ctx, "default", contact) + _, err := client.Update(ctx, name, contact) if err != nil { return fmt.Errorf("Error updating Security Center Workspace: %+v", err) } + } - stateConf := &resource.StateChangeConf{ - Pending: []string{"Waiting"}, - Target: []string{"Populated"}, - Timeout: 60 * time.Minute, - MinTimeout: 30 * time.Second, - Refresh: func() (interface{}, string, error) { - - resp, err := client.Get(ctx, "default") - if err != nil { - return resp, "Error", fmt.Errorf("Error reading Security Center Workspace: %+v", err) + stateConf := &resource.StateChangeConf{ + Pending: []string{"Waiting"}, + Target: []string{"Populated"}, + Timeout: 60 * time.Minute, + MinTimeout: 30 * time.Second, + Refresh: func() (interface{}, string, error) { + + resp, err := client.Get(ctx, name) + if err != nil { + return resp, "Error", fmt.Errorf("Error reading Security Center Workspace: %+v", err) + } + + if properties := resp.WorkspaceSettingProperties; properties != nil { + if properties.WorkspaceID != nil && *properties.WorkspaceID != "" { + return resp, "Populated", nil } + } - if properties := resp.WorkspaceSettingProperties; properties != nil { - if properties.WorkspaceID != nil && *properties.WorkspaceID != "" { - return resp, "Populated", nil - } - } + return resp, "Waiting", nil + }, + } - return resp, "Waiting", nil - }, - } + resp, err := stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting: %+v", err) + } - _, err = stateConf.WaitForState() - if err != nil { - return fmt.Errorf("Error waiting: %+v", err) - } + if d.IsNewResource() { + d.SetId(*resp.(security.WorkspaceSetting).ID) } return resourceArmSecurityCenterWorkspaceRead(d, meta) @@ -131,7 +106,7 @@ func resourceArmSecurityCenterWorkspaceRead(d *schema.ResourceData, meta interfa client := meta.(*ArmClient).securityCenterWorkspaceClient ctx := meta.(*ArmClient).StopContext - resp, err := client.Get(ctx, "default") + resp, err := client.Get(ctx, resourceArmSecurityCenterWorkspaceName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[DEBUG] Security Center Subscription Workspace was not found: %v", err) @@ -154,7 +129,7 @@ func resourceArmSecurityCenterWorkspaceDelete(_ *schema.ResourceData, meta inter client := meta.(*ArmClient).securityCenterWorkspaceClient ctx := meta.(*ArmClient).StopContext - resp, err := client.Delete(ctx, "default") + resp, err := client.Delete(ctx, resourceArmSecurityCenterWorkspaceName) if err != nil { if utils.ResponseWasNotFound(resp) { log.Printf("[DEBUG] Security Center Subscription Workspace was not found: %v", err) diff --git a/azurerm/resource_arm_securitycenter_workspace_test.go b/azurerm/resource_arm_security_center_workspace_test.go similarity index 92% rename from azurerm/resource_arm_securitycenter_workspace_test.go rename to azurerm/resource_arm_security_center_workspace_test.go index acb5d108f71c..c6eadaa56e27 100644 --- a/azurerm/resource_arm_securitycenter_workspace_test.go +++ b/azurerm/resource_arm_security_center_workspace_test.go @@ -12,7 +12,7 @@ import ( ) func TestAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { - resourceName := "azurerm_securitycenter_workspace.test" + resourceName := "azurerm_security_center_workspace.test" ri := acctest.RandInt() scope := fmt.Sprintf("/subscriptions/%s", os.Getenv("ARM_SUBSCRIPTION_ID")) @@ -39,7 +39,7 @@ func TestAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { } func TestAccAzureRMSecurityCenterWorkspace_update(t *testing.T) { - resourceName := "azurerm_securitycenter_workspace.test" + resourceName := "azurerm_security_center_workspace.test" ri := acctest.RandInt() scope := fmt.Sprintf("/subscriptions/%s", os.Getenv("ARM_SUBSCRIPTION_ID")) @@ -101,11 +101,11 @@ func testCheckAzureRMSecurityCenterWorkspaceDestroy(s *terraform.State) error { ctx := testAccProvider.Meta().(*ArmClient).StopContext for _, res := range s.RootModule().Resources { - if res.Type != "azurerm_securitycenter_workspace" { + if res.Type != "azurerm_security_center_workspace" { continue } - resp, err := client.Get(ctx, "default") + resp, err := client.Get(ctx, resourceArmSecurityCenterWorkspaceName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return nil @@ -134,7 +134,7 @@ resource "azurerm_log_analytics_workspace" "test1" { sku = "PerGB2018" } -resource "azurerm_securitycenter_workspace" "test" { +resource "azurerm_security_center_workspace" "test" { scope = "%[3]s" workspace_id = "${azurerm_log_analytics_workspace.test1.id}" } @@ -155,7 +155,7 @@ resource "azurerm_log_analytics_workspace" "test2" { sku = "PerGB2018" } -resource "azurerm_securitycenter_workspace" "test" { +resource "azurerm_security_center_workspace" "test" { scope = "%[3]s" workspace_id = "${azurerm_log_analytics_workspace.test2.id}" } diff --git a/website/azurerm.erb b/website/azurerm.erb index 174617fa581c..47837f55cf12 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -981,8 +981,13 @@ + diff --git a/website/docs/r/security_center_workspace.markdown b/website/docs/r/security_center_workspace.markdown new file mode 100644 index 000000000000..f5f4c04a6a4c --- /dev/null +++ b/website/docs/r/security_center_workspace.markdown @@ -0,0 +1,53 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_security_center_workspace" +sidebar_current: "docs-azurerm-security-center-workspace" +description: |- + Manages the subscription's Security Center Workspace. +--- + +# azurerm_security_center_workspace + +Manages the subscription's Security Center Workspace. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "tfex-security-workspace" + location = "westus" +} + +resource "azurerm_log_analytics_workspace" "example" { + name = "tfex-security-workspace" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + sku = "PerGB2018" +} + +resource "azurerm_security_center_contact" "example" { + scope = "/subscriptions/00000000-0000-0000-0000-000000000000" + workspace_id = "${azurerm_log_analytics_workspace.example.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `scope` - (Required) The scope of VMs to send their security data to the desired workspace, unless overridden by a setting with more specific scope. +* `workspace_id` - (Required) The resource ID of the log analytics workspace to save the data in. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The Security Center Contact ID. + +## Import + +The contact can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_securitycenter_workspace.example /subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Security/securityWorkspaces/default +``` From 841b37459e42ef299f1334e32f2d227f6ac93cff Mon Sep 17 00:00:00 2001 From: kt Date: Sat, 13 Oct 2018 14:19:58 -0700 Subject: [PATCH 3/5] Address PR #2072 comments --- .../resource_arm_security_center_workspace.go | 26 +++++++++++++++---- ...urce_arm_security_center_workspace_test.go | 2 +- .../docs/r/security_center_contact.markdown | 4 +++ .../docs/r/security_center_workspace.markdown | 4 ++- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/azurerm/resource_arm_security_center_workspace.go b/azurerm/resource_arm_security_center_workspace.go index f9253ec80121..a5d5acd600f4 100644 --- a/azurerm/resource_arm_security_center_workspace.go +++ b/azurerm/resource_arm_security_center_workspace.go @@ -14,7 +14,7 @@ import ( //only valid name is default // Message="Invalid workspace settings name 'kttest' , only default is allowed " -const resourceArmSecurityCenterWorkspaceName = "default" +const securityCenterWorkspaceName = "default" func resourceArmSecurityCenterWorkspace() *schema.Resource { return &schema.Resource{ @@ -47,7 +47,23 @@ func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta client := meta.(*ArmClient).securityCenterWorkspaceClient ctx := meta.(*ArmClient).StopContext - name := resourceArmSecurityCenterWorkspaceName + priceClient := meta.(*ArmClient).securityCenterPricingClient + + //get pricing tier, workspace can only be configured when tier is not Free. + //API does not error, it just doesn't set the workspace scope + price, err := priceClient.GetSubscriptionPricing(ctx, securityCenterConfigurationSubscriptionPricingName) + if err != nil { + return fmt.Errorf("Error reading Security Center Subscription pricing: %+v", err) + } + + if price.PricingProperties == nil { + return fmt.Errorf("Security Center Subscription pricing propertier is nil") + } + if price.PricingProperties.PricingTier == security.Free { + return fmt.Errorf("Security Center Subscription workspace cannot be set when pricing tier is `Free`") + } + + name := securityCenterWorkspaceName contact := security.WorkspaceSetting{ WorkspaceSettingProperties: &security.WorkspaceSettingProperties{ @@ -71,7 +87,7 @@ func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta stateConf := &resource.StateChangeConf{ Pending: []string{"Waiting"}, Target: []string{"Populated"}, - Timeout: 60 * time.Minute, + Timeout: 15 * time.Minute, MinTimeout: 30 * time.Second, Refresh: func() (interface{}, string, error) { @@ -106,7 +122,7 @@ func resourceArmSecurityCenterWorkspaceRead(d *schema.ResourceData, meta interfa client := meta.(*ArmClient).securityCenterWorkspaceClient ctx := meta.(*ArmClient).StopContext - resp, err := client.Get(ctx, resourceArmSecurityCenterWorkspaceName) + resp, err := client.Get(ctx, securityCenterWorkspaceName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[DEBUG] Security Center Subscription Workspace was not found: %v", err) @@ -129,7 +145,7 @@ func resourceArmSecurityCenterWorkspaceDelete(_ *schema.ResourceData, meta inter client := meta.(*ArmClient).securityCenterWorkspaceClient ctx := meta.(*ArmClient).StopContext - resp, err := client.Delete(ctx, resourceArmSecurityCenterWorkspaceName) + resp, err := client.Delete(ctx, securityCenterWorkspaceName) if err != nil { if utils.ResponseWasNotFound(resp) { log.Printf("[DEBUG] Security Center Subscription Workspace was not found: %v", err) diff --git a/azurerm/resource_arm_security_center_workspace_test.go b/azurerm/resource_arm_security_center_workspace_test.go index c6eadaa56e27..9498c1efeb26 100644 --- a/azurerm/resource_arm_security_center_workspace_test.go +++ b/azurerm/resource_arm_security_center_workspace_test.go @@ -105,7 +105,7 @@ func testCheckAzureRMSecurityCenterWorkspaceDestroy(s *terraform.State) error { continue } - resp, err := client.Get(ctx, resourceArmSecurityCenterWorkspaceName) + resp, err := client.Get(ctx, securityCenterWorkspaceName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return nil diff --git a/website/docs/r/security_center_contact.markdown b/website/docs/r/security_center_contact.markdown index a7a3c081831a..fb9b07e942db 100644 --- a/website/docs/r/security_center_contact.markdown +++ b/website/docs/r/security_center_contact.markdown @@ -10,6 +10,10 @@ description: |- Manages the subscription's Security Center Contact. +~> **NOTE:** Owner access permission is required. + +~> **NOTE:** The subscription's pricing model can not be `Free` for this to have any affect and it may take up to 15-30 minutes after switching pricing tiers for it to work. + ## Example Usage ```hcl diff --git a/website/docs/r/security_center_workspace.markdown b/website/docs/r/security_center_workspace.markdown index f5f4c04a6a4c..854b1dc13ebc 100644 --- a/website/docs/r/security_center_workspace.markdown +++ b/website/docs/r/security_center_workspace.markdown @@ -10,6 +10,8 @@ description: |- Manages the subscription's Security Center Workspace. + + ## Example Usage ```hcl @@ -49,5 +51,5 @@ The following attributes are exported: The contact can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_securitycenter_workspace.example /subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Security/securityWorkspaces/default +terraform import azurerm_security_center_workspace.example /subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Security/workspaceSettings/default ``` From e592b322bd00daddc65f73bc6a68529cf3797ab2 Mon Sep 17 00:00:00 2001 From: kt Date: Sat, 13 Oct 2018 19:31:28 -0700 Subject: [PATCH 4/5] go fmt --- azurerm/provider.go | 2 +- azurerm/resource_arm_security_center_workspace.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index 94a9d5434b19..08cf4b539ec0 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -248,6 +248,7 @@ func Provider() terraform.ResourceProvider { "azurerm_search_service": resourceArmSearchService(), "azurerm_security_center_subscription_pricing": resourceArmSecurityCenterSubscriptionPricing(), "azurerm_security_center_contact": resourceArmSecurityCenterContact(), + "azurerm_security_center_workspace": resourceArmSecurityCenterWorkspace(), "azurerm_servicebus_namespace": resourceArmServiceBusNamespace(), "azurerm_servicebus_namespace_authorization_rule": resourceArmServiceBusNamespaceAuthorizationRule(), "azurerm_servicebus_queue": resourceArmServiceBusQueue(), @@ -290,7 +291,6 @@ func Provider() terraform.ResourceProvider { "azurerm_virtual_network_gateway": resourceArmVirtualNetworkGateway(), "azurerm_virtual_network_gateway_connection": resourceArmVirtualNetworkGatewayConnection(), "azurerm_virtual_network_peering": resourceArmVirtualNetworkPeering(), - "azurerm_security_center_workspace": resourceArmSecurityCenterWorkspace(), }, } diff --git a/azurerm/resource_arm_security_center_workspace.go b/azurerm/resource_arm_security_center_workspace.go index a5d5acd600f4..2e605c1b72d4 100644 --- a/azurerm/resource_arm_security_center_workspace.go +++ b/azurerm/resource_arm_security_center_workspace.go @@ -51,7 +51,7 @@ func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta //get pricing tier, workspace can only be configured when tier is not Free. //API does not error, it just doesn't set the workspace scope - price, err := priceClient.GetSubscriptionPricing(ctx, securityCenterConfigurationSubscriptionPricingName) + price, err := priceClient.GetSubscriptionPricing(ctx, securityCenterSubscriptionPricingName) if err != nil { return fmt.Errorf("Error reading Security Center Subscription pricing: %+v", err) } From 8d17f21c780e3c7162cf60595e43f9a12127d4c1 Mon Sep 17 00:00:00 2001 From: kt Date: Sat, 13 Oct 2018 20:25:03 -0700 Subject: [PATCH 5/5] combined security center pricing and workspace tests to prevent conflicts --- .../resource_arm_security_center_contact.go | 3 +- ...curity_center_subscription_pricing_test.go | 2 +- azurerm/resource_arm_security_center_test.go | 31 +++++++++++++++++ .../resource_arm_security_center_workspace.go | 6 ++-- ...urce_arm_security_center_workspace_test.go | 33 ++++++++++++++----- .../docs/r/security_center_contact.markdown | 4 +-- .../docs/r/security_center_workspace.markdown | 2 ++ 7 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 azurerm/resource_arm_security_center_test.go diff --git a/azurerm/resource_arm_security_center_contact.go b/azurerm/resource_arm_security_center_contact.go index 6d1d24529d01..027b9f37d691 100644 --- a/azurerm/resource_arm_security_center_contact.go +++ b/azurerm/resource_arm_security_center_contact.go @@ -2,11 +2,12 @@ package azurerm import ( "fmt" + "log" + "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/2017-08-01-preview/security" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - "log" ) //seems you can only set one contact: diff --git a/azurerm/resource_arm_security_center_subscription_pricing_test.go b/azurerm/resource_arm_security_center_subscription_pricing_test.go index cc3504667fd3..6629cdcafa44 100644 --- a/azurerm/resource_arm_security_center_subscription_pricing_test.go +++ b/azurerm/resource_arm_security_center_subscription_pricing_test.go @@ -9,7 +9,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMSecurityCenterSubscriptionPricing_update(t *testing.T) { +func testAccAzureRMSecurityCenterSubscriptionPricing_update(t *testing.T) { resourceName := "azurerm_security_center_subscription_pricing.test" resource.Test(t, resource.TestCase{ diff --git a/azurerm/resource_arm_security_center_test.go b/azurerm/resource_arm_security_center_test.go new file mode 100644 index 000000000000..4a3ed04a4b07 --- /dev/null +++ b/azurerm/resource_arm_security_center_test.go @@ -0,0 +1,31 @@ +package azurerm + +import ( + "testing" +) + +func TestAccAzureRMSecurityCenter_pricingAndWorkspace(t *testing.T) { + // NOTE: this is a combined test rather than separate split out tests + // due to the workspace tests depending on the current pricing tier + testCases := map[string]map[string]func(t *testing.T){ + "pricing": { + "update": testAccAzureRMSecurityCenterSubscriptionPricing_update, + }, + "workspace": { + "basic": testAccAzureRMSecurityCenterWorkspace_basic, + "update": testAccAzureRMSecurityCenterWorkspace_update, + }, + } + + for group, m := range testCases { + m := m + t.Run(group, func(t *testing.T) { + for name, tc := range m { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } + }) + } +} diff --git a/azurerm/resource_arm_security_center_workspace.go b/azurerm/resource_arm_security_center_workspace.go index 2e605c1b72d4..670deda4657d 100644 --- a/azurerm/resource_arm_security_center_workspace.go +++ b/azurerm/resource_arm_security_center_workspace.go @@ -2,14 +2,15 @@ package azurerm import ( "fmt" + "log" + "time" + "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/2017-08-01-preview/security" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - "log" - "time" ) //only valid name is default @@ -84,6 +85,7 @@ func resourceArmSecurityCenterWorkspaceCreateUpdate(d *schema.ResourceData, meta } } + //api returns "" for workspace id after an create/update and eventually the new value stateConf := &resource.StateChangeConf{ Pending: []string{"Waiting"}, Target: []string{"Populated"}, diff --git a/azurerm/resource_arm_security_center_workspace_test.go b/azurerm/resource_arm_security_center_workspace_test.go index 9498c1efeb26..01497ab5f9d3 100644 --- a/azurerm/resource_arm_security_center_workspace_test.go +++ b/azurerm/resource_arm_security_center_workspace_test.go @@ -2,16 +2,16 @@ package azurerm import ( "fmt" - "github.com/hashicorp/terraform/helper/acctest" "os" "testing" + "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { +func testAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { resourceName := "azurerm_security_center_workspace.test" ri := acctest.RandInt() @@ -23,7 +23,7 @@ func TestAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { CheckDestroy: testCheckAzureRMSecurityCenterWorkspaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMSecurityCenterWorkspace_basic(ri, testLocation(), scope), + Config: testAccAzureRMSecurityCenterWorkspace_basicCfg(ri, testLocation(), scope), Check: resource.ComposeTestCheckFunc( testCheckAzureRMSecurityCenterWorkspaceExists(resourceName), resource.TestCheckResourceAttr(resourceName, "scope", scope), @@ -34,11 +34,15 @@ func TestAccAzureRMSecurityCenterWorkspace_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + //reset pricing to free + Config: testAccAzureRMSecurityCenterSubscriptionPricing_tier("Free"), + }, }, }) } -func TestAccAzureRMSecurityCenterWorkspace_update(t *testing.T) { +func testAccAzureRMSecurityCenterWorkspace_update(t *testing.T) { resourceName := "azurerm_security_center_workspace.test" ri := acctest.RandInt() @@ -49,14 +53,14 @@ func TestAccAzureRMSecurityCenterWorkspace_update(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAzureRMSecurityCenterWorkspace_basic(ri, testLocation(), scope), + Config: testAccAzureRMSecurityCenterWorkspace_basicCfg(ri, testLocation(), scope), Check: resource.ComposeTestCheckFunc( testCheckAzureRMSecurityCenterWorkspaceExists(resourceName), resource.TestCheckResourceAttr(resourceName, "scope", scope), ), }, { - Config: testAccAzureRMSecurityCenterWorkspace_differentWorkspace(ri, testLocation(), scope), + Config: testAccAzureRMSecurityCenterWorkspace_differentWorkspaceCfg(ri, testLocation(), scope), Check: resource.ComposeTestCheckFunc( testCheckAzureRMSecurityCenterWorkspaceExists(resourceName), resource.TestCheckResourceAttr(resourceName, "scope", scope), @@ -67,6 +71,10 @@ func TestAccAzureRMSecurityCenterWorkspace_update(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + //reset pricing to free + Config: testAccAzureRMSecurityCenterSubscriptionPricing_tier("Free"), + }, }, }) } @@ -120,8 +128,13 @@ func testCheckAzureRMSecurityCenterWorkspaceDestroy(s *terraform.State) error { return nil } -func testAccAzureRMSecurityCenterWorkspace_basic(rInt int, location, scope string) string { +func testAccAzureRMSecurityCenterWorkspace_basicCfg(rInt int, location, scope string) string { return fmt.Sprintf(` + +resource "azurerm_security_center_subscription_pricing" "test" { + tier = "Standard" +} + resource "azurerm_resource_group" "test" { name = "acctestRG-%[1]d" location = "%[2]s" @@ -141,8 +154,12 @@ resource "azurerm_security_center_workspace" "test" { `, rInt, location, scope) } -func testAccAzureRMSecurityCenterWorkspace_differentWorkspace(rInt int, location, scope string) string { +func testAccAzureRMSecurityCenterWorkspace_differentWorkspaceCfg(rInt int, location, scope string) string { return fmt.Sprintf(` +resource "azurerm_security_center_subscription_pricing" "test" { + tier = "Standard" +} + resource "azurerm_resource_group" "test" { name = "acctestRG-%[1]d" location = "%[2]s" diff --git a/website/docs/r/security_center_contact.markdown b/website/docs/r/security_center_contact.markdown index 73f77972c27b..52a5fdcc0d99 100644 --- a/website/docs/r/security_center_contact.markdown +++ b/website/docs/r/security_center_contact.markdown @@ -10,9 +10,7 @@ description: |- Manages the subscription's Security Center Contact. -~> **NOTE:** Owner access permission is required. - -~> **NOTE:** The subscription's pricing model can not be `Free` for this to have any affect and it may take up to 15-30 minutes after switching pricing tiers for it to work. +~> **NOTE:** Owner access permission is required. ## Example Usage diff --git a/website/docs/r/security_center_workspace.markdown b/website/docs/r/security_center_workspace.markdown index 854b1dc13ebc..6ed8aaaea36e 100644 --- a/website/docs/r/security_center_workspace.markdown +++ b/website/docs/r/security_center_workspace.markdown @@ -10,7 +10,9 @@ description: |- Manages the subscription's Security Center Workspace. +~> **NOTE:** Owner access permission is required. +~> **NOTE:** The subscription's pricing model can not be `Free` for this to have any affect. ## Example Usage