From 91b444fc5356d99adb9bc6104ece9a2c5d6b8b7d Mon Sep 17 00:00:00 2001 From: Yun Liu <yunliu1@microsoft.com> Date: Fri, 9 Jun 2023 05:47:26 +0800 Subject: [PATCH] `azurerm_automanage_configuration` - support new property block `backup` and `azure_security_baseline` (#22081) --- .../automanage_configuration_resource.go | 636 +++++++++++++++--- .../automanage_configuration_resource_test.go | 223 +++++- .../r/automanage_configuration.html.markdown | 113 +++- 3 files changed, 862 insertions(+), 110 deletions(-) diff --git a/internal/services/automanage/automanage_configuration_resource.go b/internal/services/automanage/automanage_configuration_resource.go index becc10581f44..9743fb9a57d5 100644 --- a/internal/services/automanage/automanage_configuration_resource.go +++ b/internal/services/automanage/automanage_configuration_resource.go @@ -3,6 +3,7 @@ package automanage import ( "context" "fmt" + "regexp" "time" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" @@ -17,19 +18,8 @@ import ( "github.com/tombuildsstuff/kermit/sdk/automanage/2022-05-04/automanage" ) -type ConfigurationModel struct { - Name string `tfschema:"name"` - ResourceGroupName string `tfschema:"resource_group_name"` - - Antimalware []AntimalwareConfiguration `tfschema:"antimalware"` - AutomationAccountEnabled bool `tfschema:"automation_account_enabled"` - BootDiagnosticsEnabled bool `tfschema:"boot_diagnostics_enabled"` - DefenderForCloudEnabled bool `tfschema:"defender_for_cloud_enabled"` - GuestConfigurationEnabled bool `tfschema:"guest_configuration_enabled"` - StatusChangeAlertEnabled bool `tfschema:"status_change_alert_enabled"` - - Location string `tfschema:"location"` - Tags map[string]string `tfschema:"tags"` +type AzureSecurityBaselineConfiguration struct { + AssignmentType string `tfschema:"assignment_type"` } type AntimalwareConfiguration struct { @@ -47,6 +37,54 @@ type AntimalwareExclusions struct { Processes string `tfschema:"processes"` } +type BackupConfiguration struct { + PolicyName string `tfschema:"policy_name"` + TimeZone string `tfschema:"time_zone"` + InstantRpRetentionRangeInDays int `tfschema:"instant_rp_retention_range_in_days"` + SchedulePolicy []SchedulePolicyConfiguration `tfschema:"schedule_policy"` + RetentionPolicy []RetentionPolicyConfiguration `tfschema:"retention_policy"` +} + +type ConfigurationModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + + Antimalware []AntimalwareConfiguration `tfschema:"antimalware"` + AzureSecurityBaseline []AzureSecurityBaselineConfiguration `tfschema:"azure_security_baseline"` + Backup []BackupConfiguration `tfschema:"backup"` + AutomationAccountEnabled bool `tfschema:"automation_account_enabled"` + BootDiagnosticsEnabled bool `tfschema:"boot_diagnostics_enabled"` + DefenderForCloudEnabled bool `tfschema:"defender_for_cloud_enabled"` + GuestConfigurationEnabled bool `tfschema:"guest_configuration_enabled"` + StatusChangeAlertEnabled bool `tfschema:"status_change_alert_enabled"` + + Location string `tfschema:"location"` + Tags map[string]string `tfschema:"tags"` +} + +type ScheduleConfiguration struct { + RetentionTimes []string `tfschema:"retention_times"` + RetentionDuration []RetentionDurationConfiguration `tfschema:"retention_duration"` +} + +type RetentionPolicyConfiguration struct { + RetentionPolicyType string `tfschema:"retention_policy_type"` + DailySchedule []ScheduleConfiguration `tfschema:"daily_schedule"` + WeeklySchedule []ScheduleConfiguration `tfschema:"weekly_schedule"` +} + +type RetentionDurationConfiguration struct { + Count int `tfschema:"count"` + DurationType string `tfschema:"duration_type"` +} + +type SchedulePolicyConfiguration struct { + ScheduleRunFrequency string `tfschema:"schedule_run_frequency"` + ScheduleRunTimes []string `tfschema:"schedule_run_times"` + ScheduleRunDays []string `tfschema:"schedule_run_days"` + SchedulePolicyType string `tfschema:"schedule_policy_type"` +} + type AutoManageConfigurationResource struct{} var _ sdk.ResourceWithUpdate = AutoManageConfigurationResource{} @@ -149,6 +187,225 @@ func (r AutoManageConfigurationResource) Arguments() map[string]*pluginsdk.Schem }, }, + // "AzureSecurityBaseline/Enable": boolean, true if block exists + // "AzureSecurityBaseline/AssignmentType": string ("ApplyAndAutoCorrect", "ApplyAndMonitor", "Audit", "DeployAndAutoCorrect"), + "azure_security_baseline": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "assignment_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "ApplyAndAutoCorrect", + ValidateFunc: validation.StringInSlice([]string{ + "ApplyAndAutoCorrect", + "ApplyAndMonitor", + "Audit", + "DeployAndAutoCorrect", + }, false), + }, + }, + }, + }, + + // "Backup/Enable": boolean, true if block exists + // "Backup/PolicyName": string (length 3 - 150, begin with alphanumeric char, only contain alphanumeric chars and hyphens), + // "Backup/TimeZone": timezone, + // "Backup/InstantRpRetentionRangeInDays": int (1 - 5 if ScheduleRunFrequency is Daily, 5 if ScheduleRunFrequency is Weekly), + // "Backup/SchedulePolicy/ScheduleRunFrequency": string ("Daily", "Weekly"), + // "Backup/SchedulePolicy/ScheduleRunTimes": list of DateTime, + // "Backup/SchedulePolicy/ScheduleRunDays": list of strings (["Sunday", "Monday", "Wednesday", "Thursday", "Friday", "Saturday"]), + // "Backup/SchedulePolicy/SchedulePolicyType": string ("SimpleSchedulePolicy"), + // "Backup/RetentionPolicy/RetentionPolicyType": string ("LongTermRetentionPolicy"), + // "Backup/RetentionPolicy/DailySchedule/RetentionTimes": list of DateTime, + // "Backup/RetentionPolicy/DailySchedule/RetentionDuration/Count": int (7 - 9999), + // "Backup/RetentionPolicy/DailySchedule/RetentionDuration/DurationType": string ("Days"), + // "Backup/RetentionPolicy/WeeklySchedule/RetentionTimes":, list of DateTime + // "Backup/RetentionPolicy/WeeklySchedule/RetentionDuration/Count":, int (1 - 5163) + // "Backup/RetentionPolicy/WeeklySchedule/RetentionDuration/DurationType": string ("Weeks"), + "backup": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "policy_name": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]{2,149}$`), "Policy name must be 3 - 150 characters long, begin with an alphanumeric character, and only contain alphanumeric characters and hyphens."), + }, + "time_zone": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "UTC", + }, + "instant_rp_retention_range_in_days": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 5, + ValidateFunc: validation.IntBetween(1, 5), + }, + "schedule_policy": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "schedule_run_frequency": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "Daily", + ValidateFunc: validation.StringInSlice([]string{ + "Daily", + "Weekly", + }, false), + }, + "schedule_run_times": { + Type: pluginsdk.TypeList, + Optional: true, + + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^([01][0-9]|[2][0-3]):([03][0])$"), // time must be on the hour or half past + "Time of day must match the format HH:mm where HH is 00-23 and mm is 00 or 30", + ), + }, + }, + "schedule_run_days": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + }, false), + }, + }, + "schedule_policy_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "SimpleSchedulePolicy", + ValidateFunc: validation.StringInSlice([]string{ + "SimpleSchedulePolicy", + }, false), + }, + }, + }, + }, + "retention_policy": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "retention_policy_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "LongTermRetentionPolicy", + ValidateFunc: validation.StringInSlice([]string{ + "LongTermRetentionPolicy", + }, false), + }, + "daily_schedule": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "retention_times": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^([01][0-9]|[2][0-3]):([03][0])$"), // time must be on the hour or half past + "Time of day must match the format HH:mm where HH is 00-23 and mm is 00 or 30", + ), + }, + }, + "retention_duration": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(7, 9999), + }, + "duration_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "Days", + ValidateFunc: validation.StringInSlice([]string{ + "Days", + }, false), + }, + }, + }, + }, + }, + }, + }, + "weekly_schedule": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "retention_times": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^([01][0-9]|[2][0-3]):([03][0])$"), // time must be on the hour or half past + "Time of day must match the format HH:mm where HH is 00-23 and mm is 00 or 30", + ), + }, + }, + "retention_duration": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "count": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 5163), + }, + "duration_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "Weeks", + ValidateFunc: validation.StringInSlice([]string{ + "Weeks", + }, false), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + // "AutomationAccount/Enable": boolean, "automation_account_enabled": { Type: pluginsdk.TypeBool, @@ -218,45 +475,7 @@ func (r AutoManageConfigurationResource) Create() sdk.ResourceFunc { Tags: tags.FromTypedObject(model.Tags), } - // building configuration profile in json format - jsonConfig := make(map[string]interface{}) - - if model.Antimalware != nil && len(model.Antimalware) > 0 { - antimalwareConfig := model.Antimalware[0] - jsonConfig["Antimalware/Enable"] = true - jsonConfig["Antimalware/EnableRealTimeProtection"] = antimalwareConfig.RealTimeProtectionEnabled - jsonConfig["Antimalware/RunScheduledScan"] = antimalwareConfig.ScheduledScanEnabled - jsonConfig["Antimalware/ScanType"] = antimalwareConfig.ScanType - jsonConfig["Antimalware/ScanDay"] = antimalwareConfig.ScanDay - jsonConfig["Antimalware/ScanTimeInMinutes"] = antimalwareConfig.ScanTimeInMinutes - if antimalwareConfig.Exclusions != nil && len(antimalwareConfig.Exclusions) > 0 { - jsonConfig["Antimalware/Exclusions/Extensions"] = antimalwareConfig.Exclusions[0].Extensions - jsonConfig["Antimalware/Exclusions/Paths"] = antimalwareConfig.Exclusions[0].Paths - jsonConfig["Antimalware/Exclusions/Processes"] = antimalwareConfig.Exclusions[0].Processes - } - } - - if model.AutomationAccountEnabled { - jsonConfig["AutomationAccount/Enable"] = model.AutomationAccountEnabled - } - - if model.BootDiagnosticsEnabled { - jsonConfig["BootDiagnostics/Enable"] = model.BootDiagnosticsEnabled - } - - if model.DefenderForCloudEnabled { - jsonConfig["DefenderForCloud/Enable"] = model.DefenderForCloudEnabled - } - - if model.GuestConfigurationEnabled { - jsonConfig["GuestConfiguration/Enable"] = model.GuestConfigurationEnabled - } - - if model.StatusChangeAlertEnabled { - jsonConfig["Alerts/AutomanageStatusChanges/Enable"] = model.StatusChangeAlertEnabled - } - - properties.Properties.Configuration = &jsonConfig + properties.Properties.Configuration = expandAutomanageConfigurationProfile(model) if _, err := client.CreateOrUpdate(ctx, id.ConfigurationProfileName, id.ResourceGroup, properties); err != nil { return fmt.Errorf("creating %s: %+v", id, err) @@ -284,58 +503,12 @@ func (r AutoManageConfigurationResource) Update() sdk.ResourceFunc { return fmt.Errorf("decoding: %+v", err) } - resp, err := client.Get(ctx, id.ConfigurationProfileName, id.ResourceGroup) - if err != nil { - return fmt.Errorf("retrieving %s: %+v", *id, err) - } - - jsonConfig := make(map[string]interface{}) - - if model.Antimalware != nil && len(model.Antimalware) > 0 { - antimalwareConfig := model.Antimalware[0] - jsonConfig["Antimalware/Enable"] = true - jsonConfig["Antimalware/EnableRealTimeProtection"] = antimalwareConfig.RealTimeProtectionEnabled - jsonConfig["Antimalware/RunScheduledScan"] = antimalwareConfig.ScheduledScanEnabled - jsonConfig["Antimalware/ScanType"] = antimalwareConfig.ScanType - jsonConfig["Antimalware/ScanDay"] = antimalwareConfig.ScanDay - jsonConfig["Antimalware/ScanTimeInMinutes"] = antimalwareConfig.ScanTimeInMinutes - if antimalwareConfig.Exclusions != nil && len(antimalwareConfig.Exclusions) > 0 { - jsonConfig["Antimalware/Exclusions/Extensions"] = antimalwareConfig.Exclusions[0].Extensions - jsonConfig["Antimalware/Exclusions/Paths"] = antimalwareConfig.Exclusions[0].Paths - jsonConfig["Antimalware/Exclusions/Processes"] = antimalwareConfig.Exclusions[0].Processes - } - } - - if metadata.ResourceData.HasChange("automation_account_enabled") { - jsonConfig["AutomationAccount/Enable"] = model.AutomationAccountEnabled - } - - if metadata.ResourceData.HasChange("boot_diagnostics_enabled") { - jsonConfig["BootDiagnostics/Enable"] = model.BootDiagnosticsEnabled - } - - if metadata.ResourceData.HasChange("defender_for_cloud_enabled") { - jsonConfig["DefenderForCloud/Enable"] = model.DefenderForCloudEnabled - } - - if metadata.ResourceData.HasChange("guest_configuration_enabled") { - jsonConfig["GuestConfiguration/Enable"] = model.GuestConfigurationEnabled - } - - if metadata.ResourceData.HasChange("status_change_alert_enabled") { - jsonConfig["Alerts/AutomanageStatusChanges/Enable"] = model.StatusChangeAlertEnabled - } - - if metadata.ResourceData.HasChange("tags") { - resp.Tags = tags.FromTypedObject(model.Tags) - } - properties := automanage.ConfigurationProfile{ - Location: utils.String(metadata.ResourceData.Get("location").(string)), + Location: utils.String(location.Normalize(metadata.ResourceData.Get("location").(string))), Properties: &automanage.ConfigurationProfileProperties{ - Configuration: &jsonConfig, + Configuration: expandAutomanageConfigurationProfile(model), }, - Tags: resp.Tags, + Tags: tags.Expand(metadata.ResourceData.Get("tags").(map[string]interface{})), } if _, err := client.CreateOrUpdate(ctx, id.ConfigurationProfileName, id.ResourceGroup, properties); err != nil { @@ -378,6 +551,10 @@ func (r AutoManageConfigurationResource) Read() sdk.ResourceFunc { state.Antimalware = flattenAntimarewareConfig(configMap) + state.AzureSecurityBaseline = flattenAzureSecurityBaselineConfig(configMap) + + state.Backup = flattenBackupConfig(configMap) + if val, ok := configMap["AutomationAccount/Enable"]; ok { state.AutomationAccountEnabled = val.(bool) } @@ -428,6 +605,102 @@ func (r AutoManageConfigurationResource) Delete() sdk.ResourceFunc { } } +func expandAutomanageConfigurationProfile(model ConfigurationModel) *map[string]interface{} { + // building configuration profile in json format + jsonConfig := make(map[string]interface{}) + + if model.Antimalware != nil && len(model.Antimalware) > 0 { + antimalwareConfig := model.Antimalware[0] + jsonConfig["Antimalware/Enable"] = true + jsonConfig["Antimalware/EnableRealTimeProtection"] = antimalwareConfig.RealTimeProtectionEnabled + jsonConfig["Antimalware/RunScheduledScan"] = antimalwareConfig.ScheduledScanEnabled + jsonConfig["Antimalware/ScanType"] = antimalwareConfig.ScanType + jsonConfig["Antimalware/ScanDay"] = antimalwareConfig.ScanDay + jsonConfig["Antimalware/ScanTimeInMinutes"] = antimalwareConfig.ScanTimeInMinutes + if antimalwareConfig.Exclusions != nil && len(antimalwareConfig.Exclusions) > 0 { + jsonConfig["Antimalware/Exclusions/Extensions"] = antimalwareConfig.Exclusions[0].Extensions + jsonConfig["Antimalware/Exclusions/Paths"] = antimalwareConfig.Exclusions[0].Paths + jsonConfig["Antimalware/Exclusions/Processes"] = antimalwareConfig.Exclusions[0].Processes + } + } + + if model.AzureSecurityBaseline != nil && len(model.AzureSecurityBaseline) > 0 { + azureSecurityBaselineConfig := model.AzureSecurityBaseline[0] + jsonConfig["AzureSecurityBaseline/Enable"] = true + jsonConfig["AzureSecurityBaseline/AssignmentType"] = azureSecurityBaselineConfig.AssignmentType + } + + if model.Backup != nil && len(model.Backup) > 0 { + backupConfig := model.Backup[0] + jsonConfig["Backup/Enable"] = true + if backupConfig.PolicyName != "" { + jsonConfig["Backup/PolicyName"] = backupConfig.PolicyName + } + jsonConfig["Backup/TimeZone"] = backupConfig.TimeZone + jsonConfig["Backup/InstantRpRetentionRangeInDays"] = backupConfig.InstantRpRetentionRangeInDays + if backupConfig.SchedulePolicy != nil && len(backupConfig.SchedulePolicy) > 0 { + schedulePolicyConfig := backupConfig.SchedulePolicy[0] + jsonConfig["Backup/SchedulePolicy/ScheduleRunFrequency"] = schedulePolicyConfig.ScheduleRunFrequency + if schedulePolicyConfig.ScheduleRunTimes != nil && len(schedulePolicyConfig.ScheduleRunTimes) > 0 { + jsonConfig["Backup/SchedulePolicy/ScheduleRunTimes"] = schedulePolicyConfig.ScheduleRunTimes + } + if schedulePolicyConfig.ScheduleRunDays != nil && len(schedulePolicyConfig.ScheduleRunDays) > 0 { + jsonConfig["Backup/SchedulePolicy/ScheduleRunDays"] = schedulePolicyConfig.ScheduleRunDays + } + jsonConfig["Backup/SchedulePolicy/SchedulePolicyType"] = schedulePolicyConfig.SchedulePolicyType + } + + if backupConfig.RetentionPolicy != nil && len(backupConfig.RetentionPolicy) > 0 { + retentionPolicyConfig := backupConfig.RetentionPolicy[0] + jsonConfig["Backup/RetentionPolicy/RetentionPolicyType"] = retentionPolicyConfig.RetentionPolicyType + if retentionPolicyConfig.DailySchedule != nil && len(retentionPolicyConfig.DailySchedule) > 0 { + dailyScheduleConfig := retentionPolicyConfig.DailySchedule[0] + if dailyScheduleConfig.RetentionTimes != nil && len(dailyScheduleConfig.RetentionTimes) > 0 { + jsonConfig["Backup/RetentionPolicy/DailySchedule/RetentionTimes"] = dailyScheduleConfig.RetentionTimes + } + + if dailyScheduleConfig.RetentionDuration != nil && len(dailyScheduleConfig.RetentionDuration) > 0 { + jsonConfig["Backup/RetentionPolicy/DailySchedule/RetentionDuration/Count"] = dailyScheduleConfig.RetentionDuration[0].Count + jsonConfig["Backup/RetentionPolicy/DailySchedule/RetentionDuration/DurationType"] = dailyScheduleConfig.RetentionDuration[0].DurationType + } + } + + if retentionPolicyConfig.WeeklySchedule != nil && len(retentionPolicyConfig.WeeklySchedule) > 0 { + weeklyScheduleConfig := retentionPolicyConfig.WeeklySchedule[0] + if weeklyScheduleConfig.RetentionTimes != nil && len(weeklyScheduleConfig.RetentionTimes) > 0 { + jsonConfig["Backup/RetentionPolicy/WeeklySchedule/RetentionTimes"] = weeklyScheduleConfig.RetentionTimes + } + + if weeklyScheduleConfig.RetentionDuration != nil && len(weeklyScheduleConfig.RetentionDuration) > 0 { + jsonConfig["Backup/RetentionPolicy/WeeklySchedule/RetentionDuration/Count"] = weeklyScheduleConfig.RetentionDuration[0].Count + jsonConfig["Backup/RetentionPolicy/WeeklySchedule/RetentionDuration/DurationType"] = weeklyScheduleConfig.RetentionDuration[0].DurationType + } + } + } + } + + if model.AutomationAccountEnabled { + jsonConfig["AutomationAccount/Enable"] = model.AutomationAccountEnabled + } + + if model.BootDiagnosticsEnabled { + jsonConfig["BootDiagnostics/Enable"] = model.BootDiagnosticsEnabled + } + + if model.DefenderForCloudEnabled { + jsonConfig["DefenderForCloud/Enable"] = model.DefenderForCloudEnabled + } + + if model.GuestConfigurationEnabled { + jsonConfig["GuestConfiguration/Enable"] = model.GuestConfigurationEnabled + } + + if model.StatusChangeAlertEnabled { + jsonConfig["Alerts/AutomanageStatusChanges/Enable"] = model.StatusChangeAlertEnabled + } + return &jsonConfig +} + func flattenAntimarewareConfig(configMap map[string]interface{}) []AntimalwareConfiguration { if val, ok := configMap["Antimalware/Enable"]; !ok || (val == nil) { return nil @@ -435,7 +708,6 @@ func flattenAntimarewareConfig(configMap map[string]interface{}) []AntimalwareCo antimalware := make([]AntimalwareConfiguration, 1) antimalware[0] = AntimalwareConfiguration{} - antimalware[0].Exclusions = make([]AntimalwareExclusions, 1) if val, ok := configMap["Antimalware/EnableRealTimeProtection"]; ok { antimalware[0].RealTimeProtectionEnabled = val.(bool) @@ -457,17 +729,171 @@ func flattenAntimarewareConfig(configMap map[string]interface{}) []AntimalwareCo antimalware[0].ScanTimeInMinutes = int(val.(float64)) } + exclusions := AntimalwareExclusions{} + exclusionsChanged := false if val, ok := configMap["Antimalware/Exclusions/Extensions"]; ok { - antimalware[0].Exclusions[0].Extensions = val.(string) + exclusions.Extensions = val.(string) + exclusionsChanged = true } if val, ok := configMap["Antimalware/Exclusions/Paths"]; ok { - antimalware[0].Exclusions[0].Paths = val.(string) + exclusions.Paths = val.(string) + exclusionsChanged = true } if val, ok := configMap["Antimalware/Exclusions/Processes"]; ok { - antimalware[0].Exclusions[0].Processes = val.(string) + exclusions.Processes = val.(string) + exclusionsChanged = true + } + + if exclusionsChanged { + antimalware[0].Exclusions = make([]AntimalwareExclusions, 1) + antimalware[0].Exclusions[0] = exclusions } return antimalware } + +func flattenAzureSecurityBaselineConfig(configMap map[string]interface{}) []AzureSecurityBaselineConfiguration { + if val, ok := configMap["AzureSecurityBaseline/Enable"]; !ok || (val == nil) { + return nil + } + + azureSecurityBaseline := make([]AzureSecurityBaselineConfiguration, 1) + azureSecurityBaseline[0] = AzureSecurityBaselineConfiguration{} + + if val, ok := configMap["AzureSecurityBaseline/AssignmentType"]; ok { + azureSecurityBaseline[0].AssignmentType = val.(string) + } + + return azureSecurityBaseline +} + +func flattenBackupConfig(configMap map[string]interface{}) []BackupConfiguration { + if val, ok := configMap["Backup/Enable"]; !ok || (val == nil) { + return nil + } + + backup := make([]BackupConfiguration, 1) + backup[0] = BackupConfiguration{} + + if val, ok := configMap["Backup/PolicyName"]; ok { + backup[0].PolicyName = val.(string) + } + + if val, ok := configMap["Backup/TimeZone"]; ok { + backup[0].TimeZone = val.(string) + } + + if val, ok := configMap["Backup/InstantRpRetentionRangeInDays"]; ok { + backup[0].InstantRpRetentionRangeInDays = int(val.(float64)) + } + + schedulePolicy := SchedulePolicyConfiguration{} + schedulePolicyChanged := false + if val, ok := configMap["Backup/SchedulePolicy/ScheduleRunFrequency"]; ok { + schedulePolicy.ScheduleRunFrequency = val.(string) + schedulePolicyChanged = true + } + + if val, ok := configMap["Backup/SchedulePolicy/ScheduleRunTimes"]; ok { + schedulePolicy.ScheduleRunTimes = flattenToListOfString(val) + schedulePolicyChanged = true + } + + if val, ok := configMap["Backup/SchedulePolicy/ScheduleRunDays"]; ok { + schedulePolicy.ScheduleRunDays = flattenToListOfString(val) + schedulePolicyChanged = true + } + + if val, ok := configMap["Backup/SchedulePolicy/SchedulePolicyType"]; ok { + schedulePolicy.SchedulePolicyType = val.(string) + schedulePolicyChanged = true + } + + if schedulePolicyChanged { + backup[0].SchedulePolicy = make([]SchedulePolicyConfiguration, 1) + backup[0].SchedulePolicy[0] = schedulePolicy + } + + retentionPolicy := RetentionPolicyConfiguration{} + retentionPolicyChanged := false + if val, ok := configMap["Backup/RetentionPolicy/RetentionPolicyType"]; ok { + retentionPolicy.RetentionPolicyType = val.(string) + retentionPolicyChanged = true + } + + dailySchedule := ScheduleConfiguration{} + dailyScheduleChanged := false + if val, ok := configMap["Backup/RetentionPolicy/DailySchedule/RetentionTimes"]; ok { + dailySchedule.RetentionTimes = flattenToListOfString(val) + dailyScheduleChanged = true + } + + retentionDuration := RetentionDurationConfiguration{} + retentionDurationChanged := false + if val, ok := configMap["Backup/RetentionPolicy/DailySchedule/RetentionDuration/Count"]; ok { + retentionDuration.Count = int(val.(float64)) + retentionDurationChanged = true + } + + if val, ok := configMap["Backup/RetentionPolicy/DailySchedule/RetentionDuration/DurationType"]; ok { + retentionDuration.DurationType = val.(string) + retentionDurationChanged = true + } + + if retentionDurationChanged { + dailySchedule.RetentionDuration = make([]RetentionDurationConfiguration, 1) + dailySchedule.RetentionDuration[0] = retentionDuration + } + + if dailyScheduleChanged || retentionDurationChanged { + retentionPolicy.DailySchedule = make([]ScheduleConfiguration, 1) + retentionPolicy.DailySchedule[0] = dailySchedule + } + + weeklySchedule := ScheduleConfiguration{} + weeklyScheduleChanged := false + if val, ok := configMap["Backup/RetentionPolicy/WeeklySchedule/RetentionTimes"]; ok { + weeklySchedule.RetentionTimes = flattenToListOfString(val) + weeklyScheduleChanged = true + } + + weeklyRetentionDuration := RetentionDurationConfiguration{} + weeklyRetentionDurationChanged := false + if val, ok := configMap["Backup/RetentionPolicy/WeeklySchedule/RetentionDuration/Count"]; ok { + weeklyRetentionDuration.Count = int(val.(float64)) + weeklyRetentionDurationChanged = true + } + + if val, ok := configMap["Backup/RetentionPolicy/WeeklySchedule/RetentionDuration/DurationType"]; ok { + weeklyRetentionDuration.DurationType = val.(string) + weeklyRetentionDurationChanged = true + } + + if weeklyRetentionDurationChanged { + weeklySchedule.RetentionDuration = make([]RetentionDurationConfiguration, 1) + weeklySchedule.RetentionDuration[0] = weeklyRetentionDuration + } + + if weeklyScheduleChanged || weeklyRetentionDurationChanged { + retentionPolicy.WeeklySchedule = make([]ScheduleConfiguration, 1) + retentionPolicy.WeeklySchedule[0] = weeklySchedule + } + + if retentionPolicyChanged || dailyScheduleChanged || retentionDurationChanged || weeklyScheduleChanged || weeklyRetentionDurationChanged { + backup[0].RetentionPolicy = make([]RetentionPolicyConfiguration, 1) + backup[0].RetentionPolicy[0] = retentionPolicy + } + + return backup +} + +func flattenToListOfString(val interface{}) []string { + lis := val.([]interface{}) + strs := make([]string, len(lis)) + for i, v := range lis { + strs[i] = v.(string) + } + return strs +} diff --git a/internal/services/automanage/automanage_configuration_resource_test.go b/internal/services/automanage/automanage_configuration_resource_test.go index c61ed5f47312..14986e27402d 100644 --- a/internal/services/automanage/automanage_configuration_resource_test.go +++ b/internal/services/automanage/automanage_configuration_resource_test.go @@ -40,9 +40,6 @@ func TestAccAutoManageConfigurationProfile_antimalware(t *testing.T) { check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("antimalware.#").HasValue("1"), check.That(data.ResourceName).Key("antimalware.0.exclusions.#").HasValue("1"), - check.That(data.ResourceName).Key("antimalware.0.exclusions.0.extensions").HasValue("exe;dll"), - check.That(data.ResourceName).Key("antimalware.0.real_time_protection_enabled").HasValue("true"), - check.That(data.ResourceName).Key("automation_account_enabled").HasValue("true"), ), }, data.ImportStep(), @@ -58,6 +55,39 @@ func TestAccAutoManageConfigurationProfile_antimalware(t *testing.T) { }) } +func TestAccAutoManageConfigurationProfile_azureSecurityBaseline(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_automanage_configuration", "test") + r := AutoManageConfigurationProfileResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.azureSecurityBaseline(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("azure_security_baseline.#").HasValue("1"), + check.That(data.ResourceName).Key("azure_security_baseline.0.assignment_type").HasValue("ApplyAndAutoCorrect"), + ), + }, + data.ImportStep(), + { + Config: r.azureSecurityBaselineUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("azure_security_baseline.#").HasValue("1"), + check.That(data.ResourceName).Key("azure_security_baseline.0.assignment_type").HasValue("DeployAndAutoCorrect"), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("azure_security_baseline.#").HasValue("0"), + ), + }, + data.ImportStep(), + }) +} + func TestAccAutoManageConfigurationProfile_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_automanage_configuration", "test") r := AutoManageConfigurationProfileResource{} @@ -72,6 +102,80 @@ func TestAccAutoManageConfigurationProfile_requiresImport(t *testing.T) { }) } +func TestAccAutoManageConfigurationProfile_backup(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_automanage_configuration", "test") + r := AutoManageConfigurationProfileResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.backup(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("backup.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.policy_name").Exists(), + check.That(data.ResourceName).Key("backup.0.time_zone").HasValue("UTC"), + check.That(data.ResourceName).Key("backup.0.instant_rp_retention_range_in_days").HasValue("2"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_frequency").HasValue("Daily"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_days.#").HasValue("2"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_days.0").HasValue("Monday"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_days.1").HasValue("Tuesday"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_times.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_times.0").HasValue("12:00"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_policy_type").HasValue("SimpleSchedulePolicy"), + check.That(data.ResourceName).Key("backup.0.retention_policy.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.retention_policy_type").HasValue("LongTermRetentionPolicy"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_times.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_times.0").HasValue("12:00"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_duration.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_duration.0.count").HasValue("7"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_duration.0.duration_type").HasValue("Days"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.0.retention_times.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.0.retention_times.0").HasValue("14:00"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.0.retention_duration.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.0.retention_duration.0.count").HasValue("4"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.0.retention_duration.0.duration_type").HasValue("Weeks"), + ), + }, + data.ImportStep(), + { + Config: r.backupUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("backup.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.policy_name").Exists(), + check.That(data.ResourceName).Key("backup.0.time_zone").HasValue("UTC"), + check.That(data.ResourceName).Key("backup.0.instant_rp_retention_range_in_days").HasValue("5"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_frequency").HasValue("Daily"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_days.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_days.0").HasValue("Monday"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_times.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.schedule_policy.0.schedule_run_times.0").HasValue("12:00"), + check.That(data.ResourceName).Key("backup.0.retention_policy.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.retention_policy_type").HasValue("LongTermRetentionPolicy"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_times.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_times.0").HasValue("12:00"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_duration.#").HasValue("1"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_duration.0.count").HasValue("7"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.daily_schedule.0.retention_duration.0.duration_type").HasValue("Days"), + check.That(data.ResourceName).Key("backup.0.retention_policy.0.weekly_schedule.#").HasValue("0"), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("backup.#").HasValue("0"), + ), + }, + data.ImportStep(), + }) +} + func TestAccAutoManageConfigurationProfile_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_automanage_configuration", "test") r := AutoManageConfigurationProfileResource{} @@ -270,3 +374,116 @@ resource "azurerm_automanage_configuration" "test" { } `, template, data.RandomInteger, data.Locations.Primary) } + +func (r AutoManageConfigurationProfileResource) azureSecurityBaseline(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_automanage_configuration" "test" { + name = "acctest-amcp-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + azure_security_baseline { + assignment_type = "ApplyAndAutoCorrect" + } +} +`, template, data.RandomInteger) +} + +func (r AutoManageConfigurationProfileResource) azureSecurityBaselineUpdate(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_automanage_configuration" "test" { + name = "acctest-amcp-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + azure_security_baseline { + assignment_type = "DeployAndAutoCorrect" + } +} +`, template, data.RandomInteger) +} + +func (r AutoManageConfigurationProfileResource) backup(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_automanage_configuration" "test" { + name = "acctest-amcp-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + backup { + policy_name = "acctest-backup-policy-%d" + time_zone = "UTC" + instant_rp_retention_range_in_days = 2 + + schedule_policy { + schedule_run_frequency = "Daily" + schedule_run_days = ["Monday", "Tuesday"] + schedule_run_times = ["12:00"] + schedule_policy_type = "SimpleSchedulePolicy" + } + + retention_policy { + retention_policy_type = "LongTermRetentionPolicy" + + daily_schedule { + retention_times = ["12:00"] + retention_duration { + count = 7 + duration_type = "Days" + } + } + + weekly_schedule { + retention_times = ["14:00"] + retention_duration { + count = 4 + duration_type = "Weeks" + } + } + } + } +} +`, template, data.RandomInteger, data.RandomInteger) +} + +func (r AutoManageConfigurationProfileResource) backupUpdate(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_automanage_configuration" "test" { + name = "acctest-amcp-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + backup { + policy_name = "acctest-backup-policy-%d" + time_zone = "UTC" + instant_rp_retention_range_in_days = 5 + + schedule_policy { + schedule_run_frequency = "Daily" + schedule_run_days = ["Monday"] + schedule_run_times = ["12:00"] + } + + retention_policy { + retention_policy_type = "LongTermRetentionPolicy" + + daily_schedule { + retention_times = ["12:00"] + retention_duration { + count = 7 + duration_type = "Days" + } + } + } + } +} +`, template, data.RandomInteger, data.RandomInteger) +} diff --git a/website/docs/r/automanage_configuration.html.markdown b/website/docs/r/automanage_configuration.html.markdown index 1473202bc255..a2759a1ab6fa 100644 --- a/website/docs/r/automanage_configuration.html.markdown +++ b/website/docs/r/automanage_configuration.html.markdown @@ -37,7 +37,45 @@ resource "azurerm_automanage_configuration" "example" { scheduled_scan_time_in_minutes = 1339 } - automation_account_enabled = true + azure_security_baseline { + assignment_type = "ApplyAndAutoCorrect" + } + + automation_account_enabled = true + + backup { + policy_name = "acctest-backup-policy-%d" + time_zone = "UTC" + instant_rp_retention_range_in_days = 2 + + schedule_policy { + schedule_run_frequency = "Daily" + schedule_run_days = ["Monday", "Tuesday"] + schedule_run_times = ["12:00"] + schedule_policy_type = "SimpleSchedulePolicy" + } + + retention_policy { + retention_policy_type = "LongTermRetentionPolicy" + + daily_schedule { + retention_times = ["12:00"] + retention_duration { + count = 7 + duration_type = "Days" + } + } + + weekly_schedule { + retention_times = ["14:00"] + retention_duration { + count = 4 + duration_type = "Weeks" + } + } + } + } + boot_diagnostics_enabled = true defender_for_cloud_enabled = true guest_configuration_enabled = true @@ -61,6 +99,10 @@ The following arguments are supported: * `antimalware` - (Optional) A `antimalware` block as defined below. +* `azure_security_baseline` - (Optional) A `azure_security_baseline` block as defined below. + +* `backup` - (Optional) A `backup` block as defined below. + * `automation_account_enabled` - (Optional) Whether the automation account is enabled. Defaults to `false`. * `boot_diagnostics_enabled` - (Optional) Whether the boot diagnostics are enabled. Defaults to `false`. @@ -71,6 +113,8 @@ The following arguments are supported: * `status_change_alert_enabled` - (Optional) Whether the status change alert is enabled. Defaults to `false`. +* `tags` - (Optional) A mapping of tags to assign to the resource. + --- * `antimalware` supports the following: @@ -97,8 +141,73 @@ The following arguments are supported: * `processes` - (Optional) The processes to exclude from the antimalware scan, separated by `;`. For example `svchost.exe;notepad.exe`. -* `tags` - (Optional) A mapping of tags which should be assigned to the Automanage Configuration. +--- + +* `azure_security_baseline` supports the following: + +* `assignment_type` - (Optional) The assignment type of the azure security baseline. Possible values are `ApplyAndAutoCorrect`, `ApplyAndMonitor`, `Audit` and `DeployAndAutoCorrect`. Defaults to `ApplyAndAutoCorrect`. + +--- + +* `backup` supports the following: + +* `policy_name` - (Optional) The name of the backup policy. + +* `time_zone` - (Optional) The timezone of the backup policy. Defaults to `UTC`. + +* `instant_rp_retention_range_in_days` - (Optional) The retention range in days of the backup policy. Defaults to `5`. + +* `schedule_policy` - (Optional) A `schedule_policy` block as defined below. + +* `retention_policy` - (Optional) A `retention_policy` block as defined below. + +--- + +* `schedule_policy` supports the following: +* `schedule_run_frequency` - (Optional) The schedule run frequency of the backup policy. Possible values are `Daily` and `Weekly`. Defaults to `Daily`. + +* `schedule_run_times` - (Optional) The schedule run times of the backup policy. + +* `schedule_run_days` - (Optional) The schedule run days of the backup policy. Possible values are `Sunday`, `Monday`, `Tuesday`, `Wednesday`, `Thursday`, `Friday` and `Saturday`. + +* `schedule_policy_type` - (Optional) The schedule policy type of the backup policy. Possible value is `SimpleSchedulePolicy`. + +--- + +* `retention_policy` supports the following: + +* `retention_policy_type` - (Optional) The retention policy type of the backup policy. Possible value is `LongTermRetentionPolicy`. + +* `daily_schedule` - (Optional) A `daily_schedule` block as defined below. + +* `weekly_schedule` - (Optional) A `weekly_schedule` block as defined below. + +--- + +* `daily_schedule` supports the following: + +* `retention_times` - (Optional) The retention times of the backup policy. + +* `retention_duration` - (Optional) A `retention_duration` block as defined below. + +--- + +* `weekly_schedule` supports the following: + +* `retention_times` - (Optional) The retention times of the backup policy. + +* `retention_duration` - (Optional) A `retention_duration` block as defined below. + +--- + +* `retention_duration` supports the following: + +* `count` - (Optional) The count of the retention duration of the backup policy. Valid value inside `daily_schedule` is `7` to `9999` and inside `weekly_schedule` is `1` to `5163`. + +* `duration_type` - (Optional) The duration type of the retention duration of the backup policy. Valid value inside `daily_schedule` is `Days` and inside `weekly_schedule` is `Weeks`. + +--- ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: