diff --git a/.changelog/2351.txt b/.changelog/2351.txt new file mode 100644 index 0000000000..845ef99d95 --- /dev/null +++ b/.changelog/2351.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/cloudflare_access_policy: Add isolation_required flag +``` diff --git a/docs/resources/access_policy.md b/docs/resources/access_policy.md index 6b67373c9a..d16a7f13aa 100644 --- a/docs/resources/access_policy.md +++ b/docs/resources/access_policy.md @@ -75,6 +75,7 @@ resource "cloudflare_access_policy" "test_policy" { - `approval_group` (Block List) (see [below for nested schema](#nestedblock--approval_group)) - `approval_required` (Boolean) - `exclude` (Block List) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--exclude)) +- `isolation_required` (Boolean) Require this application to be served in an isolated browser for users matching this policy. - `purpose_justification_prompt` (String) The prompt to display to the user for a justification for accessing the resource. Required when using `purpose_justification_required`. - `purpose_justification_required` (Boolean) Whether to prompt the user for a justification for accessing the resource. - `require` (Block List) A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions). (see [below for nested schema](#nestedblock--require)) diff --git a/internal/sdkv2provider/resource_cloudflare_access_policy.go b/internal/sdkv2provider/resource_cloudflare_access_policy.go index c5fefd2d53..6b161535e1 100644 --- a/internal/sdkv2provider/resource_cloudflare_access_policy.go +++ b/internal/sdkv2provider/resource_cloudflare_access_policy.go @@ -99,6 +99,10 @@ func resourceCloudflareAccessPolicyRead(ctx context.Context, d *schema.ResourceD return diag.FromErr(fmt.Errorf("failed to set include attribute: %w", err)) } + if accessPolicy.IsolationRequired != nil { + d.Set("isolation_required", accessPolicy.IsolationRequired) + } + if accessPolicy.PurposeJustificationRequired != nil { d.Set("purpose_justification_required", accessPolicy.PurposeJustificationRequired) } @@ -270,6 +274,9 @@ func appendConditionalAccessPolicyFields(policy cloudflare.AccessPolicy, d *sche } } + isolationRequired := d.Get("isolation_required").(bool) + policy.IsolationRequired = &isolationRequired + purposeJustificationRequired := d.Get("purpose_justification_required").(bool) policy.PurposeJustificationRequired = &purposeJustificationRequired diff --git a/internal/sdkv2provider/resource_cloudflare_access_policy_test.go b/internal/sdkv2provider/resource_cloudflare_access_policy_test.go index 483b60eeca..dd1415384c 100644 --- a/internal/sdkv2provider/resource_cloudflare_access_policy_test.go +++ b/internal/sdkv2provider/resource_cloudflare_access_policy_test.go @@ -864,3 +864,53 @@ func testAccessPolicyExternalEvalautionConfig(resourceID, zone, accountID string `, resourceID, zone, accountID) } + +func TestAccCloudflareAccessPolicy_IsolationRequired(t *testing.T) { + rnd := generateRandomResourceName() + name := "cloudflare_access_policy." + rnd + zone := os.Getenv("CLOUDFLARE_DOMAIN") + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckAccount(t) + }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: testAccessPolicyIsolationRequiredConfig(rnd, zone, accountID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), + resource.TestCheckResourceAttr(name, "isolation_required", "true"), + ), + }, + }, + }) +} + +func testAccessPolicyIsolationRequiredConfig(resourceID, zone, accountID string) string { + return fmt.Sprintf(` + resource "cloudflare_access_application" "%[1]s" { + name = "%[1]s" + account_id = "%[3]s" + domain = "%[1]s.%[2]s" + } + + resource "cloudflare_access_policy" "%[1]s" { + application_id = cloudflare_access_application.%[1]s.id + name = "%[1]s" + account_id = "%[3]s" + decision = "allow" + precedence = "1" + + include { + email = ["a@example.com", "b@example.com"] + } + + isolation_required = "true" + } + + `, resourceID, zone, accountID) +} diff --git a/internal/sdkv2provider/schema_cloudflare_access_policy.go b/internal/sdkv2provider/schema_cloudflare_access_policy.go index b276377170..4df70f820c 100644 --- a/internal/sdkv2provider/schema_cloudflare_access_policy.go +++ b/internal/sdkv2provider/schema_cloudflare_access_policy.go @@ -63,6 +63,11 @@ func resourceCloudflareAccessPolicySchema() map[string]*schema.Schema { Elem: AccessGroupOptionSchemaElement, Description: "A series of access conditions, see [Access Groups](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/access_group#conditions).", }, + "isolation_required": { + Type: schema.TypeBool, + Optional: true, + Description: "Require this application to be served in an isolated browser for users matching this policy.", + }, "purpose_justification_required": { Type: schema.TypeBool, Optional: true,