-
Notifications
You must be signed in to change notification settings - Fork 301
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
azuread_application: default the identifier_uris field as "api://application_id" as the portal does #428
Comments
Hi @AdamCoulterOz, thanks for the suggestion! I can see how this would solve this particular dependency. That said, whilst the portal has this default behavior, I don't believe it's a suitable default for Terraform. In my experience most people don't use the portal default as it's not especially usable when developing against the MS Identity Platform. There are also characteristics of the App ID URI that make it worthwhile to consider upfront what it should be, in particular:
So on balance, I believe the least problems are caused by not having a default value for this property, although I acknowledge this makes it infeasible to achieve in a single apply operation a configuration that mimics the portal for this property. |
@manicminer sure ... I can agree to that ... can you suggest how to use this resource in this very common use case then? |
Immutability concerns don't appear to conflict with the suggestion of incorporating the Application ID as a default, as the portal does when exposing an API by hand. If someone has a reason to define a distinct |
Whilst we try to provide equivalent functionality to the Portal, the two workflows (interactive and stateful infrastructure-as-config) don't always match up. Providing this as a default would allow us to embed the app ID in the URI, but it wouldn't allow users to customise this, to add additional URIs, or to return to that value after changing it to something else. The portal achieves this by patching the application as you progress through the settings blade, but Terraform currently cannot follow the [arguably anti] pattern of including a generated value of the resource, in another property of the same resource. |
After upgrading to version 2 of the provider our application |
@abergie The removal of Computed behavior from many properties is covered in our Upgrade Guide, as documented you'll need to explicitly specify these properties or Terraform will set them to their default values. When you have an existing application with the app ID embedded in properties like |
@manicminer Thanks for the response. Adding a lifecycle block is certainly a stop-gap for existing applications, but not a long-term solution for us. When adding new applications which retain the previous behavior of application ids in the URI, |
Instead of removing the computed value after version 2, you could add it as an option to compute it or not. |
Hi all, I appreciate this gap in functionality is frustrating when trying to manage apps that require an identifier URI containing their own client ID. It is a feature that we would like to support, however, given the stateful and idempotent architecture of Terraform, this is difficult - to the extent that we have been unable to implement this to date without breaking existing configurations and losing some functionality. We have not forgotten about this request, and I'm hopeful that new developments within Terraform may enable us to support this use case in some form or another in the near future. That said, this still requires investigation and at this time there are no guarantees that we'll be able to do so. In the meantime, I believe this should be possible to work around using a provisioner to manually set the identifierUris field (e.g. via Azure CLI or your own script), and adding |
@alex-oswald Unfortunately it's not possible to have a conditional Terraform schema |
Hi @manicminer, I've got a little bit of time coming up where I could work on a potential solution, and I'm keen for your thoughts before I start: Instead of trying to make this work under the current single I know it's not keeping with the convention of 1 API == 1 resource, but unless Microsoft add a new API, this seems to be a limitation that will prevent us provisioning 'correctly'. There are also similar fields where the same could be done to remove cyclic dependencies: for example, when provisioning a Function/App Service with SSO, the |
Hi @jlaundry, thanks for offering to work on this. That is fairly consistent with what we have in mind for a solution, and it's on our backlog to architect across the azuread_application resource - as it needs careful consideration about which attributes could comprise a separate resource, whether those resources are singular or plural, and ensuring that in all cases potential SDK bugs do not cause a regression (this alas is complex and depends on the circular interaction between the API behavior, Hamilton SDK limitations and Terraform Plugin SDK known issues). Off hand if I were to guess, I'd say that this probably warrants a pluralized resource pretty much as you've suggested. If you'd like to work on it, a PR would be warmly welcomed :) |
Same problem when in the "required_resource_access" block "resource_app_id" should be specified as self "application_id". |
Thanks for the discourse on this issue. As I've mentioned previously, there are impracticalities around changing the default value behavior for the Our recommendation will be to consider adopting the soon-to-be-introduced |
For clarity this is complete solution as of today: terraform {
# <-----... Add other required fields here ... ------->
required_providers {
# https://registry.terraform.io/providers/hashicorp/azuread/
azuread = {
source = "hashicorp/azuread"
version = "2.45.0"
}
}
}
resource "azuread_application" "app" {
# <-----... Add other required fields here ... ------->
lifecycle {
ignore_changes = [
# This parameter is managed by `azuread_application_identifier_uri`.
# Details: https://github.com/hashicorp/terraform-provider-azuread/issues/428#issuecomment-1788737766
identifier_uris,
]
}
}
# If you need more than one URI, create more resources like this or use `for_each`
resource "azuread_application_identifier_uri" "app" {
application_id = azuread_application.app.id
identifier_uri = "api://${azuread_application.app.client_id}"
} I just tested this approach by:
Result:
As you see |
Hi, I used @asinitson 's solution to assign the application's The reproduction example: terraform {
required_version = ">= 1.6"
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "~>2.47.0"
}
}
}
resource "azuread_application" "main" {
display_name = "test"
lifecycle {
ignore_changes = [
identifier_uris,
]
}
}
resource "azuread_service_principal" "main" {
client_id = azuread_application.main.client_id
}
resource "azuread_application_identifier_uri" "main_client_id" {
application_id = azuread_application.main.id
identifier_uri = "api://${azuread_application.main.client_id}"
} The error log: $ terraform apply
azuread_application_identifier_uri.main_client_id: Refreshing state... [id=/applications/b27be14c-e181-49e5-b17e-db9eac6fce01/identifierUris/YXBpOi8vZjI5MmIwOGYtMjg0My00NDkyLTlkYzctY2Q4ZjVkM2ZkYWU2]
azuread_service_principal.main: Refreshing state... [id=ad2049b5-1c61-44d8-a2aa-d6ff15f289c4]
azuread_application.main: Refreshing state... [id=/applications/b27be14c-e181-49e5-b17e-db9eac6fce01]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# azuread_application.main will be destroyed
# (because azuread_application.main is not in configuration)
- resource "azuread_application" "main" {
- app_role_ids = {} -> null
- application_id = "f292b08f-2843-4492-9dc7-cd8f5d3fdae6" -> null
- client_id = "f292b08f-2843-4492-9dc7-cd8f5d3fdae6" -> null
- device_only_auth_enabled = false -> null
- disabled_by_microsoft = "<nil>" -> null
- display_name = "test" -> null
- fallback_public_client_enabled = false -> null
- group_membership_claims = [] -> null
- id = "/applications/b27be14c-e181-49e5-b17e-db9eac6fce01" -> null
- identifier_uris = [
- "api://f292b08f-2843-4492-9dc7-cd8f5d3fdae6",
] -> null
- oauth2_permission_scope_ids = {} -> null
- oauth2_post_response_required = false -> null
- object_id = "b27be14c-e181-49e5-b17e-db9eac6fce01" -> null
- owners = [] -> null
- prevent_duplicate_names = false -> null
- publisher_domain = "my-lab.org" -> null
- sign_in_audience = "AzureADMyOrg" -> null
- tags = [] -> null
- api {
- known_client_applications = [] -> null
- mapped_claims_enabled = false -> null
- requested_access_token_version = 1 -> null
}
- feature_tags {
- custom_single_sign_on = false -> null
- enterprise = false -> null
- gallery = false -> null
- hide = false -> null
}
- optional_claims {
}
- public_client {
- redirect_uris = [] -> null
}
- single_page_application {
- redirect_uris = [] -> null
}
- web {
- redirect_uris = [] -> null
- implicit_grant {
- access_token_issuance_enabled = false -> null
- id_token_issuance_enabled = false -> null
}
}
}
# azuread_application_identifier_uri.main_client_id will be destroyed
# (because azuread_application_identifier_uri.main_client_id is not in configuration)
- resource "azuread_application_identifier_uri" "main_client_id" {
- application_id = "/applications/b27be14c-e181-49e5-b17e-db9eac6fce01" -> null
- id = "/applications/b27be14c-e181-49e5-b17e-db9eac6fce01/identifierUris/YXBpOi8vZjI5MmIwOGYtMjg0My00NDkyLTlkYzctY2Q4ZjVkM2ZkYWU2" -> null
- identifier_uri = "api://f292b08f-2843-4492-9dc7-cd8f5d3fdae6" -> null
}
# azuread_service_principal.main will be destroyed
# (because azuread_service_principal.main is not in configuration)
- resource "azuread_service_principal" "main" {
- account_enabled = true -> null
- alternative_names = [] -> null
- app_role_assignment_required = false -> null
- app_role_ids = {} -> null
- app_roles = [] -> null
- application_id = "f292b08f-2843-4492-9dc7-cd8f5d3fdae6" -> null
- application_tenant_id = "8c450195-9397-4658-8296-0361b9220f6b" -> null
- client_id = "f292b08f-2843-4492-9dc7-cd8f5d3fdae6" -> null
- display_name = "test" -> null
- id = "ad2049b5-1c61-44d8-a2aa-d6ff15f289c4" -> null
- notification_email_addresses = [] -> null
- oauth2_permission_scope_ids = {} -> null
- oauth2_permission_scopes = [] -> null
- object_id = "ad2049b5-1c61-44d8-a2aa-d6ff15f289c4" -> null
- owners = [] -> null
- redirect_uris = [] -> null
- service_principal_names = [
- "api://f292b08f-2843-4492-9dc7-cd8f5d3fdae6",
] -> null
- sign_in_audience = "AzureADMyOrg" -> null
- tags = [] -> null
- type = "Application" -> null
- feature_tags {
- custom_single_sign_on = false -> null
- enterprise = false -> null
- gallery = false -> null
- hide = false -> null
}
- features {
- custom_single_sign_on_app = false -> null
- enterprise_application = false -> null
- gallery_application = false -> null
- visible_to_users = true -> null
}
- saml_single_sign_on {}
}
Plan: 0 to add, 0 to change, 3 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
azuread_application_identifier_uri.main_client_id: Destroying... [id=/applications/b27be14c-e181-49e5-b17e-db9eac6fce01/identifierUris/YXBpOi8vZjI5MmIwOGYtMjg0My00NDkyLTlkYzctY2Q4ZjVkM2ZkYWU2]
azuread_service_principal.main: Destroying... [id=ad2049b5-1c61-44d8-a2aa-d6ff15f289c4]
azuread_service_principal.main: Still destroying... [id=ad2049b5-1c61-44d8-a2aa-d6ff15f289c4, 10s elapsed]
azuread_service_principal.main: Still destroying... [id=ad2049b5-1c61-44d8-a2aa-d6ff15f289c4, 20s elapsed]
azuread_service_principal.main: Destruction complete after 20s
╷
│ Error: deleting Application IdentifierUri (Application ID: "b27be14c-e181-49e5-b17e-db9eac6fce01", IdentifierUri ID: "YXBpOi8vZjI5MmIwOGYtMjg0My00NDkyLTlkYzctY2Q4ZjVkM2ZkYWU2"): ApplicationsClient.BaseClient.Patch(): unexpected status 404 with OData error: Request_ResourceNotFound: Resource 'Application_b27be14c-e181-49e5-b17e-db9eac6fce01' does not exist or one of its queried reference-property objects are not present.
│
│ deleting Application IdentifierUri (Application ID: "b27be14c-e181-49e5-b17e-db9eac6fce01", IdentifierUri ID:
│ "YXBpOi8vZjI5MmIwOGYtMjg0My00NDkyLTlkYzctY2Q4ZjVkM2ZkYWU2"): ApplicationsClient.BaseClient.Patch(): unexpected status 404 with OData error:
│ Request_ResourceNotFound: Resource 'Application_b27be14c-e181-49e5-b17e-db9eac6fce01' does not exist or one of its queried reference-property
│ objects are not present. If I then re-run Any ideas about that? |
resource "azuread_application_identifier_uri" "main_client_id" {
application_id = azuread_application.main.id
identifier_uri = "api://${azuread_application.main.client_id}"
} @joachimBurket: Maybe setting explicit dependency also on a service principal will help? Something like this (untested!): resource "azuread_application_identifier_uri" "main_client_id" {
application_id = azuread_application.main.id
identifier_uri = "api://${azuread_application.main.client_id}"
depends_on = [azuread_service_principal.main]
} From the error message:
Maybe service principal gets queried in this call which causes the dependency. |
This works like a charm! 🎉 Thanks for your help @asinitson ! |
Community Note
Description
When creating an Azure AD Application in the Azure Portal, the
identifier_uris
field (Application ID URI) defaults toapi://<application_id>
, which is required for using an application to expose APIs. This causes a circular dependency to set it explicitly using the terraform resource, as we don't know the application_id until the application is created.Proposal is to default the (Application ID URI)
identifier_uris
field toapi://<application_id>
if the attribute isn't set in the resource. If it is set, even to emptyidentifier_uris = []
it will not default toapi://....
.New or Affected Resource(s)
The text was updated successfully, but these errors were encountered: