diff --git a/mmv1/third_party/terraform/utils/config.go.erb b/mmv1/third_party/terraform/utils/config.go.erb index 5e5d065ebd3b..f90d22423ade 100644 --- a/mmv1/third_party/terraform/utils/config.go.erb +++ b/mmv1/third_party/terraform/utils/config.go.erb @@ -128,10 +128,48 @@ type Config struct { GkeHubBasePath string } +<% products.each do |product| -%> +const <%= product[:definitions].name -%>BasePathKey = "<%= product[:definitions].name -%>" +<% end -%> +const CloudBillingBasePathKey = "CloudBilling" +const ComposerBasePathKey = "Composer" +const ComputeBetaBasePathKey = "ComputeBeta" +const ContainerBasePathKey = "Container" +const DataprocBetaBasePathKey = "DataprocBeta" +const ContainerBetaBasePathKey = "ContainerBeta" +const DataflowBasePathKey = "Dataflow" +const IAMBasePathKey = "IAM" +const IamCredentialsBasePathKey = "IamCredentials" +const ResourceManagerV2BasePathKey = "ResourceManagerV2" +const ServiceNetworkingBasePathKey = "ServiceNetworking" +const StorageTransferBasePathKey = "StorageTransfer" +const BigtableAdminBasePathKey = "BigtableAdmin" +const GkeHubFeatureBasePathKey = "GkeHubFeatureBasePathKey" + // Generated product base paths +var DefaultBasePaths = map[string]string{ <% products.each do |product| -%> -var <%= product[:definitions].name -%>DefaultBasePath = "<%= product[:definitions].base_url -%>" + <%= product[:definitions].name -%>BasePathKey : "<%= product[:definitions].base_url -%>", +<% end -%> + CloudBillingBasePathKey : "https://cloudbilling.googleapis.com/v1/", +<% if version == "ga" -%> + ComposerBasePathKey : "https://composer.googleapis.com/v1/", +<% else -%> + ComposerBasePathKey : "https://composer.googleapis.com/v1beta1/", <% end -%> + ComputeBetaBasePathKey : "https://www.googleapis.com/compute/beta/", + ContainerBasePathKey : "https://container.googleapis.com/v1/", + ContainerBetaBasePathKey : "https://container.googleapis.com/v1beta1/", + DataprocBetaBasePathKey : "https://dataproc.googleapis.com/v1beta2/", + DataflowBasePathKey : "https://dataflow.googleapis.com/v1b3/", + IAMBasePathKey : "https://iam.googleapis.com/v1/", + IamCredentialsBasePathKey : "https://iamcredentials.googleapis.com/v1/", + ResourceManagerV2BasePathKey : "https://cloudresourcemanager.googleapis.com/v2/", + ServiceNetworkingBasePathKey : "https://servicenetworking.googleapis.com/v1/", + StorageTransferBasePathKey : "https://storagetransfer.googleapis.com/v1/", + BigtableAdminBasePathKey : "https://bigtableadmin.googleapis.com/v2/", + GkeHubFeatureBasePathKey: "https://gkehub.googleapis.com/v1beta/", +} var DefaultClientScopes = []string{ "https://www.googleapis.com/auth/compute", @@ -158,9 +196,11 @@ func (c *Config) LoadAndValidate(ctx context.Context) error { cleanCtx := context.WithValue(ctx, oauth2.HTTPClient, cleanhttp.DefaultClient()) - // 1. OAUTH2 TRANSPORT/CLIENT - sets up proper auth headers - client := oauth2.NewClient(cleanCtx, tokenSource) - + // 1. MTLS TRANSPORT/CLIENT - sets up proper auth headers + client, _, err := transport.NewHTTPClient(cleanCtx, option.WithTokenSource(tokenSource)) + if err != nil { + return err + } // Userinfo is fetched before request logging is enabled to reduce additional noise. err = c.logGoogleIdentities() if err != nil { @@ -886,22 +926,22 @@ func removeBasePathVersion(url string) string { func ConfigureBasePaths(c *Config) { // Generated Products <% products.map.each do |product| -%> - c.<%= product[:definitions].name -%>BasePath = <%= product[:definitions].name -%>DefaultBasePath + c.<%= product[:definitions].name -%>BasePath = DefaultBasePaths[<%= product[:definitions].name -%>BasePathKey] <% end -%> // Handwritten Products / Versioned / Atypical Entries - c.CloudBillingBasePath = CloudBillingDefaultBasePath - c.ComposerBasePath = ComposerDefaultBasePath - c.ComputeBetaBasePath = ComputeBetaDefaultBasePath - c.ContainerBasePath = ContainerDefaultBasePath - c.ContainerBetaBasePath = ContainerBetaDefaultBasePath - c.DataprocBasePath = DataprocDefaultBasePath - c.DataflowBasePath = DataflowDefaultBasePath - c.IamCredentialsBasePath = IamCredentialsDefaultBasePath - c.ResourceManagerV2BasePath = ResourceManagerV2DefaultBasePath - c.IAMBasePath = IAMDefaultBasePath - c.ServiceNetworkingBasePath = ServiceNetworkingDefaultBasePath - c.BigQueryBasePath = BigQueryDefaultBasePath - c.StorageTransferBasePath = StorageTransferDefaultBasePath - c.BigtableAdminBasePath = BigtableAdminDefaultBasePath + c.CloudBillingBasePath = DefaultBasePaths[CloudBillingBasePathKey] + c.ComposerBasePath = DefaultBasePaths[ComposerBasePathKey] + c.ComputeBetaBasePath = DefaultBasePaths[ComputeBetaBasePathKey] + c.ContainerBasePath = DefaultBasePaths[ContainerBasePathKey] + c.ContainerBetaBasePath = DefaultBasePaths[ContainerBetaBasePathKey] + c.DataprocBasePath = DefaultBasePaths[DataprocBasePathKey] + c.DataflowBasePath = DefaultBasePaths[DataflowBasePathKey] + c.IamCredentialsBasePath = DefaultBasePaths[IamCredentialsBasePathKey] + c.ResourceManagerV2BasePath = DefaultBasePaths[ResourceManagerV2BasePathKey] + c.IAMBasePath = DefaultBasePaths[IAMBasePathKey] + c.ServiceNetworkingBasePath = DefaultBasePaths[ServiceNetworkingBasePathKey] + c.BigQueryBasePath = DefaultBasePaths[BigQueryBasePathKey] + c.StorageTransferBasePath = DefaultBasePaths[StorageTransferBasePathKey] + c.BigtableAdminBasePath = DefaultBasePaths[BigtableAdminBasePathKey] } diff --git a/mmv1/third_party/terraform/utils/mtls_util.go b/mmv1/third_party/terraform/utils/mtls_util.go new file mode 100644 index 000000000000..a5ef1d933263 --- /dev/null +++ b/mmv1/third_party/terraform/utils/mtls_util.go @@ -0,0 +1,46 @@ +package google + +import ( + "context" + "fmt" + "net/url" + "strings" + + "google.golang.org/api/option/internaloption" + "google.golang.org/api/transport" +) + +// The transport libaray does not natively expose logic to determine whether +// the user is within mtls mode or not. They do return the mtls endpoint if +// it is enabled during client creation so we will use this logic to determine +// the mode the user is in and throw away the client they give us back. +func isMtls() bool { + regularEndpoint := "https://mockservice.googleapis.com/v1/" + mtlsEndpoint := getMtlsEndpoint(regularEndpoint) + _, endpoint, err := transport.NewHTTPClient(context.Background(), + internaloption.WithDefaultEndpoint(regularEndpoint), + internaloption.WithDefaultMTLSEndpoint(mtlsEndpoint), + ) + if err != nil { + return false + } + isMtls := endpoint == mtlsEndpoint + return isMtls +} + +func getMtlsEndpoint(baseEndpoint string) string { + u, err := url.Parse(baseEndpoint) + if err != nil { + if strings.Contains(baseEndpoint, ".googleapis") { + return strings.Replace(baseEndpoint, ".googleapis", ".mtls.googleapis", 1) + } + return baseEndpoint + } + domainParts := strings.Split(u.Host, ".") + if len(domainParts) > 1 { + u.Host = fmt.Sprintf("%s.mtls.%s", domainParts[0], strings.Join(domainParts[1:], ".")) + } else { + u.Host = fmt.Sprintf("%s.mtls", domainParts[0]) + } + return u.String() +} diff --git a/mmv1/third_party/terraform/utils/mtls_util_test.go b/mmv1/third_party/terraform/utils/mtls_util_test.go new file mode 100644 index 000000000000..d1e4b9cfdc98 --- /dev/null +++ b/mmv1/third_party/terraform/utils/mtls_util_test.go @@ -0,0 +1,16 @@ +package google + +import ( + "strings" + "testing" +) + +func TestUnitMtls_urlSwitching(t *testing.T) { + t.Parallel() + for key, bp := range DefaultBasePaths { + url := getMtlsEndpoint(bp) + if !strings.Contains(url, ".mtls.") { + t.Errorf("%s: mtls conversion unsuccessful preconv - %s postconv - %s", key, bp, url) + } + } +} diff --git a/mmv1/third_party/terraform/utils/provider.go.erb b/mmv1/third_party/terraform/utils/provider.go.erb index e03b4c07a47f..0fb7b23ad8a1 100644 --- a/mmv1/third_party/terraform/utils/provider.go.erb +++ b/mmv1/third_party/terraform/utils/provider.go.erb @@ -20,6 +20,18 @@ var mutexKV = NewMutexKV() // Provider returns a *schema.Provider. func Provider() *schema.Provider { + + // The mtls service client gives the type of endpoint (mtls/regular) + // at client creation. Since we use a shared client for requests we must + // rewrite the endpoints to be mtls endpoints for the scenario where + // mtls is enabled. + if isMtls() { + // if mtls is enabled switch all default endpoints to use the mtls endpoint + for key, bp := range DefaultBasePaths { + DefaultBasePaths[key] = getMtlsEndpoint(bp) + } + } + provider := &schema.Provider{ Schema: map[string]*schema.Schema{ "credentials": &schema.Schema{ @@ -134,7 +146,7 @@ func Provider() *schema.Provider { ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_<%= product[:definitions].name.underscore.upcase -%>_CUSTOM_ENDPOINT", - }, <%= product[:definitions].name -%>DefaultBasePath), + }, DefaultBasePaths[<%= product[:definitions].name -%>BasePathKey]), }, <% end -%> diff --git a/mmv1/third_party/terraform/utils/provider_handwritten_endpoint.go.erb b/mmv1/third_party/terraform/utils/provider_handwritten_endpoint.go.erb index 28a86dff9a33..3101fed4c59a 100644 --- a/mmv1/third_party/terraform/utils/provider_handwritten_endpoint.go.erb +++ b/mmv1/third_party/terraform/utils/provider_handwritten_endpoint.go.erb @@ -9,7 +9,6 @@ import ( // files. Collect handwritten ones here. If any of these are modified, be sure // to update the provider_reference docs page. -var CloudBillingDefaultBasePath = "https://cloudbilling.googleapis.com/v1/" var CloudBillingCustomEndpointEntryKey = "cloud_billing_custom_endpoint" var CloudBillingCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -17,14 +16,9 @@ var CloudBillingCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_CLOUD_BILLING_CUSTOM_ENDPOINT", - }, CloudBillingDefaultBasePath), + }, DefaultBasePaths[CloudBillingBasePathKey]), } -<% if version == "ga" -%> -var ComposerDefaultBasePath = "https://composer.googleapis.com/v1/" -<% else -%> -var ComposerDefaultBasePath = "https://composer.googleapis.com/v1beta1/" -<% end -%> var ComposerCustomEndpointEntryKey = "composer_custom_endpoint" var ComposerCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -32,10 +26,9 @@ var ComposerCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_COMPOSER_CUSTOM_ENDPOINT", - }, ComposerDefaultBasePath), + }, DefaultBasePaths[ComposerBasePathKey]), } -var ComputeBetaDefaultBasePath = "https://www.googleapis.com/compute/beta/" var ComputeBetaCustomEndpointEntryKey = "compute_beta_custom_endpoint" var ComputeBetaCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -43,10 +36,9 @@ var ComputeBetaCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_COMPUTE_BETA_CUSTOM_ENDPOINT", - }, ComputeBetaDefaultBasePath), + }, DefaultBasePaths[ComputeBetaBasePathKey]), } -var ContainerDefaultBasePath = "https://container.googleapis.com/v1/" var ContainerCustomEndpointEntryKey = "container_custom_endpoint" var ContainerCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -54,10 +46,9 @@ var ContainerCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_CONTAINER_CUSTOM_ENDPOINT", - }, ContainerDefaultBasePath), + }, DefaultBasePaths[ContainerBasePathKey]), } -var ContainerBetaDefaultBasePath = "https://container.googleapis.com/v1beta1/" var ContainerBetaCustomEndpointEntryKey = "container_beta_custom_endpoint" var ContainerBetaCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -65,10 +56,9 @@ var ContainerBetaCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_CONTAINER_BETA_CUSTOM_ENDPOINT", - }, ContainerBetaDefaultBasePath), + }, DefaultBasePaths[ContainerBetaBasePathKey]), } -var DataprocBetaDefaultBasePath = "https://dataproc.googleapis.com/v1beta2/" var DataprocBetaCustomEndpointEntryKey = "dataproc_beta_custom_endpoint" var DataprocBetaCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -76,10 +66,9 @@ var DataprocBetaCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_DATAPROC_BETA_CUSTOM_ENDPOINT", - }, DataprocBetaDefaultBasePath), + }, DefaultBasePaths[DataprocBetaBasePathKey]), } -var DataflowDefaultBasePath = "https://dataflow.googleapis.com/v1b3/" var DataflowCustomEndpointEntryKey = "dataflow_custom_endpoint" var DataflowCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -87,10 +76,9 @@ var DataflowCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_DATAFLOW_CUSTOM_ENDPOINT", - }, DataflowDefaultBasePath), + }, DefaultBasePaths[DataflowBasePathKey]), } -var IAMDefaultBasePath = "https://iam.googleapis.com/v1/" var IAMCustomEndpointEntryKey = "iam_custom_endpoint" var IAMCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -98,10 +86,9 @@ var IAMCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_IAM_CUSTOM_ENDPOINT", - }, IAMDefaultBasePath), + }, DefaultBasePaths[IAMBasePathKey]), } -var IamCredentialsDefaultBasePath = "https://iamcredentials.googleapis.com/v1/" var IamCredentialsCustomEndpointEntryKey = "iam_credentials_custom_endpoint" var IamCredentialsCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -109,10 +96,9 @@ var IamCredentialsCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_IAM_CREDENTIALS_CUSTOM_ENDPOINT", - }, IamCredentialsDefaultBasePath), + }, DefaultBasePaths[IamCredentialsBasePathKey]), } -var ResourceManagerV2DefaultBasePath = "https://cloudresourcemanager.googleapis.com/v2/" var ResourceManagerV2CustomEndpointEntryKey = "resource_manager_v2_custom_endpoint" var ResourceManagerV2CustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -120,7 +106,7 @@ var ResourceManagerV2CustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_RESOURCE_MANAGER_V2_CUSTOM_ENDPOINT", - }, ResourceManagerV2DefaultBasePath), + }, DefaultBasePaths[ResourceManagerV2BasePathKey]), } var RuntimeConfigCustomEndpointEntryKey = "runtimeconfig_custom_endpoint" @@ -130,10 +116,9 @@ var RuntimeConfigCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_RUNTIMECONFIG_CUSTOM_ENDPOINT", - }, RuntimeConfigDefaultBasePath), + }, DefaultBasePaths[RuntimeConfigBasePathKey]), } -var ServiceNetworkingDefaultBasePath = "https://servicenetworking.googleapis.com/v1/" var ServiceNetworkingCustomEndpointEntryKey = "service_networking_custom_endpoint" var ServiceNetworkingCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -141,7 +126,7 @@ var ServiceNetworkingCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_SERVICE_NETWORKING_CUSTOM_ENDPOINT", - }, ServiceNetworkingDefaultBasePath), + }, DefaultBasePaths[ServiceNetworkingBasePathKey]), } var ServiceUsageCustomEndpointEntryKey = "service_usage_custom_endpoint" @@ -151,10 +136,9 @@ var ServiceUsageCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_SERVICE_USAGE_CUSTOM_ENDPOINT", - }, ServiceUsageDefaultBasePath), + }, DefaultBasePaths[ServiceUsageBasePathKey]), } -var StorageTransferDefaultBasePath = "https://storagetransfer.googleapis.com/v1/" var StorageTransferCustomEndpointEntryKey = "storage_transfer_custom_endpoint" var StorageTransferCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -162,10 +146,9 @@ var StorageTransferCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_STORAGE_TRANSFER_CUSTOM_ENDPOINT", - }, StorageTransferDefaultBasePath), + }, DefaultBasePaths[StorageTransferBasePathKey]), } -var BigtableAdminDefaultBasePath = "https://bigtableadmin.googleapis.com/v2/" var BigtableAdminCustomEndpointEntryKey = "bigtable_custom_endpoint" var BigtableAdminCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -173,22 +156,10 @@ var BigtableAdminCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_BIGTABLE_CUSTOM_ENDPOINT", - }, BigtableAdminDefaultBasePath), -} - -var EventarcDefaultBasePath = "https://eventarc.googleapis.com/v1/" -var EventarcCustomEndpointEntryKey = "eventarc_custom_endpoint" -var EventarcCustomEndpointEntry = &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateCustomEndpoint, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{ - "GOOGLE_EVENTARC_CUSTOM_ENDPOINT", - }, EventarcDefaultBasePath), + }, DefaultBasePaths[BigtableAdminBasePathKey]), } // GkeHubFeature uses a different base path "v1beta" than GkeHubMembership "v1beta1" -var GkeHubFeatureDefaultBasePath = "https://gkehub.googleapis.com/v1beta/" var GkeHubFeatureCustomEndpointEntryKey = "gkehub_feature_custom_endpoint" var GkeHubFeatureCustomEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -196,7 +167,7 @@ var GkeHubFeatureCustomEndpointEntry = &schema.Schema{ ValidateFunc: validateCustomEndpoint, DefaultFunc: schema.MultiEnvDefaultFunc([]string{ "GOOGLE_GKEHUB_FEATURE_CUSTOM_ENDPOINT", - }, GkeHubFeatureDefaultBasePath), + }, DefaultBasePaths[GkeHubFeatureBasePathKey]), } func validateCustomEndpoint(v interface{}, k string) (ws []string, errors []error) { diff --git a/mmv1/third_party/terraform/website/docs/guides/provider_reference.html.markdown b/mmv1/third_party/terraform/website/docs/guides/provider_reference.html.markdown index 478211f0ce90..42d127facbfa 100644 --- a/mmv1/third_party/terraform/website/docs/guides/provider_reference.html.markdown +++ b/mmv1/third_party/terraform/website/docs/guides/provider_reference.html.markdown @@ -78,6 +78,10 @@ credential/authentication file. Ensure that the scope of the VM/Cluster is set t If you are running terraform outside of Google Cloud, generate a service account key and set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of the service account key. Terraform will use that key for authentication. +### Disabling mtls authentication + +[mtls authentication](https://google.aip.dev/auth/4114) will soon become enabled by default if your system supports it. To disable mtls authentication at any point set `GOOGLE_API_USE_CLIENT_CERTIFICATE` to `false`. + ### Impersonating Service Accounts Terraform can impersonate a Google Service Account as described [here](https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials). A valid credential must be provided as mentioned in the earlier section and that identity must have the `roles/iam.serviceAccountTokenCreator` role on the service account you are impersonating. diff --git a/tpgtools/templates/provider_dcl_endpoints.go.tmpl b/tpgtools/templates/provider_dcl_endpoints.go.tmpl index 3cdb51834d7c..cef39a593fb0 100644 --- a/tpgtools/templates/provider_dcl_endpoints.go.tmpl +++ b/tpgtools/templates/provider_dcl_endpoints.go.tmpl @@ -31,6 +31,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +// empty string is passed for dcl default since dcl +// [hardcodes the values](https://github.com/GoogleCloudPlatform/declarative-resource-client-library/blob/main/services/google/eventarc/beta/trigger_internal.go#L96-L103) {{range $index, $pkg := .}} {{- if $pkg.WriteBasePath }} var {{$pkg.ProductType}}EndpointEntryKey = "{{$pkg.ProductName}}_custom_endpoint"