hashicorp / terraform-provider-azuread

Terraform provider for Azure Active Directory
https://registry.terraform.io/providers/hashicorp/azuread/latest/docs
Mozilla Public License 2.0
429 stars 294 forks source link

`terraform plan -refresh-only` command shows the `logo_url` in the diff (when a logo is added to an Application in Azure AD), even if the logo was not managed by terraform #1459

Open joachimBurket opened 2 months ago

joachimBurket commented 2 months ago

Community Note

Terraform (and AzureAD Provider) Version

$ terraform -v
Terraform v1.9.5
on linux_amd64
+ provider registry.terraform.io/hashicorp/azuread v2.53.1

Affected Resource(s)

Terraform Configuration Files

terraform {
  required_version = ">= 1.6"
  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = ">=2.53.1, <3.0.0"
    }
  }
}

resource "azuread_application" "example" {
  display_name            = "example"
  sign_in_audience        = "AzureADMyOrg"
  group_membership_claims = ["SecurityGroup"]

  api {
    mapped_claims_enabled          = true
    requested_access_token_version = 2
  }

  web {
    homepage_url  = "https://app.example.net"
    logout_url    = "https://app.example.net/logout"
    redirect_uris = ["https://app.example.net/account"]
  }

  lifecycle {
    ignore_changes = [
      identifier_uris,
      owners,
      api[0].known_client_applications,
    ]
  }
}

Debug Output

$ terraform plan -refresh-only
azuread_application.example: Refreshing state... [id=/applications/58a75930-75b3-4a04-a572-4d6383a3dc27]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply" which may have affected this plan:

  # azuread_application.example has changed
  ~ resource "azuread_application" "example" {
        id                             = "/applications/58a75930-75b3-4a04-a572-4d6383a3dc27"
      + logo_url                       = "https://aadcdn.msftauthimages.net/c1c6b6c8-3dxsg3uktgsajlp-ib5nh85w5oqsatmsdyrqoxtife4/appbranding/pjyyxkyjzdxnjsrh8o5vdm4cbfst7at6j7gzkskskcw/1033/bannerlogo?ts=638602831655010723"
        tags                           = []
        # (25 unchanged attributes hidden)

        # (6 unchanged blocks hidden)
    }

This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record
the updated values in the Terraform state without changing any remote objects.

Panic Output

None

Expected Behavior

The logo_url should not be present in the diff if it was added from Azure AD.

Actual Behavior

The terraform plan -refresh-only command showed the added logo_url in the diff.

Steps to Reproduce

  1. Create the Application with terraform apply

  2. Run terraform plan -refresh-only command to check if there is a diff with the prod

    NOTE: if the terraform plan -refresh-only is launched directly after the apply, the following resources are shown in the diff:

    $ terraform plan -refresh-only
    azuread_application.example: Refreshing state... [id=/applications/58a75930-75b3-4a04-a572-4d6383a3dc27]
    
    Note: Objects have changed outside of Terraform
    
    Terraform detected the following changes made outside of Terraform since the last "terraform apply" which may have affected this plan:
    
      # azuread_application.example has changed
      ~ resource "azuread_application" "example" {
          + group_membership_claims        = []
            id                             = "/applications/48e35d3f-9c02-4a22-add9-c19bb4253bf3"
          + identifier_uris                = []
          + owners                         = []
            tags                           = []
            # (13 unchanged attributes hidden)
    
          ~ api {
              + known_client_applications      = []
                # (2 unchanged attributes hidden)
            }
    
            # (5 unchanged blocks hidden)
        }
    
    This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record the updated values in the Terraform state without changing any remote objects.

    When the terraform apply command is launched a second time, the terraform plan -refresh-only shows no more diff.

  3. Add a logo to the Application on Azure AD.

  4. Run the command tofu plan -refresh-only. The command shows the logo_url in the diff.

  5. Try to ignore the logo_url in the Application's lifecycle. Update the azuread_application:

    resource "azuread_application" "example" {
      [ ... ]
      lifecycle {
      ignore_changes = [
        identifier_uris,
        owners,
        api[0].known_client_applications,
        logo_url,     # add the logo_url
      ]
    }
  6. Re-run the plan -refresh-only command:

    $ terraform plan -refresh-only
    azuread_application.example: Refreshing state... [id=/applications/58a75930-75b3-4a04-a572-4d6383a3dc27]
    
    Note: Objects have changed outside of Terraform
    
    Terraform detected the following changes made outside of Terraform since the last "terraform apply" which may have affected this plan:
    
      # azuread_application.example has changed
      ~ resource "azuread_application" "example" {
            id                             = "/applications/58a75930-75b3-4a04-a572-4d6383a3dc27"
          + logo_url                       = "https://aadcdn.msftauthimages.net/c1c6b6c8-3dxsg3uktgsajlp-ib5nh85w5oqsatmsdyrqoxtife4/appbranding/pjyyxkyjzdxnjsrh8o5vdm4cbfst7at6j7gzkskskcw/1033/bannerlogo?ts=638602831655010723"
            tags                           = []
            # (25 unchanged attributes hidden)
    
            # (6 unchanged blocks hidden)
        }
    
    This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record
    the updated values in the Terraform state without changing any remote objects.
    β•·
    β”‚ Warning: Redundant ignore_changes element
    β”‚ 
    β”‚   on test_app.tf line 11, in resource "azuread_application" "example":
    β”‚   11: resource "azuread_application" "example" {
    β”‚ 
    β”‚ Adding an attribute name to ignore_changes tells Terraform to ignore future changes to the argument in configuration after the object has been created,
    β”‚ retaining the value originally configured.
    β”‚ 
    β”‚ The attribute logo_url is decided by the provider alone and therefore there can be no configured value to compare with. Including this attribute in
    β”‚ ignore_changes has no effect. Remove the attribute from ignore_changes to quiet this warning.

    A Warning tells that the ignore_change of the logo_url is redundant.

Important Factoids

I use the terraform plan -refresh-only command in a recurrent job to check if there was drift on the production, and create an issue in my repository.

References

None

nbaju1 commented 2 months ago

logo_image is the attribute you set in the configuration, so the ignore_changes should contain that, not logo_url.

joachimBurket commented 2 months ago

Indeed, that makes sense. I tried to change the ignore_changes to logo_image, then remove the application and state file, and re-apply the terraform file. But when I then add a logo to the Application, and run the terraform plan -refresh-only directly after, it still shows me the logo_url in the diff:

$ terraform plan -refresh-only
Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply" which may have affected this plan:

  # azuread_application.example has changed
  ~ resource "azuread_application" "example" {
        id                             = "/applications/b4cbf5d6-8aee-400f-bae9-b61257eaaf47"
      + logo_url                       = "https://aadcdn.msftauthimages.net/c1c6b6c8-3dxsg3uktgsajlp-ib5nh85w5oqsatmsdyrqoxtife4/appbranding/o-sjftxr70xasugiwvkhy4mt9wmtztrytrf0af2u04/1033/bannerlogo?ts=638603433738285255"
        tags                           = []
        # (25 unchanged attributes hidden)

        # (6 unchanged blocks hidden)
    }

This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record
the updated values in the Terraform state without changing any remote objects.

If I then run a plan, it doesn't show any changes:

$ terraform plan
azuread_application.example: Refreshing state... [id=/applications/b4cbf5d6-8aee-400f-bae9-b61257eaaf47]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

And if I run an apply, it also doesn't show any changes:

terraform apply -auto-approve
azuread_application.example: Refreshing state... [id=/applications/b4cbf5d6-8aee-400f-bae9-b61257eaaf47]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

But after this apply, the terraform plan -refresh-only doesn't show anymore changes:

$ terraform plan -refresh-only
azuread_application.example: Refreshing state... [id=/applications/b4cbf5d6-8aee-400f-bae9-b61257eaaf47]

No changes. Your infrastructure still matches the configuration.

Terraform has checked that the real remote objects still match the result of your most recent changes, and found no differences.

Any idea about this?

nbaju1 commented 2 months ago

logo_url is an attribute reference and not part of your actual configuration, so I'm guessing Terraform just updates the state file with that value when you run the terraform plan -refresh-only command. I believe Terraform would want to remove the logo if you didn't have logo_image in the ignore_changes block after you uploaded the logo manually.

joachimBurket commented 1 month ago

hm, so the issue would rather be on Terraform's side, and the terraform plan -refresh-only command should not show the changes on "computed" fields like the logo_url, or am I misunderstanding something? (I'm not using Terraform since long, so it quite likely πŸ˜…)

nbaju1 commented 1 month ago

In my opinion, this is expected behavior. Attribute references are just that, references to attributes on the resource. Since the application has a logo, Terraform updates the attribute reference in the state file with the corresponding value.

What can be confusing in this case is that the logo_url attribute reference is tied to the logo_image attribute argument. The ignore_changes configuration simply tells Terraform to ignore any difference between the actual application and the configuration of the argument(s) in that block, which in your case is logo_image.

joachimBurket commented 1 month ago

Okay so I understand the attribute references, thanks :)

So maybe I'm using wrongly the terraform plan -refresh-only command. I'm running it periodically in a CI to detect the configuration drift between Azure AD and our GitOps repository. Whenever the command outputs a diff, I create an Issue on the repository to ask a maintainer to check the drift. But even with the logo_image in the ignore_changes, when a logo is added to an Application in Azure AD, the issue is created because the terraform plan -refresh-only command outputs a diff until a terraform apply is launched. On the other hand, if I put the logo_url in the ignore_changes, the terraform plan -refresh-only doesn't output a diff.

PS: I know this is outside the provider's scope, I'm just asking in case you have a hint about this use case. But if you don't, feel free to close the issue :)