Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New resource/data source: azurerm_sentinel_alert_rule_ms_security_incident #6606

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions azurerm/internal/clients/client.go
Expand Up @@ -66,6 +66,7 @@ import (
resource "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/resource/client"
search "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/search/client"
securityCenter "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/securitycenter/client"
sentinel "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/sentinel/client"
serviceBus "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/servicebus/client"
serviceFabric "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/servicefabric/client"
signalr "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/signalr/client"
Expand Down Expand Up @@ -144,6 +145,7 @@ type Client struct {
Resource *resource.Client
Search *search.Client
SecurityCenter *securityCenter.Client
Sentinel *sentinel.Client
ServiceBus *serviceBus.Client
ServiceFabric *serviceFabric.Client
SignalR *signalr.Client
Expand Down Expand Up @@ -223,6 +225,7 @@ func (client *Client) Build(ctx context.Context, o *common.ClientOptions) error
client.Resource = resource.NewClient(o)
client.Search = search.NewClient(o)
client.SecurityCenter = securityCenter.NewClient(o)
client.Sentinel = sentinel.NewClient(o)
client.ServiceBus = serviceBus.NewClient(o)
client.ServiceFabric = serviceFabric.NewClient(o)
client.SignalR = signalr.NewClient(o)
Expand Down
1 change: 1 addition & 0 deletions azurerm/internal/provider/required_resource_providers.go
Expand Up @@ -67,6 +67,7 @@ func RequiredResourceProviders() map[string]struct{} {
"Microsoft.Resources": {},
"Microsoft.Search": {},
"Microsoft.Security": {},
"Microsoft.SecurityInsights": {},
"Microsoft.ServiceBus": {},
"Microsoft.ServiceFabric": {},
"Microsoft.Sql": {},
Expand Down
2 changes: 2 additions & 0 deletions azurerm/internal/provider/services.go
Expand Up @@ -62,6 +62,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/resource"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/search"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/securitycenter"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/sentinel"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/servicebus"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/servicefabric"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/signalr"
Expand Down Expand Up @@ -137,6 +138,7 @@ func SupportedServices() []common.ServiceRegistration {
resource.Registration{},
search.Registration{},
securitycenter.Registration{},
sentinel.Registration{},
servicebus.Registration{},
servicefabric.Registration{},
signalr.Registration{},
Expand Down
@@ -0,0 +1,33 @@
package parse

import (
"fmt"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
)

type LogAnalyticsWorkspaceId struct {
ResourceGroup string
Name string
}

func LogAnalyticsWorkspaceID(input string) (*LogAnalyticsWorkspaceId, error) {
id, err := azure.ParseAzureResourceID(input)
if err != nil {
return nil, fmt.Errorf("parsing Log Analytics Workspace ID %q: %+v", input, err)
}

server := LogAnalyticsWorkspaceId{
ResourceGroup: id.ResourceGroup,
}

if server.Name, err = id.PopSegment("workspaces"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &server, nil
}
@@ -0,0 +1,70 @@
package parse

import (
"testing"
)

func TestLogAnalyticsWorkspaceID(t *testing.T) {
testData := []struct {
Name string
Input string
Error bool
Expect *LogAnalyticsWorkspaceId
}{
{
Name: "Empty",
Input: "",
Error: true,
},
{
Name: "No Resource Groups Segment",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000",
Error: true,
},
{
Name: "No Resource Groups Value",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/",
Error: true,
},
{
Name: "Resource Group ID",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/",
Error: true,
},
{
Name: "Missing Workspace Value",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces",
Error: true,
},
{
Name: "Workspace Value",
Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1",
Error: true,
Expect: &LogAnalyticsWorkspaceId{
ResourceGroup: "resGroup1",
Name: "workspace1",
},
},
}

for _, v := range testData {
t.Logf("[DEBUG] Testing %q", v.Name)

actual, err := LogAnalyticsWorkspaceID(v.Input)
if err != nil {
if v.Error {
continue
}

t.Fatalf("Expected a value but got an error: %s", err)
}

if actual.ResourceGroup != v.Expect.ResourceGroup {
t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup)
}

if actual.Name != v.Expect.Name {
t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name)
}
}
}
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
Expand Down Expand Up @@ -167,24 +168,22 @@ func resourceArmLogAnalyticsWorkspaceRead(d *schema.ResourceData, meta interface
client := meta.(*clients.Client).LogAnalytics.WorkspacesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()
id, err := azure.ParseAzureResourceID(d.Id())
id, err := parse.LogAnalyticsWorkspaceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["workspaces"]

resp, err := client.Get(ctx, resGroup, name)
resp, err := client.Get(ctx, id.ResourceGroup, id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
d.SetId("")
return nil
}
return fmt.Errorf("Error making Read request on AzureRM Log Analytics workspaces '%s': %+v", name, err)
return fmt.Errorf("Error making Read request on AzureRM Log Analytics workspaces '%s': %+v", id.Name, err)
}

d.Set("name", resp.Name)
d.Set("resource_group_name", resGroup)
d.Set("resource_group_name", id.ResourceGroup)
if location := resp.Location; location != nil {
d.Set("location", azure.NormalizeLocation(*location))
}
Expand All @@ -196,9 +195,9 @@ func resourceArmLogAnalyticsWorkspaceRead(d *schema.ResourceData, meta interface
}
d.Set("retention_in_days", resp.RetentionInDays)

sharedKeys, err := client.GetSharedKeys(ctx, resGroup, name)
sharedKeys, err := client.GetSharedKeys(ctx, id.ResourceGroup, id.Name)
if err != nil {
log.Printf("[ERROR] Unable to List Shared keys for Log Analytics workspaces %s: %+v", name, err)
log.Printf("[ERROR] Unable to List Shared keys for Log Analytics workspaces %s: %+v", id.Name, err)
} else {
d.Set("primary_shared_key", sharedKeys.PrimarySharedKey)
d.Set("secondary_shared_key", sharedKeys.SecondarySharedKey)
Expand All @@ -211,21 +210,18 @@ func resourceArmLogAnalyticsWorkspaceDelete(d *schema.ResourceData, meta interfa
client := meta.(*clients.Client).LogAnalytics.WorkspacesClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()
id, err := azure.ParseAzureResourceID(d.Id())
id, err := parse.LogAnalyticsWorkspaceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["workspaces"]

resp, err := client.Delete(ctx, resGroup, name)
resp, err := client.Delete(ctx, id.ResourceGroup, id.Name)

if err != nil {
if utils.ResponseWasNotFound(resp) {
return nil
}

return fmt.Errorf("Error issuing AzureRM delete request for Log Analytics Workspaces '%s': %+v", name, err)
return fmt.Errorf("Error issuing AzureRM delete request for Log Analytics Workspaces '%s': %+v", id.Name, err)
}

return nil
Expand Down
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse"
)

func TestAccAzureRmLogAnalyticsWorkspaceName_validation(t *testing.T) {
Expand Down Expand Up @@ -123,10 +124,12 @@ func testCheckAzureRMLogAnalyticsWorkspaceDestroy(s *terraform.State) error {
continue
}

name := rs.Primary.Attributes["name"]
resourceGroup := rs.Primary.Attributes["resource_group_name"]
id, err := parse.LogAnalyticsWorkspaceID(rs.Primary.ID)
if err != nil {
return err
}

resp, err := conn.Get(ctx, resourceGroup, name)
resp, err := conn.Get(ctx, id.ResourceGroup, id.Name)

if err != nil {
return nil
Expand All @@ -151,19 +154,18 @@ func testCheckAzureRMLogAnalyticsWorkspaceExists(resourceName string) resource.T
return fmt.Errorf("Not found: %s", resourceName)
}

name := rs.Primary.Attributes["name"]
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
if !hasResourceGroup {
return fmt.Errorf("Bad: no resource group found in state for Log Analytics Workspace: '%s'", name)
id, err := parse.LogAnalyticsWorkspaceID(rs.Primary.ID)
if err != nil {
return err
}

resp, err := conn.Get(ctx, resourceGroup, name)
resp, err := conn.Get(ctx, id.ResourceGroup, id.Name)
if err != nil {
return fmt.Errorf("Bad: Get on Log Analytics Workspace Client: %+v", err)
}

if resp.StatusCode == http.StatusNotFound {
return fmt.Errorf("Bad: Log Analytics Workspace '%s' (resource group: '%s') does not exist", name, resourceGroup)
return fmt.Errorf("Bad: Log Analytics Workspace '%s' (resource group: '%s') does not exist", id.Name, id.ResourceGroup)
}

return nil
Expand Down
@@ -0,0 +1,22 @@
package validate

import (
"fmt"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse"
)

func LogAnalyticsWorkspaceID(i interface{}, k string) (warnings []string, errors []error) {
v, ok := i.(string)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %q to be string", k))
return
}

if _, err := parse.LogAnalyticsWorkspaceID(v); err != nil {
errors = append(errors, fmt.Errorf("parsing %q as a resource id: %v", k, err))
return
}

return warnings, errors
}
19 changes: 19 additions & 0 deletions azurerm/internal/services/sentinel/client/client.go
@@ -0,0 +1,19 @@
package client

import (
"github.com/Azure/azure-sdk-for-go/services/preview/securityinsight/mgmt/2017-08-01-preview/securityinsight"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common"
)

type Client struct {
AlertRulesClient *securityinsight.AlertRulesClient
}

func NewClient(o *common.ClientOptions) *Client {
alertRulesClient := securityinsight.NewAlertRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&alertRulesClient.Client, o.ResourceManagerAuthorizer)

return &Client{
AlertRulesClient: &alertRulesClient,
}
}
@@ -0,0 +1,67 @@
package sentinel

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"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/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func dataSourceArmSentinelAlertRule() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmSentinelAlertRuleRead,

Timeouts: &schema.ResourceTimeout{
Read: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"log_analytics_workspace_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: loganalyticsValidate.LogAnalyticsWorkspaceID,
},
},
}
}

func dataSourceArmSentinelAlertRuleRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Sentinel.AlertRulesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

name := d.Get("name").(string)
workspaceID, err := loganalyticsParse.LogAnalyticsWorkspaceID(d.Get("log_analytics_workspace_id").(string))
if err != nil {
return err
}

resp, err := client.Get(ctx, workspaceID.ResourceGroup, workspaceID.Name, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("Sentinel Alert Rule %q (Resource Group %q / Workspace: %q) was not found", name, workspaceID.ResourceGroup, workspaceID.Name)
}

return fmt.Errorf("retrieving Sentinel Alert Rule %q (Resource Group %q / Workspace: %q): %+v", name, workspaceID.ResourceGroup, workspaceID.Name, err)
}

id := alertRuleID(resp.Value)
if id == nil || *id == "" {
return fmt.Errorf("nil or empty ID of Sentinel Alert Rule %q (Resource Group %q / Workspace: %q)", name, workspaceID.ResourceGroup, workspaceID.Name)
}
d.SetId(*id)

return nil
}