Skip to content

Commit

Permalink
Initial Check-in...
Browse files Browse the repository at this point in the history
  • Loading branch information
WodansSon committed Dec 14, 2024
1 parent 8649171 commit bcd72ed
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ func dataSourceCdnFrontDoorFirewallPolicy() *pluginsdk.Resource {
Computed: true,
},

"js_challenge_cookie_expiration_in_minutes": {
Type: pluginsdk.TypeInt,
Computed: true,
},

"redirect_url": {
Type: pluginsdk.TypeString,
Computed: true,
Expand Down Expand Up @@ -103,6 +108,10 @@ func dataSourceCdnFrontDoorFirewallPolicyRead(d *pluginsdk.ResourceData, meta in
d.Set("enabled", pointer.From(policy.EnabledState) == waf.PolicyEnabledStateEnabled)
d.Set("mode", pointer.From(policy.Mode))
d.Set("redirect_url", policy.RedirectURL)

if policy.JavascriptChallengeExpirationInMinutes != nil {
d.Set("js_challenge_cookie_expiration_in_minutes", int(pointer.From(policy.JavascriptChallengeExpirationInMinutes)))
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,38 @@ func TestAccCdnFrontDoorFirewallPolicyDataSource_basic(t *testing.T) {
})
}

func TestAccCdnFrontDoorFirewallPolicyJsChallengeDataSource_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_cdn_frontdoor_firewall_policy", "test")
d := CdnFrontDoorFirewallPolicyDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: d.basicJsChallenge(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("redirect_url").MatchesOtherKey(check.That("azurerm_cdn_frontdoor_firewall_policy.test").Key("redirect_url")),
),
},
})
}

func (CdnFrontDoorFirewallPolicyDataSource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
data "azurerm_cdn_frontdoor_firewall_policy" "test" {
name = azurerm_cdn_frontdoor_firewall_policy.test.name
name = "accTestDataSourceBasic-%d"
resource_group_name = azurerm_cdn_frontdoor_profile.test.resource_group_name
}
`, CdnFrontDoorFirewallPolicyResource{}.basic(data), data.RandomInteger)
}

func (CdnFrontDoorFirewallPolicyDataSource) basicJsChallenge(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
data "azurerm_cdn_frontdoor_firewall_policy" "test" {
name = "accTestDataSourceJsChallenge-%d"
resource_group_name = azurerm_cdn_frontdoor_profile.test.resource_group_name
}
`, CdnFrontDoorFirewallPolicyResource{}.complete(data))
`, CdnFrontDoorFirewallPolicyResource{}.basicJsChallenge(data), data.RandomInteger)
}
25 changes: 24 additions & 1 deletion internal/services/cdn/cdn_frontdoor_firewall_policy_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ func resourceCdnFrontDoorFirewallPolicy() *pluginsdk.Resource {
Default: true,
},

// NOTE: This cannot have a default value as that would always set the js challenge expiration
// value meaning you could not remove that policy from the WAF and would be a breaking change
// to pre-existing resources...
"js_challenge_cookie_expiration_in_minutes": {
Type: pluginsdk.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(5, 1440),
},

"redirect_url": {
Type: pluginsdk.TypeString,
Optional: true,
Expand Down Expand Up @@ -490,6 +499,7 @@ func resourceCdnFrontDoorFirewallPolicyCreate(d *pluginsdk.ResourceData, meta in
sku := d.Get("sku_name").(string)
mode := waf.PolicyMode(d.Get("mode").(string))
redirectUrl := d.Get("redirect_url").(string)
jsChallengeExpirationInMinutes := int64(d.Get("js_challenge_cookie_expiration_in_minutes").(int))
customBlockResponseStatusCode := d.Get("custom_block_response_status_code").(int)
customBlockResponseBody := d.Get("custom_block_response_body").(string)
customRules := d.Get("custom_rule").([]interface{})
Expand Down Expand Up @@ -518,6 +528,10 @@ func resourceCdnFrontDoorFirewallPolicyCreate(d *pluginsdk.ResourceData, meta in
Tags: tags.Expand(d.Get("tags").(map[string]interface{})),
}

if jsChallengeExpirationInMinutes > 0 {
payload.Properties.PolicySettings.JavascriptChallengeExpirationInMinutes = pointer.To(jsChallengeExpirationInMinutes)
}

if managedRules != nil {
payload.Properties.ManagedRules = managedRules
}
Expand Down Expand Up @@ -570,7 +584,7 @@ func resourceCdnFrontDoorFirewallPolicyUpdate(d *pluginsdk.ResourceData, meta in

props := *model.Properties

if d.HasChanges("custom_block_response_body", "custom_block_response_status_code", "enabled", "mode", "redirect_url", "request_body_check_enabled") {
if d.HasChanges("custom_block_response_body", "custom_block_response_status_code", "enabled", "mode", "redirect_url", "request_body_check_enabled", "js_challenge_cookie_expiration_in_minutes") {
enabled := waf.PolicyEnabledStateDisabled
if d.Get("enabled").(bool) {
enabled = waf.PolicyEnabledStateEnabled
Expand All @@ -580,12 +594,17 @@ func resourceCdnFrontDoorFirewallPolicyUpdate(d *pluginsdk.ResourceData, meta in
if d.Get("request_body_check_enabled").(bool) {
requestBodyCheck = waf.PolicyRequestBodyCheckEnabled
}

props.PolicySettings = &waf.PolicySettings{
EnabledState: pointer.To(enabled),
Mode: pointer.To(waf.PolicyMode(d.Get("mode").(string))),
RequestBodyCheck: pointer.To(requestBodyCheck),
}

if jsChallengeExpirationInMinutes := int64(d.Get("js_challenge_cookie_expiration_in_minutes").(int)); jsChallengeExpirationInMinutes > 0 {
props.PolicySettings.JavascriptChallengeExpirationInMinutes = pointer.To(jsChallengeExpirationInMinutes)
}

if redirectUrl := d.Get("redirect_url").(string); redirectUrl != "" {
props.PolicySettings.RedirectURL = pointer.To(redirectUrl)
}
Expand Down Expand Up @@ -679,6 +698,10 @@ func resourceCdnFrontDoorFirewallPolicyRead(d *pluginsdk.ResourceData, meta inte
d.Set("redirect_url", policy.RedirectURL)
d.Set("custom_block_response_status_code", int(pointer.From(policy.CustomBlockResponseStatusCode)))
d.Set("custom_block_response_body", policy.CustomBlockResponseBody)

if policy.JavascriptChallengeExpirationInMinutes != nil {
d.Set("js_challenge_cookie_expiration_in_minutes", int(pointer.From(policy.JavascriptChallengeExpirationInMinutes)))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ func TestAccCdnFrontDoorFirewallPolicy_basic(t *testing.T) {
})
}

func TestAccCdnFrontDoorFirewallPolicyJsChallenge_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test")
r := CdnFrontDoorFirewallPolicyResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basicJsChallenge(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("js_challenge_cookie_expiration_in_minutes").HasValue("30"),
),
},
data.ImportStep(),
})
}

func TestAccCdnFrontDoorFirewallPolicy_requiresImport(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test")
r := CdnFrontDoorFirewallPolicyResource{}
Expand Down Expand Up @@ -75,6 +90,47 @@ func TestAccCdnFrontDoorFirewallPolicy_update(t *testing.T) {
})
}

func TestAccCdnFrontDoorFirewallPolicyJsChallenge_update(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test")
r := CdnFrontDoorFirewallPolicyResource{}
data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("request_body_check_enabled").HasValue("false"),
check.That(data.ResourceName).Key("js_challenge_cookie_expiration_in_minutes").DoesNotExist(),
),
},
data.ImportStep(),
{
Config: r.basicJsChallenge(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("js_challenge_cookie_expiration_in_minutes").HasValue("30"),
),
},
data.ImportStep(),
{
Config: r.basicJsChallengeUpdate(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("js_challenge_cookie_expiration_in_minutes").HasValue("1440"),
),
},
data.ImportStep(),
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("request_body_check_enabled").HasValue("false"),
check.That(data.ResourceName).Key("js_challenge_cookie_expiration_in_minutes").DoesNotExist(),
),
},
data.ImportStep(),
})
}

func TestAccCdnFrontDoorFirewallPolicy_complete(t *testing.T) {
// NOTE: Regression test case for issue #19088
data := acceptance.BuildTestData(t, "azurerm_cdn_frontdoor_firewall_policy", "test")
Expand Down Expand Up @@ -303,6 +359,38 @@ resource "azurerm_cdn_frontdoor_firewall_policy" "test" {
`, tmp, data.RandomInteger)
}

func (r CdnFrontDoorFirewallPolicyResource) basicJsChallenge(data acceptance.TestData) string {
tmp := r.template(data)
return fmt.Sprintf(`
%s
resource "azurerm_cdn_frontdoor_firewall_policy" "test" {
name = "accTestWAF%d"
resource_group_name = azurerm_resource_group.test.name
sku_name = azurerm_cdn_frontdoor_profile.test.sku_name
mode = "Prevention"
js_challenge_cookie_expiration_in_minutes = 30
}
`, tmp, data.RandomInteger)
}

func (r CdnFrontDoorFirewallPolicyResource) basicJsChallengeUpdate(data acceptance.TestData) string {
tmp := r.template(data)
return fmt.Sprintf(`
%s
resource "azurerm_cdn_frontdoor_firewall_policy" "test" {
name = "accTestWAF%d"
resource_group_name = azurerm_resource_group.test.name
sku_name = azurerm_cdn_frontdoor_profile.test.sku_name
mode = "Prevention"
js_challenge_cookie_expiration_in_minutes = 1440
}
`, tmp, data.RandomInteger)
}

func (r CdnFrontDoorFirewallPolicyResource) requiresImport(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
Expand Down Expand Up @@ -389,6 +477,8 @@ resource "azurerm_cdn_frontdoor_firewall_policy" "test" {
custom_block_response_status_code = 403
custom_block_response_body = "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg=="
js_challenge_cookie_expiration_in_minutes = 30
custom_rule {
name = "Rule1"
enabled = true
Expand Down
2 changes: 2 additions & 0 deletions website/docs/d/cdn_frontdoor_firewall_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ The following attributes are exported:

* `frontend_endpoint_ids` - The Front Door Profiles frontend endpoints associated with this Front Door Firewall Policy.

* `js_challenge_cookie_expiration_in_minutes` - The Front Door Firewall Policy JavaScript challenge cookie lifetime in minutes.

* `mode` - The Front Door Firewall Policy mode.

* `redirect_url` - The redirect URL for the client.
Expand Down
14 changes: 9 additions & 5 deletions website/docs/r/cdn_frontdoor_firewall_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,19 @@ The following arguments are supported:

* `sku_name` - (Required) The sku's pricing tier for this Front Door Firewall Policy. Possible values include `Standard_AzureFrontDoor` or `Premium_AzureFrontDoor`. Changing this forces a new resource to be created.

-> **NOTE:** The `Standard_AzureFrontDoor` Front Door Firewall Policy sku may contain `custom` rules only. The `Premium_AzureFrontDoor` Front Door Firewall Policy skus may contain both `custom` and `managed` rules.
-> **Note:** The `Standard_AzureFrontDoor` Front Door Firewall Policy sku may contain `custom` rules only. The `Premium_AzureFrontDoor` Front Door Firewall Policy skus may contain both `custom` and `managed` rules.

* `enabled` - (Optional) Is the Front Door Firewall Policy enabled? Defaults to `true`.

* `js_challenge_cookie_expiration_in_minutes` - (Optional) Specifies the JavaScript challenge cookie lifetime in minutes, after which the user will be revalidated. Possible values are between `5` to `1440` minutes.

!> **Important:** Azure Web Application Firewall JavaScript challenge is currently in **PREVIEW**. See the [Supplemental Terms of Use for Microsoft Azure Previews](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) for legal terms that apply to Azure features that are in beta, preview, or otherwise not yet released into general availability.

* `mode` - (Required) The Front Door Firewall Policy mode. Possible values are `Detection`, `Prevention`.

* `request_body_check_enabled` - (Optional) Should policy managed rules inspect the request body content? Defaults to `true`.

-> **NOTE:** When run in `Detection` mode, the Front Door Firewall Policy doesn't take any other actions other than monitoring and logging the request and its matched Front Door Rule to the Web Application Firewall logs.
-> **Note:** When run in `Detection` mode, the Front Door Firewall Policy doesn't take any other actions other than monitoring and logging the request and its matched Front Door Rule to the Web Application Firewall logs.

* `redirect_url` - (Optional) If action type is redirect, this field represents redirect URL for the client.

Expand Down Expand Up @@ -227,7 +231,7 @@ A `rule` block supports the following:

* `action` - (Required) The action to be applied when the managed rule matches or when the anomaly score is 5 or greater. Possible values for DRS `1.1` and below are `Allow`, `Log`, `Block`, and `Redirect`. For DRS `2.0` and above the possible values are `Log` or `AnomalyScoring`.

->**NOTE:** Please see the DRS [product documentation](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-drs?tabs=drs20#anomaly-scoring-mode) for more information.
->**Note:** Please see the DRS [product documentation](https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-drs?tabs=drs20#anomaly-scoring-mode) for more information.

* `enabled` - (Optional) Is the managed rule override enabled or disabled. Defaults to `false`

Expand All @@ -239,13 +243,13 @@ An `exclusion` block supports the following:

* `match_variable` - (Required) The variable type to be excluded. Possible values are `QueryStringArgNames`, `RequestBodyPostArgNames`, `RequestCookieNames`, `RequestHeaderNames`, `RequestBodyJsonArgNames`

-> **NOTE:** `RequestBodyJsonArgNames` is only available on Default Rule Set (DRS) 2.0 or later
-> **Note:** `RequestBodyJsonArgNames` is only available on Default Rule Set (DRS) 2.0 or later

* `operator` - (Required) Comparison operator to apply to the selector when specifying which elements in the collection this exclusion applies to. Possible values are: `Equals`, `Contains`, `StartsWith`, `EndsWith`, `EqualsAny`.

* `selector` - (Required) Selector for the value in the `match_variable` attribute this exclusion applies to.

-> **NOTE:** `selector` must be set to `*` if `operator` is set to `EqualsAny`.
-> **Note:** `selector` must be set to `*` if `operator` is set to `EqualsAny`.

## Attributes Reference

Expand Down

0 comments on commit bcd72ed

Please sign in to comment.