Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## [Unreleased]

- Fix regression restricting the characters in an `elasticstack_elasticsearch_role_mapping` `name`. ([#1373](https://github.com/elastic/terraform-provider-elasticstack/pull/1373))
- Add schema validations to require either (but not both) `index` and `data_view_id` is set for relevant Security Detection Rules

## [0.12.0] - 2025-10-15

Expand Down
7 changes: 2 additions & 5 deletions internal/fleet/output/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,18 +152,15 @@ func getSchema() schema.Schema {
int64planmodifier.UseStateForUnknown(),
},
Validators: []validator.Int64{
validators.Int64ConditionalRequirement(
path.Root("kafka").AtName("compression"),
[]string{"gzip"},
),
validators.AllowedIfDependentPathEquals(path.Root("kafka").AtName("compression"), "gzip"),
},
},
"connection_type": schema.StringAttribute{
Description: "Connection type for Kafka output.",
Optional: true,
Validators: []validator.String{
stringvalidator.OneOf("plaintext", "encryption"),
validators.StringConditionalRequirementSingle(
validators.AllowedIfDependentPathEquals(
path.Root("kafka").AtName("auth_type"),
"none",
),
Expand Down
219 changes: 188 additions & 31 deletions internal/kibana/security_detection_rule/acc_test.go

Large diffs are not rendered by default.

32 changes: 0 additions & 32 deletions internal/kibana/security_detection_rule/models_esql.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
)

Expand Down Expand Up @@ -59,35 +58,10 @@ func (e EsqlRuleProcessor) ExtractId(response any) (string, diag.Diagnostics) {
return value.Id.String(), diags
}

// applyEsqlValidations validates that ESQL-specific constraints are met
func (d SecurityDetectionRuleData) applyEsqlValidations(diags *diag.Diagnostics) {
if utils.IsKnown(d.Index) {
diags.AddAttributeError(
path.Root("index"),
"Invalid attribute 'index'",
"ESQL rules do not use index patterns. Please remove the 'index' attribute.",
)
}

if utils.IsKnown(d.Filters) {
diags.AddAttributeError(
path.Root("filters"),
"Invalid attribute 'filters'",
"ESQL rules do not support filters. Please remove the 'filters' attribute.",
)
}
}

func (d SecurityDetectionRuleData) toEsqlRuleCreateProps(ctx context.Context, client clients.MinVersionEnforceable) (kbapi.SecurityDetectionsAPIRuleCreateProps, diag.Diagnostics) {
var diags diag.Diagnostics
var createProps kbapi.SecurityDetectionsAPIRuleCreateProps

// Apply ESQL-specific validations
d.applyEsqlValidations(&diags)
if diags.HasError() {
return createProps, diags
}

esqlRule := kbapi.SecurityDetectionsAPIEsqlRuleCreateProps{
Name: kbapi.SecurityDetectionsAPIRuleName(d.Name.ValueString()),
Description: kbapi.SecurityDetectionsAPIRuleDescription(d.Description.ValueString()),
Expand Down Expand Up @@ -153,12 +127,6 @@ func (d SecurityDetectionRuleData) toEsqlRuleUpdateProps(ctx context.Context, cl
var diags diag.Diagnostics
var updateProps kbapi.SecurityDetectionsAPIRuleUpdateProps

// Apply ESQL-specific validations
d.applyEsqlValidations(&diags)
if diags.HasError() {
return updateProps, diags
}

// Parse ID to get space_id and rule_id
compId, resourceIdDiags := clients.CompositeIdFromStrFw(d.Id.ValueString())
diags.Append(resourceIdDiags...)
Expand Down
21 changes: 0 additions & 21 deletions internal/kibana/security_detection_rule/models_machine_learning.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,10 @@ func (m MachineLearningRuleProcessor) ExtractId(response any) (string, diag.Diag
return value.Id.String(), diags
}

// applyMachineLearningValidations validates that Machine learning-specific constraints are met
func (d SecurityDetectionRuleData) applyMachineLearningValidations(diags *diag.Diagnostics) {
if !utils.IsKnown(d.AnomalyThreshold) {
diags.AddAttributeError(
path.Root("anomaly_threshold"),
"Missing attribute 'anomaly_threshold'",
"Machine learning rules require an 'anomaly_threshold' attribute.",
)
}
}

func (d SecurityDetectionRuleData) toMachineLearningRuleCreateProps(ctx context.Context, client clients.MinVersionEnforceable) (kbapi.SecurityDetectionsAPIRuleCreateProps, diag.Diagnostics) {
var diags diag.Diagnostics
var createProps kbapi.SecurityDetectionsAPIRuleCreateProps

d.applyMachineLearningValidations(&diags)
if diags.HasError() {
return createProps, diags
}

mlRule := kbapi.SecurityDetectionsAPIMachineLearningRuleCreateProps{
Name: kbapi.SecurityDetectionsAPIRuleName(d.Name.ValueString()),
Description: kbapi.SecurityDetectionsAPIRuleDescription(d.Description.ValueString()),
Expand Down Expand Up @@ -156,11 +140,6 @@ func (d SecurityDetectionRuleData) toMachineLearningRuleUpdateProps(ctx context.
var diags diag.Diagnostics
var updateProps kbapi.SecurityDetectionsAPIRuleUpdateProps

d.applyMachineLearningValidations(&diags)
if diags.HasError() {
return updateProps, diags
}

// Parse ID to get space_id and rule_id
compId, resourceIdDiags := clients.CompositeIdFromStrFw(d.Id.ValueString())
diags.Append(resourceIdDiags...)
Expand Down
65 changes: 65 additions & 0 deletions internal/kibana/security_detection_rule/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import (
"context"
"regexp"

"github.com/elastic/terraform-provider-elasticstack/internal/utils"
"github.com/elastic/terraform-provider-elasticstack/internal/utils/customtypes"
"github.com/elastic/terraform-provider-elasticstack/internal/utils/validators"
"github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
Expand Down Expand Up @@ -73,6 +76,13 @@ func GetSchema() schema.Schema {
"data_view_id": schema.StringAttribute{
MarkdownDescription: "Data view ID for the rule. Not supported for esql and machine_learning rule types.",
Optional: true,
Validators: []validator.String{
// Enforce that data_view_id is not set if the rule type is ml or esql
validators.ForbiddenIfDependentPathOneOf(
path.Root("type"),
[]string{"machine_learning", "esql"},
),
},
},
"namespace": schema.StringAttribute{
MarkdownDescription: "Alerts index namespace. Available for all rule types.",
Expand Down Expand Up @@ -108,6 +118,13 @@ func GetSchema() schema.Schema {
MarkdownDescription: "Indices on which the rule functions.",
Optional: true,
Computed: true,
Validators: []validator.List{
// Enforce that index is not set if the rule type is ml or esql
validators.ForbiddenIfDependentPathOneOf(
path.Root("type"),
[]string{"machine_learning", "esql"},
),
},
},
"enabled": schema.BoolAttribute{
MarkdownDescription: "Determines whether the rule is enabled.",
Expand Down Expand Up @@ -302,6 +319,12 @@ func GetSchema() schema.Schema {
MarkdownDescription: "Query and filter context array to define alert conditions as JSON. Supports complex filter structures including bool queries, term filters, range filters, etc. Available for all rule types.",
Optional: true,
CustomType: jsontypes.NormalizedType{},
Validators: []validator.String{
validators.ForbiddenIfDependentPathOneOf(
path.Root("type"),
[]string{"machine_learning", "esql"},
),
},
},
"note": schema.StringAttribute{
MarkdownDescription: "Notes to help investigate alerts produced by the rule.",
Expand Down Expand Up @@ -602,6 +625,10 @@ func GetSchema() schema.Schema {
MarkdownDescription: "Anomaly score threshold above which the rule creates an alert. Valid values are from 0 to 100. Required for machine_learning rules.",
Optional: true,
Validators: []validator.Int64{
validators.RequiredIfDependentPathEquals(
path.Root("type"),
"machine_learning",
),
int64validator.Between(0, 100),
},
},
Expand Down Expand Up @@ -913,3 +940,41 @@ func getThreatSubtechniqueElementType() attr.Type {
techniqueType := threatType.AttributeTypes()["technique"].(attr.TypeWithElementType).ElementType().(attr.TypeWithAttributeTypes)
return techniqueType.AttributeTypes()["subtechnique"].(attr.TypeWithElementType).ElementType()
}

// ValidateConfig validates the configuration for a security detection rule resource.
// It ensures that the configuration meets the following requirements:
//
// - For rule types "esql" and "machine_learning", no additional validation is performed
// - For other rule types, exactly one of 'index' or 'data_view_id' must be specified
// - Both 'index' and 'data_view_id' cannot be set simultaneously
//
// The function adds appropriate error diagnostics if validation fails.
func (r securityDetectionRuleResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
var data SecurityDetectionRuleData

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

if data.Type.ValueString() == "esql" || data.Type.ValueString() == "machine_learning" {
return
}

if utils.IsKnown(data.Index) && utils.IsKnown(data.DataViewId) {
resp.Diagnostics.AddError(
"Invalid Configuration",
"Both 'index' and 'data_view_id' cannot be set at the same time.",
)

}

if !utils.IsKnown(data.Index) && !utils.IsKnown(data.DataViewId) {
resp.Diagnostics.AddError(
"Invalid Configuration",
"One of 'index' or 'data_view_id' must be set.",
)

}
}
Loading
Loading