From 16469c19a25013feca54eee22e9cf8f934b725fa Mon Sep 17 00:00:00 2001 From: The Magician Date: Fri, 15 Jan 2021 11:39:39 -0800 Subject: [PATCH] Add Certificate Authority Resource (Certificate Authority Service) (#4382) (#2877) * Add resource google_privateca_certificate_authority In Certificate Authority Service (privateca). See https://cloud.google.com/certificate-authority-service/docs/reference/rest/v1beta1/projects.locations.certificateAuthorities for resource documentation. Notes: - This change doesn't implement support for subordinate CAs, which require additional customization because they must be activated. Customizations: - Use POST :scheduleDelete to delete the resource (delete is not supported) - On pre_delete, POST :disable to disable the resources (required for scheduling deletd) - Check resource deletion by checking that status is DELETION_PENDING * Set key_spec input=true Co-authored-by: Scott Suarez * Make algorithm required Co-authored-by: Scott Suarez * Make include_ca_cert_url required. Co-authored-by: Scott Suarez * Make include_crl_access_url required. Co-authored-by: Scott Suarez * Mark additional required fields as required, and add createTime/updateTime. * Fix tests by removing required markers where default_value is also set. Co-authored-by: Scott Suarez Signed-off-by: Modular Magician Co-authored-by: Scott Suarez --- .changelog/4382.txt | 3 + google-beta/config.go | 3 + google-beta/privateca_operation.go | 78 + google-beta/provider.go | 14 +- ...esource_privateca_certificate_authority.go | 1273 +++++++++++++++++ ...ca_certificate_authority_generated_test.go | 168 +++ ...vateca_certificate_authority.html.markdown | 359 +++++ website/google.erb | 16 + 8 files changed, 1912 insertions(+), 2 deletions(-) create mode 100644 .changelog/4382.txt create mode 100644 google-beta/privateca_operation.go create mode 100644 google-beta/resource_privateca_certificate_authority.go create mode 100644 google-beta/resource_privateca_certificate_authority_generated_test.go create mode 100644 website/docs/r/privateca_certificate_authority.html.markdown diff --git a/.changelog/4382.txt b/.changelog/4382.txt new file mode 100644 index 0000000000..777129940b --- /dev/null +++ b/.changelog/4382.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_privateca_certificate_authority` +``` diff --git a/google-beta/config.go b/google-beta/config.go index 22184050fa..48a606d22c 100644 --- a/google-beta/config.go +++ b/google-beta/config.go @@ -132,6 +132,7 @@ type Config struct { NotebooksBasePath string OSConfigBasePath string OSLoginBasePath string + PrivatecaBasePath string PubsubBasePath string PubsubLiteBasePath string RedisBasePath string @@ -220,6 +221,7 @@ var NetworkManagementDefaultBasePath = "https://networkmanagement.googleapis.com var NotebooksDefaultBasePath = "https://notebooks.googleapis.com/v1beta1/" var OSConfigDefaultBasePath = "https://osconfig.googleapis.com/v1beta/" var OSLoginDefaultBasePath = "https://oslogin.googleapis.com/v1/" +var PrivatecaDefaultBasePath = "https://privateca.googleapis.com/v1beta1/" var PubsubDefaultBasePath = "https://pubsub.googleapis.com/v1/" var PubsubLiteDefaultBasePath = "https://{{region}}-pubsublite.googleapis.com/v1/admin/" var RedisDefaultBasePath = "https://redis.googleapis.com/v1beta1/" @@ -1020,6 +1022,7 @@ func ConfigureBasePaths(c *Config) { c.NotebooksBasePath = NotebooksDefaultBasePath c.OSConfigBasePath = OSConfigDefaultBasePath c.OSLoginBasePath = OSLoginDefaultBasePath + c.PrivatecaBasePath = PrivatecaDefaultBasePath c.PubsubBasePath = PubsubDefaultBasePath c.PubsubLiteBasePath = PubsubLiteDefaultBasePath c.RedisBasePath = RedisDefaultBasePath diff --git a/google-beta/privateca_operation.go b/google-beta/privateca_operation.go new file mode 100644 index 0000000000..2b65db65e8 --- /dev/null +++ b/google-beta/privateca_operation.go @@ -0,0 +1,78 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- +package google + +import ( + "encoding/json" + "fmt" + "time" +) + +type PrivatecaOperationWaiter struct { + Config *Config + UserAgent string + Project string + CommonOperationWaiter +} + +func (w *PrivatecaOperationWaiter) QueryOp() (interface{}, error) { + if w == nil { + return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") + } + // Returns the proper get. + url := fmt.Sprintf("https://privateca.googleapis.com/v1beta1/%s", w.CommonOperationWaiter.Op.Name) + + return sendRequest(w.Config, "GET", w.Project, url, w.UserAgent, nil) +} + +func createPrivatecaWaiter(config *Config, op map[string]interface{}, project, activity, userAgent string) (*PrivatecaOperationWaiter, error) { + if val, ok := op["name"]; !ok || val == "" { + // An operation could also be indicated with a "metadata" field. + if _, ok := op["metadata"]; !ok { + // This was a synchronous call - there is no operation to wait for. + return nil, nil + } + } + w := &PrivatecaOperationWaiter{ + Config: config, + UserAgent: userAgent, + Project: project, + } + if err := w.CommonOperationWaiter.SetOp(op); err != nil { + return nil, err + } + return w, nil +} + +// nolint: deadcode,unused +func privatecaOperationWaitTimeWithResponse(config *Config, op map[string]interface{}, response *map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { + w, err := createPrivatecaWaiter(config, op, project, activity, userAgent) + if err != nil || w == nil { + // If w is nil, the op was synchronous. + return err + } + if err := OperationWait(w, activity, timeout, config.PollInterval); err != nil { + return err + } + return json.Unmarshal([]byte(w.CommonOperationWaiter.Op.Response), response) +} + +func privatecaOperationWaitTime(config *Config, op map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { + w, err := createPrivatecaWaiter(config, op, project, activity, userAgent) + if err != nil || w == nil { + // If w is nil, the op was synchronous. + return err + } + return OperationWait(w, activity, timeout, config.PollInterval) +} diff --git a/google-beta/provider.go b/google-beta/provider.go index 3d3971a47b..14d31e74b4 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -527,6 +527,14 @@ func Provider() *schema.Provider { "GOOGLE_OS_LOGIN_CUSTOM_ENDPOINT", }, OSLoginDefaultBasePath), }, + "privateca_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateCustomEndpoint, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_PRIVATECA_CUSTOM_ENDPOINT", + }, PrivatecaDefaultBasePath), + }, "pubsub_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -790,9 +798,9 @@ func Provider() *schema.Provider { return provider } -// Generated resources: 206 +// Generated resources: 207 // Generated IAM resources: 105 -// Total generated resources: 311 +// Total generated resources: 312 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1063,6 +1071,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_os_config_patch_deployment": resourceOSConfigPatchDeployment(), "google_os_config_guest_policies": resourceOSConfigGuestPolicies(), "google_os_login_ssh_public_key": resourceOSLoginSSHPublicKey(), + "google_privateca_certificate_authority": resourcePrivatecaCertificateAuthority(), "google_pubsub_topic": resourcePubsubTopic(), "google_pubsub_topic_iam_binding": ResourceIamBinding(PubsubTopicIamSchema, PubsubTopicIamUpdaterProducer, PubsubTopicIdParseFunc), "google_pubsub_topic_iam_member": ResourceIamMember(PubsubTopicIamSchema, PubsubTopicIamUpdaterProducer, PubsubTopicIdParseFunc), @@ -1350,6 +1359,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.NotebooksBasePath = d.Get("notebooks_custom_endpoint").(string) config.OSConfigBasePath = d.Get("os_config_custom_endpoint").(string) config.OSLoginBasePath = d.Get("os_login_custom_endpoint").(string) + config.PrivatecaBasePath = d.Get("privateca_custom_endpoint").(string) config.PubsubBasePath = d.Get("pubsub_custom_endpoint").(string) config.PubsubLiteBasePath = d.Get("pubsub_lite_custom_endpoint").(string) config.RedisBasePath = d.Get("redis_custom_endpoint").(string) diff --git a/google-beta/resource_privateca_certificate_authority.go b/google-beta/resource_privateca_certificate_authority.go new file mode 100644 index 0000000000..d753b73fbb --- /dev/null +++ b/google-beta/resource_privateca_certificate_authority.go @@ -0,0 +1,1273 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourcePrivatecaCertificateAuthority() *schema.Resource { + return &schema.Resource{ + Create: resourcePrivatecaCertificateAuthorityCreate, + Read: resourcePrivatecaCertificateAuthorityRead, + Update: resourcePrivatecaCertificateAuthorityUpdate, + Delete: resourcePrivatecaCertificateAuthorityDelete, + + Importer: &schema.ResourceImporter{ + State: resourcePrivatecaCertificateAuthorityImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "certificate_authority_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `GCP region of the Realm.`, + }, + "config": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Description: `The config used to create a self-signed X.509 certificate or CSR.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "reusable_config": { + Type: schema.TypeList, + Required: true, + Description: `Specifies some of the values in a certificate that are related to the subject.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "reusable_config": { + Type: schema.TypeString, + Required: true, + Description: `A resource path to a ReusableConfig in the format +projects/*/locations/*/reusableConfigs/*.`, + }, + }, + }, + }, + "subject_config": { + Type: schema.TypeList, + Required: true, + Description: `Specifies some of the values in a certificate that are related to the subject.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subject": { + Type: schema.TypeList, + Required: true, + Description: `Contains distinguished name fields such as the location and organization.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "country_code": { + Type: schema.TypeString, + Optional: true, + Description: `The country code of the subject.`, + }, + "locality": { + Type: schema.TypeString, + Optional: true, + Description: `The locality or city of the subject.`, + }, + "organization": { + Type: schema.TypeString, + Optional: true, + Description: `The organization of the subject.`, + }, + "organizational_unit": { + Type: schema.TypeString, + Optional: true, + Description: `The organizational unit of the subject.`, + }, + "postal_code": { + Type: schema.TypeString, + Optional: true, + Description: `The postal code of the subject.`, + }, + "province": { + Type: schema.TypeString, + Optional: true, + Description: `The province, territory, or regional state of the subject.`, + }, + "street_address": { + Type: schema.TypeString, + Optional: true, + Description: `The street address of the subject.`, + }, + }, + }, + }, + "common_name": { + Type: schema.TypeString, + Optional: true, + Description: `The common name of the distinguished name.`, + }, + "subject_alt_name": { + Type: schema.TypeList, + Optional: true, + Description: `The subject alternative name fields.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dns_names": { + Type: schema.TypeList, + Optional: true, + Description: `Contains only valid, fully-qualified host names.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "email_addresses": { + Type: schema.TypeList, + Optional: true, + Description: `Contains only valid RFC 2822 E-mail addresses.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "ip_addresses": { + Type: schema.TypeList, + Optional: true, + Description: `Contains only valid 32-bit IPv4 addresses or RFC 4291 IPv6 addresses.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "uris": { + Type: schema.TypeList, + Optional: true, + Description: `Contains only valid RFC 3986 URIs.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "key_spec": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Description: `Used when issuing certificates for this CertificateAuthority. If this CertificateAuthority +is a self-signed CertificateAuthority, this key is also used to sign the self-signed CA +certificate. Otherwise, it is used to sign a CSR.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "algorithm": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"SIGN_HASH_ALGORITHM_UNSPECIFIED", "RSA_PSS_2048_SHA256", "RSA_PSS_3072_SHA256", "RSA_PSS_4096_SHA256", "RSA_PKCS1_2048_SHA256", "RSA_PKCS1_3072_SHA256", "RSA_PKCS1_4096_SHA256", "EC_P256_SHA256", "EC_P384_SHA384"}, false), + Description: `The algorithm to use for creating a managed Cloud KMS key for a for a simplified +experience. All managed keys will be have their ProtectionLevel as HSM. Possible values: ["SIGN_HASH_ALGORITHM_UNSPECIFIED", "RSA_PSS_2048_SHA256", "RSA_PSS_3072_SHA256", "RSA_PSS_4096_SHA256", "RSA_PKCS1_2048_SHA256", "RSA_PKCS1_3072_SHA256", "RSA_PKCS1_4096_SHA256", "EC_P256_SHA256", "EC_P384_SHA384"]`, + }, + }, + }, + }, + "location": { + Type: schema.TypeString, + Required: true, + Description: `Location of the Certificate Authority.`, + }, + "gcs_bucket": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `The name of a Cloud Storage bucket where this CertificateAuthority will publish content, +such as the CA certificate and CRLs. This must be a bucket name, without any prefixes +(such as gs://) or suffixes (such as .googleapis.com). For example, to use a bucket named +my-bucket, you would simply specify my-bucket. If not specified, a managed bucket will be +created.`, + }, + "issuing_options": { + Type: schema.TypeList, + Optional: true, + Description: `Options that affect all certificates issued by a CertificateAuthority.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "include_ca_cert_url": { + Type: schema.TypeBool, + Optional: true, + Description: `When true, includes a URL to the issuing CA certificate in the "authority +information access" X.509 extension.`, + Default: true, + }, + "include_crl_access_url": { + Type: schema.TypeBool, + Optional: true, + Description: `When true, includes a URL to the CRL corresponding to certificates issued from a +CertificateAuthority. CRLs will expire 7 days from their creation. However, we will +rebuild daily. CRLs are also rebuilt shortly after a certificate is revoked.`, + Default: false, + }, + }, + }, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `Labels with user-defined metadata. + +An object containing a list of "key": value pairs. Example: { "name": "wrench", "mass": +"1.3kg", "count": "3" }.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "lifetime": { + Type: schema.TypeString, + Optional: true, + Description: `The desired lifetime of the CA certificate. Used to create the "notBeforeTime" and +"notAfterTime" fields inside an X.509 certificate. A duration in seconds with up to nine +fractional digits, terminated by 's'. Example: "3.5s".`, + Default: "315360000s", + }, + "tier": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"ENTERPRISE", "DEVOPS", ""}, false), + Description: `The Tier of this CertificateAuthority. Default value: "ENTERPRISE" Possible values: ["ENTERPRISE", "DEVOPS"]`, + Default: "ENTERPRISE", + }, + "type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"SELF_SIGNED", ""}, false), + Description: `The Type of this CertificateAuthority. Default value: "SELF_SIGNED" Possible values: ["SELF_SIGNED"]`, + Default: "SELF_SIGNED", + }, + "access_urls": { + Type: schema.TypeList, + Computed: true, + Description: `URLs for accessing content published by this CA, such as the CA certificate and CRLs.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ca_certificate_access_url": { + Type: schema.TypeString, + Computed: true, + Description: `The URL where this CertificateAuthority's CA certificate is published. This will only be +set for CAs that have been activated.`, + }, + "crl_access_url": { + Type: schema.TypeString, + Computed: true, + Description: `The URL where this CertificateAuthority's CRLs are published. This will only be set for +CAs that have been activated.`, + }, + }, + }, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time at which this CertificateAuthority was created. + +A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine +fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z".`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The resource name for this CertificateAuthority in the format +projects/*/locations/*/certificateAuthorities/*.`, + }, + "pem_ca_certificates": { + Type: schema.TypeList, + Computed: true, + Description: `This CertificateAuthority's certificate chain, including the current +CertificateAuthority's certificate. Ordered such that the root issuer is the final +element (consistent with RFC 5246). For a self-signed CA, this will only list the current +CertificateAuthority's certificate.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: `The State for this CertificateAuthority.`, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time at which this CertificateAuthority was updated. + +A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine +fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z".`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourcePrivatecaCertificateAuthorityCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + typeProp, err := expandPrivatecaCertificateAuthorityType(d.Get("type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("type"); !isEmptyValue(reflect.ValueOf(typeProp)) && (ok || !reflect.DeepEqual(v, typeProp)) { + obj["type"] = typeProp + } + tierProp, err := expandPrivatecaCertificateAuthorityTier(d.Get("tier"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("tier"); !isEmptyValue(reflect.ValueOf(tierProp)) && (ok || !reflect.DeepEqual(v, tierProp)) { + obj["tier"] = tierProp + } + configProp, err := expandPrivatecaCertificateAuthorityConfig(d.Get("config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("config"); !isEmptyValue(reflect.ValueOf(configProp)) && (ok || !reflect.DeepEqual(v, configProp)) { + obj["config"] = configProp + } + lifetimeProp, err := expandPrivatecaCertificateAuthorityLifetime(d.Get("lifetime"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("lifetime"); !isEmptyValue(reflect.ValueOf(lifetimeProp)) && (ok || !reflect.DeepEqual(v, lifetimeProp)) { + obj["lifetime"] = lifetimeProp + } + keySpecProp, err := expandPrivatecaCertificateAuthorityKeySpec(d.Get("key_spec"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("key_spec"); !isEmptyValue(reflect.ValueOf(keySpecProp)) && (ok || !reflect.DeepEqual(v, keySpecProp)) { + obj["keySpec"] = keySpecProp + } + issuingOptionsProp, err := expandPrivatecaCertificateAuthorityIssuingOptions(d.Get("issuing_options"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("issuing_options"); !isEmptyValue(reflect.ValueOf(issuingOptionsProp)) && (ok || !reflect.DeepEqual(v, issuingOptionsProp)) { + obj["issuingOptions"] = issuingOptionsProp + } + gcsBucketProp, err := expandPrivatecaCertificateAuthorityGcsBucket(d.Get("gcs_bucket"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("gcs_bucket"); !isEmptyValue(reflect.ValueOf(gcsBucketProp)) && (ok || !reflect.DeepEqual(v, gcsBucketProp)) { + obj["gcsBucket"] = gcsBucketProp + } + labelsProp, err := expandPrivatecaCertificateAuthorityLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/certificateAuthorities?certificateAuthorityId={{certificate_authority_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new CertificateAuthority: %#v", obj) + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for CertificateAuthority: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating CertificateAuthority: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + // Use the resource in the operation response to populate + // identity fields and d.Id() before read + var opRes map[string]interface{} + err = privatecaOperationWaitTimeWithResponse( + config, res, &opRes, project, "Creating CertificateAuthority", userAgent, + d.Timeout(schema.TimeoutCreate)) + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create CertificateAuthority: %s", err) + } + + if err := d.Set("name", flattenPrivatecaCertificateAuthorityName(opRes["name"], d, config)); err != nil { + return err + } + + // This may have caused the ID to update - update it if so. + id, err = replaceVars(d, config, "projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating CertificateAuthority %q: %#v", d.Id(), res) + + return resourcePrivatecaCertificateAuthorityRead(d, meta) +} + +func resourcePrivatecaCertificateAuthorityRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for CertificateAuthority: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("PrivatecaCertificateAuthority %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + + if err := d.Set("name", flattenPrivatecaCertificateAuthorityName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("type", flattenPrivatecaCertificateAuthorityType(res["type"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("tier", flattenPrivatecaCertificateAuthorityTier(res["tier"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("config", flattenPrivatecaCertificateAuthorityConfig(res["config"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("lifetime", flattenPrivatecaCertificateAuthorityLifetime(res["lifetime"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("key_spec", flattenPrivatecaCertificateAuthorityKeySpec(res["keySpec"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("issuing_options", flattenPrivatecaCertificateAuthorityIssuingOptions(res["issuingOptions"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("state", flattenPrivatecaCertificateAuthorityState(res["state"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("pem_ca_certificates", flattenPrivatecaCertificateAuthorityPemCaCertificates(res["pemCaCertificates"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("gcs_bucket", flattenPrivatecaCertificateAuthorityGcsBucket(res["gcsBucket"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("access_urls", flattenPrivatecaCertificateAuthorityAccessUrls(res["accessUrls"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("create_time", flattenPrivatecaCertificateAuthorityCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("update_time", flattenPrivatecaCertificateAuthorityUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + if err := d.Set("labels", flattenPrivatecaCertificateAuthorityLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading CertificateAuthority: %s", err) + } + + return nil +} + +func resourcePrivatecaCertificateAuthorityUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for CertificateAuthority: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + typeProp, err := expandPrivatecaCertificateAuthorityType(d.Get("type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("type"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, typeProp)) { + obj["type"] = typeProp + } + tierProp, err := expandPrivatecaCertificateAuthorityTier(d.Get("tier"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("tier"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, tierProp)) { + obj["tier"] = tierProp + } + configProp, err := expandPrivatecaCertificateAuthorityConfig(d.Get("config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, configProp)) { + obj["config"] = configProp + } + lifetimeProp, err := expandPrivatecaCertificateAuthorityLifetime(d.Get("lifetime"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("lifetime"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, lifetimeProp)) { + obj["lifetime"] = lifetimeProp + } + keySpecProp, err := expandPrivatecaCertificateAuthorityKeySpec(d.Get("key_spec"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("key_spec"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, keySpecProp)) { + obj["keySpec"] = keySpecProp + } + issuingOptionsProp, err := expandPrivatecaCertificateAuthorityIssuingOptions(d.Get("issuing_options"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("issuing_options"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, issuingOptionsProp)) { + obj["issuingOptions"] = issuingOptionsProp + } + gcsBucketProp, err := expandPrivatecaCertificateAuthorityGcsBucket(d.Get("gcs_bucket"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("gcs_bucket"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, gcsBucketProp)) { + obj["gcsBucket"] = gcsBucketProp + } + labelsProp, err := expandPrivatecaCertificateAuthorityLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating CertificateAuthority %q: %#v", d.Id(), obj) + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "PUT", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating CertificateAuthority %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating CertificateAuthority %q: %#v", d.Id(), res) + } + + err = privatecaOperationWaitTime( + config, res, project, "Updating CertificateAuthority", userAgent, + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + + return resourcePrivatecaCertificateAuthorityRead(d, meta) +} + +func resourcePrivatecaCertificateAuthorityDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := getProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for CertificateAuthority: %s", err) + } + billingProject = project + + url, err := replaceVars(d, config, "{{PrivatecaBasePath}}{{name}}:scheduleDelete") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Disabling CertificateAuthority %q", d.Id()) + + disableURL, err := replaceVars(d, config, "{{PrivatecaBasePath}}{{name}}:disable") + if err != nil { + return err + } + + disableRes, err := sendRequestWithTimeout(config, "POST", billingProject, disableURL, userAgent, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + + err = privatecaOperationWaitTime(config, disableRes, project, "Disabling CertificateAuthority", userAgent, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + log.Printf("[DEBUG] Deleting CertificateAuthority %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "CertificateAuthority") + } + + err = privatecaOperationWaitTime( + config, res, project, "Deleting CertificateAuthority", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting CertificateAuthority %q: %#v", d.Id(), res) + return nil +} + +func resourcePrivatecaCertificateAuthorityImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/locations/(?P[^/]+)/certificateAuthorities/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenPrivatecaCertificateAuthorityName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityTier(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfig(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["subject_config"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfig(original["subjectConfig"], d, config) + transformed["reusable_config"] = + flattenPrivatecaCertificateAuthorityConfigReusableConfig(original["reusableConfig"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityConfigSubjectConfig(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["subject"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubject(original["subject"], d, config) + transformed["common_name"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigCommonName(original["commonName"], d, config) + transformed["subject_alt_name"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltName(original["subjectAltName"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubject(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["country_code"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectCountryCode(original["countryCode"], d, config) + transformed["organization"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganization(original["organization"], d, config) + transformed["organizational_unit"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganizationalUnit(original["organizationalUnit"], d, config) + transformed["locality"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectLocality(original["locality"], d, config) + transformed["province"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectProvince(original["province"], d, config) + transformed["street_address"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectStreetAddress(original["streetAddress"], d, config) + transformed["postal_code"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectPostalCode(original["postalCode"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectCountryCode(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganization(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganizationalUnit(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectLocality(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectProvince(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectStreetAddress(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectPostalCode(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigCommonName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["dns_names"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameDnsNames(original["dnsNames"], d, config) + transformed["uris"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameUris(original["uris"], d, config) + transformed["email_addresses"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameEmailAddresses(original["emailAddresses"], d, config) + transformed["ip_addresses"] = + flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameIpAddresses(original["ipAddresses"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameDnsNames(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameUris(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameEmailAddresses(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameIpAddresses(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityConfigReusableConfig(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["reusable_config"] = + flattenPrivatecaCertificateAuthorityConfigReusableConfigReusableConfig(original["reusableConfig"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityConfigReusableConfigReusableConfig(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityLifetime(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityKeySpec(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["algorithm"] = + flattenPrivatecaCertificateAuthorityKeySpecAlgorithm(original["algorithm"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityKeySpecAlgorithm(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityIssuingOptions(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["include_ca_cert_url"] = + flattenPrivatecaCertificateAuthorityIssuingOptionsIncludeCaCertUrl(original["includeCaCertUrl"], d, config) + transformed["include_crl_access_url"] = + flattenPrivatecaCertificateAuthorityIssuingOptionsIncludeCrlAccessUrl(original["includeCrlAccessUrl"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityIssuingOptionsIncludeCaCertUrl(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityIssuingOptionsIncludeCrlAccessUrl(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityState(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityPemCaCertificates(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityGcsBucket(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityAccessUrls(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["ca_certificate_access_url"] = + flattenPrivatecaCertificateAuthorityAccessUrlsCaCertificateAccessUrl(original["caCertificateAccessUrl"], d, config) + transformed["crl_access_url"] = + flattenPrivatecaCertificateAuthorityAccessUrlsCrlAccessUrl(original["crlAccessUrl"], d, config) + return []interface{}{transformed} +} +func flattenPrivatecaCertificateAuthorityAccessUrlsCaCertificateAccessUrl(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityAccessUrlsCrlAccessUrl(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityCreateTime(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityUpdateTime(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenPrivatecaCertificateAuthorityLabels(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func expandPrivatecaCertificateAuthorityType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityTier(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSubjectConfig, err := expandPrivatecaCertificateAuthorityConfigSubjectConfig(original["subject_config"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSubjectConfig); val.IsValid() && !isEmptyValue(val) { + transformed["subjectConfig"] = transformedSubjectConfig + } + + transformedReusableConfig, err := expandPrivatecaCertificateAuthorityConfigReusableConfig(original["reusable_config"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedReusableConfig); val.IsValid() && !isEmptyValue(val) { + transformed["reusableConfig"] = transformedReusableConfig + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSubject, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubject(original["subject"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSubject); val.IsValid() && !isEmptyValue(val) { + transformed["subject"] = transformedSubject + } + + transformedCommonName, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigCommonName(original["common_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCommonName); val.IsValid() && !isEmptyValue(val) { + transformed["commonName"] = transformedCommonName + } + + transformedSubjectAltName, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltName(original["subject_alt_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSubjectAltName); val.IsValid() && !isEmptyValue(val) { + transformed["subjectAltName"] = transformedSubjectAltName + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubject(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedCountryCode, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectCountryCode(original["country_code"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCountryCode); val.IsValid() && !isEmptyValue(val) { + transformed["countryCode"] = transformedCountryCode + } + + transformedOrganization, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganization(original["organization"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedOrganization); val.IsValid() && !isEmptyValue(val) { + transformed["organization"] = transformedOrganization + } + + transformedOrganizationalUnit, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganizationalUnit(original["organizational_unit"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedOrganizationalUnit); val.IsValid() && !isEmptyValue(val) { + transformed["organizationalUnit"] = transformedOrganizationalUnit + } + + transformedLocality, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectLocality(original["locality"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLocality); val.IsValid() && !isEmptyValue(val) { + transformed["locality"] = transformedLocality + } + + transformedProvince, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectProvince(original["province"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProvince); val.IsValid() && !isEmptyValue(val) { + transformed["province"] = transformedProvince + } + + transformedStreetAddress, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectStreetAddress(original["street_address"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStreetAddress); val.IsValid() && !isEmptyValue(val) { + transformed["streetAddress"] = transformedStreetAddress + } + + transformedPostalCode, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectPostalCode(original["postal_code"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPostalCode); val.IsValid() && !isEmptyValue(val) { + transformed["postalCode"] = transformedPostalCode + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectCountryCode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganization(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectOrganizationalUnit(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectLocality(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectProvince(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectStreetAddress(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectPostalCode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigCommonName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDnsNames, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameDnsNames(original["dns_names"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDnsNames); val.IsValid() && !isEmptyValue(val) { + transformed["dnsNames"] = transformedDnsNames + } + + transformedUris, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameUris(original["uris"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUris); val.IsValid() && !isEmptyValue(val) { + transformed["uris"] = transformedUris + } + + transformedEmailAddresses, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameEmailAddresses(original["email_addresses"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEmailAddresses); val.IsValid() && !isEmptyValue(val) { + transformed["emailAddresses"] = transformedEmailAddresses + } + + transformedIpAddresses, err := expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameIpAddresses(original["ip_addresses"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIpAddresses); val.IsValid() && !isEmptyValue(val) { + transformed["ipAddresses"] = transformedIpAddresses + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameDnsNames(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameUris(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameEmailAddresses(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigSubjectConfigSubjectAltNameIpAddresses(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityConfigReusableConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedReusableConfig, err := expandPrivatecaCertificateAuthorityConfigReusableConfigReusableConfig(original["reusable_config"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedReusableConfig); val.IsValid() && !isEmptyValue(val) { + transformed["reusableConfig"] = transformedReusableConfig + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityConfigReusableConfigReusableConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityLifetime(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityKeySpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedAlgorithm, err := expandPrivatecaCertificateAuthorityKeySpecAlgorithm(original["algorithm"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAlgorithm); val.IsValid() && !isEmptyValue(val) { + transformed["algorithm"] = transformedAlgorithm + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityKeySpecAlgorithm(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityIssuingOptions(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedIncludeCaCertUrl, err := expandPrivatecaCertificateAuthorityIssuingOptionsIncludeCaCertUrl(original["include_ca_cert_url"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIncludeCaCertUrl); val.IsValid() && !isEmptyValue(val) { + transformed["includeCaCertUrl"] = transformedIncludeCaCertUrl + } + + transformedIncludeCrlAccessUrl, err := expandPrivatecaCertificateAuthorityIssuingOptionsIncludeCrlAccessUrl(original["include_crl_access_url"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIncludeCrlAccessUrl); val.IsValid() && !isEmptyValue(val) { + transformed["includeCrlAccessUrl"] = transformedIncludeCrlAccessUrl + } + + return transformed, nil +} + +func expandPrivatecaCertificateAuthorityIssuingOptionsIncludeCaCertUrl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityIssuingOptionsIncludeCrlAccessUrl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityGcsBucket(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandPrivatecaCertificateAuthorityLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google-beta/resource_privateca_certificate_authority_generated_test.go b/google-beta/resource_privateca_certificate_authority_generated_test.go new file mode 100644 index 0000000000..e41f7a00b9 --- /dev/null +++ b/google-beta/resource_privateca_certificate_authority_generated_test.go @@ -0,0 +1,168 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckPrivatecaCertificateAuthorityDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityBasicExample(context), + }, + }, + }) +} + +func testAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityBasicExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_privateca_certificate_authority" "default" { + provider = google-beta + certificate_authority_id = "tf-test-my-certificate-authority%{random_suffix}" + location = "us-central1" + config { + subject_config { + subject { + organization = "HashiCorp" + } + common_name = "my-certificate-authority" + subject_alt_name { + dns_names = ["hashicorp.com"] + } + } + reusable_config { + reusable_config = "projects/568668481468/locations/us-central1/reusableConfigs/root-unconstrained" + } + } + key_spec { + algorithm = "RSA_PKCS1_4096_SHA256" + } +} +`, context) +} + +func TestAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityFullExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersOiCS, + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckPrivatecaCertificateAuthorityDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityFullExample(context), + }, + }, + }) +} + +func testAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityFullExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_privateca_certificate_authority" "default" { + provider = google-beta + certificate_authority_id = "tf-test-my-certificate-authority%{random_suffix}" + location = "us-central1" + tier = "DEVOPS" + config { + subject_config { + subject { + country_code = "US" + organization = "HashiCorp" + organizational_unit = "Terraform" + locality = "San Francisco" + province = "CA" + street_address = "101 2nd St #700" + postal_code = "94105" + } + common_name = "my-certificate-authority" + subject_alt_name { + dns_names = ["hashicorp.com"] + email_addresses = ["email@example.com"] + ip_addresses = ["127.0.0.1"] + uris = ["http://www.ietf.org/rfc/rfc3986.txt"] + } + } + reusable_config { + reusable_config = "projects/568668481468/locations/us-central1/reusableConfigs/root-unconstrained" + } + } + lifetime = "86400s" + issuing_options { + include_ca_cert_url = true + include_crl_access_url = false + } + key_spec { + algorithm = "EC_P256_SHA256" + } +} +`, context) +} + +func testAccCheckPrivatecaCertificateAuthorityDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_privateca_certificate_authority" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}") + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", "", url, config.userAgent, nil) + if err != nil { + return nil + } + + if s := res["state"]; s != "PENDING_DELETION" { + return fmt.Errorf("CertificateAuthority %s got %s, want PENDING_DELETION", url, s) + } + } + + return nil + } +} diff --git a/website/docs/r/privateca_certificate_authority.html.markdown b/website/docs/r/privateca_certificate_authority.html.markdown new file mode 100644 index 0000000000..203c3f85bf --- /dev/null +++ b/website/docs/r/privateca_certificate_authority.html.markdown @@ -0,0 +1,359 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Certificate Authority" +layout: "google" +page_title: "Google: google_privateca_certificate_authority" +sidebar_current: "docs-google-privateca-certificate-authority" +description: |- + A CertificateAuthority represents an individual Certificate Authority. +--- + +# google\_privateca\_certificate\_authority + +A CertificateAuthority represents an individual Certificate Authority. A +CertificateAuthority can be used to create Certificates. + +~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. + +To get more information about CertificateAuthority, see: + +* [API documentation](https://https://cloud.google.com/certificate-authority-service/docs/reference/rest) +* How-to Guides + * [Official Documentation](https://cloud.google.com/certificate-authority-service) + + +## Example Usage - Privateca Certificate Authority Basic + + +```hcl +resource "google_privateca_certificate_authority" "default" { + provider = google-beta + certificate_authority_id = "my-certificate-authority" + location = "us-central1" + config { + subject_config { + subject { + organization = "HashiCorp" + } + common_name = "my-certificate-authority" + subject_alt_name { + dns_names = ["hashicorp.com"] + } + } + reusable_config { + reusable_config = "projects/568668481468/locations/us-central1/reusableConfigs/root-unconstrained" + } + } + key_spec { + algorithm = "RSA_PKCS1_4096_SHA256" + } +} +``` + +## Example Usage - Privateca Certificate Authority Full + + +```hcl +resource "google_privateca_certificate_authority" "default" { + provider = google-beta + certificate_authority_id = "my-certificate-authority" + location = "us-central1" + tier = "DEVOPS" + config { + subject_config { + subject { + country_code = "US" + organization = "HashiCorp" + organizational_unit = "Terraform" + locality = "San Francisco" + province = "CA" + street_address = "101 2nd St #700" + postal_code = "94105" + } + common_name = "my-certificate-authority" + subject_alt_name { + dns_names = ["hashicorp.com"] + email_addresses = ["email@example.com"] + ip_addresses = ["127.0.0.1"] + uris = ["http://www.ietf.org/rfc/rfc3986.txt"] + } + } + reusable_config { + reusable_config = "projects/568668481468/locations/us-central1/reusableConfigs/root-unconstrained" + } + } + lifetime = "86400s" + issuing_options { + include_ca_cert_url = true + include_crl_access_url = false + } + key_spec { + algorithm = "EC_P256_SHA256" + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `location` - + (Required) + Location of the Certificate Authority. + +* `certificate_authority_id` - + (Required) + GCP region of the Realm. + +* `config` - + (Required) + The config used to create a self-signed X.509 certificate or CSR. + Structure is documented below. + +* `key_spec` - + (Required) + Used when issuing certificates for this CertificateAuthority. If this CertificateAuthority + is a self-signed CertificateAuthority, this key is also used to sign the self-signed CA + certificate. Otherwise, it is used to sign a CSR. + Structure is documented below. + + +The `config` block supports: + +* `subject_config` - + (Required) + Specifies some of the values in a certificate that are related to the subject. + Structure is documented below. + +* `reusable_config` - + (Required) + Specifies some of the values in a certificate that are related to the subject. + Structure is documented below. + + +The `subject_config` block supports: + +* `subject` - + (Required) + Contains distinguished name fields such as the location and organization. + Structure is documented below. + +* `common_name` - + (Optional) + The common name of the distinguished name. + +* `subject_alt_name` - + (Optional) + The subject alternative name fields. + Structure is documented below. + + +The `subject` block supports: + +* `country_code` - + (Optional) + The country code of the subject. + +* `organization` - + (Optional) + The organization of the subject. + +* `organizational_unit` - + (Optional) + The organizational unit of the subject. + +* `locality` - + (Optional) + The locality or city of the subject. + +* `province` - + (Optional) + The province, territory, or regional state of the subject. + +* `street_address` - + (Optional) + The street address of the subject. + +* `postal_code` - + (Optional) + The postal code of the subject. + +The `subject_alt_name` block supports: + +* `dns_names` - + (Optional) + Contains only valid, fully-qualified host names. + +* `uris` - + (Optional) + Contains only valid RFC 3986 URIs. + +* `email_addresses` - + (Optional) + Contains only valid RFC 2822 E-mail addresses. + +* `ip_addresses` - + (Optional) + Contains only valid 32-bit IPv4 addresses or RFC 4291 IPv6 addresses. + +The `reusable_config` block supports: + +* `reusable_config` - + (Required) + A resource path to a ReusableConfig in the format + projects/*/locations/*/reusableConfigs/*. + +The `key_spec` block supports: + +* `algorithm` - + (Required) + The algorithm to use for creating a managed Cloud KMS key for a for a simplified + experience. All managed keys will be have their ProtectionLevel as HSM. + Possible values are `SIGN_HASH_ALGORITHM_UNSPECIFIED`, `RSA_PSS_2048_SHA256`, `RSA_PSS_3072_SHA256`, `RSA_PSS_4096_SHA256`, `RSA_PKCS1_2048_SHA256`, `RSA_PKCS1_3072_SHA256`, `RSA_PKCS1_4096_SHA256`, `EC_P256_SHA256`, and `EC_P384_SHA384`. + +- - - + + +* `type` - + (Optional) + The Type of this CertificateAuthority. + Default value is `SELF_SIGNED`. + Possible values are `SELF_SIGNED`. + +* `tier` - + (Optional) + The Tier of this CertificateAuthority. + Default value is `ENTERPRISE`. + Possible values are `ENTERPRISE` and `DEVOPS`. + +* `lifetime` - + (Optional) + The desired lifetime of the CA certificate. Used to create the "notBeforeTime" and + "notAfterTime" fields inside an X.509 certificate. A duration in seconds with up to nine + fractional digits, terminated by 's'. Example: "3.5s". + +* `issuing_options` - + (Optional) + Options that affect all certificates issued by a CertificateAuthority. + Structure is documented below. + +* `gcs_bucket` - + (Optional) + The name of a Cloud Storage bucket where this CertificateAuthority will publish content, + such as the CA certificate and CRLs. This must be a bucket name, without any prefixes + (such as gs://) or suffixes (such as .googleapis.com). For example, to use a bucket named + my-bucket, you would simply specify my-bucket. If not specified, a managed bucket will be + created. + +* `labels` - + (Optional) + Labels with user-defined metadata. + An object containing a list of "key": value pairs. Example: { "name": "wrench", "mass": + "1.3kg", "count": "3" }. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `issuing_options` block supports: + +* `include_ca_cert_url` - + (Optional) + When true, includes a URL to the issuing CA certificate in the "authority + information access" X.509 extension. + +* `include_crl_access_url` - + (Optional) + When true, includes a URL to the CRL corresponding to certificates issued from a + CertificateAuthority. CRLs will expire 7 days from their creation. However, we will + rebuild daily. CRLs are also rebuilt shortly after a certificate is revoked. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}` + +* `name` - + The resource name for this CertificateAuthority in the format + projects/*/locations/*/certificateAuthorities/*. + +* `state` - + The State for this CertificateAuthority. + +* `pem_ca_certificates` - + This CertificateAuthority's certificate chain, including the current + CertificateAuthority's certificate. Ordered such that the root issuer is the final + element (consistent with RFC 5246). For a self-signed CA, this will only list the current + CertificateAuthority's certificate. + +* `access_urls` - + URLs for accessing content published by this CA, such as the CA certificate and CRLs. + Structure is documented below. + +* `create_time` - + The time at which this CertificateAuthority was created. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine + fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + +* `update_time` - + The time at which this CertificateAuthority was updated. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine + fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + + +The `access_urls` block contains: + +* `ca_certificate_access_url` - + The URL where this CertificateAuthority's CA certificate is published. This will only be + set for CAs that have been activated. + +* `crl_access_url` - + The URL where this CertificateAuthority's CRLs are published. This will only be set for + CAs that have been activated. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + + +CertificateAuthority can be imported using any of these accepted formats: + +``` +$ terraform import google_privateca_certificate_authority.default projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}} +$ terraform import google_privateca_certificate_authority.default {{project}}/{{location}}/{{certificate_authority_id}} +$ terraform import google_privateca_certificate_authority.default {{location}}/{{certificate_authority_id}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override). diff --git a/website/google.erb b/website/google.erb index cc84342946..2c130f9555 100644 --- a/website/google.erb +++ b/website/google.erb @@ -355,6 +355,22 @@ +
  • + Certificate Authority + +
  • +
  • Cloud (Stackdriver) Logging