diff --git a/azurerm/internal/services/sentinel/registration.go b/azurerm/internal/services/sentinel/registration.go index 33a54ae3b1ca..960eaf8e4085 100644 --- a/azurerm/internal/services/sentinel/registration.go +++ b/azurerm/internal/services/sentinel/registration.go @@ -29,8 +29,9 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_sentinel_alert_rule_fusion": resourceSentinelAlertRuleFusion(), - "azurerm_sentinel_alert_rule_ms_security_incident": resourceSentinelAlertRuleMsSecurityIncident(), - "azurerm_sentinel_alert_rule_scheduled": resourceSentinelAlertRuleScheduled(), + "azurerm_sentinel_alert_rule_fusion": resourceSentinelAlertRuleFusion(), + "azurerm_sentinel_alert_rule_ms_security_incident": resourceSentinelAlertRuleMsSecurityIncident(), + "azurerm_sentinel_alert_rule_scheduled": resourceSentinelAlertRuleScheduled(), + "azurerm_sentinel_data_connector_threat_intelligence": resourceSentinelDataConnectorThreatIntelligence(), } } diff --git a/azurerm/internal/services/sentinel/sentinel.go b/azurerm/internal/services/sentinel/sentinel.go index 4632a5226017..944cb25dbecf 100644 --- a/azurerm/internal/services/sentinel/sentinel.go +++ b/azurerm/internal/services/sentinel/sentinel.go @@ -1,3 +1,3 @@ package sentinel -const operationalInsightsResourceProvider = "Microsoft.OperationalInsights" +const OperationalInsightsResourceProvider = "Microsoft.OperationalInsights" diff --git a/azurerm/internal/services/sentinel/sentinel_alert_rule.go b/azurerm/internal/services/sentinel/sentinel_alert_rule.go index 011d3a2f32d6..0e8da8b6ebb0 100644 --- a/azurerm/internal/services/sentinel/sentinel_alert_rule.go +++ b/azurerm/internal/services/sentinel/sentinel_alert_rule.go @@ -37,7 +37,7 @@ func importSentinelAlertRule(expectKind securityinsight.AlertRuleKind) func(d *s ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - resp, err := client.Get(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name) + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name) if err != nil { return nil, fmt.Errorf("retrieving Sentinel Alert Rule %q: %+v", id, err) } diff --git a/azurerm/internal/services/sentinel/sentinel_alert_rule_data_source.go b/azurerm/internal/services/sentinel/sentinel_alert_rule_data_source.go index f9ec71ff1f05..e5a704f8b912 100644 --- a/azurerm/internal/services/sentinel/sentinel_alert_rule_data_source.go +++ b/azurerm/internal/services/sentinel/sentinel_alert_rule_data_source.go @@ -51,7 +51,7 @@ func dataSourceSentinelAlertRuleRead(d *schema.ResourceData, meta interface{}) e } id := parse.NewAlertRuleID(workspaceID.SubscriptionId, workspaceID.ResourceGroup, workspaceID.WorkspaceName, name) - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return fmt.Errorf("Sentinel Alert Rule %q was not found", id) diff --git a/azurerm/internal/services/sentinel/sentinel_alert_rule_fusion_resource.go b/azurerm/internal/services/sentinel/sentinel_alert_rule_fusion_resource.go index c7a065e5946e..a85f961264da 100644 --- a/azurerm/internal/services/sentinel/sentinel_alert_rule_fusion_resource.go +++ b/azurerm/internal/services/sentinel/sentinel_alert_rule_fusion_resource.go @@ -82,7 +82,7 @@ func resourceSentinelAlertRuleFusionCreateUpdate(d *schema.ResourceData, meta in id := parse.NewAlertRuleID(workspaceID.SubscriptionId, workspaceID.ResourceGroup, workspaceID.WorkspaceName, name) if d.IsNewResource() { - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { if !utils.ResponseWasNotFound(resp.Response) { return fmt.Errorf("checking for existing Sentinel Alert Rule Fusion %q: %+v", id, err) @@ -105,7 +105,7 @@ func resourceSentinelAlertRuleFusionCreateUpdate(d *schema.ResourceData, meta in // Service avoid concurrent update of this resource via checking the "etag" to guarantee it is the same value as last Read. if !d.IsNewResource() { - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { return fmt.Errorf("retrieving Sentinel Alert Rule Fusion %q: %+v", id, err) } @@ -116,7 +116,7 @@ func resourceSentinelAlertRuleFusionCreateUpdate(d *schema.ResourceData, meta in params.Etag = resp.Value.(securityinsight.FusionAlertRule).Etag } - if _, err := client.CreateOrUpdate(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name, params); err != nil { + if _, err := client.CreateOrUpdate(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name, params); err != nil { return fmt.Errorf("creating Sentinel Alert Rule Fusion %q: %+v", id, err) } @@ -135,7 +135,7 @@ func resourceSentinelAlertRuleFusionRead(d *schema.ResourceData, meta interface{ return err } - resp, err := client.Get(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name) + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[DEBUG] Sentinel Alert Rule Fusion %q was not found - removing from state!", id) @@ -174,7 +174,7 @@ func resourceSentinelAlertRuleFusionDelete(d *schema.ResourceData, meta interfac return err } - if _, err := client.Delete(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { + if _, err := client.Delete(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { return fmt.Errorf("deleting Sentinel Alert Rule Fusion %q: %+v", id, err) } diff --git a/azurerm/internal/services/sentinel/sentinel_alert_rule_ms_security_incident_resource.go b/azurerm/internal/services/sentinel/sentinel_alert_rule_ms_security_incident_resource.go index 37a4927a8b78..a298e5c84d89 100644 --- a/azurerm/internal/services/sentinel/sentinel_alert_rule_ms_security_incident_resource.go +++ b/azurerm/internal/services/sentinel/sentinel_alert_rule_ms_security_incident_resource.go @@ -155,7 +155,7 @@ func resourceSentinelAlertRuleMsSecurityIncidentCreateUpdate(d *schema.ResourceD id := parse.NewAlertRuleID(workspaceID.SubscriptionId, workspaceID.ResourceGroup, workspaceID.WorkspaceName, name) if d.IsNewResource() { - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { if !utils.ResponseWasNotFound(resp.Response) { return fmt.Errorf("checking for existing Sentinel Alert Rule Ms Security Incident %q: %+v", id, err) @@ -195,7 +195,7 @@ func resourceSentinelAlertRuleMsSecurityIncidentCreateUpdate(d *schema.ResourceD // Service avoid concurrent update of this resource via checking the "etag" to guarantee it is the same value as last Read. if !d.IsNewResource() { - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { return fmt.Errorf("retrieving Sentinel Alert Rule Ms Security Incident %q: %+v", id, err) } @@ -206,7 +206,7 @@ func resourceSentinelAlertRuleMsSecurityIncidentCreateUpdate(d *schema.ResourceD param.Etag = resp.Value.(securityinsight.MicrosoftSecurityIncidentCreationAlertRule).Etag } - if _, err := client.CreateOrUpdate(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name, param); err != nil { + if _, err := client.CreateOrUpdate(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name, param); err != nil { return fmt.Errorf("creating Sentinel Alert Rule Ms Security Incident %q: %+v", id, err) } @@ -225,7 +225,7 @@ func resourceSentinelAlertRuleMsSecurityIncidentRead(d *schema.ResourceData, met return err } - resp, err := client.Get(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name) + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[DEBUG] Sentinel Alert Rule Ms Security Incident %q was not found - removing from state!", id) @@ -279,7 +279,7 @@ func resourceSentinelAlertRuleMsSecurityIncidentDelete(d *schema.ResourceData, m return err } - if _, err := client.Delete(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { + if _, err := client.Delete(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { return fmt.Errorf("deleting Sentinel Alert Rule Ms Security Incident %q: %+v", id, err) } diff --git a/azurerm/internal/services/sentinel/sentinel_alert_rule_scheduled_resource.go b/azurerm/internal/services/sentinel/sentinel_alert_rule_scheduled_resource.go index cd9157d0ccba..57a5c6baa35a 100644 --- a/azurerm/internal/services/sentinel/sentinel_alert_rule_scheduled_resource.go +++ b/azurerm/internal/services/sentinel/sentinel_alert_rule_scheduled_resource.go @@ -262,7 +262,7 @@ func resourceSentinelAlertRuleScheduledCreateUpdate(d *schema.ResourceData, meta id := parse.NewAlertRuleID(workspaceID.SubscriptionId, workspaceID.ResourceGroup, workspaceID.WorkspaceName, name) if d.IsNewResource() { - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { if !utils.ResponseWasNotFound(resp.Response) { return fmt.Errorf("checking for existing Sentinel Alert Rule Scheduled %q: %+v", id, err) @@ -326,7 +326,7 @@ func resourceSentinelAlertRuleScheduledCreateUpdate(d *schema.ResourceData, meta // Service avoid concurrent update of this resource via checking the "etag" to guarantee it is the same value as last Read. if !d.IsNewResource() { - resp, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + resp, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { return fmt.Errorf("retrieving Sentinel Alert Rule Scheduled %q: %+v", id, err) } @@ -337,7 +337,7 @@ func resourceSentinelAlertRuleScheduledCreateUpdate(d *schema.ResourceData, meta param.Etag = resp.Value.(securityinsight.ScheduledAlertRule).Etag } - if _, err := client.CreateOrUpdate(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name, param); err != nil { + if _, err := client.CreateOrUpdate(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name, param); err != nil { return fmt.Errorf("creating Sentinel Alert Rule Scheduled %q: %+v", id, err) } @@ -356,7 +356,7 @@ func resourceSentinelAlertRuleScheduledRead(d *schema.ResourceData, meta interfa return err } - resp, err := client.Get(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name) + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[DEBUG] Sentinel Alert Rule Scheduled %q was not found - removing from state!", id) @@ -421,7 +421,7 @@ func resourceSentinelAlertRuleScheduledDelete(d *schema.ResourceData, meta inter return err } - if _, err := client.Delete(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { + if _, err := client.Delete(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { return fmt.Errorf("deleting Sentinel Alert Rule Scheduled %q: %+v", id, err) } diff --git a/azurerm/internal/services/sentinel/sentinel_alert_rule_template_data_source.go b/azurerm/internal/services/sentinel/sentinel_alert_rule_template_data_source.go index f6db127c3515..231da1638941 100644 --- a/azurerm/internal/services/sentinel/sentinel_alert_rule_template_data_source.go +++ b/azurerm/internal/services/sentinel/sentinel_alert_rule_template_data_source.go @@ -156,7 +156,7 @@ func dataSourceSentinelAlertRuleTemplateRead(d *schema.ResourceData, meta interf } func getAlertRuleTemplateByName(ctx context.Context, client *securityinsight.AlertRuleTemplatesClient, workspaceID *loganalyticsParse.LogAnalyticsWorkspaceId, name string) (res securityinsight.BasicAlertRuleTemplate, err error) { - template, err := client.Get(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName, name) + template, err := client.Get(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName, name) if err != nil { return nil, err } @@ -164,7 +164,7 @@ func getAlertRuleTemplateByName(ctx context.Context, client *securityinsight.Ale } func getAlertRuleTemplateByDisplayName(ctx context.Context, client *securityinsight.AlertRuleTemplatesClient, workspaceID *loganalyticsParse.LogAnalyticsWorkspaceId, name string) (res securityinsight.BasicAlertRuleTemplate, err error) { - templates, err := client.ListComplete(ctx, workspaceID.ResourceGroup, operationalInsightsResourceProvider, workspaceID.WorkspaceName) + templates, err := client.ListComplete(ctx, workspaceID.ResourceGroup, OperationalInsightsResourceProvider, workspaceID.WorkspaceName) if err != nil { return nil, err } diff --git a/azurerm/internal/services/sentinel/sentinel_data_connector.go b/azurerm/internal/services/sentinel/sentinel_data_connector.go index 66e35d235cb5..12dda210711f 100644 --- a/azurerm/internal/services/sentinel/sentinel_data_connector.go +++ b/azurerm/internal/services/sentinel/sentinel_data_connector.go @@ -10,10 +10,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" ) -// TODO: remove once one of the PR's has been merged -var _ = importSentinelDataConnector(securityinsight.DataConnectorKindAmazonWebServicesCloudTrail) -var _ = assertDataConnectorKind(securityinsight.AADDataConnector{}, securityinsight.DataConnectorKindAmazonWebServicesCloudTrail) - func importSentinelDataConnector(expectKind securityinsight.DataConnectorKind) func(d *schema.ResourceData, meta interface{}) (data []*schema.ResourceData, err error) { return func(d *schema.ResourceData, meta interface{}) (data []*schema.ResourceData, err error) { id, err := parse.DataConnectorID(d.Id()) @@ -25,7 +21,7 @@ func importSentinelDataConnector(expectKind securityinsight.DataConnectorKind) f ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - resp, err := client.Get(ctx, id.ResourceGroup, operationalInsightsResourceProvider, id.WorkspaceName, id.Name) + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name) if err != nil { return nil, fmt.Errorf("retrieving Sentinel Alert Rule %q: %+v", id, err) } diff --git a/azurerm/internal/services/sentinel/sentinel_data_connector_threat_intelligence.go b/azurerm/internal/services/sentinel/sentinel_data_connector_threat_intelligence.go new file mode 100644 index 000000000000..02978c159bd8 --- /dev/null +++ b/azurerm/internal/services/sentinel/sentinel_data_connector_threat_intelligence.go @@ -0,0 +1,165 @@ +package sentinel + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/securityinsight/mgmt/2019-01-01-preview/securityinsight" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + loganalyticsParse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse" + loganalyticsValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/sentinel/parse" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceSentinelDataConnectorThreatIntelligence() *schema.Resource { + return &schema.Resource{ + Create: resourceSentinelDataConnectorThreatIntelligenceCreateUpdate, + Read: resourceSentinelDataConnectorThreatIntelligenceRead, + Delete: resourceSentinelDataConnectorThreatIntelligenceDelete, + + Importer: azSchema.ValidateResourceIDPriorToImportThen(func(id string) error { + _, err := parse.DataConnectorID(id) + return err + }, importSentinelDataConnector(securityinsight.DataConnectorKindThreatIntelligence)), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "log_analytics_workspace_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: loganalyticsValidate.LogAnalyticsWorkspaceID, + }, + + "tenant_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.IsUUID, + }, + }, + } +} + +func resourceSentinelDataConnectorThreatIntelligenceCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Sentinel.DataConnectorsClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + workspaceId, err := loganalyticsParse.LogAnalyticsWorkspaceID(d.Get("log_analytics_workspace_id").(string)) + if err != nil { + return err + } + name := d.Get("name").(string) + id := parse.NewDataConnectorID(workspaceId.SubscriptionId, workspaceId.ResourceGroup, workspaceId.WorkspaceName, name) + + if d.IsNewResource() { + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, name) + if err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + } + + if !utils.ResponseWasNotFound(resp.Response) { + return tf.ImportAsExistsError("azurerm_sentinel_data_connector_threat_intelligence", id.ID()) + } + } + + tenantId := d.Get("tenant_id").(string) + if tenantId == "" { + tenantId = meta.(*clients.Client).Account.TenantId + } + + param := securityinsight.TIDataConnector{ + Name: &name, + TIDataConnectorProperties: &securityinsight.TIDataConnectorProperties{ + TenantID: &tenantId, + DataTypes: &securityinsight.TIDataConnectorDataTypes{ + Indicators: &securityinsight.TIDataConnectorDataTypesIndicators{ + State: securityinsight.Enabled, + }, + }, + }, + Kind: securityinsight.KindThreatIntelligence, + } + + if _, err = client.CreateOrUpdate(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name, param); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceSentinelDataConnectorThreatIntelligenceRead(d, meta) +} + +func resourceSentinelDataConnectorThreatIntelligenceRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Sentinel.DataConnectorsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DataConnectorID(d.Id()) + if err != nil { + return err + } + workspaceId := loganalyticsParse.NewLogAnalyticsWorkspaceID(id.SubscriptionId, id.ResourceGroup, id.WorkspaceName) + + resp, err := client.Get(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] %s was not found - removing from state!", id) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + dc, ok := resp.Value.(securityinsight.TIDataConnector) + if !ok { + return fmt.Errorf("%s was not a Threat Intelligence Data Connector", id) + } + + d.Set("name", id.Name) + d.Set("log_analytics_workspace_id", workspaceId.ID()) + d.Set("tenant_id", dc.TenantID) + + return nil +} + +func resourceSentinelDataConnectorThreatIntelligenceDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Sentinel.DataConnectorsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.DataConnectorID(d.Id()) + if err != nil { + return err + } + + if _, err = client.Delete(ctx, id.ResourceGroup, OperationalInsightsResourceProvider, id.WorkspaceName, id.Name); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil +} diff --git a/azurerm/internal/services/sentinel/sentinel_data_connector_threat_intelligence_test.go b/azurerm/internal/services/sentinel/sentinel_data_connector_threat_intelligence_test.go new file mode 100644 index 000000000000..ebaf4bdc37b9 --- /dev/null +++ b/azurerm/internal/services/sentinel/sentinel_data_connector_threat_intelligence_test.go @@ -0,0 +1,142 @@ +package sentinel_test + +import ( + "context" + "fmt" + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/sentinel" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/sentinel/parse" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type SentinelDataConnectorThreatIntelligenceResource struct{} + +func TestAccAzureRMSentinelDataConnectorThreatIntelligence_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sentinel_data_connector_threat_intelligence", "test") + r := SentinelDataConnectorThreatIntelligenceResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccAzureRMSentinelDataConnectorThreatIntelligence_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sentinel_data_connector_threat_intelligence", "test") + r := SentinelDataConnectorThreatIntelligenceResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccAzureRMSentinelDataConnectorThreatIntelligence_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sentinel_data_connector_threat_intelligence", "test") + r := SentinelDataConnectorThreatIntelligenceResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (r SentinelDataConnectorThreatIntelligenceResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.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, sentinel.OperationalInsightsResourceProvider, 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 SentinelDataConnectorThreatIntelligenceResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_sentinel_data_connector_threat_intelligence" "test" { + name = "accTestDC-%d" + log_analytics_workspace_id = azurerm_log_analytics_workspace.test.id +} +`, template, data.RandomInteger) +} + +func (r SentinelDataConnectorThreatIntelligenceResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +data "azurerm_client_config" "test" {} + +resource "azurerm_sentinel_data_connector_threat_intelligence" "test" { + name = "accTestDC-%d" + log_analytics_workspace_id = azurerm_log_analytics_workspace.test.id + tenant_id = data.azurerm_client_config.test.tenant_id +} +`, template, data.RandomInteger) +} + +func (r SentinelDataConnectorThreatIntelligenceResource) requiresImport(data acceptance.TestData) string { + template := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_sentinel_data_connector_threat_intelligence" "import" { + name = azurerm_sentinel_data_connector_threat_intelligence.test.name + log_analytics_workspace_id = azurerm_sentinel_data_connector_threat_intelligence.test.log_analytics_workspace_id +} +`, template) +} + +func (r SentinelDataConnectorThreatIntelligenceResource) 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" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index ef53cb8dafc0..b54f1efc6d9d 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -2850,6 +2850,10 @@
  • azurerm_sentinel_alert_rule_scheduled
  • + +
  • + azurerm_data_connector_threat_intelligence +
  • diff --git a/website/docs/r/sentinel_data_connector_threat_intelligence.html.markdown b/website/docs/r/sentinel_data_connector_threat_intelligence.html.markdown new file mode 100644 index 000000000000..e3e29d33b057 --- /dev/null +++ b/website/docs/r/sentinel_data_connector_threat_intelligence.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: "Sentinel" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_sentinel_data_connector_threat_intelligence" +description: |- + Manages a Threat Intelligence Data Connector. +--- + +# azurerm_sentinel_data_connector_threat_intelligence + +Manages a Threat Intelligence 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_sentinel_data_connector_threat_intelligence" "example" { + name = "example" + log_analytics_workspace_id = azurerm_log_analytics_workspace.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `log_analytics_workspace_id` - (Required) The ID of the Log Analytics Workspace that this Threat Intelligence Data Connector resides in. Changing this forces a new Threat Intelligence Data Connector to be created. + +* `name` - (Required) The name which should be used for this Threat Intelligence Data Connector. Changing this forces a new Threat Intelligence Data Connector to be created. + +--- + +* `tenant_id` - (Optional) The ID of the tenant that this Threat Intelligence Data Connector connects to. Changing this forces a new Threat Intelligence Data Connector to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Threat Intelligence Data Connector. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Threat Intelligence Data Connector. +* `read` - (Defaults to 5 minutes) Used when retrieving the Threat Intelligence Data Connector. +* `delete` - (Defaults to 30 minutes) Used when deleting the Threat Intelligence Data Connector. + +## Import + +Threat Intelligence Data Connectors can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_sentinel_data_connector_threat_intelligence.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/dataConnectors/dc1 +```