Skip to content

Commit

Permalink
Support field signature_bits in relevant PKI resources (#2401)
Browse files Browse the repository at this point in the history
* Add signature_bits to vault_pki_secret_backend_intermediate_cert_request.

* Add signature_bits to vault_pki_secret_backend_root_sign_intermediate.

* Add signature_bits to vault_pki_secret_backend_role.

* Add signature_bits to vault_pki_secret_backend_root_cert.
  • Loading branch information
victorr authored Feb 7, 2025
1 parent a0b8d1e commit b126c89
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ FEATURES:
* Update `vault_pki_secret_backend_root_cert` and `vault_pki_secret_backend_root_sign_intermediate` to support the new fields for the name constraints extension. Requires Vault 1.19+ ([#2396](https://github.com/hashicorp/terraform-provider-vault/pull/2396)).
* Update `vault_pki_secret_backend_issuer` resource with the new issuer configuration fields to control certificate verification. Requires Vault Enterprise 1.19+ ([#2400](https://github.com/hashicorp/terraform-provider-vault/pull/2400)).
* Add support for certificate revocation with `revoke_with_key` in `vault_pki_secret_backend_cert` ([#2242](https://github.com/hashicorp/terraform-provider-vault/pull/2242))
* Add support for signature_bits field to `vault_pki_secret_backend_role`, `vault_pki_secret_backend_root_cert`, `vault_pki_secret_backend_root_sign_intermediate` and `vault_pki_secret_backend_intermediate_cert_request` ([#2401])(https://github.com/hashicorp/terraform-provider-vault/pull/2401)

BUGS:

Expand Down
1 change: 1 addition & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const (
FieldTokenLabel = "token_label"
FieldCurve = "curve"
FieldKeyBits = "key_bits"
FieldSignatureBits = "signature_bits"
FieldForceRWSession = "force_rw_session"
FieldAccessKey = "access_key"
FieldSecretKey = "secret_key"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ func pkiSecretBackendIntermediateCertRequestResource() *schema.Resource {
ForceNew: true,
Default: 2048,
},
consts.FieldSignatureBits: {
Type: schema.TypeInt,
Optional: true,
Description: "The number of bits to use in the signature algorithm.",
ForceNew: true,
},
consts.FieldExcludeCNFromSans: {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -249,6 +255,7 @@ func pkiSecretBackendIntermediateCertRequestCreate(ctx context.Context, d *schem
consts.FieldPostalCode,
consts.FieldManagedKeyName,
consts.FieldManagedKeyID,
consts.FieldSignatureBits,
}

intermediateCertBooleanAPIFields := []string{
Expand Down Expand Up @@ -333,7 +340,6 @@ func pkiSecretBackendIntermediateCertRequestCreate(ctx context.Context, d *schem
if err := d.Set(consts.FieldPrivateKeyType, resp.Data[consts.FieldPrivateKeyType]); err != nil {
return diag.FromErr(err)
}

}

id := path
Expand Down
107 changes: 107 additions & 0 deletions vault/resource_pki_secret_backend_intermediate_cert_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
package vault

import (
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"strconv"
"testing"

Expand Down Expand Up @@ -74,6 +77,110 @@ func TestPkiSecretBackendIntermediateCertRequest_managedKeys(t *testing.T) {
})
}

func TestPkiSecretBackendIntermediateCertRequest_signature_bits(t *testing.T) {
path := "pki-" + strconv.Itoa(acctest.RandInt())

resourceName := "vault_pki_secret_backend_intermediate_cert_request.test"
testCheckFunc := []resource.TestCheckFunc{
resource.TestCheckResourceAttr(resourceName, "backend", path),
resource.TestCheckResourceAttr(resourceName, "type", "internal"),
resource.TestCheckResourceAttr(resourceName, "common_name", "test.my.domain"),
resource.TestCheckResourceAttr(resourceName, "uri_sans.#", "1"),
resource.TestCheckResourceAttr(resourceName, "uri_sans.0", "spiffe://test.my.domain"),
resource.TestCheckResourceAttr(resourceName, consts.FieldKeyType, "rsa"),
resource.TestCheckResourceAttr(resourceName, consts.FieldKeyBits, "4096"),
}

resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() { testutil.TestAccPreCheck(t) },
CheckDestroy: testCheckMountDestroyed("vault_mount", consts.MountTypePKI, consts.FieldPath),
Steps: []resource.TestStep{
{
Config: testPkiSecretBackendIntermediateCertRequestConfig_signature_bits(path, ""),
Check: resource.ComposeTestCheckFunc(append(testCheckFunc,
resource.TestCheckNoResourceAttr(resourceName, consts.FieldSignatureBits),
assertCsrAttributes(resourceName, x509.SHA256WithRSA),
)...),
},
{
Config: testPkiSecretBackendIntermediateCertRequestConfig_signature_bits(path, "384"),
Check: resource.ComposeTestCheckFunc(append(testCheckFunc,
resource.TestCheckResourceAttr(resourceName, consts.FieldSignatureBits, "384"),
assertCsrAttributes(resourceName, x509.SHA384WithRSA),
)...),
},
{
Config: testPkiSecretBackendIntermediateCertRequestConfig_signature_bits(path, "512"),
Check: resource.ComposeTestCheckFunc(append(testCheckFunc,
resource.TestCheckResourceAttr(resourceName, consts.FieldSignatureBits, "512"),
assertCsrAttributes(resourceName, x509.SHA512WithRSA),
)...),
},
},
})
}

// assertCsrAttributes so far only checks signature algorithm...
func assertCsrAttributes(resourceName string, expectedSignatureAlgorithm x509.SignatureAlgorithm) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, err := testutil.GetResourceFromRootModule(s, resourceName)
if err != nil {
return err
}

attrs := rs.Primary.Attributes

if attrs["format"] != "pem" {
// assumes that the certificate `format` is `pem`
return fmt.Errorf("test only valid for resources configured with the 'pem' format")
}

csrPEM := attrs["csr"]
if csrPEM == "" {
return fmt.Errorf("CSR from state cannot be empty")
}

c, _ := pem.Decode([]byte(csrPEM))
csr, err := x509.ParseCertificateRequest(c.Bytes)
if err != nil {
return err
}

if expectedSignatureAlgorithm != csr.SignatureAlgorithm {
return fmt.Errorf("expected signature algorithm (form signature_bits) %s, actual %s", expectedSignatureAlgorithm, csr.SignatureAlgorithm)
}

return nil
}
}

func testPkiSecretBackendIntermediateCertRequestConfig_signature_bits(path string, optionalSignatureBits string) string {
var signatureBits string
if optionalSignatureBits != "" {
signatureBits = fmt.Sprintf(`signature_bits = "%s"`, optionalSignatureBits)
}
return fmt.Sprintf(`
resource "vault_mount" "test" {
path = "%s"
type = "pki"
description = "test"
default_lease_ttl_seconds = 86400
max_lease_ttl_seconds = 86400
}
resource "vault_pki_secret_backend_intermediate_cert_request" "test" {
backend = vault_mount.test.path
type = "internal"
common_name = "test.my.domain"
uri_sans = ["spiffe://test.my.domain"]
key_type = "rsa"
key_bits = "4096"
%s
}
`, path, signatureBits)
}

func TestPkiSecretBackendIntermediateCertificate_multiIssuer(t *testing.T) {
path := acctest.RandomWithPrefix("test-pki-mount")

Expand Down
15 changes: 11 additions & 4 deletions vault/resource_pki_secret_backend_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var pkiSecretFields = []string{
consts.FieldAllowedURISans,
consts.FieldCountry,
consts.FieldKeyBits,
consts.FieldSignatureBits,
consts.FieldKeyType,
consts.FieldLocality,
consts.FieldMaxTTL,
Expand Down Expand Up @@ -255,6 +256,12 @@ func pkiSecretBackendRoleResource() *schema.Resource {
Description: "The number of bits of generated keys.",
Default: 2048,
},
consts.FieldSignatureBits: {
Type: schema.TypeInt,
Optional: true,
Computed: true,
Description: "The number of bits to use in the signature algorithm.",
},
consts.FieldKeyUsage: {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -593,12 +600,12 @@ func pkiSecretBackendRoleRead(_ context.Context, d *schema.ResourceData, meta in
switch {
case k == consts.FieldNotBeforeDuration:
d.Set(k, flattenVaultDuration(secret.Data[k]))
case k == consts.FieldKeyBits:
keyBits, err := secret.Data[consts.FieldKeyBits].(json.Number).Int64()
case k == consts.FieldKeyBits || k == consts.FieldSignatureBits:
keyBits, err := secret.Data[k].(json.Number).Int64()
if err != nil {
return diag.Errorf("expected key_bits %q to be a number", secret.Data[consts.FieldKeyBits])
return diag.Errorf("expected %s %q to be a number", k, secret.Data[k])
}
d.Set(consts.FieldKeyBits, keyBits)
d.Set(k, keyBits)
default:
d.Set(k, secret.Data[k])
}
Expand Down
2 changes: 2 additions & 0 deletions vault/resource_pki_secret_backend_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ func TestPkiSecretBackendRole_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "email_protection_flag", "false"),
resource.TestCheckResourceAttr(resourceName, "key_type", "rsa"),
resource.TestCheckResourceAttr(resourceName, "key_bits", "2048"),
resource.TestCheckResourceAttr(resourceName, "signature_bits", "512"),
resource.TestCheckResourceAttr(resourceName, "email_protection_flag", "false"),
resource.TestCheckResourceAttr(resourceName, "email_protection_flag", "false"),
resource.TestCheckResourceAttr(resourceName, "key_usage.#", "3"),
Expand Down Expand Up @@ -378,6 +379,7 @@ resource "vault_pki_secret_backend_role" "test" {
email_protection_flag = false
key_type = "rsa"
key_bits = 2048
signature_bits = 512
ext_key_usage = []
ext_key_usage_oids = ["1.3.6.1.4.1.311.4"]
use_csr_common_name = true
Expand Down
7 changes: 7 additions & 0 deletions vault/resource_pki_secret_backend_root_cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ func pkiSecretBackendRootCertResource() *schema.Resource {
ForceNew: true,
Default: 2048,
},
consts.FieldSignatureBits: {
Type: schema.TypeInt,
Optional: true,
Computed: true,
Description: "The number of bits to use in the signature algorithm.",
},
consts.FieldMaxPathLength: {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -423,6 +429,7 @@ func pkiSecretBackendRootCertCreate(_ context.Context, d *schema.ResourceData, m
consts.FieldPostalCode,
consts.FieldManagedKeyName,
consts.FieldManagedKeyID,
consts.FieldSignatureBits,
}

rootCertBooleanAPIFields := []string{
Expand Down
4 changes: 3 additions & 1 deletion vault/resource_pki_secret_backend_root_cert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ func TestPkiSecretBackendRootCertificate_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, consts.FieldPrivateKeyFormat, "der"),
resource.TestCheckResourceAttr(resourceName, consts.FieldKeyType, "rsa"),
resource.TestCheckResourceAttr(resourceName, consts.FieldKeyBits, "4096"),
resource.TestCheckResourceAttr(resourceName, consts.FieldSignatureBits, "512"),
resource.TestCheckResourceAttr(resourceName, consts.FieldOu, "test"),
resource.TestCheckResourceAttr(resourceName, consts.FieldOrganization, "test"),
resource.TestCheckResourceAttr(resourceName, consts.FieldCountry, "test"),
resource.TestCheckResourceAttr(resourceName, consts.FieldLocality, "test"),
resource.TestCheckResourceAttr(resourceName, consts.FieldProvince, "test"),
resource.TestCheckResourceAttrSet(resourceName, consts.FieldSerialNumber),
assertCertificateAttributes(resourceName),
assertCertificateAttributes(resourceName, x509.SHA512WithRSA),
}

testPkiSecretBackendRootCertificate(t, path, config, resourceName, checks, nil)
Expand Down Expand Up @@ -378,6 +379,7 @@ resource "vault_pki_secret_backend_root_cert" "test" {
private_key_format = "der"
key_type = "rsa"
key_bits = 4096
signature_bits = 512
exclude_cn_from_sans = true
ou = "test"
organization = "test"
Expand Down
7 changes: 7 additions & 0 deletions vault/resource_pki_secret_backend_root_sign_intermediate.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ func pkiSecretBackendRootSignIntermediateResource() *schema.Resource {
Description: "The postal code.",
ForceNew: true,
},
consts.FieldSignatureBits: {
Type: schema.TypeInt,
Optional: true,
Description: "The number of bits to use in the signature algorithm.",
ForceNew: true,
},
consts.FieldCertificate: {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -310,6 +316,7 @@ func pkiSecretBackendRootSignIntermediateCreate(ctx context.Context, d *schema.R
consts.FieldProvince,
consts.FieldStreetAddress,
consts.FieldPostalCode,
consts.FieldSignatureBits,
}

intermediateSignBooleanAPIFields := []string{
Expand Down
Loading

0 comments on commit b126c89

Please sign in to comment.