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

Terraform tries recreating the SSL cert everytime due to domain name mismatch #6658

Closed
Assignees
Labels

Comments

@universalvishwa
Copy link

universalvishwa commented Jun 22, 2020

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 the modular-magician user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to hashibot, a community member has claimed the issue already.

Terraform Version

Terraform v0.12.26
provider.google v3.9.0
provider.google-beta v3.9.0

Affected Resource(s)

  • google_compute_managed_ssl_certificate

Terraform Configuration Files

# DNS records in CloudDNS
resource "google_dns_record_set" "ipv4" {
  name         = "iam.sorry.com"
  type         = "A"
  ttl          = 300
  managed_zone = "sorry.com"
  rrdatas      = ["10.20.30.40"]
}


# Google managed SSL certificate for HTTPS load balancing
resource "google_compute_managed_ssl_certificate" "default" {
  provider = google-beta

  name = "example-httplb"
  managed {
    domains = [google_dns_record_set.ipv4.name]
  }

  depends_on = [google_dns_record_set.ipv4
}


# Output
output "dns_names" {
  value = google_dns_record_set.ipv4.name
}

output "ssl_cert" {
  value = {
    certificate_id     = google_compute_managed_ssl_certificate.default.certificate_id,
    creation_timestamp = google_compute_managed_ssl_certificate.default.creation_timestamp,
    expire_time        = google_compute_managed_ssl_certificate.default.expire_time
  }
}

Expected Behavior

  • Intelligently compare the trimsuffixes of Domain names used in SSL cert and Cloud DNS record sets and identify when it's the same and avoid triggering recreation of the Google managed-SSL cert.

Actual Behavior

Steps to Reproduce

  1. terraform plan
    When running plan after on an existing apply, it will always result in an update like this.
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # google_compute_managed_ssl_certificate.default must be replaced
-/+ resource "google_compute_managed_ssl_certificate" "default" {
      ~ certificate_id            = 0000000000000000 -> (known after apply)
      ~ creation_timestamp        = "2020-06-22T15:41:23.093-07:00" -> (known after apply)
      + expire_time               = (known after apply)
      ~ id                        = "projects/example-264/global/sslCertificates/example-httplb" -> (known after apply)
        name                      = "example-264-httplb"
        project                   = "example-264"
      ~ self_link                 = "https://www.googleapis.com/compute/v1/projects/example-264/global/sslCertificates/example-httplb" -> (known after apply)
      ~ subject_alternative_names = [] -> (known after apply)
        type                      = "MANAGED"

      ~ managed {
          ~ domains = [ # forces replacement
              - "iam.sorry.com",
              + "iam.sorry.com.",
            ]
        }
    }

  # google_compute_target_https_proxy.https will be updated in-place
  ~ resource "google_compute_target_https_proxy" "https" {
        creation_timestamp = "2020-06-22T15:41:27.062-07:00"
        description        = "HTTPS load balancer"
        id                 = "projects/example-264/global/targetHttpsProxies/example-httplb-https"
        name               = "example-httplb-https"
        project            = "example-264"
        proxy_id           = 6374t273493109666000
        quic_override      = "NONE"
        self_link          = "https://www.googleapis.com/compute/v1/projects/example-264/global/targetHttpsProxies/example-httplb-https"
      ~ ssl_certificates   = [
          - "https://www.googleapis.com/compute/v1/projects/example-264/global/sslCertificates/example-httplb",
        ] -> (known after apply)
        url_map            = "https://www.googleapis.com/compute/v1/projects/example-264/global/urlMaps/example-httplb"
    }

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

------------------------------------------------------------------------

This plan was saved to: dev-plan.tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "dev-plan.tfplan"
  1. terraform apply

Fails with the following error.

Error: Error reading ManagedSslCertificate: googleapi: Error 400: The ssl_certificate resource 'projects/example-264/global/sslCertificates/example-httplb' is already being used by 'projects/example-264/global/targetHttpsProxies/example-httplb-https', resourceInUseByAnotherResource

Important Factoids

Things I noticed,

  • google_compute_managed_ssl_certificate stores DNS names without a . (root) at the end as part of the SSL cert domains.
  • I also tried supplying DNS names with . at the end. Even at that time, the final DNS names shown in the cert had no .
  • TF plan operation somehow compares the existing DNS names from record sets with the . and Domain names from the SSL cert without the . -> Always sees them as two different things (even though they are the same, and wants to go and recreate the SSL Cert every time. Then trigger other dependencies etc..)

References

It may be the same as #10546. I'm opening this because, I'm not allowed to comment or vote up the issue.
Do note that this is now #5356. But it is related. The workaround suggested by @chrisst is not an acceptable solution for our scenarios because it always enables recreates the SSL cert (Which we don't want)

@ghost ghost added the bug label Jun 22, 2020
@edwardmedia edwardmedia self-assigned this Jun 23, 2020
@edwardmedia
Copy link
Contributor

@universalvishwa I ran below code and can't repro your issue. It does not show difference after initial apply. Your error complains related to google_compute_target_https_proxywhich is not listed here. Can you post all code so I can repro the issue?

# Google managed SSL certificate for HTTPS load balancing
resource "google_compute_managed_ssl_certificate" "default" {
  provider = google-beta
  name = "example-httplb"
  managed {
    domains = [google_dns_record_set.ipv4.name]
  }
  depends_on = [google_dns_record_set.ipv4]
}
# Output
output "dns_names" {
  value = google_dns_record_set.ipv4.name
}
output "ssl_cert" {
  value = {
    certificate_id     = google_compute_managed_ssl_certificate.default.certificate_id,
    creation_timestamp = google_compute_managed_ssl_certificate.default.creation_timestamp,
    expire_time        = google_compute_managed_ssl_certificate.default.expire_time
  }
}
resource "google_dns_record_set" "ipv4" {
  name = "frontend.${google_dns_managed_zone.prod.dns_name}"
  type = "A"
  ttl  = 300
  managed_zone = google_dns_managed_zone.prod.name
  rrdatas = ["10.20.30.40"]
}
resource "google_dns_managed_zone" "prod" {
  name     = "prod-zone"
  dns_name = "myvaliddomain.net."
}

@universalvishwa
Copy link
Author

@edwardmedia, Here is the actual code that I am sure will reproduce the problem.

provider "google" {
  project     = "example-464"
}

terraform {
  required_version = ">= 0.12.26"
}

terraform {
  backend "gcs" {
    bucket = "my-remote-state"
    prefix = "ssltest/clouddns"
  }
}

resource "google_dns_record_set" "ipv4" {
  name = "frontend.${google_dns_managed_zone.prod.dns_name}"
  type = "A"
  ttl  = 300
  managed_zone = google_dns_managed_zone.prod.name
  rrdatas = ["10.20.30.40"]
  project     = "example-464"
}

resource "google_dns_record_set" "ipv6" {
  name = "frontend6.${google_dns_managed_zone.prod.dns_name}"
  type         = "AAAA"
  ttl          = 300
  managed_zone = google_dns_managed_zone.prod.name
  rrdatas = ["2600:1901:0:1717::"]
  project     = "example-464"
}

resource "google_dns_managed_zone" "prod" {
  name     = "prod-zone"
  dns_name = "myvaliddomain.net."
  project     = "example-464"
}

resource "google_compute_url_map" "default" {
  name        = "url-map"
  description = "a description"
  project     = "example-464"

  default_service = google_compute_backend_service.default.id
}

resource "google_compute_backend_service" "default" {
  name        = "backend-service"
  port_name   = "http"
  protocol    = "HTTP"
  timeout_sec = 10
  project     = "example-464"

  health_checks = [google_compute_http_health_check.default.id]
}

resource "google_compute_http_health_check" "default" {
  name               = "http-health-check"
  request_path       = "/"
  check_interval_sec = 1
  timeout_sec        = 1
  project     = "example-464"
}

resource "google_compute_target_https_proxy" "default" {
  name             = "test-proxy"
  url_map          = google_compute_url_map.default.id
  ssl_certificates = [google_compute_managed_ssl_certificate.default.id]
  project     = "example-464"
}

# Google managed SSL certificate for HTTPS load balancing
resource "google_compute_managed_ssl_certificate" "default" {
  provider = google-beta
  name = "example-httplb"
  managed {
    domains = [google_dns_record_set.ipv4.name, google_dns_record_set.ipv6.name]
  }
  project     = "example-464"
  depends_on = [google_dns_record_set.ipv4, google_dns_record_set.ipv6]
}

# Output
output "dns_names" {
  value = google_dns_record_set.ipv4.name
}

output "ssl_cert" {
  value = {
    certificate_id     = google_compute_managed_ssl_certificate.default.certificate_id,
    creation_timestamp = google_compute_managed_ssl_certificate.default.creation_timestamp,
    expire_time        = google_compute_managed_ssl_certificate.default.expire_time
  }
}

@ghost ghost removed the waiting-response label Jun 24, 2020
@edwardmedia
Copy link
Contributor

I do see now the plan shows the differences. Thank you, @universalvishwa

@universalvishwa
Copy link
Author

@edwardmedia @c2thorn , is there any chance that you can confirm if this is a clear bug or not. I'm somewhat blocked on a project I'm working on without clarity. To me it seemed like bug that can be fixed. I would be grateful if you can confirm. Thanks.

@c2thorn
Copy link
Collaborator

c2thorn commented Jun 25, 2020

Hi @universalvishwa
This certainly seems like unintended behavior and can most likely be solved by suppressing differences in the provider when the domain is read with an extra period. I'll be looking into it further today.

@c2thorn
Copy link
Collaborator

c2thorn commented Jun 25, 2020

@universalvishwa
Turns out there was already diff suppression in place that was intended to catch this issue, but fails because it doesn't account for multiple domain names. A fix should be ready soon, but will likely not be released for about a week and a half.

I'm not sure if this would be a viable workaround for you, but you may be able to quickly get around this error by splitting up your IPv4 and IPv6 domains into separate certs in the config.

@universalvishwa
Copy link
Author

Is this fix been released yet?

@c2thorn
Copy link
Collaborator

c2thorn commented Jul 9, 2020

@universalvishwa yes this should be a part ofv3.29 of google-beta

@ghost
Copy link

ghost commented Jul 27, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 hashibot-feedback@hashicorp.com. Thanks!

@ghost ghost locked and limited conversation to collaborators Jul 27, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.