Skip to content

Commit

Permalink
Misc improvements for Certificate Authority (#4407)
Browse files Browse the repository at this point in the history
  • Loading branch information
drebes authored Jan 19, 2021
1 parent 9f55afd commit f5c85ec
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 22 deletions.
70 changes: 62 additions & 8 deletions products/privateca/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

--- !ruby/object:Api::Product
name: Privateca
display_name: Certificate Authority
display_name: Certificate Authority Service
versions:
- !ruby/object:Api::Product::Version
name: beta
Expand Down Expand Up @@ -53,6 +53,8 @@ objects:
self_link: projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}
min_version: beta
create_verb: :POST
update_verb: :PATCH
update_mask: true
delete_url: '{{name}}:scheduleDelete'
delete_verb: :POST
references: !ruby/object:Api::Resource::ReferenceLinks
Expand All @@ -63,12 +65,15 @@ objects:
properties:
- !ruby/object:Api::Type::String
name: location
description: Location of the Certificate Authority.
description: |
Location of the CertificateAuthority. A full list of valid locations can be found by
running `gcloud beta privateca locations list`.
required: true
input: true
url_param_only: true
- !ruby/object:Api::Type::String
name: certificateAuthorityId
description: GCP region of the Realm.
description: The user provided Resource ID for this Certificate Authority.
required: true
input: true
url_param_only: true
Expand All @@ -84,10 +89,14 @@ objects:
input: true
values:
- :SELF_SIGNED
- :SUBORDINATE
default_value: :SELF_SIGNED
- !ruby/object:Api::Type::Enum
name: 'tier'
description: The Tier of this CertificateAuthority.
description: |
The Tier of this CertificateAuthority. `ENTERPRISE` Certificate Authorities track
server side certificates issued, and support certificate revocation. For more details,
please check the [associated documentation](https://cloud.google.com/certificate-authority-service/docs/tiers).
input: true
values:
- :ENTERPRISE
Expand All @@ -113,27 +122,36 @@ objects:
- !ruby/object:Api::Type::String
name: 'countryCode'
description: The country code of the subject.
input: true
- !ruby/object:Api::Type::String
name: 'organization'
description: The organization of the subject.
input: true
required: true
- !ruby/object:Api::Type::String
name: 'organizationalUnit'
description: The organizational unit of the subject.
input: true
- !ruby/object:Api::Type::String
name: 'locality'
description: The locality or city of the subject.
input: true
- !ruby/object:Api::Type::String
name: 'province'
description: The province, territory, or regional state of the subject.
input: true
- !ruby/object:Api::Type::String
name: 'streetAddress'
description: The street address of the subject.
input: true
- !ruby/object:Api::Type::String
name: 'postalCode'
description: The postal code of the subject.
input: true
- !ruby/object:Api::Type::String
name: 'commonName'
description: The common name of the distinguished name.
required: true
- !ruby/object:Api::Type::NestedObject
name: 'subjectAltName'
description: The subject alternative name fields.
Expand All @@ -142,18 +160,42 @@ objects:
name: 'dnsNames'
description: Contains only valid, fully-qualified host names.
item_type: Api::Type::String
at_least_one_of:
- config.0.subject_config.0.subject_alt_name.0.dns_names
- config.0.subject_config.0.subject_alt_name.0.uris
- config.0.subject_config.0.subject_alt_name.0.email_addresses
- config.0.subject_config.0.subject_alt_name.0.ip_addresses
input: true
- !ruby/object:Api::Type::Array
name: 'uris'
description: Contains only valid RFC 3986 URIs.
item_type: Api::Type::String
at_least_one_of:
- config.0.subject_config.0.subject_alt_name.0.dns_names
- config.0.subject_config.0.subject_alt_name.0.uris
- config.0.subject_config.0.subject_alt_name.0.email_addresses
- config.0.subject_config.0.subject_alt_name.0.ip_addresses
input: true
- !ruby/object:Api::Type::Array
name: 'emailAddresses'
description: Contains only valid RFC 2822 E-mail addresses.
item_type: Api::Type::String
at_least_one_of:
- config.0.subject_config.0.subject_alt_name.0.dns_names
- config.0.subject_config.0.subject_alt_name.0.uris
- config.0.subject_config.0.subject_alt_name.0.email_addresses
- config.0.subject_config.0.subject_alt_name.0.ip_addresses
input: true
- !ruby/object:Api::Type::Array
name: 'ipAddresses'
description: Contains only valid 32-bit IPv4 addresses or RFC 4291 IPv6 addresses.
item_type: Api::Type::String
at_least_one_of:
- config.0.subject_config.0.subject_alt_name.0.dns_names
- config.0.subject_config.0.subject_alt_name.0.uris
- config.0.subject_config.0.subject_alt_name.0.email_addresses
- config.0.subject_config.0.subject_alt_name.0.ip_addresses
input: true
- !ruby/object:Api::Type::NestedObject
name: 'reusableConfig'
description: |
Expand All @@ -164,15 +206,17 @@ objects:
name: 'reusableConfig'
description: |
A resource path to a ReusableConfig in the format
projects/*/locations/*/reusableConfigs/*.
`projects/*/locations/*/reusableConfigs/*`.
required: true
input: true
- !ruby/object:Api::Type::String
name: 'lifetime'
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_value: 315360000s # 10 years
input: true
- !ruby/object:Api::Type::NestedObject
name: 'keySpec'
description: |
Expand All @@ -182,12 +226,19 @@ objects:
required: true
input: true
properties:
- !ruby/object:Api::Type::String
name: 'cloudKmsKeyVersion'
description: |
The resource name for an existing Cloud KMS CryptoKeyVersion in the format
`projects/*/locations/*/keyRings/*/cryptoKeys/*/cryptoKeyVersions/*`.
exactly_one_of:
- key_spec.0.cloud_kms_key_version
- key_spec.0.algorithm
- !ruby/object:Api::Type::Enum
name: 'algorithm'
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.
required: true
values:
- :SIGN_HASH_ALGORITHM_UNSPECIFIED
- :RSA_PSS_2048_SHA256
Expand All @@ -198,6 +249,9 @@ objects:
- :RSA_PKCS1_4096_SHA256
- :EC_P256_SHA256
- :EC_P384_SHA384
exactly_one_of:
- key_spec.0.cloud_kms_key_version
- key_spec.0.algorithm
- !ruby/object:Api::Type::NestedObject
name: 'issuingOptions'
description: |
Expand Down Expand Up @@ -240,8 +294,8 @@ objects:
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
(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.
input: true
- !ruby/object:Api::Type::NestedObject
Expand Down
44 changes: 44 additions & 0 deletions products/privateca/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@
overrides: !ruby/object:Overrides::ResourceOverrides
CertificateAuthority: !ruby/object:Overrides::Terraform::ResourceOverride
autogen_async: true
iam_policy: !ruby/object:Api::Resource::IamPolicy
parent_resource_attribute: certificate_authority
allowed_iam_role: 'roles/privateca.certificateManager'
method_name_separator: ':'
example_config_body: 'templates/terraform/iam/example_config_body/privateca_certificate_authority.tf.erb'
base_url: '{{name}}'
description: |
{{description}}
~> **Warning:** Please remember that all resources created during preview (via the terraform-provider-google-beta)
will be deleted when CA service transitions to General Availability (GA). Relying on these
certificate authorities for production traffic is discouraged.
import_format: ["projects/{{project}}/locations/{{location}}/certificateAuthorities/{{certificate_authority_id}}"]
examples:
- !ruby/object:Provider::Terraform::Examples
Expand All @@ -29,6 +41,38 @@ overrides: !ruby/object:Overrides::ResourceOverrides
primary_resource_id: "default"
vars:
certificate_authority_id: "my-certificate-authority"
- !ruby/object:Provider::Terraform::Examples
min_version: beta
name: "privateca_certificate_authority_cmek"
min_version: "beta"
primary_resource_id: "default"
vars:
kms_key_name: "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key"
test_vars_overrides:
kms_key_name: 'BootstrapKMSKeyWithPurposeInLocation(t, "ASYMMETRIC_SIGN", "us-central1").CryptoKey.Name'
virtual_fields:
- !ruby/object:Api::Type::Boolean
name: 'disable_on_delete'
default_value: false
description: |
If set to `true`, the Certificate Authority will be disabled
on delete. If the Certitificate Authorities is not disabled,
it cannot be deleted. Use with care. Defaults to `false`.
properties:
type: !ruby/object:Overrides::Terraform::PropertyOverride
description: |
{{description}}
~> **Note:** For `SUBORDINATE` Certificate Authorities, they need to
be manually activated (via Cloud Console of `gcloud`) before they can
issue certificates.
config.reusableConfig.reusableConfig: !ruby/object:Overrides::Terraform::PropertyOverride
description: |
{{description}}. Alternatively, one of the short names
found by running `gcloud beta privateca reusable-configs list`.
diff_suppress_func: 'certificateAuthorityReusableConfigDiffSuppress'
custom_code: !ruby/object:Provider::Terraform::CustomCode
constants: templates/terraform/constants/certificate_authority.go.erb
encoder: templates/terraform/encoders/certificate_authority.go.erb
pre_delete: templates/terraform/pre_delete/privateca_certificate_authority.go.erb
test_check_destroy: templates/terraform/custom_check_destroy/privateca_certificate_authority.go.erb
11 changes: 11 additions & 0 deletions templates/terraform/constants/certificate_authority.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
func certificateAuthorityReusableConfigDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
if old != "" && new != "" {
newParts := strings.Split(new, "/")
// If the new form is a short version, we just
// check if it matches the suffix of the old version
if len(newParts) == 1 {
return strings.HasSuffix(old, new)
}
}
return old == new
}
13 changes: 13 additions & 0 deletions templates/terraform/encoders/certificate_authority.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
rc := d.Get("config.0.reusable_config.0.reusable_config").(string)

parts := strings.Split(rc, "/")

if len(parts) == 1 {
// If we have a short form: add the full path to the reusable-configs from
// the Google-managed project and the location of the CA.
config := obj["config"].(map[string]interface{})
configReusableConfig := config["reusableConfig"].(map[string]interface{})
configReusableConfig["reusableConfig"] = fmt.Sprintf("projects/568668481468/locations/%s/reusableConfigs/%s", d.Get("location"), parts[0])
}

return obj, nil
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ resource "google_privateca_certificate_authority" "<%= ctx[:primary_resource_id]
key_spec {
algorithm = "RSA_PKCS1_4096_SHA256"
}
}
disable_on_delete = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
resource "google_project_service_identity" "privateca_sa" {
provider = google-beta
service = "privateca.googleapis.com"
}

resource "google_kms_crypto_key_iam_binding" "privateca_sa_keyuser" {
provider = google-beta
crypto_key_id = "<%= ctx[:vars]['kms_key_name'] %>"
role = "roles/cloudkms.signerVerifier"

members = [
"serviceAccount:${google_project_service_identity.privateca_sa.email}",
]
}

resource "google_privateca_certificate_authority" "<%= ctx[:primary_resource_id] %>" {
provider = google-beta
certificate_authority_id = "tf-test%{random_suffix}"
location = "us-central1"

key_spec {
cloud_kms_key_version = "<%= ctx[:vars]['kms_key_name'] %>/cryptoKeyVersions/1"
}

config {
subject_config {
common_name = "Example Authority"
subject {
organization = "Example, Org."
}
}

reusable_config {
reusable_config= "root-unconstrained"
}
}

depends_on = [
google_kms_crypto_key_iam_binding.privateca_sa_keyuser,
]

disable_on_delete = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ resource "google_privateca_certificate_authority" "<%= ctx[:primary_resource_id]
key_spec {
algorithm = "EC_P256_SHA256"
}
}
disable_on_delete = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
certificate_authority = google_privateca_certificate_authority.default.id
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
log.Printf("[DEBUG] Disabling CertificateAuthority %q", d.Id())
if d.Get("disable_on_delete").(bool) && d.Get("state").(string) == "ENABLED" {
log.Printf("[DEBUG] Disabling CertificateAuthority %q", d.Id())

disableURL, err := replaceVars(d, config, "{{PrivatecaBasePath}}{{name}}:disable")
if err != nil {
return err
}
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
}
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
err = privatecaOperationWaitTime(config, disableRes, project, "Disabling CertificateAuthority", userAgent, d.Timeout(schema.TimeoutDelete))
if err != nil {
return err
}
}

0 comments on commit f5c85ec

Please sign in to comment.