Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for external evaluation as a new access group rule #1625

Merged
merged 9 commits into from
May 25, 2022
3 changes: 3 additions & 0 deletions .changelog/1623.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_access_group: add support for external evaluation as a new access group rule
```
27 changes: 27 additions & 0 deletions internal/provider/resource_cloudflare_access_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,17 @@ func BuildAccessGroupCondition(options map[string]interface{}) []interface{} {
IdentityProviderID: samlCfg["identity_provider_id"].(string),
}})
}
} else if accessGroupType == "external_evaluation" {
for _, v := range values.([]interface{}) {
eeCfg := v.(map[string]interface{})
group = append(group, cloudflare.AccessGroupExternalEvaluation{ExternalEvaluation: struct {
EvaluateURL string `json:"evaluate_url"`
KeysURL string `json:"keys_url"`
}{
EvaluateURL: eeCfg["evaluate_url"].(string),
KeysURL: eeCfg["keys_url"].(string),
}})
}
} else {
for _, value := range values.([]interface{}) {
switch accessGroupType {
Expand Down Expand Up @@ -376,6 +387,8 @@ func TransformAccessGroupForSchema(ctx context.Context, accessGroup []interface{
azureIDs := []string{}
samlAttrName := ""
samlAttrValue := ""
externalEvaluationURL := ""
externalEvaluationKeysURL := ""
devicePostureRuleIDs := []string{}

for _, group := range accessGroup {
Expand Down Expand Up @@ -440,6 +453,10 @@ func TransformAccessGroupForSchema(ctx context.Context, accessGroup []interface{
samlCfg := groupValue.(map[string]interface{})
samlAttrName = samlCfg["attribute_name"].(string)
samlAttrValue = samlCfg["attribute_value"].(string)
case "external_evaluation":
eeCfg := groupValue.(map[string]interface{})
externalEvaluationURL = eeCfg["evaluate_url"].(string)
externalEvaluationKeysURL = eeCfg["keys_url"].(string)
case "group":
for _, group := range groupValue.(map[string]interface{}) {
groups = append(groups, group.(string))
Expand Down Expand Up @@ -553,6 +570,16 @@ func TransformAccessGroupForSchema(ctx context.Context, accessGroup []interface{
})
}

if externalEvaluationURL != "" && externalEvaluationKeysURL != "" {
data = append(data, map[string]interface{}{
"external_evaluation": []interface{}{
map[string]interface{}{
"evaluate_url": externalEvaluationURL,
"keys_url": externalEvaluationKeysURL,
}},
})
}

if len(groups) > 0 {
data = append(data, map[string]interface{}{
"group": groups,
Expand Down
82 changes: 67 additions & 15 deletions internal/provider/resource_cloudflare_access_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccCloudflareAccessPolicyServiceToken(t *testing.T) {
func TestAccCloudflareAccessPolicy_ServiceToken(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
// service does not yet support the API tokens and it results in
// misleading state error messages.
Expand Down Expand Up @@ -43,7 +43,7 @@ func TestAccCloudflareAccessPolicyServiceToken(t *testing.T) {
})
}

func TestAccCloudflareAccessPolicyAnyServiceToken(t *testing.T) {
func TestAccCloudflareAccessPolicy_AnyServiceToken(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand All @@ -68,7 +68,7 @@ func TestAccCloudflareAccessPolicyAnyServiceToken(t *testing.T) {
})
}

func TestAccCloudflareAccessPolicyWithZoneID(t *testing.T) {
func TestAccCloudflareAccessPolicy_WithZoneID(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -197,7 +197,7 @@ func testAccessPolicyWithZoneIDUpdated(resourceID, zone, zoneID string) string {
`, resourceID, zone, zoneID)
}

func TestAccCloudflareAccessPolicyGroup(t *testing.T) {
func TestAccCloudflareAccessPolicy_Group(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -254,7 +254,7 @@ func testAccessPolicyGroupConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyMTLS(t *testing.T) {
func TestAccCloudflareAccessPolicy_MTLS(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -302,7 +302,7 @@ func testAccessPolicyMTLSConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyCommonName(t *testing.T) {
func TestAccCloudflareAccessPolicy_CommonName(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -350,7 +350,7 @@ func testAccessPolicyCommonNameConfig(resourceID, zone, accountID string) string
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyEmailDomain(t *testing.T) {
func TestAccCloudflareAccessPolicy_EmailDomain(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -398,7 +398,7 @@ func testAccessPolicyEmailDomainConfig(resourceID, zone, accountID string) strin
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyEmails(t *testing.T) {
func TestAccCloudflareAccessPolicy_Emails(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -448,7 +448,7 @@ func testAccessPolicyEmailsConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyEveryone(t *testing.T) {
func TestAccCloudflareAccessPolicy_Everyone(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -496,7 +496,7 @@ func testAccessPolicyEveryoneConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyIPs(t *testing.T) {
func TestAccCloudflareAccessPolicy_IPs(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -546,7 +546,7 @@ func testAccessPolicyIPsConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyAuthMethod(t *testing.T) {
func TestAccCloudflareAccessPolicy_AuthMethod(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -594,7 +594,7 @@ func testAccessPolicyAuthMethodConfig(resourceID, zone, accountID string) string
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyGeo(t *testing.T) {
func TestAccCloudflareAccessPolicy_Geo(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -644,7 +644,7 @@ func testAccessPolicyGeoConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyOkta(t *testing.T) {
func TestAccCloudflareAccessPolicy_Okta(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -697,7 +697,7 @@ func testAccessPolicyOktaConfig(resourceID, zone, accountID string) string {
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyPurposeJustification(t *testing.T) {
func TestAccCloudflareAccessPolicy_PurposeJustification(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -747,7 +747,7 @@ func testAccessPolicyPurposeJustificationConfig(resourceID, zone, accountID stri
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicyApprovalGroup(t *testing.T) {
func TestAccCloudflareAccessPolicy_ApprovalGroup(t *testing.T) {
rnd := generateRandomResourceName()
name := "cloudflare_access_policy." + rnd
zone := os.Getenv("CLOUDFLARE_DOMAIN")
Expand Down Expand Up @@ -814,3 +814,55 @@ func testAccessPolicyApprovalGroupConfig(resourceID, zone, accountID string) str
}
`, resourceID, zone, accountID)
}

func TestAccCloudflareAccessPolicy_ExternalEvaluation(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() {
testAccessAccPreCheck(t)
testAccPreCheckAccount(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccessPolicyExternalEvalautionConfig(rnd, zone, accountID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "account_id", accountID),
resource.TestCheckResourceAttr(name, "include.0.external_evaluation.0.evaluate_url", "https://example.com"),
resource.TestCheckResourceAttr(name, "include.0.external_evaluation.0.keys_url", "https://example.com/keys"),
),
},
},
})
}

func testAccessPolicyExternalEvalautionConfig(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 {
external_evaluation {
evaluate_url = "https://example.com"
keys_url = "https://example.com/keys"
}
}
}

`, resourceID, zone, accountID)
}
17 changes: 17 additions & 0 deletions internal/provider/schema_cloudflare_access_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,22 @@ var AccessGroupOptionSchemaElement = &schema.Resource{
},
},
},
"external_evaluation": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"evaluate_url": {
Type: schema.TypeString,
Optional: true,
},
"keys_url": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
}
12 changes: 12 additions & 0 deletions website/docs/r/access_group.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ conditions which can be applied. The conditions are:
}
}
```
* `external_evaluation` - (Optional) Pass a user's identity to an external URL as the `include` condition.
Example:

```hcl
# ... other configuration
include {
external {
jacobbednarz marked this conversation as resolved.
Show resolved Hide resolved
evaluate_url = "https://example.com/login"
keys_url = "https://example.com/keys"
}
}
```

## Import

Expand Down