Skip to content

feat(cdn): Add support for configuring WAF#1372

Open
matheuspolitano wants to merge 81 commits intostackitcloud:mainfrom
matheuspolitano:mp/cdn/feat/implement-configuring-waf
Open

feat(cdn): Add support for configuring WAF#1372
matheuspolitano wants to merge 81 commits intostackitcloud:mainfrom
matheuspolitano:mp/cdn/feat/implement-configuring-waf

Conversation

@matheuspolitano
Copy link
Copy Markdown
Contributor

@matheuspolitano matheuspolitano commented Apr 13, 2026

Description

https://jira.schwarz/browse/STACKITCDN-723

I want to add support for the waf configuration block in the CDN distribution resource,so that users can programmatically manage security tiers, paranoia levels, and granular rule overrides (Enabled/Disabled/Log-only) via Terraform.

Checklist

  • Issue was linked above
  • Code format was applied: make fmt
  • Examples were added / adjusted (see examples/ directory)
  • Docs are up-to-date: make generate-docs (will be checked by CI)
  • Unit tests got implemented or updated
  • Acceptance tests got implemented or updated (see e.g. here)
  • Unit tests are passing: make test (will be checked by CI)
  • No linter issues: make lint (will be checked by CI)

@matheuspolitano matheuspolitano requested a review from a team as a code owner April 13, 2026 13:30
@matheuspolitano matheuspolitano changed the title Mp/cdn/feat/implement configuring waf feat(cdn): Add support for configuring WAF Apr 13, 2026
@matheuspolitano
Copy link
Copy Markdown
Contributor Author

@Fyusel @marceljk Kindly prioritize the review of PR #1333, as the current pull request builds upon those changes.

Comment thread stackit/internal/services/cdn/distribution/datasource.go Outdated
Comment thread stackit/internal/services/cdn/distribution/resource.go Outdated
Comment on lines +1752 to +1765

// getWafSet extracts strings from HCL set, sorts them and returns the slice
func getWafSet(ctx context.Context, tfSet basetypes.SetValue) []string {
if utils.IsUndefined(tfSet) {
return nil
}
var elements []string
diags := tfSet.ElementsAs(ctx, &elements, true)
if diags.HasError() {
return []string{}
}
sort.Strings(elements)
return elements
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it needed to sort the slice? Takes the API care of the order? If not, you can use conversion.StringSetToSlice() instead this function, there you shouldn't ignore the error like it was done here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've removed the sort

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, remove this function and use instead everywhere conversion.StringSetToSlice()

Suggested change
// getWafSet extracts strings from HCL set, sorts them and returns the slice
func getWafSet(ctx context.Context, tfSet basetypes.SetValue) []string {
if utils.IsUndefined(tfSet) {
return nil
}
var elements []string
diags := tfSet.ElementsAs(ctx, &elements, true)
if diags.HasError() {
return []string{}
}
sort.Strings(elements)
return elements
}

Comment thread stackit/internal/services/cdn/distribution/resource.go Outdated
Comment on lines +1322 to +1327
mapWafString := func(apiVal *string) types.String {
if apiVal != nil {
return types.StringValue(*apiVal)
}
return types.StringNull()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use the function types.StringPointerValue() from the terraform framework itself instead of this function

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant here to remove the whole mapWafString function and use everywhere types.StringPointerValue() instead. It does the same thing but keeps the code clean because this is a function of the framework

Suggested change
mapWafString := func(apiVal *string) types.String {
if apiVal != nil {
return types.StringValue(*apiVal)
}
return types.StringNull()
}

Comment thread stackit/internal/services/cdn/distribution/resource.go Outdated
Comment thread stackit/internal/services/cdn/cdn_acc_test.go Outdated
Comment thread stackit/internal/services/cdn/cdn_acc_test.go
Comment thread stackit/internal/services/cdn/cdn_acc_test.go Outdated
Comment thread stackit/internal/services/cdn/cdn_acc_test.go Outdated
Comment thread stackit/internal/services/cdn/distribution/resource.go
Comment thread stackit/internal/services/cdn/distribution/resource.go Outdated
Comment on lines +1322 to +1327
mapWafString := func(apiVal *string) types.String {
if apiVal != nil {
return types.StringValue(*apiVal)
}
return types.StringNull()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant here to remove the whole mapWafString function and use everywhere types.StringPointerValue() instead. It does the same thing but keeps the code clean because this is a function of the framework

Suggested change
mapWafString := func(apiVal *string) types.String {
if apiVal != nil {
return types.StringValue(*apiVal)
}
return types.StringNull()
}

Comment on lines +1752 to +1765

// getWafSet extracts strings from HCL set, sorts them and returns the slice
func getWafSet(ctx context.Context, tfSet basetypes.SetValue) []string {
if utils.IsUndefined(tfSet) {
return nil
}
var elements []string
diags := tfSet.ElementsAs(ctx, &elements, true)
if diags.HasError() {
return []string{}
}
sort.Strings(elements)
return elements
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, remove this function and use instead everywhere conversion.StringSetToSlice()

Suggested change
// getWafSet extracts strings from HCL set, sorts them and returns the slice
func getWafSet(ctx context.Context, tfSet basetypes.SetValue) []string {
if utils.IsUndefined(tfSet) {
return nil
}
var elements []string
diags := tfSet.ElementsAs(ctx, &elements, true)
if diags.HasError() {
return []string{}
}
sort.Strings(elements)
return elements
}

Comment on lines +1751 to +1760
// Helper to unconditionally map set fields
func mustMapStringSet(ctx context.Context, apiList []string) types.Set {
if apiList != nil {
setVal, diags := types.SetValueFrom(ctx, types.StringType, apiList)
if !diags.HasError() {
return setVal
}
}
return types.SetNull(types.StringType)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to the conversion package and name it to something like SliceToStringSet and avoid context if possible and don't ignore the error.

Could be something like this:

func SliceToStringSet(list []string) (types.Set, error) {
	if list == nil {
		return types.SetNull(types.StringType), nil
	}
	set := make([]attr.Value, len(list))
	for idx, v := range list {
		stringValue := types.StringValue(v)
		set[idx] = stringValue
	}
	result, diags := types.SetValue(types.StringType, set)
	if diags.HasError() {
		return types.SetNull(types.StringType), fmt.Errorf("converting to SetValue: %v", diags.Errors())
	}
	return result, nil
}

Comment on lines +1346 to +1352
isWafDisabled := (distribution.Config.Waf.Mode == cdnSdk.WAFMODE_DISABLED) &&
(distribution.Config.Waf.Type == cdnSdk.WAFTYPE_FREE)

var wafVal attr.Value
if isWafDisabled && (isImport || utils.IsUndefined(oldConfig.Waf)) {
wafVal = types.ObjectNull(wafTypes)
} else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against this workaround here. The datasource shows always waf with the attributes and the resource should behave the same, even if it's not configured by the customer

Comment on lines +231 to +232
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.waf.allowed_http_methods.#", "1"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.waf.allowed_http_methods.0", "GET"),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't set the values here by hand. Use them from you config.

Suggested change
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.waf.allowed_http_methods.#", "1"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.waf.allowed_http_methods.0", "GET"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.waf.allowed_http_methods.#", "1"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.waf.allowed_http_methods.0", testConfigVarsHttp["waf_allowed_http_methods"]),

Change it also for all other checks, even in the Read via datasource and update step

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants