Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add allowlistedCertificates field to TrustConfig #18587

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/10906.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
certificatemanager: added `allowlisted_certificates` to `google_certificate_manager_trust_config`
```
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ func ResourceCertificateManagerTrustConfig() *schema.Resource {
ForceNew: true,
Description: `A user-defined name of the trust config. Trust config names must be unique globally.`,
},
"allowlisted_certificates": {
Type: schema.TypeList,
Optional: true,
Description: `Allowlisted PEM-encoded certificates. A certificate matching an allowlisted certificate is always considered valid as long as
the certificate is parseable, proof of private key possession is established, and constraints on the certificate's SAN field are met.`,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"pem_certificate": {
Type: schema.TypeString,
Required: true,
Description: `PEM certificate that is allowlisted. The certificate can be up to 5k bytes, and must be a parseable X.509 certificate.`,
},
},
},
},
"description": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -134,7 +149,6 @@ Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z".`,
"effective_labels": {
Type: schema.TypeMap,
Computed: true,
ForceNew: true,
Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
Expand Down Expand Up @@ -184,6 +198,12 @@ func resourceCertificateManagerTrustConfigCreate(d *schema.ResourceData, meta in
} else if v, ok := d.GetOkExists("trust_stores"); !tpgresource.IsEmptyValue(reflect.ValueOf(trustStoresProp)) && (ok || !reflect.DeepEqual(v, trustStoresProp)) {
obj["trustStores"] = trustStoresProp
}
allowlistedCertificatesProp, err := expandCertificateManagerTrustConfigAllowlistedCertificates(d.Get("allowlisted_certificates"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("allowlisted_certificates"); !tpgresource.IsEmptyValue(reflect.ValueOf(allowlistedCertificatesProp)) && (ok || !reflect.DeepEqual(v, allowlistedCertificatesProp)) {
obj["allowlistedCertificates"] = allowlistedCertificatesProp
}
labelsProp, err := expandCertificateManagerTrustConfigEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -304,6 +324,9 @@ func resourceCertificateManagerTrustConfigRead(d *schema.ResourceData, meta inte
if err := d.Set("trust_stores", flattenCertificateManagerTrustConfigTrustStores(res["trustStores"], d, config)); err != nil {
return fmt.Errorf("Error reading TrustConfig: %s", err)
}
if err := d.Set("allowlisted_certificates", flattenCertificateManagerTrustConfigAllowlistedCertificates(res["allowlistedCertificates"], d, config)); err != nil {
return fmt.Errorf("Error reading TrustConfig: %s", err)
}
if err := d.Set("terraform_labels", flattenCertificateManagerTrustConfigTerraformLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading TrustConfig: %s", err)
}
Expand Down Expand Up @@ -342,6 +365,18 @@ func resourceCertificateManagerTrustConfigUpdate(d *schema.ResourceData, meta in
} else if v, ok := d.GetOkExists("trust_stores"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, trustStoresProp)) {
obj["trustStores"] = trustStoresProp
}
allowlistedCertificatesProp, err := expandCertificateManagerTrustConfigAllowlistedCertificates(d.Get("allowlisted_certificates"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("allowlisted_certificates"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, allowlistedCertificatesProp)) {
obj["allowlistedCertificates"] = allowlistedCertificatesProp
}
labelsProp, err := expandCertificateManagerTrustConfigEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
obj["labels"] = labelsProp
}

url, err := tpgresource.ReplaceVars(d, config, "{{CertificateManagerBasePath}}projects/{{project}}/locations/{{location}}/trustConfigs/{{name}}")
if err != nil {
Expand All @@ -350,10 +385,6 @@ func resourceCertificateManagerTrustConfigUpdate(d *schema.ResourceData, meta in

log.Printf("[DEBUG] Updating TrustConfig %q: %#v", d.Id(), obj)
headers := make(http.Header)
url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": "*"})
if err != nil {
return err
}

// err == nil indicates that the billing_project value was found
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
Expand Down Expand Up @@ -554,6 +585,28 @@ func flattenCertificateManagerTrustConfigTrustStoresIntermediateCasPemCertificat
return v
}

func flattenCertificateManagerTrustConfigAllowlistedCertificates(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
}
l := v.([]interface{})
transformed := make([]interface{}, 0, len(l))
for _, raw := range l {
original := raw.(map[string]interface{})
if len(original) < 1 {
// Do not include empty json objects coming back from the api
continue
}
transformed = append(transformed, map[string]interface{}{
"pem_certificate": flattenCertificateManagerTrustConfigAllowlistedCertificatesPemCertificate(original["pemCertificate"], d, config),
})
}
return transformed
}
func flattenCertificateManagerTrustConfigAllowlistedCertificatesPemCertificate(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenCertificateManagerTrustConfigTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
Expand Down Expand Up @@ -658,6 +711,32 @@ func expandCertificateManagerTrustConfigTrustStoresIntermediateCasPemCertificate
return v, nil
}

func expandCertificateManagerTrustConfigAllowlistedCertificates(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
if raw == nil {
continue
}
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedPemCertificate, err := expandCertificateManagerTrustConfigAllowlistedCertificatesPemCertificate(original["pem_certificate"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedPemCertificate); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["pemCertificate"] = transformedPemCertificate
}

req = append(req, transformed)
}
return req, nil
}

func expandCertificateManagerTrustConfigAllowlistedCertificatesPemCertificate(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandCertificateManagerTrustConfigEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,52 @@ resource "google_certificate_manager_trust_config" "default" {
`, context)
}

func TestAccCertificateManagerTrustConfig_certificateManagerTrustConfigAllowlistedCertificatesExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckCertificateManagerTrustConfigDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccCertificateManagerTrustConfig_certificateManagerTrustConfigAllowlistedCertificatesExample(context),
},
{
ResourceName: "google_certificate_manager_trust_config.default",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"labels", "location", "name", "terraform_labels"},
},
},
})
}

func testAccCertificateManagerTrustConfig_certificateManagerTrustConfigAllowlistedCertificatesExample(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_certificate_manager_trust_config" "default" {
name = "tf-test-trust-config%{random_suffix}"
description = "A sample trust config resource with allowlisted certificates"
location = "global"

allowlisted_certificates {
pem_certificate = file("test-fixtures/cert.pem")
}
allowlisted_certificates {
pem_certificate = file("test-fixtures/cert2.pem")
}

labels = {
foo = "bar"
}
}
`, context)
}

func testAccCheckCertificateManagerTrustConfigDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func testAccCertificateManagerTrustConfig_update0(context map[string]interface{}
resource "google_certificate_manager_trust_config" "default" {
name = "tf-test-trust-config%{random_suffix}"
description = "sample description for the trust config"
location = "us-central1"
location = "global"

trust_stores {
trust_anchors {
Expand All @@ -59,6 +59,10 @@ resource "google_certificate_manager_trust_config" "default" {
}
}

allowlisted_certificates {
pem_certificate = file("test-fixtures/cert.pem")
}

labels = {
"foo" = "bar"
}
Expand All @@ -71,7 +75,7 @@ func testAccCertificateManagerTrustConfig_update1(context map[string]interface{}
resource "google_certificate_manager_trust_config" "default" {
name = "tf-test-trust-config%{random_suffix}"
description = "sample description for the trust config 2"
location = "us-central1"
location = "global"

trust_stores {
trust_anchors {
Expand All @@ -82,6 +86,10 @@ resource "google_certificate_manager_trust_config" "default" {
}
}

allowlisted_certificates {
pem_certificate = file("test-fixtures/cert.pem")
}

labels = {
"bar" = "foo"
}
Expand Down
38 changes: 38 additions & 0 deletions website/docs/r/certificate_manager_trust_config.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ resource "google_certificate_manager_trust_config" "default" {
}
}
```
<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgit.luolix.top%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_image=gcr.io%2Fcloudshell-images%2Fcloudshell%3Alatest&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md&cloudshell_working_dir=certificate_manager_trust_config_allowlisted_certificates&open_in_editor=main.tf" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
</a>
</div>
## Example Usage - Certificate Manager Trust Config Allowlisted Certificates


```hcl
resource "google_certificate_manager_trust_config" "default" {
name = "trust-config"
description = "A sample trust config resource with allowlisted certificates"
location = "global"

allowlisted_certificates {
pem_certificate = file("test-fixtures/cert.pem")
}
allowlisted_certificates {
pem_certificate = file("test-fixtures/cert2.pem")
}

labels = {
foo = "bar"
}
}
```

## Argument Reference

Expand Down Expand Up @@ -94,6 +120,12 @@ The following arguments are supported:
This field is supported when TrustConfig is configured with Load Balancers, currently not supported for SPIFFE certificate validation.
Structure is [documented below](#nested_trust_stores).

* `allowlisted_certificates` -
(Optional)
Allowlisted PEM-encoded certificates. A certificate matching an allowlisted certificate is always considered valid as long as
the certificate is parseable, proof of private key possession is established, and constraints on the certificate's SAN field are met.
Structure is [documented below](#nested_allowlisted_certificates).

* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.

Expand Down Expand Up @@ -128,6 +160,12 @@ The following arguments are supported:
Each certificate provided in PEM format may occupy up to 5kB.
**Note**: This property is sensitive and will not be displayed in the plan.

<a name="nested_allowlisted_certificates"></a>The `allowlisted_certificates` block supports:

* `pem_certificate` -
(Required)
PEM certificate that is allowlisted. The certificate can be up to 5k bytes, and must be a parseable X.509 certificate.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are exported:
Expand Down