From 5653b2a183c604f56d61336369b60e3891afde8f Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 19 Oct 2022 14:15:05 +0800 Subject: [PATCH 1/2] New resource: `azurerm_sentinel_data_connector_office_irm` --- internal/services/sentinel/registration.go | 1 + .../sentinel/sentinel_data_connector.go | 2 + .../sentinel_data_connector_office_irm.go | 194 ++++++++++++++++++ ...sentinel_data_connector_office_irm_test.go | 153 ++++++++++++++ ...el_data_connector_office_irm.html.markdown | 81 ++++++++ 5 files changed, 431 insertions(+) create mode 100644 internal/services/sentinel/sentinel_data_connector_office_irm.go create mode 100644 internal/services/sentinel/sentinel_data_connector_office_irm_test.go create mode 100644 website/docs/r/sentinel_data_connector_office_irm.html.markdown diff --git a/internal/services/sentinel/registration.go b/internal/services/sentinel/registration.go index 4c98e3d6e6cf..c5f65850b10f 100644 --- a/internal/services/sentinel/registration.go +++ b/internal/services/sentinel/registration.go @@ -63,5 +63,6 @@ func (r Registration) Resources() []sdk.Resource { WatchlistResource{}, WatchlistItemResource{}, DataConnectorAwsS3Resource{}, + DataConnectorOfficeIRMResource{}, } } diff --git a/internal/services/sentinel/sentinel_data_connector.go b/internal/services/sentinel/sentinel_data_connector.go index ee7070d14bcf..6ee4b238e245 100644 --- a/internal/services/sentinel/sentinel_data_connector.go +++ b/internal/services/sentinel/sentinel_data_connector.go @@ -43,6 +43,8 @@ func assertDataConnectorKind(dc securityinsight.BasicDataConnector, expectKind s kind = securityinsight.DataConnectorKindMicrosoftCloudAppSecurity case securityinsight.TIDataConnector: kind = securityinsight.DataConnectorKindThreatIntelligence + case securityinsight.OfficeIRMDataConnector: + kind = securityinsight.DataConnectorKindOfficeIRM case securityinsight.OfficeDataConnector: kind = securityinsight.DataConnectorKindOffice365 case securityinsight.OfficeATPDataConnector: diff --git a/internal/services/sentinel/sentinel_data_connector_office_irm.go b/internal/services/sentinel/sentinel_data_connector_office_irm.go new file mode 100644 index 000000000000..409e0c2ff4b2 --- /dev/null +++ b/internal/services/sentinel/sentinel_data_connector_office_irm.go @@ -0,0 +1,194 @@ +package sentinel + +import ( + "context" + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/securityinsight/mgmt/2022-01-01-preview/securityinsight" + "github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2020-08-01/workspaces" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DataConnectorOfficeIRMResource struct{} + +var _ sdk.ResourceWithCustomImporter = DataConnectorOfficeIRMResource{} + +type DataConnectorOfficeIRMModel struct { + Name string `tfschema:"name"` + LogAnalyticsWorkspaceId string `tfschema:"log_analytics_workspace_id"` + TenantId string `tfschema:"tenant_id"` +} + +func (r DataConnectorOfficeIRMResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "log_analytics_workspace_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: workspaces.ValidateWorkspaceID, + }, + + "tenant_id": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.IsUUID, + }, + } +} + +func (r DataConnectorOfficeIRMResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r DataConnectorOfficeIRMResource) ResourceType() string { + return "azurerm_sentinel_data_connector_office_irm" +} + +func (r DataConnectorOfficeIRMResource) ModelObject() interface{} { + return &DataConnectorOfficeIRMModel{} +} + +func (r DataConnectorOfficeIRMResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return validate.DataConnectorID +} + +func (r DataConnectorOfficeIRMResource) CustomImporter() sdk.ResourceRunFunc { + return func(ctx context.Context, metadata sdk.ResourceMetaData) error { + _, err := importSentinelDataConnector(securityinsight.DataConnectorKindOfficeIRM)(ctx, metadata.ResourceData, metadata.Client) + return err + } +} + +func (r DataConnectorOfficeIRMResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Sentinel.DataConnectorsClient + + var plan DataConnectorOfficeIRMModel + if err := metadata.Decode(&plan); err != nil { + return fmt.Errorf("decoding %+v", err) + } + + workspaceId, err := workspaces.ParseWorkspaceID(plan.LogAnalyticsWorkspaceId) + if err != nil { + return err + } + + id := parse.NewDataConnectorID(workspaceId.SubscriptionId, workspaceId.ResourceGroupName, workspaceId.WorkspaceName, plan.Name) + existing, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + tenantId := plan.TenantId + if tenantId == "" { + tenantId = metadata.Client.Account.TenantId + } + + params := securityinsight.OfficeIRMDataConnector{ + Name: &plan.Name, + OfficeIRMDataConnectorProperties: &securityinsight.OfficeIRMDataConnectorProperties{ + TenantID: &tenantId, + DataTypes: &securityinsight.AlertsDataTypeOfDataConnector{ + Alerts: &securityinsight.DataConnectorDataTypeCommon{ + State: securityinsight.DataTypeStateEnabled, + }, + }, + }, + Kind: securityinsight.KindBasicDataConnectorKindOfficeIRM, + } + + if _, err = client.CreateOrUpdate(ctx, id.ResourceGroup, id.WorkspaceName, id.Name, params); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r DataConnectorOfficeIRMResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Sentinel.DataConnectorsClient + id, err := parse.DataConnectorID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + workspaceId := workspaces.NewWorkspaceID(id.SubscriptionId, id.ResourceGroup, id.WorkspaceName) + + existing, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + dc, ok := existing.Value.(securityinsight.OfficeIRMDataConnector) + if !ok { + return fmt.Errorf("%s was not an Office IRM Data Connector", id) + } + + var tenantId string + if props := dc.OfficeIRMDataConnectorProperties; props != nil { + if props.TenantID != nil { + tenantId = *props.TenantID + } + } + + model := DataConnectorOfficeIRMModel{ + Name: id.Name, + LogAnalyticsWorkspaceId: workspaceId.ID(), + TenantId: tenantId, + } + + return metadata.Encode(&model) + }, + } +} + +func (r DataConnectorOfficeIRMResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Sentinel.DataConnectorsClient + + id, err := parse.DataConnectorID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, id.ResourceGroup, id.WorkspaceName, id.Name); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} diff --git a/internal/services/sentinel/sentinel_data_connector_office_irm_test.go b/internal/services/sentinel/sentinel_data_connector_office_irm_test.go new file mode 100644 index 000000000000..ae0d791ceeb0 --- /dev/null +++ b/internal/services/sentinel/sentinel_data_connector_office_irm_test.go @@ -0,0 +1,153 @@ +package sentinel_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type SentinelDataConnectorOfficeIRMResource struct{} + +func TestAccSentinelDataConnectorOfficeIRM_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sentinel_data_connector_office_irm", "test") + r := SentinelDataConnectorOfficeIRMResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSentinelDataConnectorOfficeIRM_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sentinel_data_connector_office_irm", "test") + r := SentinelDataConnectorOfficeIRMResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSentinelDataConnectorOfficeIRM_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sentinel_data_connector_office_irm", "test") + r := SentinelDataConnectorOfficeIRMResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (r SentinelDataConnectorOfficeIRMResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + client := clients.Sentinel.DataConnectorsClient + + id, err := parse.DataConnectorID(state.ID) + if err != nil { + return nil, err + } + + if resp, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.Name); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + + return utils.Bool(true), nil +} + +func (r SentinelDataConnectorOfficeIRMResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_sentinel_data_connector_office_irm" "test" { + name = "accTestDC-%d" + log_analytics_workspace_id = azurerm_log_analytics_workspace.test.id + depends_on = [azurerm_log_analytics_solution.test] +} +`, template, data.RandomInteger) +} + +func (r SentinelDataConnectorOfficeIRMResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +data "azurerm_client_config" "test" {} + +resource "azurerm_sentinel_data_connector_office_irm" "test" { + name = "accTestDC-%d" + log_analytics_workspace_id = azurerm_log_analytics_workspace.test.id + tenant_id = data.azurerm_client_config.test.tenant_id + depends_on = [azurerm_log_analytics_solution.test] +} +`, template, data.RandomInteger) +} + +func (r SentinelDataConnectorOfficeIRMResource) requiresImport(data acceptance.TestData) string { + template := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_sentinel_data_connector_office_irm" "import" { + name = azurerm_sentinel_data_connector_office_irm.test.name + log_analytics_workspace_id = azurerm_sentinel_data_connector_office_irm.test.log_analytics_workspace_id +} +`, template) +} + +func (r SentinelDataConnectorOfficeIRMResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-sentinel-%d" + location = "%s" +} + +resource "azurerm_log_analytics_workspace" "test" { + name = "acctestLAW-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "PerGB2018" +} + +resource "azurerm_log_analytics_solution" "test" { + solution_name = "SecurityInsights" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + workspace_resource_id = azurerm_log_analytics_workspace.test.id + workspace_name = azurerm_log_analytics_workspace.test.name + + plan { + publisher = "Microsoft" + product = "OMSGallery/SecurityInsights" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/website/docs/r/sentinel_data_connector_office_irm.html.markdown b/website/docs/r/sentinel_data_connector_office_irm.html.markdown new file mode 100644 index 000000000000..dabb2c268f89 --- /dev/null +++ b/website/docs/r/sentinel_data_connector_office_irm.html.markdown @@ -0,0 +1,81 @@ +--- +subcategory: "Sentinel" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_sentinel_data_connector_office_irm" +description: |- + Manages a Office IRM Data Connector. +--- + +# azurerm_sentinel_data_connector_office_irm + +Manages a Office IRM Data Connector. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-rg" + location = "West Europe" +} + +resource "azurerm_log_analytics_workspace" "example" { + name = "example-workspace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "PerGB2018" +} + +resource "azurerm_log_analytics_solution" "example" { + solution_name = "SecurityInsights" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + workspace_resource_id = azurerm_log_analytics_workspace.example.id + workspace_name = azurerm_log_analytics_workspace.example.name + + plan { + publisher = "Microsoft" + product = "OMSGallery/SecurityInsights" + } +} + +resource "azurerm_sentinel_data_connector_office_irm" "example" { + name = "example" + log_analytics_workspace_id = azurerm_log_analytics_solution.example.workspace_resource_id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `log_analytics_workspace_id` - (Required) The ID of the Log Analytics Workspace that this Office IRM Data Connector resides in. Changing this forces a new Office IRM Data Connector to be created. + +* `name` - (Required) The name which should be used for this Office IRM Data Connector. Changing this forces a new Office IRM Data Connector to be created. + +--- + +* `tenant_id` - (Optional) The ID of the tenant that this Office IRM Data Connector connects to. Changing this forces a new Office IRM Data Connector to be created. + +-> **NOTE** Currently, only the same tenant as the running account is allowed. Cross-tenant scenario is not supported yet. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Office IRM Data Connector. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Office IRM Data Connector. +* `read` - (Defaults to 5 minutes) Used when retrieving the Office IRM Data Connector. +* `delete` - (Defaults to 30 minutes) Used when deleting the Office IRM Data Connector. + +## Import + +Office IRM Data Connectors can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_sentinel_data_connector_office_irm.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/dataConnectors/dc1 +``` From 0d99e9f77946726a78222aadc4591a064245ded2 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 19 Oct 2022 15:33:14 +0800 Subject: [PATCH 2/2] grammer --- .../docs/r/sentinel_data_connector_office_irm.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/sentinel_data_connector_office_irm.html.markdown b/website/docs/r/sentinel_data_connector_office_irm.html.markdown index dabb2c268f89..3113da2a4d5e 100644 --- a/website/docs/r/sentinel_data_connector_office_irm.html.markdown +++ b/website/docs/r/sentinel_data_connector_office_irm.html.markdown @@ -3,12 +3,12 @@ subcategory: "Sentinel" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_sentinel_data_connector_office_irm" description: |- - Manages a Office IRM Data Connector. + Manages an Office IRM Data Connector. --- # azurerm_sentinel_data_connector_office_irm -Manages a Office IRM Data Connector. +Manages an Office IRM Data Connector. ## Example Usage