From c3898c945c7f8c93d111406ebf729f2ebdff61a2 Mon Sep 17 00:00:00 2001 From: Noah Fontes Date: Fri, 1 Apr 2022 21:53:21 -0700 Subject: [PATCH] Add support for creating external resources associated with self-managed certificates --- auth0/resource_auth0_custom_domain.go | 5 ++ ...source_auth0_custom_domain_verification.go | 29 +++++++- docs/resources/custom_domain.md | 1 + docs/resources/custom_domain_verification.md | 6 +- .../README.md | 7 ++ .../addresses.tf | 29 ++++++++ .../custom_domain_self_managed_certs/main.tf | 30 ++++++++ .../custom_domain_self_managed_certs/proxy.tf | 73 +++++++++++++++++++ .../variables.tf | 9 +++ .../versions.tf | 7 ++ go.mod | 4 +- go.sum | 4 +- 12 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 example/custom_domain_self_managed_certs/README.md create mode 100644 example/custom_domain_self_managed_certs/addresses.tf create mode 100644 example/custom_domain_self_managed_certs/main.tf create mode 100644 example/custom_domain_self_managed_certs/proxy.tf create mode 100644 example/custom_domain_self_managed_certs/variables.tf create mode 100644 example/custom_domain_self_managed_certs/versions.tf diff --git a/auth0/resource_auth0_custom_domain.go b/auth0/resource_auth0_custom_domain.go index fc2656af8..a15449e49 100644 --- a/auth0/resource_auth0_custom_domain.go +++ b/auth0/resource_auth0_custom_domain.go @@ -43,6 +43,10 @@ func newCustomDomain() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "origin_domain_name": { + Type: schema.TypeString, + Computed: true, + }, "verification_method": { Type: schema.TypeString, Optional: true, @@ -97,6 +101,7 @@ func readCustomDomain(ctx context.Context, d *schema.ResourceData, m interface{} d.Set("type", customDomain.Type), d.Set("primary", customDomain.Primary), d.Set("status", customDomain.Status), + d.Set("origin_domain_name", customDomain.OriginDomainName), ) if customDomain.Verification != nil { diff --git a/auth0/resource_auth0_custom_domain_verification.go b/auth0/resource_auth0_custom_domain_verification.go index 2a0366202..09e866ae2 100644 --- a/auth0/resource_auth0_custom_domain_verification.go +++ b/auth0/resource_auth0_custom_domain_verification.go @@ -8,6 +8,7 @@ import ( "time" "github.com/auth0/go-auth0/management" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -27,6 +28,15 @@ func newCustomDomainVerification() *schema.Resource { Required: true, ForceNew: true, }, + "origin_domain_name": { + Type: schema.TypeString, + Computed: true, + }, + "cname_api_key": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(5 * time.Minute), @@ -52,14 +62,20 @@ func createCustomDomainVerification(ctx context.Context, d *schema.ResourceData, d.SetId(customDomainVerification.GetID()) - if result := readCustomDomainVerification(ctx, d, m); result.HasError() { - return resource.NonRetryableError(fmt.Errorf("failed to read custom domain verification")) + // The cname_api_key field is only given once: when verification + // succeeds for the first time. Therefore, we set it on the resource in + // the creation routine only, and never touch it again. + if err := d.Set("cname_api_key", customDomainVerification.CNAMEAPIKey); err != nil { + return resource.NonRetryableError(err) } return nil }) + if err != nil { + return diag.FromErr(err) + } - return diag.FromErr(err) + return readCustomDomainVerification(ctx, d, m) } func readCustomDomainVerification(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { @@ -75,7 +91,12 @@ func readCustomDomainVerification(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(err) } - return diag.FromErr(d.Set("custom_domain_id", customDomain.GetID())) + result := multierror.Append( + d.Set("custom_domain_id", customDomain.GetID()), + d.Set("origin_domain_name", customDomain.OriginDomainName), + ) + + return diag.FromErr(result.ErrorOrNil()) } func deleteCustomDomainVerification(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { diff --git a/docs/resources/custom_domain.md b/docs/resources/custom_domain.md index afc66a1ce..485ec773c 100644 --- a/docs/resources/custom_domain.md +++ b/docs/resources/custom_domain.md @@ -35,6 +35,7 @@ Attributes exported by this resource include: * `primary` - Boolean. Indicates whether this is a primary domain. * `status` - String. Configuration status for the custom domain. Options include `disabled`, `pending`, `pending_verification`, and `ready`. +* `origin_domain_name` - String. Once the configuration status is `ready`, the DNS name of the Auth0 origin server that handles traffic for the custom domain. * `verification` - List(Resource). Configuration settings for verification. For details, see [Verification](#verification). ### Verification diff --git a/docs/resources/custom_domain_verification.md b/docs/resources/custom_domain_verification.md index 9486e1dc6..b06bffa9e 100644 --- a/docs/resources/custom_domain_verification.md +++ b/docs/resources/custom_domain_verification.md @@ -53,7 +53,11 @@ domain name record (DNS) to be created before attempting to verify the custom do ## Attributes Reference -No additional attributes are exported by this resource. +In addition to the arguments listed above, the following computed attributes are +exported: + +* `origin_domain_name` - String. The DNS name of the Auth0 origin server that handles traffic for the custom domain. +* `cname_api_key` - String. The value of the `cname-api-key` header to send when forwarding requests. Only present if the type of the custom domain is `self_managed_certs` and Terraform originally managed the domain's verification. ## Import diff --git a/example/custom_domain_self_managed_certs/README.md b/example/custom_domain_self_managed_certs/README.md new file mode 100644 index 000000000..f9d15c961 --- /dev/null +++ b/example/custom_domain_self_managed_certs/README.md @@ -0,0 +1,7 @@ +# Custom Domain with Self-managed Certificates on GCP + +This example sets up an Auth0 tenant with a custom domain that uses self-managed certificates. It also configures the appropriate resources in Google Cloud Platform to forward requests to Auth0 over HTTPS. + +To use this example, in addition to setting the usual Auth0 environment variables, you will also need to set `GOOGLE_PROJECT` and `GOOGLE_CREDENTIALS` (or equivalent; see [the provider reference](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#authentication) for more information). + +Note that Google-managed certificates take some time to provision. If everything in the configuration looks right but you're getting TLS errors trying to load your custom domain, you should wait 5-10 minutes and then refresh the page. diff --git a/example/custom_domain_self_managed_certs/addresses.tf b/example/custom_domain_self_managed_certs/addresses.tf new file mode 100644 index 000000000..f54176276 --- /dev/null +++ b/example/custom_domain_self_managed_certs/addresses.tf @@ -0,0 +1,29 @@ +resource "google_compute_global_address" "lb_ipv4" { + name = "auth0-ipv4" + ip_version = "IPV4" +} + +resource "google_compute_global_address" "lb_ipv6" { + name = "auth0-ipv6" + ip_version = "IPV6" +} + +resource "google_dns_record_set" "lb_a" { + name = "${var.domain}." + managed_zone = var.managed_zone_name + type = "A" + ttl = 300 + rrdatas = [ + google_compute_global_address.lb_ipv4.address, + ] +} + +resource "google_dns_record_set" "lb_aaaa" { + name = "${var.domain}." + managed_zone = var.managed_zone_name + type = "AAAA" + ttl = 300 + rrdatas = [ + google_compute_global_address.lb_ipv6.address, + ] +} diff --git a/example/custom_domain_self_managed_certs/main.tf b/example/custom_domain_self_managed_certs/main.tf new file mode 100644 index 000000000..d6e8676e2 --- /dev/null +++ b/example/custom_domain_self_managed_certs/main.tf @@ -0,0 +1,30 @@ +provider "auth0" {} + +provider "google" {} + +resource "auth0_custom_domain" "my_domain" { + domain = var.domain + type = "self_managed_certs" +} + +resource "google_dns_record_set" "my_domain_verification" { + name = "${auth0_custom_domain.my_domain.verification[0].methods[0].domain}." + managed_zone = var.managed_zone_name + type = upper(auth0_custom_domain.my_domain.verification[0].methods[0].name) + ttl = 300 + rrdatas = [ + "${auth0_custom_domain.my_domain.verification[0].methods[0].record}.", + ] +} + +resource "auth0_custom_domain_verification" "my_domain" { + custom_domain_id = auth0_custom_domain.my_domain.id + + depends_on = [ + google_dns_record_set.my_domain_verification, + ] + + timeouts { + create = "15m" + } +} diff --git a/example/custom_domain_self_managed_certs/proxy.tf b/example/custom_domain_self_managed_certs/proxy.tf new file mode 100644 index 000000000..94f51d6f2 --- /dev/null +++ b/example/custom_domain_self_managed_certs/proxy.tf @@ -0,0 +1,73 @@ +resource "google_compute_global_network_endpoint_group" "proxy" { + name = "auth0-proxy" + network_endpoint_type = "INTERNET_FQDN_PORT" +} + +resource "google_compute_global_network_endpoint" "proxy" { + global_network_endpoint_group = google_compute_global_network_endpoint_group.proxy.name + + fqdn = auth0_custom_domain_verification.my_domain.origin_domain_name + port = 443 +} + +resource "google_compute_backend_service" "proxy" { + name = "auth0-proxy" + description = "Auth0 authentication proxy" + + backend { + group = google_compute_global_network_endpoint_group.proxy.self_link + } + + protocol = "HTTPS" + enable_cdn = false + + log_config { + enable = true + } + + custom_request_headers = [ + "host: ${auth0_custom_domain_verification.my_domain.origin_domain_name}", + "cname-api-key: ${auth0_custom_domain_verification.my_domain.cname_api_key}", + ] +} + +resource "google_compute_url_map" "proxy_https" { + name = "auth0-proxy-https" + description = "HTTPS endpoint for the Auth0 authentication proxy" + + default_service = google_compute_backend_service.proxy.self_link +} + +resource "google_compute_managed_ssl_certificate" "proxy" { + name = "auth0-proxy-https" + + managed { + domains = [var.domain] + } +} + +resource "google_compute_target_https_proxy" "proxy" { + name = "auth0-proxy-https" + url_map = google_compute_url_map.proxy_https.self_link + ssl_certificates = [ + google_compute_managed_ssl_certificate.proxy.self_link, + ] +} + +resource "google_compute_global_forwarding_rule" "proxy_https_ipv4" { + name = "auth0-proxy-https-ipv4" + load_balancing_scheme = "EXTERNAL" + port_range = "443" + + ip_address = google_compute_global_address.lb_ipv4.address + target = google_compute_target_https_proxy.proxy.self_link +} + +resource "google_compute_global_forwarding_rule" "proxy_https_ipv6" { + name = "auth0-proxy-https-ipv6" + load_balancing_scheme = "EXTERNAL" + port_range = "443" + + ip_address = google_compute_global_address.lb_ipv6.address + target = google_compute_target_https_proxy.proxy.self_link +} diff --git a/example/custom_domain_self_managed_certs/variables.tf b/example/custom_domain_self_managed_certs/variables.tf new file mode 100644 index 000000000..5011fa68f --- /dev/null +++ b/example/custom_domain_self_managed_certs/variables.tf @@ -0,0 +1,9 @@ +variable "domain" { + description = "The name of the custom domain to provision" + type = string +} + +variable "managed_zone_name" { + description = "The name of the Cloud DNS managed zone to create DNS records in" + type = string +} diff --git a/example/custom_domain_self_managed_certs/versions.tf b/example/custom_domain_self_managed_certs/versions.tf new file mode 100644 index 000000000..f9560d77f --- /dev/null +++ b/example/custom_domain_self_managed_certs/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + auth0 = { + source = "auth0/auth0" + } + } +} diff --git a/go.mod b/go.mod index ad32fd378..1db9d600f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module github.com/auth0/terraform-provider-auth0 go 1.18 require ( - github.com/auth0/go-auth0 v0.6.1 + github.com/auth0/go-auth0 v0.6.2 + github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/terraform-plugin-sdk/v2 v2.13.0 ) @@ -20,7 +21,6 @@ require ( github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect github.com/hashicorp/go-hclog v1.2.0 // indirect github.com/hashicorp/go-plugin v1.4.3 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect diff --git a/go.sum b/go.sum index 9c5c0d168..71e0dfed1 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJE github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/auth0/go-auth0 v0.6.1 h1:D6WSxLQyr1+Ozn8qW0KJAKVcy1j7ZxbRoWdZQr0qT8s= -github.com/auth0/go-auth0 v0.6.1/go.mod h1:9rEJrEWFALKlt1VVCx1zToCG6+uddn4MLEgtKSRhlEU= +github.com/auth0/go-auth0 v0.6.2 h1:vnP0tdDqNDXnyRBM4Sxf4urQaKPOSV6BD8EtyhXIjhU= +github.com/auth0/go-auth0 v0.6.2/go.mod h1:9rEJrEWFALKlt1VVCx1zToCG6+uddn4MLEgtKSRhlEU= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=