Skip to content

Commit

Permalink
New Resource: azurerm_sentinel_alert_rule_anomaly_built_in, New Dat…
Browse files Browse the repository at this point in the history
…aSource:`azurerm_sentinel_anomaly_rule`
  • Loading branch information
ziyeqf committed Feb 8, 2023
1 parent e3ae00c commit dd10608
Show file tree
Hide file tree
Showing 14 changed files with 1,426 additions and 1 deletion.
5 changes: 5 additions & 0 deletions internal/services/sentinel/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Client struct {
WatchlistsClient *securityinsight.WatchlistsClient
WatchlistItemsClient *securityinsight.WatchlistItemsClient
OnboardingStatesClient *sentinelonboardingstates.SentinelOnboardingStatesClient
AnalyticsSettingsClient *securityinsight.SecurityMLAnalyticsSettingsClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand All @@ -39,6 +40,9 @@ func NewClient(o *common.ClientOptions) *Client {
onboardingStatesClient := sentinelonboardingstates.NewSentinelOnboardingStatesClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&onboardingStatesClient.Client, o.ResourceManagerAuthorizer)

analyticsSettingsClient := securityinsight.NewSecurityMLAnalyticsSettingsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&analyticsSettingsClient.Client, o.ResourceManagerAuthorizer)

return &Client{
AlertRulesClient: &alertRulesClient,
AlertRuleTemplatesClient: &alertRuleTemplatesClient,
Expand All @@ -47,5 +51,6 @@ func NewClient(o *common.ClientOptions) *Client {
WatchlistsClient: &watchListsClient,
WatchlistItemsClient: &watchListItemsClient,
OnboardingStatesClient: &onboardingStatesClient,
AnalyticsSettingsClient: &analyticsSettingsClient,
}
}
75 changes: 75 additions & 0 deletions internal/services/sentinel/parse/ml_analytics_settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"fmt"
"strings"

"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids"
)

type MLAnalyticsSettingsId struct {
SubscriptionId string
ResourceGroup string
WorkspaceName string
SecurityMLAnalyticsSettingName string
}

func NewMLAnalyticsSettingsID(subscriptionId, resourceGroup, workspaceName, securityMLAnalyticsSettingName string) MLAnalyticsSettingsId {
return MLAnalyticsSettingsId{
SubscriptionId: subscriptionId,
ResourceGroup: resourceGroup,
WorkspaceName: workspaceName,
SecurityMLAnalyticsSettingName: securityMLAnalyticsSettingName,
}
}

func (id MLAnalyticsSettingsId) String() string {
segments := []string{
fmt.Sprintf("Security M L Analytics Setting Name %q", id.SecurityMLAnalyticsSettingName),
fmt.Sprintf("Workspace Name %q", id.WorkspaceName),
fmt.Sprintf("Resource Group %q", id.ResourceGroup),
}
segmentsStr := strings.Join(segments, " / ")
return fmt.Sprintf("%s: (%s)", "M L Analytics Settings", segmentsStr)
}

func (id MLAnalyticsSettingsId) ID() string {
fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.OperationalInsights/workspaces/%s/providers/Microsoft.SecurityInsights/securityMLAnalyticsSettings/%s"
return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.WorkspaceName, id.SecurityMLAnalyticsSettingName)
}

// MLAnalyticsSettingsID parses a MLAnalyticsSettings ID into an MLAnalyticsSettingsId struct
func MLAnalyticsSettingsID(input string) (*MLAnalyticsSettingsId, error) {
id, err := resourceids.ParseAzureResourceID(input)
if err != nil {
return nil, err
}

resourceId := MLAnalyticsSettingsId{
SubscriptionId: id.SubscriptionID,
ResourceGroup: id.ResourceGroup,
}

if resourceId.SubscriptionId == "" {
return nil, fmt.Errorf("ID was missing the 'subscriptions' element")
}

if resourceId.ResourceGroup == "" {
return nil, fmt.Errorf("ID was missing the 'resourceGroups' element")
}

if resourceId.WorkspaceName, err = id.PopSegment("workspaces"); err != nil {
return nil, err
}
if resourceId.SecurityMLAnalyticsSettingName, err = id.PopSegment("securityMLAnalyticsSettings"); err != nil {
return nil, err
}

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

return &resourceId, nil
}
128 changes: 128 additions & 0 deletions internal/services/sentinel/parse/ml_analytics_settings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package parse

// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten

import (
"testing"

"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids"
)

var _ resourceids.Id = MLAnalyticsSettingsId{}

func TestMLAnalyticsSettingsIDFormatter(t *testing.T) {
actual := NewMLAnalyticsSettingsID("12345678-1234-9876-4563-123456789012", "resGroup1", "workspace1", "setting1").ID()
expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/securityMLAnalyticsSettings/setting1"
if actual != expected {
t.Fatalf("Expected %q but got %q", expected, actual)
}
}

func TestMLAnalyticsSettingsID(t *testing.T) {
testData := []struct {
Input string
Error bool
Expected *MLAnalyticsSettingsId
}{

{
// empty
Input: "",
Error: true,
},

{
// missing SubscriptionId
Input: "/",
Error: true,
},

{
// missing value for SubscriptionId
Input: "/subscriptions/",
Error: true,
},

{
// missing ResourceGroup
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/",
Error: true,
},

{
// missing value for ResourceGroup
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/",
Error: true,
},

{
// missing WorkspaceName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/",
Error: true,
},

{
// missing value for WorkspaceName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/",
Error: true,
},

{
// missing SecurityMLAnalyticsSettingName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/",
Error: true,
},

{
// missing value for SecurityMLAnalyticsSettingName
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/securityMLAnalyticsSettings/",
Error: true,
},

{
// valid
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/securityMLAnalyticsSettings/setting1",
Expected: &MLAnalyticsSettingsId{
SubscriptionId: "12345678-1234-9876-4563-123456789012",
ResourceGroup: "resGroup1",
WorkspaceName: "workspace1",
SecurityMLAnalyticsSettingName: "setting1",
},
},

{
// upper-cased
Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.OPERATIONALINSIGHTS/WORKSPACES/WORKSPACE1/PROVIDERS/MICROSOFT.SECURITYINSIGHTS/SECURITYMLANALYTICSSETTINGS/SETTING1",
Error: true,
},
}

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

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

t.Fatalf("Expect a value but got an error: %s", err)
}
if v.Error {
t.Fatal("Expect an error but didn't get one")
}

if actual.SubscriptionId != v.Expected.SubscriptionId {
t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId)
}
if actual.ResourceGroup != v.Expected.ResourceGroup {
t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup)
}
if actual.WorkspaceName != v.Expected.WorkspaceName {
t.Fatalf("Expected %q but got %q for WorkspaceName", v.Expected.WorkspaceName, actual.WorkspaceName)
}
if actual.SecurityMLAnalyticsSettingName != v.Expected.SecurityMLAnalyticsSettingName {
t.Fatalf("Expected %q but got %q for SecurityMLAnalyticsSettingName", v.Expected.SecurityMLAnalyticsSettingName, actual.SecurityMLAnalyticsSettingName)
}
}
}
5 changes: 4 additions & 1 deletion internal/services/sentinel/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource {
}

func (r Registration) DataSources() []sdk.DataSource {
return []sdk.DataSource{}
return []sdk.DataSource{
AlertRuleAnomalyDataSource{},
}
}

func (r Registration) Resources() []sdk.Resource {
Expand All @@ -72,5 +74,6 @@ func (r Registration) Resources() []sdk.Resource {
LogAnalyticsWorkspaceOnboardResource{},
DataConnectorThreatIntelligenceTAXIIResource{},
DataConnectorMicrosoftThreatIntelligenceResource{},
AlertRuleAnomalyBuiltInResource{},
}
}
1 change: 1 addition & 0 deletions internal/services/sentinel/resourceids.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ package sentinel
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=AutomationRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/automationRules/rule1 -rewrite=true
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Watchlist -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/watchlists/list1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=WatchlistItem -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/watchlists/list1/watchlistItems/item1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=MLAnalyticsSettings -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.OperationalInsights/workspaces/workspace1/providers/Microsoft.SecurityInsights/securityMLAnalyticsSettings/setting1
56 changes: 56 additions & 0 deletions internal/services/sentinel/sentinel_alert_rule_anomaly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package sentinel

import (
"context"
"encoding/json"
"fmt"

"github.com/hashicorp/go-azure-sdk/resource-manager/operationalinsights/2022-10-01/workspaces"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/sentinel/parse"
securityinsight "github.com/tombuildsstuff/kermit/sdk/securityinsights/2022-10-01-preview/securityinsights"
)

type AnomalyRuleRequiredDataConnectorModel struct {
ConnectorId string `tfschema:"connector_id"`
DataTypes []string `tfschema:"data_types"`
}

// the service always return a fixed one no matter what id we pass, tracked on https://github.com/Azure/azure-rest-api-specs/issues/22485
func AlertRuleAnomalyReadWithPredicate(ctx context.Context, client *securityinsight.SecurityMLAnalyticsSettingsClient, workspaceId workspaces.WorkspaceId, predicateFunc func(v *securityinsight.AnomalySecurityMLAnalyticsSettings) bool) (*securityinsight.AnomalySecurityMLAnalyticsSettings, error) {
resp, err := client.ListComplete(ctx, workspaceId.ResourceGroupName, workspaceId.WorkspaceName)
if err != nil {
return nil, fmt.Errorf("retrieving: %+v", err)
}

for resp.NotDone() {
item := resp.Value()
if v, ok := item.AsAnomalySecurityMLAnalyticsSettings(); ok {
if predicateFunc(v) {
return v, nil
}

}
if err := resp.NextWithContext(ctx); err != nil {
return nil, fmt.Errorf("listing next: %+v", err)
}
}
return nil, nil
}

// when the id of workspace is too long, the service return without workspace name:
// "/subscriptions/{sub_id}/resourceGroups/{rg_name}/providers/Microsoft.OperationalInsights/workspaces//providers/Microsoft.SecurityInsights/securityMLAnalyticsSettings/5020e404-9768-4364-98f6-679940c21362",
// tracked on https://github.com/Azure/azure-rest-api-specs/issues/22500
func AlertRuleAnomalyIdFromWorkspaceId(workspaceId workspaces.WorkspaceId, name string) string {
return parse.NewMLAnalyticsSettingsID(workspaceId.SubscriptionId, workspaceId.ResourceGroupName, workspaceId.WorkspaceName, name).ID()
}

func flattenSentinelAlertRuleAnomalyCustomizableObservations(input interface{}) (string, error) {
value := ""
val, err := json.Marshal(input)
if err != nil {
return "", fmt.Errorf("failed to marshal to json: %+v", err)
}
value = string(val)

return value, nil
}
Loading

0 comments on commit dd10608

Please sign in to comment.