From fabb0accd31161a44f96e082f243e5152f16aebf Mon Sep 17 00:00:00 2001 From: vaerh <64400271+vaerh@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:38:33 +0300 Subject: [PATCH] Fix creation of `vault_pki_secret_backend_root_sign_intermediate` resource with zero path length (#2253) fix: Fix zero integer value handling When filling the data map, values are incorrectly evaluated using the `GetOk` function, so zero integer values are discarded. For this reason it is not possible to set the `max_path_length = 0` restriction for a certificate. Co-authored-by: Steven Clark --- CHANGELOG.md | 2 + .../resource_pki_secret_backend_root_cert.go | 3 +- ...ource_pki_secret_backend_root_cert_test.go | 2 + ...i_secret_backend_root_sign_intermediate.go | 3 +- ...ret_backend_root_sign_intermediate_test.go | 47 +++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14df0de2b1..add41ebaf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,8 +54,10 @@ FEATURES: IMPROVEMENTS: * return a useful error when delete fails for the `vault_jwt_auth_backend_role` resource: ([#2232](https://github.com/hashicorp/terraform-provider-vault/pull/2232)) +BUGS: * Remove dependency on `github.com/hashicorp/vault` package: ([#2251](https://github.com/hashicorp/terraform-provider-vault/pull/2251)) * Add missing `custom_tags` and `secret_name_template` fields to `vault_secrets_sync_azure_destination` resource ([#2247](https://github.com/hashicorp/terraform-provider-vault/pull/2247)) +* Fix handling of 0 value within field `max_path_length` in `vault_pki_secret_backend_root_cert` and `vault_pki_secret_backend_root_sign_intermediate` resources ([#2253](https://github.com/hashicorp/terraform-provider-vault/pull/2253)) ## 4.2.0 (Mar 27, 2024) diff --git a/vault/resource_pki_secret_backend_root_cert.go b/vault/resource_pki_secret_backend_root_cert.go index a6afc17554..87bec540da 100644 --- a/vault/resource_pki_secret_backend_root_cert.go +++ b/vault/resource_pki_secret_backend_root_cert.go @@ -394,8 +394,9 @@ func pkiSecretBackendRootCertCreate(_ context.Context, d *schema.ResourceData, m } data := map[string]interface{}{} + rawConfig := d.GetRawConfig() for _, k := range rootCertAPIFields { - if v, ok := d.GetOk(k); ok { + if v := d.Get(k); !rawConfig.GetAttr(k).IsNull() { data[k] = v } } diff --git a/vault/resource_pki_secret_backend_root_cert_test.go b/vault/resource_pki_secret_backend_root_cert_test.go index cd952f75de..2c1c7be0f7 100644 --- a/vault/resource_pki_secret_backend_root_cert_test.go +++ b/vault/resource_pki_secret_backend_root_cert_test.go @@ -39,6 +39,7 @@ func TestPkiSecretBackendRootCertificate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, consts.FieldLocality, "test"), resource.TestCheckResourceAttr(resourceName, consts.FieldProvince, "test"), resource.TestCheckResourceAttrSet(resourceName, consts.FieldSerialNumber), + assertCertificateAttributes(resourceName), } resource.Test(t, resource.TestCase{ @@ -263,6 +264,7 @@ resource "vault_pki_secret_backend_root_cert" "test" { country = "test" locality = "test" province = "test" + max_path_length = 0 } `, path) diff --git a/vault/resource_pki_secret_backend_root_sign_intermediate.go b/vault/resource_pki_secret_backend_root_sign_intermediate.go index 54c8a60265..f11848e596 100644 --- a/vault/resource_pki_secret_backend_root_sign_intermediate.go +++ b/vault/resource_pki_secret_backend_root_sign_intermediate.go @@ -263,8 +263,9 @@ func pkiSecretBackendRootSignIntermediateCreate(ctx context.Context, d *schema.R } data := map[string]interface{}{} + rawConfig := d.GetRawConfig() for _, k := range intermediateSignAPIFields { - if v, ok := d.GetOk(k); ok { + if v := d.Get(k); !rawConfig.GetAttr(k).IsNull() { data[k] = v } } diff --git a/vault/resource_pki_secret_backend_root_sign_intermediate_test.go b/vault/resource_pki_secret_backend_root_sign_intermediate_test.go index 18ffef5f50..d520936fe1 100644 --- a/vault/resource_pki_secret_backend_root_sign_intermediate_test.go +++ b/vault/resource_pki_secret_backend_root_sign_intermediate_test.go @@ -4,6 +4,7 @@ package vault import ( + "crypto/x509" "encoding/base64" "encoding/pem" "fmt" @@ -249,6 +250,7 @@ func testCheckPKISecretRootSignIntermediate(res, path, commonName, format string resource.TestCheckResourceAttrSet(res, "serial_number"), assertPKICertificateBundle(res, format), assertPKICAChain(res), + assertCertificateAttributes(res), ) } @@ -315,6 +317,50 @@ func assertPKICAChain(res string) resource.TestCheckFunc { } } +func assertCertificateAttributes(res string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[res] + if !ok { + return fmt.Errorf("resource %q not found in the state", res) + } + format := rs.Primary.Attributes["format"] + var rawCert []byte + switch format { + case "pem", "pem_bundle": + pemCert := []byte(rs.Primary.Attributes["certificate"]) + b, _ := pem.Decode(pemCert) + if b == nil { + return fmt.Errorf("error decoding PEM certificate") + } + + rawCert = b.Bytes + case "der": + certAttr := rs.Primary.Attributes["certificate"] + var err error + rawCert, err = base64.StdEncoding.DecodeString(certAttr) + if err != nil { + return fmt.Errorf("error decoding der certificate: %w", err) + } + } + + crt, err := x509.ParseCertificate(rawCert) + if err != nil { + return fmt.Errorf("error parsing certificate: %w", err) + } + + expectedMaxPathLen, err := strconv.Atoi(rs.Primary.Attributes["max_path_length"]) + if err != nil { + return fmt.Errorf("error parsing max_path_length value as int: %w", err) + } + + if expectedMaxPathLen != crt.MaxPathLen { + return fmt.Errorf("expected MaxPathLen %d, actual %d", expectedMaxPathLen, crt.MaxPathLen) + } + + return nil + } +} + func testPkiSecretBackendRootSignIntermediateConfig_basic(rootPath, path, format string, revoke bool, issuerRef string) string { config := fmt.Sprintf(` resource "vault_mount" "test-root" { @@ -368,6 +414,7 @@ resource "vault_pki_secret_backend_root_sign_intermediate" "test" { locality = "San Francisco" province = "CA" revoke = %t + max_path_length = 0 `, rootPath, path, revoke) if format != "" {