From 142f61d5e93035b4034fc18dd63600b1880f022a Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sat, 4 Oct 2025 19:45:33 +1000 Subject: [PATCH 1/7] updates --- docs/resources/conditional_access_policy.md | 32 ++++++++++++ .../conditional_access_policy_resource.go | 2 + ...conditional_access_policy_resource_test.go | 51 +++++++++++++++++++ .../conditionalaccess/conditionalaccess.go | 6 +++ 4 files changed, 91 insertions(+) diff --git a/docs/resources/conditional_access_policy.md b/docs/resources/conditional_access_policy.md index 501214961..473f0d315 100644 --- a/docs/resources/conditional_access_policy.md +++ b/docs/resources/conditional_access_policy.md @@ -75,6 +75,37 @@ resource "azuread_conditional_access_policy" "example" { } ``` +### Application filter + +```terraform +resource "azuread_conditional_access_policy" "example" { + display_name = "example policy" + state = "disabled" + + conditions { + client_app_types = ["all"] + + applications { + included_applications = ["All"] + + application_filter { + mode = "include" + rule = "CustomSecurityAttribute.Engineering_Project -eq \"Baker\"" + } + } + + users { + included_users = ["All"] + } + } + + grant_controls { + operator = "OR" + built_in_controls = ["mfa"] + } +} +``` + ### Included client applications / service principals ```terraform @@ -175,6 +206,7 @@ The following arguments are supported: `applications` block supports the following: +* `application_filter` - (Optional) A `filter` block as documented below. * `excluded_applications` - (Optional) A list of application IDs explicitly excluded from the policy. Can also be set to `Office365`. * `included_applications` - (Optional) A list of application IDs the policy applies to, unless explicitly excluded (in `excluded_applications`). Can also be set to `All`, `None` or `Office365`. Cannot be specified with `included_user_actions`. One of `included_applications` or `included_user_actions` must be specified. * `included_user_actions` - (Optional) A list of user actions to include. Supported values are `urn:user:registerdevice` and `urn:user:registersecurityinfo`. Cannot be specified with `included_applications`. One of `included_applications` or `included_user_actions` must be specified. diff --git a/internal/services/conditionalaccess/conditional_access_policy_resource.go b/internal/services/conditionalaccess/conditional_access_policy_resource.go index f37e5c5bf..c8c2c4eb0 100644 --- a/internal/services/conditionalaccess/conditional_access_policy_resource.go +++ b/internal/services/conditionalaccess/conditional_access_policy_resource.go @@ -111,6 +111,8 @@ func conditionalAccessPolicyResource() *pluginsdk.Resource { ValidateFunc: validation.StringIsNotEmpty, }, }, + + "application_filter": schemaConditionalAccessFilter(), }, }, }, diff --git a/internal/services/conditionalaccess/conditional_access_policy_resource_test.go b/internal/services/conditionalaccess/conditional_access_policy_resource_test.go index 571547960..edb2536df 100644 --- a/internal/services/conditionalaccess/conditional_access_policy_resource_test.go +++ b/internal/services/conditionalaccess/conditional_access_policy_resource_test.go @@ -481,6 +481,24 @@ func TestAccConditionalAccessPolicy_namedLocation(t *testing.T) { }) } +func TestAccConditionalAccessPolicy_applicationFilter(t *testing.T) { + data := acceptance.BuildTestData(t, "azuread_conditional_access_policy", "test") + r := ConditionalAccessPolicyResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.applicationFilter(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("id").Exists(), + check.That(data.ResourceName).Key("display_name").HasValue(fmt.Sprintf("acctest-CONPOLICY-%d", data.RandomInteger)), + check.That(data.ResourceName).Key("state").HasValue("disabled"), + ), + }, + data.ImportStep(), + }) +} + func (ConditionalAccessPolicyResource) basic(data acceptance.TestData) string { return fmt.Sprintf(` provider "azuread" {} @@ -1278,3 +1296,36 @@ resource "azuread_conditional_access_policy" "test" { %s `, data.RandomInteger, location) } + +func (ConditionalAccessPolicyResource) applicationFilter(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azuread" {} + +resource "azuread_conditional_access_policy" "test" { + display_name = "acctest-CONPOLICY-%[1]d" + state = "disabled" + + conditions { + client_app_types = ["all"] + + applications { + included_applications = ["All"] + + application_filter { + mode = "include" + rule = "CustomSecurityAttribute.Engineering_Project -eq \"Baker\"" + } + } + + users { + included_users = ["All"] + } + } + + grant_controls { + operator = "OR" + built_in_controls = ["block"] + } +} +`, data.RandomInteger) +} diff --git a/internal/services/conditionalaccess/conditionalaccess.go b/internal/services/conditionalaccess/conditionalaccess.go index 455d437ca..f6f639873 100644 --- a/internal/services/conditionalaccess/conditionalaccess.go +++ b/internal/services/conditionalaccess/conditionalaccess.go @@ -90,6 +90,7 @@ func flattenConditionalAccessApplications(in stable.ConditionalAccessApplication "included_applications": tf.FlattenStringSlicePtr(in.IncludeApplications), "excluded_applications": tf.FlattenStringSlicePtr(in.ExcludeApplications), "included_user_actions": tf.FlattenStringSlicePtr(in.IncludeUserActions), + "application_filter": flattenConditionalAccessFilter(in.ApplicationFilter), }, } } @@ -450,11 +451,16 @@ func expandConditionalAccessApplications(in []interface{}) stable.ConditionalAcc includeApplications := config["included_applications"].([]interface{}) excludeApplications := config["excluded_applications"].([]interface{}) includeUserActions := config["included_user_actions"].([]interface{}) + applicationFilter := config["application_filter"].([]interface{}) result.IncludeApplications = tf.ExpandStringSlicePtr(includeApplications) result.ExcludeApplications = tf.ExpandStringSlicePtr(excludeApplications) result.IncludeUserActions = tf.ExpandStringSlicePtr(includeUserActions) + if len(applicationFilter) > 0 { + result.ApplicationFilter = expandConditionalAccessFilter(applicationFilter) + } + return result } From b761fd90ff2a1ec98a5323261691a5023c74010b Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sat, 4 Oct 2025 19:51:35 +1000 Subject: [PATCH 2/7] fmt --- api-response.json | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 api-response.json diff --git a/api-response.json b/api-response.json new file mode 100644 index 000000000..9685a0d29 --- /dev/null +++ b/api-response.json @@ -0,0 +1,61 @@ +{ + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#identity/conditionalAccess/policies/$entity", + "@microsoft.graph.tips": "Use $select to choose only the properties your app needs, as this can lead to performance improvements. For example: GET identity/conditionalAccess/policies('')?$select=conditions,createdDateTime", + "id": "79c4d38f-2c0d-4373-9e7c-1205b903b07f", + "templateId": null, + "displayName": "test-filter", + "createdDateTime": "2025-10-04T07:40:10.7151313Z", + "modifiedDateTime": null, + "state": "enabled", + "sessionControls": null, + "conditions": { + "userRiskLevels": [], + "signInRiskLevels": [], + "clientAppTypes": [ + "all" + ], + "servicePrincipalRiskLevels": [], + "insiderRiskLevels": null, + "platforms": null, + "locations": null, + "devices": null, + "clientApplications": null, + "authenticationFlows": null, + "applications": { + "includeApplications": [], + "excludeApplications": [], + "includeUserActions": [], + "includeAuthenticationContextClassReferences": [], + "applicationFilter": { + "mode": "include", + "rule": "CustomSecurityAttribute.PROTECTEDApps_Classification -eq \"PROTECTED\"" + } + }, + "users": { + "includeUsers": [], + "excludeUsers": [], + "includeGroups": [], + "excludeGroups": [], + "includeRoles": [], + "excludeRoles": [], + "excludeGuestsOrExternalUsers": null, + "includeGuestsOrExternalUsers": { + "guestOrExternalUserTypes": "b2bCollaborationGuest", + "externalTenants": { + "@odata.type": "#microsoft.graph.conditionalAccessAllExternalTenants", + "membershipKind": "all" + } + } + } + }, + "grantControls": { + "operator": "OR", + "builtInControls": [ + "mfa" + ], + "customAuthenticationFactors": [], + "termsOfUse": [], + "authenticationStrength@odata.context": "https://graph.microsoft.com/v1.0/$metadata#identity/conditionalAccess/policies('79c4d38f-2c0d-4373-9e7c-1205b903b07f')/grantControls/authenticationStrength/$entity", + "authenticationStrength": null + } +} \ No newline at end of file From e122027d52caaa0340fa8f352798eb8b09a6ed5a Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sat, 4 Oct 2025 19:52:27 +1000 Subject: [PATCH 3/7] remove --- api-response.json | 61 ----------------------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 api-response.json diff --git a/api-response.json b/api-response.json deleted file mode 100644 index 9685a0d29..000000000 --- a/api-response.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#identity/conditionalAccess/policies/$entity", - "@microsoft.graph.tips": "Use $select to choose only the properties your app needs, as this can lead to performance improvements. For example: GET identity/conditionalAccess/policies('')?$select=conditions,createdDateTime", - "id": "79c4d38f-2c0d-4373-9e7c-1205b903b07f", - "templateId": null, - "displayName": "test-filter", - "createdDateTime": "2025-10-04T07:40:10.7151313Z", - "modifiedDateTime": null, - "state": "enabled", - "sessionControls": null, - "conditions": { - "userRiskLevels": [], - "signInRiskLevels": [], - "clientAppTypes": [ - "all" - ], - "servicePrincipalRiskLevels": [], - "insiderRiskLevels": null, - "platforms": null, - "locations": null, - "devices": null, - "clientApplications": null, - "authenticationFlows": null, - "applications": { - "includeApplications": [], - "excludeApplications": [], - "includeUserActions": [], - "includeAuthenticationContextClassReferences": [], - "applicationFilter": { - "mode": "include", - "rule": "CustomSecurityAttribute.PROTECTEDApps_Classification -eq \"PROTECTED\"" - } - }, - "users": { - "includeUsers": [], - "excludeUsers": [], - "includeGroups": [], - "excludeGroups": [], - "includeRoles": [], - "excludeRoles": [], - "excludeGuestsOrExternalUsers": null, - "includeGuestsOrExternalUsers": { - "guestOrExternalUserTypes": "b2bCollaborationGuest", - "externalTenants": { - "@odata.type": "#microsoft.graph.conditionalAccessAllExternalTenants", - "membershipKind": "all" - } - } - } - }, - "grantControls": { - "operator": "OR", - "builtInControls": [ - "mfa" - ], - "customAuthenticationFactors": [], - "termsOfUse": [], - "authenticationStrength@odata.context": "https://graph.microsoft.com/v1.0/$metadata#identity/conditionalAccess/policies('79c4d38f-2c0d-4373-9e7c-1205b903b07f')/grantControls/authenticationStrength/$entity", - "authenticationStrength": null - } -} \ No newline at end of file From c9ceefac35533542f20aecb649be96541ce80ef8 Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sun, 5 Oct 2025 10:40:58 +1100 Subject: [PATCH 4/7] mfa --- .../conditional_access_policy_resource_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/conditionalaccess/conditional_access_policy_resource_test.go b/internal/services/conditionalaccess/conditional_access_policy_resource_test.go index edb2536df..75fe09572 100644 --- a/internal/services/conditionalaccess/conditional_access_policy_resource_test.go +++ b/internal/services/conditionalaccess/conditional_access_policy_resource_test.go @@ -1324,7 +1324,7 @@ resource "azuread_conditional_access_policy" "test" { grant_controls { operator = "OR" - built_in_controls = ["block"] + built_in_controls = ["mfa"] } } `, data.RandomInteger) From 4f760e2fc7aa03354872722026c36e22e00fdd25 Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sun, 5 Oct 2025 20:18:59 +1100 Subject: [PATCH 5/7] updated filters --- .../conditional_access_policy_resource_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/conditionalaccess/conditional_access_policy_resource_test.go b/internal/services/conditionalaccess/conditional_access_policy_resource_test.go index 75fe09572..01726dae7 100644 --- a/internal/services/conditionalaccess/conditional_access_policy_resource_test.go +++ b/internal/services/conditionalaccess/conditional_access_policy_resource_test.go @@ -1313,7 +1313,7 @@ resource "azuread_conditional_access_policy" "test" { application_filter { mode = "include" - rule = "CustomSecurityAttribute.Engineering_Project -eq \"Baker\"" + rule = "CustomSecurityAttribute.AzureADProviderTesting_Usage -contains \"Acceptance Tests\"" } } From e0829306e0d87b3e96e7edc355583613b9e49ba8 Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sun, 5 Oct 2025 20:21:44 +1100 Subject: [PATCH 6/7] docs --- docs/resources/conditional_access_policy.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/resources/conditional_access_policy.md b/docs/resources/conditional_access_policy.md index 473f0d315..0c27a96b4 100644 --- a/docs/resources/conditional_access_policy.md +++ b/docs/resources/conditional_access_policy.md @@ -207,6 +207,9 @@ The following arguments are supported: `applications` block supports the following: * `application_filter` - (Optional) A `filter` block as documented below. + +~> **Note:** Specifying `filter` requires the `Attribute Definition Reader` role, this is not included in the `Global Administrator` or other administrator roles and must be separately assigned. + * `excluded_applications` - (Optional) A list of application IDs explicitly excluded from the policy. Can also be set to `Office365`. * `included_applications` - (Optional) A list of application IDs the policy applies to, unless explicitly excluded (in `excluded_applications`). Can also be set to `All`, `None` or `Office365`. Cannot be specified with `included_user_actions`. One of `included_applications` or `included_user_actions` must be specified. * `included_user_actions` - (Optional) A list of user actions to include. Supported values are `urn:user:registerdevice` and `urn:user:registersecurityinfo`. Cannot be specified with `included_applications`. One of `included_applications` or `included_user_actions` must be specified. From 7ea0e0a35d7a70bcd4656fb3c494099bfc3eba12 Mon Sep 17 00:00:00 2001 From: bubblestrobules Date: Sun, 5 Oct 2025 20:30:26 +1100 Subject: [PATCH 7/7] clean-docs --- docs/resources/conditional_access_policy.md | 31 --------------------- 1 file changed, 31 deletions(-) diff --git a/docs/resources/conditional_access_policy.md b/docs/resources/conditional_access_policy.md index 0c27a96b4..bb84fd468 100644 --- a/docs/resources/conditional_access_policy.md +++ b/docs/resources/conditional_access_policy.md @@ -75,37 +75,6 @@ resource "azuread_conditional_access_policy" "example" { } ``` -### Application filter - -```terraform -resource "azuread_conditional_access_policy" "example" { - display_name = "example policy" - state = "disabled" - - conditions { - client_app_types = ["all"] - - applications { - included_applications = ["All"] - - application_filter { - mode = "include" - rule = "CustomSecurityAttribute.Engineering_Project -eq \"Baker\"" - } - } - - users { - included_users = ["All"] - } - } - - grant_controls { - operator = "OR" - built_in_controls = ["mfa"] - } -} -``` - ### Included client applications / service principals ```terraform