Skip to content

google_recaptcha_enterprise_key silently skips updates when challenge_settings.action_settings map keys change #28502

Description

@strobil

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request.
  • Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment.
  • If an issue is assigned to a user, that user is claiming responsibility for the issue.
  • Customers working with a Google Technical Account Manager or Customer Engineer can ask them to reach out internally to expedite investigation and resolution of this issue.

Terraform Version & Provider Version(s)

Terraform v1.15.7
on linux_amd64
+ provider registry.terraform.io/hashicorp/google v7.38.0

The same relevant generated source is still present in provider v7.41.0 and the current main branch.

Affected Resource(s)

  • google_recaptcha_enterprise_key

Terraform Configuration

Apply this initial configuration:

resource "google_recaptcha_enterprise_key" "example" {
  project      = var.project_id
  display_name = "policy-based-challenge-example"

  web_settings {
    integration_type  = "POLICY_BASED_CHALLENGE"
    allow_all_domains = false
    allowed_domains   = ["example.com"]

    challenge_settings {
      default_settings {
        score_threshold = 0.1
      }

      action_settings {
        action          = "auth_email"
        score_threshold = 0.45
      }

      action_settings {
        action          = "auth_phone"
        score_threshold = 0.1
      }
    }
  }
}

Then change only the membership of action_settings:

resource "google_recaptcha_enterprise_key" "example" {
  project      = var.project_id
  display_name = "policy-based-challenge-example"

  web_settings {
    integration_type  = "POLICY_BASED_CHALLENGE"
    allow_all_domains = false
    allowed_domains   = ["example.com"]

    challenge_settings {
      default_settings {
        score_threshold = 0.1
      }

      action_settings {
        action          = "auth"
        score_threshold = 0.45
      }
    }
  }
}

Debug Output

Standard Terraform logs report an in-place modification completing successfully, but do not contain a PATCH request or updateMask. Cloud Audit Logs contain no UpdateKey event for the apply window.

Expected Behavior

The provider should send an update to replace the two existing action-map entries with the single auth entry.

After apply:

  • a direct projects.keys.get request should return only auth = 0.45;
  • Terraform state should contain only auth = 0.45;
  • a refresh should detect any difference between state and the live API.

Actual Behavior

The Terraform plan correctly reports one in-place update:

Plan: 0 to add, 1 to change, 0 to destroy.

The apply reports success after approximately one second. However:

  • no PATCH request is sent to the reCAPTCHA Enterprise API;
  • no UpdateKey audit event is created;
  • direct REST GET and gcloud recaptcha keys describe continue to return the old auth_email and auth_phone entries after more than 45 minutes;
  • Terraform state is nevertheless rewritten to contain only auth;
  • the next refresh/plan incorrectly reports 0 to change.

This creates a false-success result and hides live drift.

Steps to reproduce

  1. Apply the initial configuration.
  2. Confirm with projects.keys.get that the key contains auth_email and auth_phone.
  3. Replace both action blocks with the single auth action shown above.
  4. Run terraform plan and observe an in-place update.
  5. Run terraform apply.
  6. Query the key directly with projects.keys.get.
  7. Run another Terraform refresh/plan.

Root cause analysis

The problem occurs before PATCH/update-mask generation:

  1. The resource update builds a desired object and calls ApplyKey:
    resource_recaptcha_enterprise_key.go.
  2. keyDiffsForRawDesired uses the complete desired object as fetchState and passes it to GetKey:
    key_internal.go.
  3. GetKey retrieves the real REST response and then canonicalizes it with the supplied desired object:
    key.go.
  4. canonicalizeNewKeyWebSettingsChallengeSettingsActionSettingsMap iterates only over desired map keys. A desired-only key is copied into the canonicalized result, while actual-only keys are omitted:
    key_internal.go.
  5. The canonicalized initial state and desired state therefore both contain only auth. The internal diff is empty, the operation list is empty, and the PATCH code is never reached:
    key.go.

The same canonicalization during reads also explains why subsequent refreshes mask the live drift.

The existing policy-based challenge acceptance test updates score values while keeping the same login and signup map keys. It does not cover adding, removing, or renaming action-map keys:
resource_recaptcha_enterprise_key_generated_test.go.

Suggested fix

The map canonicalizer should preserve the distinction between desired-only and actual-only map entries until after the internal diff is calculated. Please also add an acceptance-test step that changes the action map from two keys to a differently named single key and verifies the live API response, not only Terraform state.

Important Factoids

  • The default Google endpoint is used.
  • Authentication uses a service account.
  • No custom provider endpoint or manual concurrent key update is involved.
  • Updating scalar thresholds while retaining the same action-map keys follows a different path and is already covered by the existing acceptance test.

References

b/539545848

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions