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.v0.11.13 (we cannot upgrade right now due to breaking changes at the v0.12 level)
Working:
resource "google_compute_managed_ssl_certificate" "default" {
provider = "google-beta"
name = "test-cert"
project = "my-gcp-project"
managed {
domains = [
"foo.domain.org",
]
}
}
Broken:
resource "google_compute_managed_ssl_certificate" "default" {
provider = "google-beta"
name = "test-cert"
project = "my-gcp-project"
managed {
domains = [
"foo.domain.org",
"foo2.domain.org",
]
}
}
N/A
N/A
A cert can be created with more than one name covered on it (Alternative Names/ANs). Certs can be created on GCP using the gcloud command. For the above example, if I wanted to create a cert covering foo.domain.org and foo2.domain.org, I would use:
gcloud beta compute ssl-certificates create test-cert --domains="foo.domain.org","foo2.domain.org"
And it would succeed:
Created [https://www.googleapis.com/compute/beta/projects/my-gcp-project/global/sslCertificates/test-cert].
NAME TYPE CREATION_TIMESTAMP EXPIRE_TIME MANAGED_STATUS
test-cert MANAGED 2020-07-07T05:07:45.387-07:00 PROVISIONING
foo.domain.org: PROVISIONING
foo2.domain.org: PROVISIONING
However, when you use the Terraform file with more than one name on the domains, even though the documentation (link at end of report) says it supports up to 100 domains, it refuses to accept the additional domains:
$ terraform plan -out tfplan
Error: google_compute_managed_ssl_certificate.default: managed.0.domains: attribute supports 1 item maximum, config has 2 declared
Provider refuses the second domain even though it is supported underneath.
terraform plan and terraform apply the "working" example earlier, updating the project and credentials values. It will create a SSL cert to "foo.domain.org" (it won't provision, but that's not the problem here)terraform destroyterraform plan the "broken" example -- it will fail the plan with the message "attribute supports 1 item maximum, config has 2 declared"N/A
It fails after adding another domain
Hi @huang-jy ! I'm sorry you're running into this. This was fixed in the 3.3.0 release, once you are able to upgrade to 0.12 you will be able to use this fix. Can I ask what breaking change you are seeing in 0.12 that is preventing you from upgrading?
Thanks!
Thanks for the reply, @megan07
I'll try to confirm what was breaking our upgrade and come back to you.
Is 3.3.0 reliant on 0.12+ terraform?
@huang-jy I'm sorry, unfortunately, yes. We don't support 0.11 anymore, so you would have to upgrade.
Okay, I have reviewed this and the upgrade wasn't done due to the syntax changes in 0.12. The upgrade tool is helping reduce the concerns, but will still require more testing before we upgrade.
As for the original issue, I've tested using 0.12.0 and 0.12.28 and can confirm the cert does work. However, I have discovered something else, which may or may not be an expected behaviour.
I have a Cloud CDN using the SSL cert, fronting a Google Storage bucket to serve static content.
If I add a new name to the cert, Terraform correctly identifies it needs to be replaced, but seems like it is unable to do so:
$ terraform-0.12.28 apply tfplan
static_website_cdn.google_compute_managed_ssl_certificate.default: Destroying... [id=test-cert]
Error: Error when reading or editing ManagedSslCertificate: googleapi: Error 400: The ssl_certificate resource 'projects/my-gcp-project/global/sslCertificates/test-cert' is already being used by 'projects/my-gcp-project/global/targetHttpsProxies/static-website-proxy', resourceInUseByAnotherResource
This does make sense at the cert is attached to the CDN, but how would we update the cert contents in that case?
Hi @huang-jy! I'm glad it is working after the upgrade. I did a little looking and found this section here. It looks like it's suggesting you create a new cert and then go back and delete the old cert. I've never done this before, but theoretically, if you have all the resources in your terraform config, I think you could copy/paste the old cert, make any changes, then reference the new cert on any necessary resources. Once it's updated, you could do a targeted destroy of the old cert. Let me know if you have further questions. Thanks!
The problem here, I think is the ordering. In other to update the cert, the provider would have to
The provider currently recognises it needs to replace the cert if I add a new domain to the list, but when it tries to delete it, it can't since the proxy still holds it.
@huang-jy I'm afraid I'm not understanding what your expectations of the provider would be here? Reading from the document, I think the suggestion is that a new cert should be created in parallel to the existing cert and added to the proxy, and once the new cert status becomes active, the proxy would be reconfigured to remove the old cert and the old cert can than be deleted.
This process would take a couple of terraform runs, but I think is the process the document is suggesting. I may be misreading it or misunderstanding what your expectations are. In either case, please feel free to clarify and let me know how I can help. Thanks!
Indeed, it would take several runs, each time having to manipulate my terraform files -- meaning each time I have to add an additional domain to the cert, I would need to run Terraform multiple times, to manipulate the cert and proxy states as above, rather than just say "Hey, Terraform, here's an additional domain name on the cert, make my config state like this", and then let the provider manage the juggling under the hood.
@huang-jy, would you be willing to share your configuration so I could play around with it some and try to find a more ideal solution? I have never personally done this before, so if I had your configuration handy, I might be able to find a quicker/better work around. Thanks!
Sure, let me sanitise it a bit and I'll share it in a repo.
On Tue, 14 Jul 2020 at 14:04, megan07 notifications@github.com wrote:
@huang-jy https://github.com/huang-jy, would you be willing to share
your configuration so I could play around with it some and try to find a
more ideal solution? I have never personally done this before, so if I had
your configuration handy, I might be able to find a quicker/better work
around. Thanks!—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/terraform-providers/terraform-provider-google/issues/6746#issuecomment-658166777,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAVA5O2KPJY5VD5K34B6GJLR3RJU5ANCNFSM4OSYJEXQ
.
@megan07 I've put a cut-down version in a repo on GitLab: https://gitlab.com/blenderfox/gcp-static-website-terraform
To use, checkout the repo, and edit the variables in the two scripts terraformDestroy.sh and terraformPlanAndRun.sh
Run the terraformPlanAndRun.sh like this:
EXTRA_CERT_NAMES="[]" ./terraformDestroy.sh
This will create a stack with a cert of only one name (will not add any Alternative Names to the cert)
To create a stack with a cert of more than one name, add one or more names to the list, with the double-quotes escaped:
EXTRA_CERT_NAMES="[\"another-name.domain.com\"]" ./terraformPlanAndRun.sh
If you add an additional name to the cert, like this:
EXTRA_CERT_NAMES="[\"another-name.domain.com\",\"yet-another-name.domain.com\"]" ./terraformPlanAndRun.sh
Terraform will try to replace the cert, but will bomb out.
One final note, you will see on this Terraform that I've split out "single" certs (certs with only one name) and "multi" certs (certs with more than one name), this is because on my "prod" version (not included in the repo), when I have additional cert names, I have to also add a DNS entry externally. For the purposes of this test, it doesn't really matter, though, so I removed that.
Hi @huang-jy! Thank you for your patience and letting me see your code!
I think what you're seeing is actually a known upstream issue in terraform. However, I was able to manipulate what you had to circumvent the bug.
The bug you're hitting can be avoided if your proxy depends on the cert's self_link field, and lucky for you, the self_link can be passed into the proxy's ssl_certificates field.
I had to make a few changes, but with these changes it _should_ follow the best practices that I mentioned before - in the sense that it will create a new cert, apply it to the proxy, and then delete the old cert. However, it won't wait for the cert to be active - but my understanding is that this was not important to you.
certs.tf (I added/modified the following code)
locals {
len_certs = length(var.alternative-cert-names)
last_cert_name = local.len_certs == 0 ? "" : "${var.alternative-cert-names[local.len_certs - 1]}"
}
resource "random_integer" "cert-suffix" {
min = 1
max = 100
keepers = {
# Generate a new integer each time we add a new domain to the end of the cert name list
alternative_cert_names = local.last_cert_name
}
}
resource "google_compute_managed_ssl_certificate" "multi-name-cert" {
count = length(var.alternative-cert-names) != 0 ? 1 : 0
provider = google-beta
name = "${var.backend_name}-cert-${random_integer.cert-suffix.result}"
project = var.project_id
lifecycle {
create_before_destroy = true
}
managed {
domains = concat(["${var.backend_name}.${var.domain}."], "${var.alternative-cert-names}")
}
}
As you can see, I added the lifecycle.create_before_destroy block to the cert. What this will do is create a new cert before destroying the current one, allowing us to update the proxy to the new value before the current cert is destroyed.
I had to also add the random int to the end of the cert name so that we didn't try to recreate a cert of the same name, since the name has to be unique. The catch here is that whenever you want to add a domain to alternative-cert-names, you will need to add it to the end of the list, as that is the value that it's checking to generate a new random int.
lb_cdn.tf (I modified the following code)
resource "google_compute_target_https_proxy" "single-name-cert-proxy" {
count = length(var.alternative-cert-names) == 0 ? 1 : 0
name = "${var.backend_name}-${var.env}-static-website-proxy-single"
project = var.project_id
url_map = google_compute_url_map.urlmap.self_link
ssl_certificates = [google_compute_managed_ssl_certificate.single-name-cert.0.self_link]
}
resource "google_compute_target_https_proxy" "multi-name-cert-proxy" {
count = length(var.alternative-cert-names) != 0 ? 1 : 0
name = "${var.backend_name}-${var.env}-static-website-proxy-multiple"
project = var.project_id
url_map = google_compute_url_map.urlmap.self_link
ssl_certificates = [google_compute_managed_ssl_certificate.multi-name-cert.0.self_link]
}
I deleted the depends_on per the bug above, and instead created the dependency by referencing the self_link of each cert here. This will circumvent the bug and create the appropriate dependency, acknowledging that the proxy needs to be updated when the cert self_link changes (which will happen when it's name changes).
I also added "single/multiple" to the end of the proxy names so there wasn't any race condition when deleting the single-cert proxy and creating the multiple-cert proxy.
Please let me know if this helps. Thanks!
Thanks for all the help, @megan07 I will implement and check your changes then incorporate those into the prod setup if they work. I'll come back and let you know if it all works or not.
I have had a play with the updates you made to the terraform code, @megan07 and for the most part it works. One thing I have noticed though, and that is with ordering.
If I go from an empty list "[]" to a list with names, say "["a.com", "b.com]", this update works.
If I add a third: "["a.com", "b.com", "c.com"]", it also works.
If I _change_ the last element of the list: "["a.com", "b.com", "d.com"]", it also works.
If I change any other element of the list, it won't work. For example: changing "["a.com", "b.com", "d.com"]" to "["e.com", "b.com", "d.com"]", BUT if I apply the change put putting the change at the end of the list instead: "["b.com", "d.com","e.com"]"
I think this is centred around the use of the block here:
locals {
len_certs = length(var.alternative-cert-names)
last_cert_name = local.len_certs == 0 ? "" : "${var.alternative-cert-names[local.len_certs - 1]}"
}
resource "random_integer" "cert-suffix" {
min = 1
max = 100
keepers = {
# Generate a new integer each time we add a new domain to the end of the cert name list
alternative_cert_names = local.last_cert_name
}
}
While we could use this, having to ask a user to "remember" to put updates at the end of the list is going to at some point in the future be missed.
Are we able to monitor the entire cert name list for changes, rather than just the last cert name?
@huang-jy yes, great point! i brought this up to my team, and this didn't even cross my mind, but we can join the list together, and that should work fine, so just change that block to
locals {
len_certs = length(var.alternative-cert-names)
domain_names = join(", ", var.alternative-cert-names)
}
resource "random_integer" "cert-suffix" {
min = 1
max = 100
keepers = {
# Generate a new integer each time we change the cert name list
alternative_cert_names = local.domain_names
}
}
I am closing this issue now. The updates work perfectly, thanks for your help @megan07
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 👉 [email protected]. Thanks!