From 58c923bb383a3dd98c32219ab5f19a8f50140d86 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 28 Apr 2022 16:58:43 +0100 Subject: [PATCH 1/9] Revamp all tests to use TestCheckFunc helpers --- internal/openssh/lib_test.go | 3 +- .../provider/resource_cert_request_test.go | 241 +++--- .../resource_locally_signed_cert_test.go | 641 +++++++------- .../provider/resource_private_key_test.go | 403 ++------- .../resource_self_signed_cert_test.go | 788 +++++++++--------- 5 files changed, 823 insertions(+), 1253 deletions(-) diff --git a/internal/openssh/lib_test.go b/internal/openssh/lib_test.go index 521797fa..667b5185 100644 --- a/internal/openssh/lib_test.go +++ b/internal/openssh/lib_test.go @@ -7,8 +7,9 @@ import ( "crypto/rand" "crypto/rsa" "encoding/pem" - "golang.org/x/crypto/ssh" "testing" + + "golang.org/x/crypto/ssh" ) func TestOpenSSHFormat_MarshalAndUnmarshal_RSA(t *testing.T) { diff --git a/internal/provider/resource_cert_request_test.go b/internal/provider/resource_cert_request_test.go index 583e5a1f..2f0b4281 100644 --- a/internal/provider/resource_cert_request_test.go +++ b/internal/provider/resource_cert_request_test.go @@ -4,11 +4,10 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "strings" + "regexp" "testing" r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestCertRequest(t *testing.T) { @@ -49,86 +48,76 @@ func TestCertRequest(t *testing.T) { %s EOT } - output "key_pem_1" { - value = "${tls_cert_request.test1.cert_request_pem}" - } `, testPrivateKeyPEM), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE REQUEST----") { - return fmt.Errorf("key is missing CSR PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - csr, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) - } - if expected, got := "2", csr.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", csr.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", csr.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", csr.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", csr.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", csr.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", csr.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", csr.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", csr.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_cert_request.test1", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----`)), + r.TestCheckResourceAttrWith("tls_cert_request.test1", "cert_request_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + csr, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing CSR: %s", err) + } + if expected, got := "2", csr.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "example.com", csr.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := "Example, Inc", csr.Subject.Organization[0]; got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := "Department of Terraform Testing", csr.Subject.OrganizationalUnit[0]; got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := "5879 Cotton Link", csr.Subject.StreetAddress[0]; got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := "Pirate Harbor", csr.Subject.Locality[0]; got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := "CA", csr.Subject.Province[0]; got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := "US", csr.Subject.Country[0]; got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := "95559-1227", csr.Subject.PostalCode[0]; got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } - if expected, got := 2, len(csr.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", csr.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", csr.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } + if expected, got := 2, len(csr.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } + if expected, got := "example.com", csr.DNSNames[0]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } + if expected, got := "example.net", csr.DNSNames[1]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(csr.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", csr.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", csr.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } + if expected, got := 2, len(csr.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.1", csr.IPAddresses[0].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.2", csr.IPAddresses[1].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(csr.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload", csr.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload2", csr.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } + if expected, got := 2, len(csr.URIs); got != expected { + return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/workload", csr.URIs[0].String(); got != expected { + return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/workload2", csr.URIs[1].String(); got != expected { + return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) + } - return nil - }, + return nil + }), + ), }, { Config: fmt.Sprintf(` @@ -141,62 +130,52 @@ EOT %s EOT } - output "key_pem_2" { - value = "${tls_cert_request.test2.cert_request_pem}" - } `, testPrivateKeyPEM), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_2"].Value - - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_2\" is not a string") - } - - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE REQUEST----") { - return fmt.Errorf("key is missing CSR PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - csr, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) - } - if expected, got := "42", csr.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "", csr.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Organization); got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.OrganizationalUnit); got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.StreetAddress); got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Locality); got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Province); got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Country); got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.PostalCode); got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_cert_request.test2", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----`)), + r.TestCheckResourceAttrWith("tls_cert_request.test2", "cert_request_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + csr, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing CSR: %s", err) + } + if expected, got := "42", csr.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "", csr.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.Organization); got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.OrganizationalUnit); got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.StreetAddress); got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.Locality); got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.Province); got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.Country); got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.Subject.PostalCode); got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } + if expected, got := 0, len(csr.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } - return nil - }, + return nil + }), + ), }, }, }) diff --git a/internal/provider/resource_locally_signed_cert_test.go b/internal/provider/resource_locally_signed_cert_test.go index 9d18fbf6..a85ae638 100644 --- a/internal/provider/resource_locally_signed_cert_test.go +++ b/internal/provider/resource_locally_signed_cert_test.go @@ -5,12 +5,10 @@ import ( "encoding/pem" "fmt" "regexp" - "strings" "testing" "time" r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestLocallySignedCert(t *testing.T) { @@ -18,126 +16,121 @@ func TestLocallySignedCert(t *testing.T) { ProviderFactories: testProviders, Steps: []r.TestStep{ { - Config: locallySignedCertConfig(1, 0, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE----") { - return fmt.Errorf("key is missing cert PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } + Config: locallySignedCertConfig(1, 0), + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing cert: %s", err) + } + if expected, got := "2", cert.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := "CA", cert.Subject.Province[0]; got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := "US", cert.Subject.Country[0]; got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.DNSNames[0]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } + if expected, got := "example.net", cert.DNSNames[1]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := 2, len(cert.URIs); got != expected { + return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/workload", cert.URIs[0].String(); got != expected { + return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/workload2", cert.URIs[1].String(); got != expected { + return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) + } - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.ExtKeyUsage); got != expected { + return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) + } - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } + if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { + return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) + } - caBlock, _ := pem.Decode([]byte(testCACert)) - caCert, err := x509.ParseCertificate(caBlock.Bytes) - if err != nil { - return fmt.Errorf("error parsing ca cert: %s", err) - } - certPool := x509.NewCertPool() + // This time checking is a bit sloppy to avoid inconsistent test results + // depending on the power of the machine running the tests. + now := time.Now() + if cert.NotBefore.After(now) { + return fmt.Errorf("certificate validity begins in the future") + } + if now.Sub(cert.NotBefore) > (2 * time.Minute) { + return fmt.Errorf("certificate validity begins more than two minutes in the past") + } + if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { + return fmt.Errorf("certificate validity is not one hour") + } - // Verify certificate - _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}) - if err == nil { - return fmt.Errorf("incorrectly verified certificate") - } else if _, ok := err.(x509.UnknownAuthorityError); !ok { - return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) - } - certPool.AddCert(caCert) - if _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { - return fmt.Errorf("verify failed: %s", err) - } + caBlock, _ := pem.Decode([]byte(testCACert)) + caCert, err := x509.ParseCertificate(caBlock.Bytes) + if err != nil { + return fmt.Errorf("error parsing ca cert: %s", err) + } + certPool := x509.NewCertPool() + + // Verify certificate + _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}) + if err == nil { + return fmt.Errorf("incorrectly verified certificate") + } else if _, ok := err.(x509.UnknownAuthorityError); !ok { + return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) + } + certPool.AddCert(caCert) + if _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { + return fmt.Errorf("verify failed: %s", err) + } - return nil - }, + return nil + }), + ), }, }, }) @@ -151,69 +144,43 @@ func TestAccLocallySignedCertRecreatesAfterExpired(t *testing.T) { PreCheck: setTimeForTest("2019-06-14T12:00:00Z"), Steps: []r.TestStep{ { - Config: locallySignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - previousCert = got + Config: locallySignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + previousCert = value return nil - }, + }), }, { - Config: locallySignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - - if got != previousCert { + Config: locallySignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + if value != previousCert { return fmt.Errorf("certificate updated even though no time has passed") } - - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T19:00:00Z"), - Config: locallySignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - - if got != previousCert { + Config: locallySignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + if value != previousCert { return fmt.Errorf("certificate updated even though not enough time has passed") } - - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T21:00:00Z"), - Config: locallySignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - - if got == previousCert { + Config: locallySignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + if value == previousCert { return fmt.Errorf("certificate not updated even though passed early renewal") } - - previousCert = got + previousCert = value return nil - }, + }), }, }, }) @@ -228,69 +195,43 @@ func TestAccLocallySignedCertNotRecreatedForEarlyRenewalUpdateInFuture(t *testin PreCheck: setTimeForTest("2019-06-14T12:00:00Z"), Steps: []r.TestStep{ { - Config: locallySignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - previousCert = got + Config: locallySignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + previousCert = value return nil - }, + }), }, { - Config: locallySignedCertConfig(10, 3, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - - if got != previousCert { + Config: locallySignedCertConfig(10, 3), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + if value != previousCert { return fmt.Errorf("certificate updated even though still time until early renewal") } - - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T16:00:00Z"), - Config: locallySignedCertConfig(10, 3, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - - if got != previousCert { + Config: locallySignedCertConfig(10, 3), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + if value != previousCert { return fmt.Errorf("certificate updated even though still time until early renewal") } - - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T16:00:00Z"), - Config: locallySignedCertConfig(10, 9, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - - if got == previousCert { + Config: locallySignedCertConfig(10, 9), + Check: r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + if value == previousCert { return fmt.Errorf("certificate not updated even though early renewal time has passed") } - - previousCert = got + previousCert = value return nil - }, + }), }, }, }) @@ -303,165 +244,171 @@ func TestAccLocallySignedCert_HandleKeyAlgorithmDeprecation(t *testing.T) { ProviderFactories: testProviders, Steps: []r.TestStep{ { - Config: locallySignedCertConfig(1, 0, true), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["cert_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"cert_pem\" is not a string") - } - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE----") { - return fmt.Errorf("key is missing cert PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } + Config: locallySignedCertConfigWithDeprecatedKeyAlgorithm(1, 0), + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing cert: %s", err) + } + if expected, got := "2", cert.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := "CA", cert.Subject.Province[0]; got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := "US", cert.Subject.Country[0]; got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.DNSNames[0]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } + if expected, got := "example.net", cert.DNSNames[1]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := 2, len(cert.URIs); got != expected { + return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/workload", cert.URIs[0].String(); got != expected { + return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/workload2", cert.URIs[1].String(); got != expected { + return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) + } - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.ExtKeyUsage); got != expected { + return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) + } - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } + if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { + return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) + } - caBlock, _ := pem.Decode([]byte(testCACert)) - caCert, err := x509.ParseCertificate(caBlock.Bytes) - if err != nil { - return fmt.Errorf("error parsing ca cert: %s", err) - } - certPool := x509.NewCertPool() + // This time checking is a bit sloppy to avoid inconsistent test results + // depending on the power of the machine running the tests. + now := time.Now() + if cert.NotBefore.After(now) { + return fmt.Errorf("certificate validity begins in the future") + } + if now.Sub(cert.NotBefore) > (2 * time.Minute) { + return fmt.Errorf("certificate validity begins more than two minutes in the past") + } + if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { + return fmt.Errorf("certificate validity is not one hour") + } - // Verify certificate - _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}) - if err == nil { - return fmt.Errorf("incorrectly verified certificate") - } else if _, ok := err.(x509.UnknownAuthorityError); !ok { - return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) - } - certPool.AddCert(caCert) - if _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { - return fmt.Errorf("verify failed: %s", err) - } + caBlock, _ := pem.Decode([]byte(testCACert)) + caCert, err := x509.ParseCertificate(caBlock.Bytes) + if err != nil { + return fmt.Errorf("error parsing ca cert: %s", err) + } + certPool := x509.NewCertPool() + + // Verify certificate + _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}) + if err == nil { + return fmt.Errorf("incorrectly verified certificate") + } else if _, ok := err.(x509.UnknownAuthorityError); !ok { + return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) + } + certPool.AddCert(caCert) + if _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { + return fmt.Errorf("verify failed: %s", err) + } - return nil - }, + return nil + }), + ), }, }, }) } -func locallySignedCertConfig(validity, earlyRenewal uint32, setKeyAlgorithm bool) string { - caKeyAlgorithmCfg := "" - if setKeyAlgorithm { - caKeyAlgorithmCfg = `ca_key_algorithm = "RSA"` - } - +func locallySignedCertConfig(validity, earlyRenewal uint32) string { return fmt.Sprintf(` - resource "tls_locally_signed_cert" "test" { - cert_request_pem = < 1700 { - return fmt.Errorf("private key PEM looks too long for a 2048-bit key (got %v characters)", len(gotPrivate)) - } - - // Check `.public_key_pem` - gotPublicUntyped := s.RootModule().Outputs["public_key_pem"].Value - gotPublic, ok := gotPublicUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPublic, "-----BEGIN PUBLIC KEY----") { - return fmt.Errorf("public key is missing public key PEM preamble") - } - - // Check `.public_key_openssh` - gotPublicSSHUntyped := s.RootModule().Outputs["public_key_openssh"].Value - gotPublicSSH, ok := gotPublicSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_openssh\" is not a string") - } - if !strings.HasPrefix(gotPublicSSH, "ssh-rsa ") { - return fmt.Errorf("SSH public key is missing ssh-rsa prefix") - } - - // Check `.private_key_openssh` - gotPrivateSSHUntyped := s.RootModule().Outputs["private_key_openssh"].Value - gotPrivateSSH, ok := gotPrivateSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_openssh\" is not a string") - } - if !strings.HasPrefix(gotPrivateSSH, "-----BEGIN OPENSSH PRIVATE KEY----") { - return fmt.Errorf("private key is missing RSA key OPENSSH PEM preamble") - } - - // Check `.public_key_fingerprint_md5` - gotPublicFingerprintMD5Untyped := s.RootModule().Outputs["public_key_fingerprint_md5"].Value - gotPublicFingerprintMD5, ok := gotPublicFingerprintMD5Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_md5\" is not a string") - } - if gotPublicFingerprintMD5[2] != ':' { - return fmt.Errorf("MD5 public key fingerprint is missing ':' in the correct place") - } - - // Check `.public_key_fingerprint_sha256` - gotPublicFingerprintSHA256Untyped := s.RootModule().Outputs["public_key_fingerprint_sha256"].Value - gotPublicFingerprintSHA256, ok := gotPublicFingerprintSHA256Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_sha256\" is not a string") - } - if !(strings.HasPrefix(gotPublicFingerprintSHA256, "SHA256:")) { - return fmt.Errorf("SHA256 public key fingerprint is is missing the expected preamble") - } - - return nil - }, + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----`)), + r.TestCheckResourceAttrWith("tls_private_key.test", "private_key_pem", func(pem string) error { + if len(pem) > 1700 { + return fmt.Errorf("private key PEM looks too long for a 2048-bit key (got %v characters)", len(pem)) + } + return nil + }), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ssh-rsa `)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), + ), }, { Config: ` @@ -112,25 +39,16 @@ func TestPrivateKeyRSA(t *testing.T) { algorithm = "RSA" rsa_bits = 4096 } - output "key_pem" { - value = "${tls_private_key.test.private_key_pem}" - sensitive = true - } `, - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem\" is not a string") - } - if !strings.HasPrefix(got, "-----BEGIN RSA PRIVATE KEY----") { - return fmt.Errorf("key is missing RSA key PEM preamble") - } - if len(got) < 1700 { - return fmt.Errorf("key PEM looks too short for a 4096-bit key (got %v characters)", len(got)) - } - return nil - }, + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----`)), + r.TestCheckResourceAttrWith("tls_private_key.test", "private_key_pem", func(pem string) error { + if len(pem) < 1700 { + return fmt.Errorf("private key PEM looks too short for a 4096-bit key (got %v characters)", len(pem)) + } + return nil + }), + ), }, }, }) @@ -145,90 +63,15 @@ func TestPrivateKeyECDSA(t *testing.T) { resource "tls_private_key" "test" { algorithm = "ECDSA" } - output "private_key_pem" { - value = "${tls_private_key.test.private_key_pem}" - sensitive = true - } - output "private_key_openssh" { - value = "${tls_private_key.test.private_key_openssh}" - sensitive = true - } - output "public_key_pem" { - value = "${tls_private_key.test.public_key_pem}" - } - output "public_key_openssh" { - value = "${tls_private_key.test.public_key_openssh}" - } - output "public_key_fingerprint_md5" { - value = "${tls_private_key.test.public_key_fingerprint_md5}" - } - output "public_key_fingerprint_sha256" { - value = "${tls_private_key.test.public_key_fingerprint_sha256}" - } `, - Check: func(s *terraform.State) error { - // Check `.private_key_pem` - gotPrivateUntyped := s.RootModule().Outputs["private_key_pem"].Value - gotPrivate, ok := gotPrivateUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPrivate, "-----BEGIN EC PRIVATE KEY----") { - return fmt.Errorf("private key is missing EC key PEM preamble") - } - - // Check `.public_key_pem` - gotPublicUntyped := s.RootModule().Outputs["public_key_pem"].Value - gotPublic, ok := gotPublicUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPublic, "-----BEGIN PUBLIC KEY----") { - return fmt.Errorf("public key is missing public key PEM preamble") - } - - // Check `.public_key_openssh` - gotPublicSSHUntyped := s.RootModule().Outputs["public_key_openssh"].Value - gotPublicSSH, ok := gotPublicSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_openssh\" is not a string") - } - if gotPublicSSH != "" { - return fmt.Errorf("SSH public key should not be set for ECDSA P-224 key") - } - - // Check `.private_key_openssh` - gotPrivateSSHUntyped := s.RootModule().Outputs["private_key_openssh"].Value - gotPrivateSSH, ok := gotPrivateSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_openssh\" is not a string") - } - if gotPrivateSSH != "" { - return fmt.Errorf("SSH private key should not be set for ECDSA P-224 key") - } - - // Check `.public_key_fingerprint_md5` - gotPublicFingerprintMD5Untyped := s.RootModule().Outputs["public_key_fingerprint_md5"].Value - gotPublicFingerprintMD5, ok := gotPublicFingerprintMD5Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_md5\" is not a string") - } - if gotPublicFingerprintMD5 != "" { - return fmt.Errorf("MD5 public key fingerprint should not be set for ECDSA P-224 key") - } - - // Check `.public_key_fingerprint_sha256` - gotPublicFingerprintSHA256Untyped := s.RootModule().Outputs["public_key_fingerprint_sha256"].Value - gotPublicFingerprintSHA256, ok := gotPublicFingerprintSHA256Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_sha256\" is not a string") - } - if gotPublicFingerprintSHA256 != "" { - return fmt.Errorf("SHA256 public key fingerprint should not be st for ECDSA P-224 key") - } - - return nil - }, + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), + r.TestCheckResourceAttr("tls_private_key.test", "private_key_openssh", ""), + r.TestCheckResourceAttr("tls_private_key.test", "public_key_openssh", ""), + r.TestCheckResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", ""), + r.TestCheckResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", ""), + ), }, { Config: ` @@ -236,90 +79,15 @@ func TestPrivateKeyECDSA(t *testing.T) { algorithm = "ECDSA" ecdsa_curve = "P256" } - output "private_key_pem" { - value = "${tls_private_key.test.private_key_pem}" - sensitive = true - } - output "private_key_openssh" { - value = "${tls_private_key.test.private_key_openssh}" - sensitive = true - } - output "public_key_pem" { - value = "${tls_private_key.test.public_key_pem}" - } - output "public_key_openssh" { - value = "${tls_private_key.test.public_key_openssh}" - } - output "public_key_fingerprint_md5" { - value = "${tls_private_key.test.public_key_fingerprint_md5}" - } - output "public_key_fingerprint_sha256" { - value = "${tls_private_key.test.public_key_fingerprint_sha256}" - } `, - Check: func(s *terraform.State) error { - // Check `.private_key_pem` - gotPrivateUntyped := s.RootModule().Outputs["private_key_pem"].Value - gotPrivate, ok := gotPrivateUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPrivate, "-----BEGIN EC PRIVATE KEY----") { - return fmt.Errorf("private key is missing EC key PEM preamble") - } - - // Check `.public_key_pem` - gotPublicUntyped := s.RootModule().Outputs["public_key_pem"].Value - gotPublic, ok := gotPublicUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPublic, "-----BEGIN PUBLIC KEY----") { - return fmt.Errorf("public key is missing public key PEM preamble") - } - - // Check `.public_key_openssh` - gotPublicSSHUntyped := s.RootModule().Outputs["public_key_openssh"].Value - gotPublicSSH, ok := gotPublicSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_openssh\" is not a string") - } - if !strings.HasPrefix(gotPublicSSH, "ecdsa-sha2-nistp256 ") { - return fmt.Errorf("SSH public key is missing ecdsa-sha2-nistp256 prefix") - } - - // Check `.private_key_openssh` - gotPrivateSSHUntyped := s.RootModule().Outputs["private_key_openssh"].Value - gotPrivateSSH, ok := gotPrivateSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_openssh\" is not a string") - } - if !strings.HasPrefix(gotPrivateSSH, "-----BEGIN OPENSSH PRIVATE KEY----") { - return fmt.Errorf("private key is missing RSA key OPENSSH PEM preamble") - } - - // Check `.public_key_fingerprint_md5` - gotPublicFingerprintMD5Untyped := s.RootModule().Outputs["public_key_fingerprint_md5"].Value - gotPublicFingerprintMD5, ok := gotPublicFingerprintMD5Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_md5\" is not a string") - } - if gotPublicFingerprintMD5[2] != ':' { - return fmt.Errorf("MD5 public key fingerprint is missing ':' in the correct place") - } - - // Check `.public_key_fingerprint_sha256` - gotPublicFingerprintSHA256Untyped := s.RootModule().Outputs["public_key_fingerprint_sha256"].Value - gotPublicFingerprintSHA256, ok := gotPublicFingerprintSHA256Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_sha256\" is not a string") - } - if !(strings.HasPrefix(gotPublicFingerprintSHA256, "SHA256:")) { - return fmt.Errorf("SHA256 public key fingerprint is is missing the expected preamble") - } - - return nil - }, + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ecdsa-sha2-nistp256 `)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), + ), }, }, }) @@ -334,90 +102,15 @@ func TestPrivateKeyED25519(t *testing.T) { resource "tls_private_key" "test" { algorithm = "ED25519" } - output "private_key_pem" { - value = "${tls_private_key.test.private_key_pem}" - sensitive = true - } - output "private_key_openssh" { - value = "${tls_private_key.test.private_key_openssh}" - sensitive = true - } - output "public_key_pem" { - value = "${tls_private_key.test.public_key_pem}" - } - output "public_key_openssh" { - value = "${tls_private_key.test.public_key_openssh}" - } - output "public_key_fingerprint_md5" { - value = "${tls_private_key.test.public_key_fingerprint_md5}" - } - output "public_key_fingerprint_sha256" { - value = "${tls_private_key.test.public_key_fingerprint_sha256}" - } `, - Check: func(s *terraform.State) error { - // Check `.private_key_pem` - gotPrivateUntyped := s.RootModule().Outputs["private_key_pem"].Value - gotPrivate, ok := gotPrivateUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPrivate, "-----BEGIN PRIVATE KEY----") { - return fmt.Errorf("private key is missing ED25519 key PEM preamble") - } - - // Check `.public_key_pem` - gotPublicUntyped := s.RootModule().Outputs["public_key_pem"].Value - gotPublic, ok := gotPublicUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_pem\" is not a string") - } - if !strings.HasPrefix(gotPublic, "-----BEGIN PUBLIC KEY----") { - return fmt.Errorf("public key is missing public key PEM preamble") - } - - // Check `.public_key_openssh` - gotPublicSSHUntyped := s.RootModule().Outputs["public_key_openssh"].Value - gotPublicSSH, ok := gotPublicSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_openssh\" is not a string") - } - if !strings.HasPrefix(gotPublicSSH, "ssh-ed25519 ") { - return fmt.Errorf("SSH public key is missing sh-ed25519 prefix") - } - - // Check `.private_key_openssh` - gotPrivateSSHUntyped := s.RootModule().Outputs["private_key_openssh"].Value - gotPrivateSSH, ok := gotPrivateSSHUntyped.(string) - if !ok { - return fmt.Errorf("output for \"private_key_openssh\" is not a string") - } - if !strings.HasPrefix(gotPrivateSSH, "-----BEGIN OPENSSH PRIVATE KEY----") { - return fmt.Errorf("private key is missing RSA key OPENSSH PEM preamble") - } - - // Check `.public_key_fingerprint_md5` - gotPublicFingerprintMD5Untyped := s.RootModule().Outputs["public_key_fingerprint_md5"].Value - gotPublicFingerprintMD5, ok := gotPublicFingerprintMD5Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_md5\" is not a string") - } - if gotPublicFingerprintMD5[2] != ':' { - return fmt.Errorf("MD5 public key fingerprint is missing ':' in the correct place") - } - - // Check `.public_key_fingerprint_sha256` - gotPublicFingerprintSHA256Untyped := s.RootModule().Outputs["public_key_fingerprint_sha256"].Value - gotPublicFingerprintSHA256, ok := gotPublicFingerprintSHA256Untyped.(string) - if !ok { - return fmt.Errorf("output for \"public_key_fingerprint_sha256\" is not a string") - } - if !(strings.HasPrefix(gotPublicFingerprintSHA256, "SHA256:")) { - return fmt.Errorf("SHA256 public key fingerprint is is missing the expected preamble") - } - - return nil - }, + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN PRIVATE KEY----(.|\s)+-----END PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ssh-ed25519 `)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), + ), }, }, }) diff --git a/internal/provider/resource_self_signed_cert_test.go b/internal/provider/resource_self_signed_cert_test.go index c70140c1..1e2f62fb 100644 --- a/internal/provider/resource_self_signed_cert_test.go +++ b/internal/provider/resource_self_signed_cert_test.go @@ -6,12 +6,10 @@ import ( "encoding/pem" "fmt" "regexp" - "strings" "testing" "time" r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestSelfSignedCert(t *testing.T) { @@ -19,109 +17,103 @@ func TestSelfSignedCert(t *testing.T) { ProviderFactories: testProviders, Steps: []r.TestStep{ { - Config: selfSignedCertConfig(1, 0, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE----") { - return fmt.Errorf("key is missing cert PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } + Config: selfSignedCertConfig(1, 0), + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing cert: %s", err) + } + if expected, got := "2", cert.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := "CA", cert.Subject.Province[0]; got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := "US", cert.Subject.Country[0]; got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.DNSNames[0]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } + if expected, got := "example.net", cert.DNSNames[1]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.URIs); got != expected { + return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/ca", cert.URIs[0].String(); got != expected { + return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/ca2", cert.URIs[1].String(); got != expected { + return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.ExtKeyUsage); got != expected { + return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) + } - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } + if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { + return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) + } - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } + // This time checking is a bit sloppy to avoid inconsistent test results + // depending on the power of the machine running the tests. + now := time.Now() + if cert.NotBefore.After(now) { + return fmt.Errorf("certificate validity begins in the future") + } + if now.Sub(cert.NotBefore) > (2 * time.Minute) { + return fmt.Errorf("certificate validity begins more than two minutes in the past") + } + if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { + return fmt.Errorf("certificate validity is not one hour") + } - return nil - }, + return nil + }), + ), }, { Config: fmt.Sprintf(` @@ -135,74 +127,65 @@ func TestSelfSignedCert(t *testing.T) { %s EOT } - output "key_pem_2" { - value = tls_self_signed_cert.test2.cert_pem - } `, testPrivateKeyPEM), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_2"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_2\" is not a string") - } - - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE----") { - return fmt.Errorf("key is missing cert PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "42", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Organization); got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.OrganizationalUnit); got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.StreetAddress); got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Locality); got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Province); got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Country); got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.PostalCode); got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_self_signed_cert.test2", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestCheckResourceAttrWith("tls_self_signed_cert.test2", "cert_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing cert: %s", err) + } + if expected, got := "42", cert.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "", cert.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.Organization); got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.OrganizationalUnit); got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.StreetAddress); got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.Locality); got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.Province); got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.Country); got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := 0, len(cert.Subject.PostalCode); got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } - if expected, got := 0, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } + if expected, got := 0, len(cert.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } - if expected, got := 0, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } + if expected, got := 0, len(cert.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } - if expected, got := 0, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := []byte(``), cert.SubjectKeyId; !bytes.Equal(got, expected) { - return fmt.Errorf("incorrect subject key id: expected %v, got %v", expected, got) - } + if expected, got := 0, len(cert.ExtKeyUsage); got != expected { + return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) + } + if expected, got := []byte(``), cert.SubjectKeyId; !bytes.Equal(got, expected) { + return fmt.Errorf("incorrect subject key id: expected %v, got %v", expected, got) + } - if expected, got := x509.KeyUsage(0), cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } + if expected, got := x509.KeyUsage(0), cert.KeyUsage; got != expected { + return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) + } - return nil - }, + return nil + }), + ), }, }, }) @@ -214,109 +197,103 @@ func TestSelfSignedCert_HandleKeyAlgorithmDeprecation(t *testing.T) { ProviderFactories: testProviders, Steps: []r.TestStep{ { - Config: selfSignedCertConfig(1, 0, true), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if !strings.HasPrefix(got, "-----BEGIN CERTIFICATE----") { - return fmt.Errorf("key is missing cert PEM preamble") - } - block, _ := pem.Decode([]byte(got)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } + Config: selfSignedCertConfigWithDeprecatedKeyAlgorithm(1, 0), + Check: r.ComposeAggregateTestCheckFunc( + r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + block, _ := pem.Decode([]byte(value)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing cert: %s", err) + } + if expected, got := "2", cert.Subject.SerialNumber; got != expected { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.Subject.CommonName; got != expected { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) + } + if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) + } + if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) + } + if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) + } + if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) + } + if expected, got := "CA", cert.Subject.Province[0]; got != expected { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) + } + if expected, got := "US", cert.Subject.Country[0]; got != expected { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) + } + if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.DNSNames); got != expected { + return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) + } + if expected, got := "example.com", cert.DNSNames[0]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } + if expected, got := "example.net", cert.DNSNames[1]; got != expected { + return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.IPAddresses); got != expected { + return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } + if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { + return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.URIs); got != expected { + return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/ca", cert.URIs[0].String(); got != expected { + return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) + } + if expected, got := "spiffe://example-trust-domain/ca2", cert.URIs[1].String(); got != expected { + return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) + } - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } + if expected, got := 2, len(cert.ExtKeyUsage); got != expected { + return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) + } + if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { + return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) + } - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } + if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { + return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) + } - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } + // This time checking is a bit sloppy to avoid inconsistent test results + // depending on the power of the machine running the tests. + now := time.Now() + if cert.NotBefore.After(now) { + return fmt.Errorf("certificate validity begins in the future") + } + if now.Sub(cert.NotBefore) > (2 * time.Minute) { + return fmt.Errorf("certificate validity begins more than two minutes in the past") + } + if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { + return fmt.Errorf("certificate validity is not one hour") + } - return nil - }, + return nil + }), + ), }, }, }) @@ -330,69 +307,46 @@ func TestAccSelfSignedCertRecreatesAfterExpired(t *testing.T) { PreCheck: setTimeForTest("2019-06-14T12:00:00Z"), Steps: []r.TestStep{ { - Config: selfSignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - previousCert = got + Config: selfSignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + previousCert = value return nil - }, + }), }, { - Config: selfSignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if got != previousCert { + Config: selfSignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + if previousCert != value { return fmt.Errorf("certificate updated even though no time has passed") } - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T19:00:00Z"), - Config: selfSignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if got != previousCert { + Config: selfSignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + if previousCert != value { return fmt.Errorf("certificate updated even though not enough time has passed") } - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T21:00:00Z"), - Config: selfSignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if got == previousCert { + Config: selfSignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + if previousCert == value { return fmt.Errorf("certificate not updated even though passed early renewal") } - previousCert = got + previousCert = value return nil - }, + }), }, }, }) @@ -407,69 +361,46 @@ func TestAccSelfSignedCertNotRecreatedForEarlyRenewalUpdateInFuture(t *testing.T PreCheck: setTimeForTest("2019-06-14T12:00:00Z"), Steps: []r.TestStep{ { - Config: selfSignedCertConfig(10, 2, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - previousCert = got + Config: selfSignedCertConfig(10, 2), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + previousCert = value return nil - }, + }), }, { - Config: selfSignedCertConfig(10, 3, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if got != previousCert { + Config: selfSignedCertConfig(10, 3), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + if previousCert != value { return fmt.Errorf("certificate updated even though still time until early renewal") } - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T16:00:00Z"), - Config: selfSignedCertConfig(10, 3, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if got != previousCert { + Config: selfSignedCertConfig(10, 3), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + if previousCert != value { return fmt.Errorf("certificate updated even though still time until early renewal") } - previousCert = got + previousCert = value return nil - }, + }), }, { PreConfig: setTimeForTest("2019-06-14T16:00:00Z"), - Config: selfSignedCertConfig(10, 9, false), - Check: func(s *terraform.State) error { - gotUntyped := s.RootModule().Outputs["key_pem_1"].Value - got, ok := gotUntyped.(string) - if !ok { - return fmt.Errorf("output for \"key_pem_1\" is not a string") - } - - if got == previousCert { + Config: selfSignedCertConfig(10, 9), + Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { + if previousCert == value { return fmt.Errorf("certificate not updated even though early renewal time has passed") } - previousCert = got + previousCert = value return nil - }, + }), }, }, }) @@ -483,24 +414,20 @@ func TestAccSelfSignedCertSetSubjectKeyID(t *testing.T) { Steps: []r.TestStep{ { Config: fmt.Sprintf(` - resource "tls_self_signed_cert" "test" { - subject { - serial_number = "42" - } - validity_period_hours = 1 - allowed_uses = [] - set_subject_key_id = true - private_key_pem = < Date: Thu, 28 Apr 2022 16:58:57 +0100 Subject: [PATCH 2/9] .go-version: 1.17.8 -> 1.17.9 --- .go-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.go-version b/.go-version index a23a1564..19fb7bd9 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.17.8 +1.17.9 From 3905fe8aa8f7a7e8b95643ffa65d5d8c8ba4aeec Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 28 Apr 2022 16:59:24 +0100 Subject: [PATCH 3/9] Updating doc to refer to the official page that explains how to use `dev_overrides` in `.terraformrc` --- README.md | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 8e771bd3..7a797ce5 100644 --- a/README.md +++ b/README.md @@ -66,28 +66,13 @@ If [running tests and acceptance tests](#testing) isn't enough, it's possible to to use a development builds of the provider. This can be achieved by leveraging the Terraform CLI [configuration file development overrides](https://www.terraform.io/cli/config/config-file#development-overrides-for-provider-developers). -First, use `make install` to place a fresh development build of the provider in your [`${GOBIN}`](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies) (defaults to `${GOPATH}/bin` or `${HOME}/go/bin` if `${GOPATH}` is not set). Repeat +First, use `make install` to place a fresh development build of the provider in your +[`${GOBIN}`](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies) +(defaults to `${GOPATH}/bin` or `${HOME}/go/bin` if `${GOPATH}` is not set). Repeat this every time you make changes to the provider locally. -Then, in your `${HOME}/.terraformrc` (Unix) / `%APPDATA%\terraform.rc` (Windows), a `provider_installation` that contains -the following `dev_overrides`: - -```hcl -provider_installation { - dev_overrides { - "hashicorp/tls" = "${GOBIN}" //< replace `${GOBIN}` with the actual path on your system - } - - direct {} -} -``` - -Note that it's also possible to use a dedicated Terraform configuration file and invoke `terraform` while setting -the environment variable `TF_CLI_CONFIG_FILE=my_terraform_config_file`. - -Once the `dev_overrides` are in place, any local execution of `terraform plan` and `terraform apply` will -use the version of the provider found in the given `${GOBIN}` directory, -instead of the one indicated in your terraform configuration. +Then, setup your environment following [these instructions](https://www.terraform.io/plugin/debugging#terraform-cli-development-overrides) +to make your local terraform use your local build. ### Testing GitHub Actions From 258a2a310c2198fbb7c5141976ed3236cc808bc3 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 5 May 2022 12:38:44 +0100 Subject: [PATCH 4/9] lint --- internal/openssh/lib_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/openssh/lib_test.go b/internal/openssh/lib_test.go index 667b5185..88b26370 100644 --- a/internal/openssh/lib_test.go +++ b/internal/openssh/lib_test.go @@ -8,7 +8,7 @@ import ( "crypto/rsa" "encoding/pem" "testing" - + "golang.org/x/crypto/ssh" ) From d4bca120bfd57eddc758e7eaeec371cf75c61a1e Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 5 May 2022 17:37:00 +0100 Subject: [PATCH 5/9] Altering tests that check format of PEM (keys and certs) to match with a regexp that considers both beginning and end of the string --- .../provider/resource_cert_request_test.go | 4 ++-- .../resource_locally_signed_cert_test.go | 10 ++++---- .../provider/resource_private_key_test.go | 24 +++++++++---------- .../resource_self_signed_cert_test.go | 12 +++++----- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/internal/provider/resource_cert_request_test.go b/internal/provider/resource_cert_request_test.go index 2f0b4281..e97aed7d 100644 --- a/internal/provider/resource_cert_request_test.go +++ b/internal/provider/resource_cert_request_test.go @@ -50,7 +50,7 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_cert_request.test1", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----`)), + r.TestMatchResourceAttr("tls_cert_request.test1", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----(.|\s)+-----END CERTIFICATE REQUEST-----\n$`)), r.TestCheckResourceAttrWith("tls_cert_request.test1", "cert_request_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) csr, err := x509.ParseCertificateRequest(block.Bytes) @@ -132,7 +132,7 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_cert_request.test2", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----`)), + r.TestMatchResourceAttr("tls_cert_request.test2", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----(.|\s)+-----END CERTIFICATE REQUEST-----\n$`)), r.TestCheckResourceAttrWith("tls_cert_request.test2", "cert_request_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) csr, err := x509.ParseCertificateRequest(block.Bytes) diff --git a/internal/provider/resource_locally_signed_cert_test.go b/internal/provider/resource_locally_signed_cert_test.go index a85ae638..1ad7186c 100644 --- a/internal/provider/resource_locally_signed_cert_test.go +++ b/internal/provider/resource_locally_signed_cert_test.go @@ -18,7 +18,7 @@ func TestLocallySignedCert(t *testing.T) { { Config: locallySignedCertConfig(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) cert, err := x509.ParseCertificate(block.Bytes) @@ -246,7 +246,7 @@ func TestAccLocallySignedCert_HandleKeyAlgorithmDeprecation(t *testing.T) { { Config: locallySignedCertConfigWithDeprecatedKeyAlgorithm(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) cert, err := x509.ParseCertificate(block.Bytes) @@ -454,7 +454,7 @@ func TestAccResourceLocallySignedCert_FromED25519PrivateKeyResource(t *testing.T `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_locally_signed_cert.test", "ca_key_algorithm", "ED25519"), - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----((.|\n)+?)-----END CERTIFICATE-----`)), + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----(.|\s)+-----END CERTIFICATE-----\n$`)), ), }, }, @@ -504,7 +504,7 @@ func TestAccResourceLocallySignedCert_FromECDSAPrivateKeyResource(t *testing.T) `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_locally_signed_cert.test", "ca_key_algorithm", "ECDSA"), - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----((.|\n)+?)-----END CERTIFICATE-----`)), + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), ), }, }, @@ -554,7 +554,7 @@ func TestAccResourceLocallySignedCert_FromRSAPrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_locally_signed_cert.test", "ca_key_algorithm", "RSA"), - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----((.|\n)+?)-----END CERTIFICATE-----`)), + r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), ), }, }, diff --git a/internal/provider/resource_private_key_test.go b/internal/provider/resource_private_key_test.go index d5009f04..4bef014d 100644 --- a/internal/provider/resource_private_key_test.go +++ b/internal/provider/resource_private_key_test.go @@ -19,15 +19,15 @@ func TestPrivateKeyRSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----\n$`)), r.TestCheckResourceAttrWith("tls_private_key.test", "private_key_pem", func(pem string) error { if len(pem) > 1700 { return fmt.Errorf("private key PEM looks too long for a 2048-bit key (got %v characters)", len(pem)) } return nil }), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), - r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----\n$`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ssh-rsa `)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), @@ -41,7 +41,7 @@ func TestPrivateKeyRSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----\n$`)), r.TestCheckResourceAttrWith("tls_private_key.test", "private_key_pem", func(pem string) error { if len(pem) < 1700 { return fmt.Errorf("private key PEM looks too short for a 4096-bit key (got %v characters)", len(pem)) @@ -65,8 +65,8 @@ func TestPrivateKeyECDSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----`)), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----\n$`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), r.TestCheckResourceAttr("tls_private_key.test", "private_key_openssh", ""), r.TestCheckResourceAttr("tls_private_key.test", "public_key_openssh", ""), r.TestCheckResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", ""), @@ -81,9 +81,9 @@ func TestPrivateKeyECDSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----`)), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), - r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----\n$`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----\n$`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ecdsa-sha2-nistp256 `)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), @@ -104,9 +104,9 @@ func TestPrivateKeyED25519(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN PRIVATE KEY----(.|\s)+-----END PRIVATE KEY-----`)), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----`)), - r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN PRIVATE KEY----(.|\s)+-----END PRIVATE KEY-----\n$`)), + r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), + r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----\n$`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ssh-ed25519 `)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), diff --git a/internal/provider/resource_self_signed_cert_test.go b/internal/provider/resource_self_signed_cert_test.go index 1e2f62fb..29960901 100644 --- a/internal/provider/resource_self_signed_cert_test.go +++ b/internal/provider/resource_self_signed_cert_test.go @@ -19,7 +19,7 @@ func TestSelfSignedCert(t *testing.T) { { Config: selfSignedCertConfig(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) cert, err := x509.ParseCertificate(block.Bytes) @@ -129,7 +129,7 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_self_signed_cert.test2", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestMatchResourceAttr("tls_self_signed_cert.test2", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), r.TestCheckResourceAttrWith("tls_self_signed_cert.test2", "cert_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) cert, err := x509.ParseCertificate(block.Bytes) @@ -199,7 +199,7 @@ func TestSelfSignedCert_HandleKeyAlgorithmDeprecation(t *testing.T) { { Config: selfSignedCertConfigWithDeprecatedKeyAlgorithm(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----`)), + r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { block, _ := pem.Decode([]byte(value)) cert, err := x509.ParseCertificate(block.Bytes) @@ -601,7 +601,7 @@ func TestAccResourceSelfSignedCert_FromED25519PrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_self_signed_cert.test", "key_algorithm", "ED25519"), - r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----((.|\n)+?)-----END CERTIFICATE-----`)), + r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), ), }, }, @@ -633,7 +633,7 @@ func TestAccResourceSelfSignedCert_FromECDSAPrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_self_signed_cert.test", "key_algorithm", "ECDSA"), - r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----((.|\n)+?)-----END CERTIFICATE-----`)), + r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), ), }, }, @@ -664,7 +664,7 @@ func TestAccResourceSelfSignedCert_FromRSAPrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_self_signed_cert.test", "key_algorithm", "RSA"), - r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----((.|\n)+?)-----END CERTIFICATE-----`)), + r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), ), }, }, From 6396e82822aa02e4e584e12a99cb9f709a2344bb Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Fri, 6 May 2022 19:03:55 +0100 Subject: [PATCH 6/9] Adding utilities built on top of `TestCheckResourceAttrWith` to make testing of PEM certificates more declarative This is still a work in progress: in this first iteration we have moved `tls_cert_request` resouce to use it. --- .../provider/resource_cert_request_test.go | 159 ++++++------------ internal/provider/test_check_func_test.go | 137 +++++++++++++++ 2 files changed, 185 insertions(+), 111 deletions(-) create mode 100644 internal/provider/test_check_func_test.go diff --git a/internal/provider/resource_cert_request_test.go b/internal/provider/resource_cert_request_test.go index e97aed7d..b38aead6 100644 --- a/internal/provider/resource_cert_request_test.go +++ b/internal/provider/resource_cert_request_test.go @@ -1,10 +1,10 @@ package provider import ( - "crypto/x509" - "encoding/pem" + "crypto/x509/pkix" "fmt" - "regexp" + "net" + "net/url" "testing" r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -50,72 +50,37 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_cert_request.test1", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----(.|\s)+-----END CERTIFICATE REQUEST-----\n$`)), - r.TestCheckResourceAttrWith("tls_cert_request.test1", "cert_request_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - csr, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) - } - if expected, got := "2", csr.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", csr.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", csr.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", csr.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", csr.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", csr.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", csr.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", csr.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", csr.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(csr.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", csr.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", csr.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(csr.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", csr.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", csr.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(csr.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload", csr.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload2", csr.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } - - return nil + testCheckPEMCertificateFormat("tls_cert_request.test1", "cert_request_pem", PreambleCertificateRequest), + testCheckPEMCertificateRequestSubject("tls_cert_request.test1", "cert_request_pem", &pkix.Name{ + SerialNumber: "2", + CommonName: "example.com", + Organization: []string{"Example, Inc"}, + OrganizationalUnit: []string{"Department of Terraform Testing"}, + StreetAddress: []string{"5879 Cotton Link"}, + Locality: []string{"Pirate Harbor"}, + Province: []string{"CA"}, + Country: []string{"US"}, + PostalCode: []string{"95559-1227"}, + }), + testCheckPEMCertificateRequestDNSNames("tls_cert_request.test1", "cert_request_pem", []string{ + "example.com", + "example.net", + }), + testCheckPEMCertificateRequestIPAddresses("tls_cert_request.test1", "cert_request_pem", []net.IP{ + net.ParseIP("127.0.0.1"), + net.ParseIP("127.0.0.2"), + }), + testCheckPEMCertificateRequestURIs("tls_cert_request.test1", "cert_request_pem", []*url.URL{ + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "workload", + }, + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "workload2", + }, }), ), }, @@ -132,49 +97,21 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_cert_request.test2", "cert_request_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE REQUEST----(.|\s)+-----END CERTIFICATE REQUEST-----\n$`)), - r.TestCheckResourceAttrWith("tls_cert_request.test2", "cert_request_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - csr, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) - } - if expected, got := "42", csr.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "", csr.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Organization); got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.OrganizationalUnit); got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.StreetAddress); got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Locality); got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Province); got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.Country); got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.Subject.PostalCode); got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := 0, len(csr.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - - return nil + testCheckPEMCertificateFormat("tls_cert_request.test2", "cert_request_pem", PreambleCertificateRequest), + testCheckPEMCertificateRequestSubject("tls_cert_request.test2", "cert_request_pem", &pkix.Name{ + SerialNumber: "42", + CommonName: "", + Organization: []string{}, + OrganizationalUnit: []string{}, + StreetAddress: []string{}, + Locality: []string{}, + Province: []string{}, + Country: []string{}, + PostalCode: []string{}, }), + testCheckPEMCertificateRequestDNSNames("tls_cert_request.test2", "cert_request_pem", []string{}), + testCheckPEMCertificateRequestIPAddresses("tls_cert_request.test2", "cert_request_pem", []net.IP{}), + testCheckPEMCertificateRequestURIs("tls_cert_request.test2", "cert_request_pem", []*url.URL{}), ), }, }, diff --git a/internal/provider/test_check_func_test.go b/internal/provider/test_check_func_test.go new file mode 100644 index 00000000..2b744f07 --- /dev/null +++ b/internal/provider/test_check_func_test.go @@ -0,0 +1,137 @@ +package provider + +import ( + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "net" + "net/url" + "reflect" + "regexp" + "strings" + + r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func testCheckPEMCertificateFormat(name, key string, expected PEMPreamble) r.TestCheckFunc { + return r.TestMatchResourceAttr(name, key, regexp.MustCompile(fmt.Sprintf(`^-----BEGIN %[1]s----(.|\s)+-----END %[1]s-----\n$`, expected))) +} + +func testCheckPEMCertificateRequestSubject(name, key string, expected *pkix.Name) r.TestCheckFunc { + return r.TestCheckResourceAttrWith(name, key, func(value string) error { + block, _ := pem.Decode([]byte(value)) + actual, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing CSR: %s", err) + } + return compareCertSubjects(expected, &actual.Subject) + }) +} + +func testCheckPEMCertificateRequestDNSNames(name, key string, expected []string) r.TestCheckFunc { + return r.TestCheckResourceAttrWith(name, key, func(value string) error { + block, _ := pem.Decode([]byte(value)) + actual, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing CSR: %s", err) + } + return compareCertDNSNames(expected, actual.DNSNames) + }) +} + +func testCheckPEMCertificateRequestIPAddresses(name, key string, expected []net.IP) r.TestCheckFunc { + return r.TestCheckResourceAttrWith(name, key, func(value string) error { + block, _ := pem.Decode([]byte(value)) + actual, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing CSR: %s", err) + } + return compareCertIPAddresses(expected, actual.IPAddresses) + }) +} + +func testCheckPEMCertificateRequestURIs(name, key string, expected []*url.URL) r.TestCheckFunc { + return r.TestCheckResourceAttrWith(name, key, func(value string) error { + block, _ := pem.Decode([]byte(value)) + actual, err := x509.ParseCertificateRequest(block.Bytes) + if err != nil { + return fmt.Errorf("error parsing CSR: %s", err) + } + return compareCertURIs(expected, actual.URIs) + }) +} + +func compareCertSubjects(expected, actualSubject *pkix.Name) error { + if expected.SerialNumber != "" && expected.SerialNumber != actualSubject.SerialNumber { + return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected.SerialNumber, actualSubject.SerialNumber) + } + if expected.CommonName != "" && expected.CommonName != actualSubject.CommonName { + return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected.CommonName, actualSubject.CommonName) + } + if len(expected.Organization) > 0 && !reflect.DeepEqual(expected.Organization, actualSubject.Organization) { + return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected.Organization, actualSubject.Organization) + } + if len(expected.OrganizationalUnit) > 0 && !reflect.DeepEqual(expected.OrganizationalUnit, actualSubject.OrganizationalUnit) { + return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected.OrganizationalUnit, actualSubject.OrganizationalUnit) + } + if len(expected.StreetAddress) > 0 && !reflect.DeepEqual(expected.StreetAddress, actualSubject.StreetAddress) { + return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected.StreetAddress, actualSubject.StreetAddress) + } + if len(expected.Locality) > 0 && !reflect.DeepEqual(expected.Locality, actualSubject.Locality) { + return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected.Locality, actualSubject.Locality) + } + if len(expected.Province) > 0 && !reflect.DeepEqual(expected.Province, actualSubject.Province) { + return fmt.Errorf("incorrect subject province: expected %v, got %v", expected.Province, actualSubject.Province) + } + if len(expected.Country) > 0 && !reflect.DeepEqual(expected.Country, actualSubject.Country) { + return fmt.Errorf("incorrect subject country: expected %v, got %v", expected.Country, actualSubject.Country) + } + if len(expected.PostalCode) > 0 && !reflect.DeepEqual(expected.PostalCode, actualSubject.PostalCode) { + return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected.PostalCode, actualSubject.PostalCode) + } + + return nil +} + +func compareCertDNSNames(expected, actual []string) error { + if len(expected) != len(actual) { + return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + } + + for i := range expected { + if !strings.EqualFold(expected[i], actual[i]) { + return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + } + } + + return nil +} + +func compareCertIPAddresses(expected, actual []net.IP) error { + if len(expected) != len(actual) { + return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + } + + for i := range expected { + if !expected[i].Equal(actual[i]) { + return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + } + } + + return nil +} + +func compareCertURIs(expected, actual []*url.URL) error { + if len(expected) != len(actual) { + return fmt.Errorf("incorrect URIs: expected %v, got %v", expected, actual) + } + + for i := range expected { + if !strings.EqualFold(expected[i].String(), actual[i].String()) { + return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + } + } + + return nil +} From 0b933c12246480a43449755f226a350d14fba4b7 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Mon, 9 May 2022 18:04:34 +0100 Subject: [PATCH 7/9] Turn PEM validation declarative for all types of PEM we produce --- .../provider/data_source_public_key_test.go | 2 + internal/provider/fixtures_test.go | 5 +- .../provider/resource_cert_request_test.go | 14 +- .../resource_locally_signed_cert_test.go | 309 +++++----------- .../provider/resource_private_key_test.go | 24 +- .../resource_self_signed_cert_test.go | 340 +++++------------- internal/provider/test_check_func_test.go | 162 +++++++-- internal/provider/types.go | 7 +- 8 files changed, 331 insertions(+), 532 deletions(-) diff --git a/internal/provider/data_source_public_key_test.go b/internal/provider/data_source_public_key_test.go index 04a699fe..54ae25f7 100644 --- a/internal/provider/data_source_public_key_test.go +++ b/internal/provider/data_source_public_key_test.go @@ -36,6 +36,7 @@ func TestAccPublicKey_dataSource_PEM(t *testing.T) { resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_pem", strings.TrimSpace(testPublicKeyPEM)+"\n"), resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_openssh", strings.TrimSpace(testPublicKeyOpenSSH)+"\n"), resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_fingerprint_md5", strings.TrimSpace(testPublicKeyOpenSSHFingerprintMD5)), + resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_fingerprint_sha256", strings.TrimSpace(testPublicKeyOpenSSHFingerprintSHA256)), resource.TestCheckResourceAttr("data.tls_public_key.test", "algorithm", "RSA"), ), }, @@ -89,6 +90,7 @@ func TestAccPublicKey_dataSource_OpenSSHPEM(t *testing.T) { resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_pem", strings.TrimSpace(testPublicKeyPEM)+"\n"), resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_openssh", strings.TrimSpace(testPublicKeyOpenSSH)+"\n"), resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_fingerprint_md5", strings.TrimSpace(testPublicKeyOpenSSHFingerprintMD5)), + resource.TestCheckResourceAttr("data.tls_public_key.test", "public_key_fingerprint_sha256", strings.TrimSpace(testPublicKeyOpenSSHFingerprintSHA256)), resource.TestCheckResourceAttr("data.tls_public_key.test", "algorithm", "RSA"), ), }, diff --git a/internal/provider/fixtures_test.go b/internal/provider/fixtures_test.go index 1232f830..c600c0ca 100644 --- a/internal/provider/fixtures_test.go +++ b/internal/provider/fixtures_test.go @@ -65,8 +65,9 @@ RhFs18D3wBDBqXLIoP7W3rm5S292/JiNPa+mX76IYFF416zTBGG9J5w4d4VFrROn 8IuMWqHgdXsCUf2szN7EnJcVBsBzTxxWqz4DjX315vbm/PFOLlKzC0Ngs4h1iDiC D9Hk2MajZuFnJiqj1QIDAQAB -----END PUBLIC KEY-----` - testPublicKeyOpenSSH = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDPLaq43D9C596ko9yQipWUf2FbRhFs18D3wBDBqXLIoP7W3rm5S292/JiNPa+mX76IYFF416zTBGG9J5w4d4VFrROn8IuMWqHgdXsCUf2szN7EnJcVBsBzTxxWqz4DjX315vbm/PFOLlKzC0Ngs4h1iDiCD9Hk2MajZuFnJiqj1Q==` - testPublicKeyOpenSSHFingerprintMD5 = `62:c2:c6:7a:d0:27:72:e7:0d:bc:4e:97:42:0e:9e:e6` + testPublicKeyOpenSSH = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDPLaq43D9C596ko9yQipWUf2FbRhFs18D3wBDBqXLIoP7W3rm5S292/JiNPa+mX76IYFF416zTBGG9J5w4d4VFrROn8IuMWqHgdXsCUf2szN7EnJcVBsBzTxxWqz4DjX315vbm/PFOLlKzC0Ngs4h1iDiCD9Hk2MajZuFnJiqj1Q==` + testPublicKeyOpenSSHFingerprintMD5 = `62:c2:c6:7a:d0:27:72:e7:0d:bc:4e:97:42:0e:9e:e6` + testPublicKeyOpenSSHFingerprintSHA256 = `SHA256:V5XlMMAMdN4T4S2uBqiXBuI2C9VPNG2J8a5r1Vb8Vn8` // NOTE: See ../scripts/make-test-ca.tf for a Terraform script to create the following CA Private Key and Certificate. testCAPrivateKey = ` diff --git a/internal/provider/resource_cert_request_test.go b/internal/provider/resource_cert_request_test.go index b38aead6..05e5e196 100644 --- a/internal/provider/resource_cert_request_test.go +++ b/internal/provider/resource_cert_request_test.go @@ -50,7 +50,7 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - testCheckPEMCertificateFormat("tls_cert_request.test1", "cert_request_pem", PreambleCertificateRequest), + testCheckPEMFormat("tls_cert_request.test1", "cert_request_pem", PreambleCertificateRequest), testCheckPEMCertificateRequestSubject("tls_cert_request.test1", "cert_request_pem", &pkix.Name{ SerialNumber: "2", CommonName: "example.com", @@ -97,17 +97,9 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - testCheckPEMCertificateFormat("tls_cert_request.test2", "cert_request_pem", PreambleCertificateRequest), + testCheckPEMFormat("tls_cert_request.test2", "cert_request_pem", PreambleCertificateRequest), testCheckPEMCertificateRequestSubject("tls_cert_request.test2", "cert_request_pem", &pkix.Name{ - SerialNumber: "42", - CommonName: "", - Organization: []string{}, - OrganizationalUnit: []string{}, - StreetAddress: []string{}, - Locality: []string{}, - Province: []string{}, - Country: []string{}, - PostalCode: []string{}, + SerialNumber: "42", }), testCheckPEMCertificateRequestDNSNames("tls_cert_request.test2", "cert_request_pem", []string{}), testCheckPEMCertificateRequestIPAddresses("tls_cert_request.test2", "cert_request_pem", []net.IP{}), diff --git a/internal/provider/resource_locally_signed_cert_test.go b/internal/provider/resource_locally_signed_cert_test.go index 1ad7186c..5df99508 100644 --- a/internal/provider/resource_locally_signed_cert_test.go +++ b/internal/provider/resource_locally_signed_cert_test.go @@ -2,9 +2,10 @@ package provider import ( "crypto/x509" - "encoding/pem" + "crypto/x509/pkix" "fmt" - "regexp" + "net" + "net/url" "testing" "time" @@ -18,118 +19,45 @@ func TestLocallySignedCert(t *testing.T) { { Config: locallySignedCertConfig(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), - r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } - - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } - - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } - - caBlock, _ := pem.Decode([]byte(testCACert)) - caCert, err := x509.ParseCertificate(caBlock.Bytes) - if err != nil { - return fmt.Errorf("error parsing ca cert: %s", err) - } - certPool := x509.NewCertPool() - - // Verify certificate - _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}) - if err == nil { - return fmt.Errorf("incorrectly verified certificate") - } else if _, ok := err.(x509.UnknownAuthorityError); !ok { - return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) - } - certPool.AddCert(caCert) - if _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { - return fmt.Errorf("verify failed: %s", err) - } - - return nil + testCheckPEMFormat("tls_locally_signed_cert.test", "cert_pem", PreambleCertificate), + testCheckPEMCertificateSubject("tls_locally_signed_cert.test", "cert_pem", &pkix.Name{ + SerialNumber: "2", + CommonName: "example.com", + Organization: []string{"Example, Inc"}, + OrganizationalUnit: []string{"Department of Terraform Testing"}, + StreetAddress: []string{"5879 Cotton Link"}, + Locality: []string{"Pirate Harbor"}, + Province: []string{"CA"}, + Country: []string{"US"}, + PostalCode: []string{"95559-1227"}, + }), + testCheckPEMCertificateDNSNames("tls_locally_signed_cert.test", "cert_pem", []string{ + "example.com", + "example.net", + }), + testCheckPEMCertificateIPAddresses("tls_locally_signed_cert.test", "cert_pem", []net.IP{ + net.ParseIP("127.0.0.1"), + net.ParseIP("127.0.0.2"), + }), + testCheckPEMCertificateURIs("tls_locally_signed_cert.test", "cert_pem", []*url.URL{ + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "workload", + }, + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "workload2", + }, + }), + testCheckPEMCertificateKeyUsage("tls_locally_signed_cert.test", "cert_pem", x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature), + testCheckPEMCertificateExtKeyUsages("tls_locally_signed_cert.test", "cert_pem", []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, }), + testCheckPEMCertificateAgainstPEMRootCA("tls_locally_signed_cert.test", "cert_pem", []byte(testCACert)), + testCheckPEMCertificateDuration("tls_locally_signed_cert.test", "cert_pem", time.Hour), ), }, }, @@ -246,118 +174,45 @@ func TestAccLocallySignedCert_HandleKeyAlgorithmDeprecation(t *testing.T) { { Config: locallySignedCertConfigWithDeprecatedKeyAlgorithm(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), - r.TestCheckResourceAttrWith("tls_locally_signed_cert.test", "cert_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/workload2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } - - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } - - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } - - caBlock, _ := pem.Decode([]byte(testCACert)) - caCert, err := x509.ParseCertificate(caBlock.Bytes) - if err != nil { - return fmt.Errorf("error parsing ca cert: %s", err) - } - certPool := x509.NewCertPool() - - // Verify certificate - _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}) - if err == nil { - return fmt.Errorf("incorrectly verified certificate") - } else if _, ok := err.(x509.UnknownAuthorityError); !ok { - return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) - } - certPool.AddCert(caCert) - if _, err = cert.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { - return fmt.Errorf("verify failed: %s", err) - } - - return nil + testCheckPEMFormat("tls_locally_signed_cert.test", "cert_pem", PreambleCertificate), + testCheckPEMCertificateSubject("tls_locally_signed_cert.test", "cert_pem", &pkix.Name{ + SerialNumber: "2", + CommonName: "example.com", + Organization: []string{"Example, Inc"}, + OrganizationalUnit: []string{"Department of Terraform Testing"}, + StreetAddress: []string{"5879 Cotton Link"}, + Locality: []string{"Pirate Harbor"}, + Province: []string{"CA"}, + Country: []string{"US"}, + PostalCode: []string{"95559-1227"}, + }), + testCheckPEMCertificateDNSNames("tls_locally_signed_cert.test", "cert_pem", []string{ + "example.com", + "example.net", + }), + testCheckPEMCertificateIPAddresses("tls_locally_signed_cert.test", "cert_pem", []net.IP{ + net.ParseIP("127.0.0.1"), + net.ParseIP("127.0.0.2"), + }), + testCheckPEMCertificateURIs("tls_locally_signed_cert.test", "cert_pem", []*url.URL{ + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "workload", + }, + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "workload2", + }, + }), + testCheckPEMCertificateKeyUsage("tls_locally_signed_cert.test", "cert_pem", x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature), + testCheckPEMCertificateExtKeyUsages("tls_locally_signed_cert.test", "cert_pem", []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, }), + testCheckPEMCertificateAgainstPEMRootCA("tls_locally_signed_cert.test", "cert_pem", []byte(testCACert)), + testCheckPEMCertificateDuration("tls_locally_signed_cert.test", "cert_pem", time.Hour), ), }, }, @@ -454,7 +309,7 @@ func TestAccResourceLocallySignedCert_FromED25519PrivateKeyResource(t *testing.T `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_locally_signed_cert.test", "ca_key_algorithm", "ED25519"), - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`-----BEGIN CERTIFICATE-----(.|\s)+-----END CERTIFICATE-----\n$`)), + testCheckPEMFormat("tls_locally_signed_cert.test", "cert_pem", PreambleCertificate), ), }, }, @@ -504,7 +359,7 @@ func TestAccResourceLocallySignedCert_FromECDSAPrivateKeyResource(t *testing.T) `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_locally_signed_cert.test", "ca_key_algorithm", "ECDSA"), - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), + testCheckPEMFormat("tls_locally_signed_cert.test", "cert_pem", PreambleCertificate), ), }, }, @@ -554,7 +409,7 @@ func TestAccResourceLocallySignedCert_FromRSAPrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_locally_signed_cert.test", "ca_key_algorithm", "RSA"), - r.TestMatchResourceAttr("tls_locally_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), + testCheckPEMFormat("tls_locally_signed_cert.test", "cert_pem", PreambleCertificate), ), }, }, diff --git a/internal/provider/resource_private_key_test.go b/internal/provider/resource_private_key_test.go index 4bef014d..2c0a01c1 100644 --- a/internal/provider/resource_private_key_test.go +++ b/internal/provider/resource_private_key_test.go @@ -19,15 +19,15 @@ func TestPrivateKeyRSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----\n$`)), + testCheckPEMFormat("tls_private_key.test", "private_key_pem", PreamblePrivateKeyRSA), r.TestCheckResourceAttrWith("tls_private_key.test", "private_key_pem", func(pem string) error { if len(pem) > 1700 { return fmt.Errorf("private key PEM looks too long for a 2048-bit key (got %v characters)", len(pem)) } return nil }), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), - r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----\n$`)), + testCheckPEMFormat("tls_private_key.test", "public_key_pem", PreamblePublicKey), + testCheckPEMFormat("tls_private_key.test", "private_key_openssh", PreamblePrivateKeyOpenSSH), r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ssh-rsa `)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), @@ -41,7 +41,7 @@ func TestPrivateKeyRSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY----(.|\s)+-----END RSA PRIVATE KEY-----\n$`)), + testCheckPEMFormat("tls_private_key.test", "private_key_pem", PreamblePrivateKeyRSA), r.TestCheckResourceAttrWith("tls_private_key.test", "private_key_pem", func(pem string) error { if len(pem) < 1700 { return fmt.Errorf("private key PEM looks too short for a 4096-bit key (got %v characters)", len(pem)) @@ -65,8 +65,8 @@ func TestPrivateKeyECDSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----\n$`)), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), + testCheckPEMFormat("tls_private_key.test", "private_key_pem", PreamblePrivateKeyEC), + testCheckPEMFormat("tls_private_key.test", "public_key_pem", PreamblePublicKey), r.TestCheckResourceAttr("tls_private_key.test", "private_key_openssh", ""), r.TestCheckResourceAttr("tls_private_key.test", "public_key_openssh", ""), r.TestCheckResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", ""), @@ -81,9 +81,9 @@ func TestPrivateKeyECDSA(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN EC PRIVATE KEY----(.|\s)+-----END EC PRIVATE KEY-----\n$`)), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), - r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----\n$`)), + testCheckPEMFormat("tls_private_key.test", "private_key_pem", PreamblePrivateKeyEC), + testCheckPEMFormat("tls_private_key.test", "public_key_pem", PreamblePublicKey), + testCheckPEMFormat("tls_private_key.test", "private_key_openssh", PreamblePrivateKeyOpenSSH), r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ecdsa-sha2-nistp256 `)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), @@ -104,9 +104,9 @@ func TestPrivateKeyED25519(t *testing.T) { } `, Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_private_key.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN PRIVATE KEY----(.|\s)+-----END PRIVATE KEY-----\n$`)), - r.TestMatchResourceAttr("tls_private_key.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY----(.|\s)+-----END PUBLIC KEY-----\n$`)), - r.TestMatchResourceAttr("tls_private_key.test", "private_key_openssh", regexp.MustCompile(`^-----BEGIN OPENSSH PRIVATE KEY----(.|\s)+-----END OPENSSH PRIVATE KEY-----\n$`)), + testCheckPEMFormat("tls_private_key.test", "private_key_pem", PreamblePrivateKeyPKCS8), + testCheckPEMFormat("tls_private_key.test", "public_key_pem", PreamblePublicKey), + testCheckPEMFormat("tls_private_key.test", "private_key_openssh", PreamblePrivateKeyOpenSSH), r.TestMatchResourceAttr("tls_private_key.test", "public_key_openssh", regexp.MustCompile(`^ssh-ed25519 `)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_md5", regexp.MustCompile(`^([abcdef\d]{2}:){15}[abcdef\d]{2}`)), r.TestMatchResourceAttr("tls_private_key.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^SHA256:`)), diff --git a/internal/provider/resource_self_signed_cert_test.go b/internal/provider/resource_self_signed_cert_test.go index 29960901..12a1d07b 100644 --- a/internal/provider/resource_self_signed_cert_test.go +++ b/internal/provider/resource_self_signed_cert_test.go @@ -3,8 +3,10 @@ package provider import ( "bytes" "crypto/x509" - "encoding/pem" + "crypto/x509/pkix" "fmt" + "net" + "net/url" "regexp" "testing" "time" @@ -19,100 +21,44 @@ func TestSelfSignedCert(t *testing.T) { { Config: selfSignedCertConfig(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), - r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } - - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } - - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } - - return nil + testCheckPEMFormat("tls_self_signed_cert.test1", "cert_pem", PreambleCertificate), + testCheckPEMCertificateSubject("tls_self_signed_cert.test1", "cert_pem", &pkix.Name{ + SerialNumber: "2", + CommonName: "example.com", + Organization: []string{"Example, Inc"}, + OrganizationalUnit: []string{"Department of Terraform Testing"}, + StreetAddress: []string{"5879 Cotton Link"}, + Locality: []string{"Pirate Harbor"}, + Province: []string{"CA"}, + Country: []string{"US"}, + PostalCode: []string{"95559-1227"}, + }), + testCheckPEMCertificateDNSNames("tls_self_signed_cert.test1", "cert_pem", []string{ + "example.com", + "example.net", + }), + testCheckPEMCertificateIPAddresses("tls_self_signed_cert.test1", "cert_pem", []net.IP{ + net.ParseIP("127.0.0.1"), + net.ParseIP("127.0.0.2"), + }), + testCheckPEMCertificateURIs("tls_self_signed_cert.test1", "cert_pem", []*url.URL{ + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "ca", + }, + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "ca2", + }, }), + testCheckPEMCertificateKeyUsage("tls_self_signed_cert.test1", "cert_pem", x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature), + testCheckPEMCertificateExtKeyUsages("tls_self_signed_cert.test1", "cert_pem", []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }), + testCheckPEMCertificateDuration("tls_self_signed_cert.test1", "cert_pem", time.Hour), ), }, { @@ -129,62 +75,15 @@ EOT } `, testPrivateKeyPEM), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_self_signed_cert.test2", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), - r.TestCheckResourceAttrWith("tls_self_signed_cert.test2", "cert_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "42", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Organization); got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.OrganizationalUnit); got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.StreetAddress); got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Locality); got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Province); got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.Country); got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := 0, len(cert.Subject.PostalCode); got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 0, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - - if expected, got := 0, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - - if expected, got := 0, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := []byte(``), cert.SubjectKeyId; !bytes.Equal(got, expected) { - return fmt.Errorf("incorrect subject key id: expected %v, got %v", expected, got) - } - - if expected, got := x509.KeyUsage(0), cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } - - return nil + testCheckPEMFormat("tls_self_signed_cert.test2", "cert_pem", PreambleCertificate), + testCheckPEMCertificateSubject("tls_self_signed_cert.test2", "cert_pem", &pkix.Name{ + SerialNumber: "42", }), + testCheckPEMCertificateDNSNames("tls_self_signed_cert.test2", "cert_pem", []string{}), + testCheckPEMCertificateIPAddresses("tls_self_signed_cert.test2", "cert_pem", []net.IP{}), + testCheckPEMCertificateURIs("tls_self_signed_cert.test2", "cert_pem", []*url.URL{}), + testCheckPEMCertificateKeyUsage("tls_self_signed_cert.test2", "cert_pem", x509.KeyUsage(0)), + testCheckPEMCertificateExtKeyUsages("tls_self_signed_cert.test2", "cert_pem", []x509.ExtKeyUsage{}), ), }, }, @@ -199,100 +98,44 @@ func TestSelfSignedCert_HandleKeyAlgorithmDeprecation(t *testing.T) { { Config: selfSignedCertConfigWithDeprecatedKeyAlgorithm(1, 0), Check: r.ComposeAggregateTestCheckFunc( - r.TestMatchResourceAttr("tls_self_signed_cert.test1", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), - r.TestCheckResourceAttrWith("tls_self_signed_cert.test1", "cert_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } - if expected, got := "2", cert.Subject.SerialNumber; got != expected { - return fmt.Errorf("incorrect subject serial number: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.Subject.CommonName; got != expected { - return fmt.Errorf("incorrect subject common name: expected %v, got %v", expected, got) - } - if expected, got := "Example, Inc", cert.Subject.Organization[0]; got != expected { - return fmt.Errorf("incorrect subject organization: expected %v, got %v", expected, got) - } - if expected, got := "Department of Terraform Testing", cert.Subject.OrganizationalUnit[0]; got != expected { - return fmt.Errorf("incorrect subject organizational unit: expected %v, got %v", expected, got) - } - if expected, got := "5879 Cotton Link", cert.Subject.StreetAddress[0]; got != expected { - return fmt.Errorf("incorrect subject street address: expected %v, got %v", expected, got) - } - if expected, got := "Pirate Harbor", cert.Subject.Locality[0]; got != expected { - return fmt.Errorf("incorrect subject locality: expected %v, got %v", expected, got) - } - if expected, got := "CA", cert.Subject.Province[0]; got != expected { - return fmt.Errorf("incorrect subject province: expected %v, got %v", expected, got) - } - if expected, got := "US", cert.Subject.Country[0]; got != expected { - return fmt.Errorf("incorrect subject country: expected %v, got %v", expected, got) - } - if expected, got := "95559-1227", cert.Subject.PostalCode[0]; got != expected { - return fmt.Errorf("incorrect subject postal code: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.DNSNames); got != expected { - return fmt.Errorf("incorrect number of DNS names: expected %v, got %v", expected, got) - } - if expected, got := "example.com", cert.DNSNames[0]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - if expected, got := "example.net", cert.DNSNames[1]; got != expected { - return fmt.Errorf("incorrect DNS name 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.IPAddresses); got != expected { - return fmt.Errorf("incorrect number of IP addresses: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.1", cert.IPAddresses[0].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - if expected, got := "127.0.0.2", cert.IPAddresses[1].String(); got != expected { - return fmt.Errorf("incorrect IP address 0: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.URIs); got != expected { - return fmt.Errorf("incorrect number of URIs: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca", cert.URIs[0].String(); got != expected { - return fmt.Errorf("incorrect URI 0: expected %v, got %v", expected, got) - } - if expected, got := "spiffe://example-trust-domain/ca2", cert.URIs[1].String(); got != expected { - return fmt.Errorf("incorrect URI 1: expected %v, got %v", expected, got) - } - - if expected, got := 2, len(cert.ExtKeyUsage); got != expected { - return fmt.Errorf("incorrect number of ExtKeyUsage: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageServerAuth, cert.ExtKeyUsage[0]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[0]: expected %v, got %v", expected, got) - } - if expected, got := x509.ExtKeyUsageClientAuth, cert.ExtKeyUsage[1]; got != expected { - return fmt.Errorf("incorrect ExtKeyUsage[1]: expected %v, got %v", expected, got) - } - - if expected, got := x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature, cert.KeyUsage; got != expected { - return fmt.Errorf("incorrect KeyUsage: expected %v, got %v", expected, got) - } - - // This time checking is a bit sloppy to avoid inconsistent test results - // depending on the power of the machine running the tests. - now := time.Now() - if cert.NotBefore.After(now) { - return fmt.Errorf("certificate validity begins in the future") - } - if now.Sub(cert.NotBefore) > (2 * time.Minute) { - return fmt.Errorf("certificate validity begins more than two minutes in the past") - } - if cert.NotAfter.Sub(cert.NotBefore) != time.Hour { - return fmt.Errorf("certificate validity is not one hour") - } - - return nil + testCheckPEMFormat("tls_self_signed_cert.test1", "cert_pem", PreambleCertificate), + testCheckPEMCertificateSubject("tls_self_signed_cert.test1", "cert_pem", &pkix.Name{ + SerialNumber: "2", + CommonName: "example.com", + Organization: []string{"Example, Inc"}, + OrganizationalUnit: []string{"Department of Terraform Testing"}, + StreetAddress: []string{"5879 Cotton Link"}, + Locality: []string{"Pirate Harbor"}, + Province: []string{"CA"}, + Country: []string{"US"}, + PostalCode: []string{"95559-1227"}, }), + testCheckPEMCertificateDNSNames("tls_self_signed_cert.test1", "cert_pem", []string{ + "example.com", + "example.net", + }), + testCheckPEMCertificateIPAddresses("tls_self_signed_cert.test1", "cert_pem", []net.IP{ + net.ParseIP("127.0.0.1"), + net.ParseIP("127.0.0.2"), + }), + testCheckPEMCertificateURIs("tls_self_signed_cert.test1", "cert_pem", []*url.URL{ + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "ca", + }, + { + Scheme: "spiffe", + Host: "example-trust-domain", + Path: "ca2", + }, + }), + testCheckPEMCertificateKeyUsage("tls_self_signed_cert.test1", "cert_pem", x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature), + testCheckPEMCertificateExtKeyUsages("tls_self_signed_cert.test1", "cert_pem", []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }), + testCheckPEMCertificateDuration("tls_self_signed_cert.test1", "cert_pem", time.Hour), ), }, }, @@ -426,12 +269,7 @@ func TestAccSelfSignedCertSetSubjectKeyID(t *testing.T) { EOT } `, testPrivateKeyPEM), - Check: r.TestCheckResourceAttrWith("tls_self_signed_cert.test", "cert_pem", func(value string) error { - block, _ := pem.Decode([]byte(value)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing cert: %s", err) - } + Check: testCheckPEMCertificateWith("tls_self_signed_cert.test", "cert_pem", func(cert *x509.Certificate) error { got := cert.SubjectKeyId want := []byte{207, 81, 38, 63, 172, 18, 241, 109, 195, 169, 6, 109, 237, 6, 18, 214, 52, 231, 17, 222} if !bytes.Equal(got, want) { @@ -601,7 +439,7 @@ func TestAccResourceSelfSignedCert_FromED25519PrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_self_signed_cert.test", "key_algorithm", "ED25519"), - r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), + testCheckPEMFormat("tls_self_signed_cert.test", "cert_pem", PreambleCertificate), ), }, }, @@ -633,7 +471,7 @@ func TestAccResourceSelfSignedCert_FromECDSAPrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_self_signed_cert.test", "key_algorithm", "ECDSA"), - r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), + testCheckPEMFormat("tls_self_signed_cert.test", "cert_pem", PreambleCertificate), ), }, }, @@ -664,7 +502,7 @@ func TestAccResourceSelfSignedCert_FromRSAPrivateKeyResource(t *testing.T) { `, Check: r.ComposeTestCheckFunc( r.TestCheckResourceAttr("tls_self_signed_cert.test", "key_algorithm", "RSA"), - r.TestMatchResourceAttr("tls_self_signed_cert.test", "cert_pem", regexp.MustCompile(`^-----BEGIN CERTIFICATE----(.|\s)+-----END CERTIFICATE-----\n$`)), + testCheckPEMFormat("tls_self_signed_cert.test", "cert_pem", PreambleCertificate), ), }, }, diff --git a/internal/provider/test_check_func_test.go b/internal/provider/test_check_func_test.go index 2b744f07..028e7deb 100644 --- a/internal/provider/test_check_func_test.go +++ b/internal/provider/test_check_func_test.go @@ -4,61 +4,157 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "errors" "fmt" "net" "net/url" "reflect" "regexp" "strings" + "time" r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func testCheckPEMCertificateFormat(name, key string, expected PEMPreamble) r.TestCheckFunc { - return r.TestMatchResourceAttr(name, key, regexp.MustCompile(fmt.Sprintf(`^-----BEGIN %[1]s----(.|\s)+-----END %[1]s-----\n$`, expected))) +func testCheckPEMFormat(name, key string, expected PEMPreamble) r.TestCheckFunc { + return r.TestMatchResourceAttr(name, key, regexp.MustCompile(fmt.Sprintf(`^-----BEGIN %[1]s-----\n(.|\s)+\n-----END %[1]s-----\n$`, expected))) } -func testCheckPEMCertificateRequestSubject(name, key string, expected *pkix.Name) r.TestCheckFunc { +func testCheckPEMCertificateRequestWith(name, key string, f func(csr *x509.CertificateRequest) error) r.TestCheckFunc { return r.TestCheckResourceAttrWith(name, key, func(value string) error { block, _ := pem.Decode([]byte(value)) - actual, err := x509.ParseCertificateRequest(block.Bytes) + csr, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) + return fmt.Errorf("error parsing Certificate Request: %s", err) } - return compareCertSubjects(expected, &actual.Subject) + + return f(csr) + }) +} + +func testCheckPEMCertificateRequestSubject(name, key string, expected *pkix.Name) r.TestCheckFunc { + return testCheckPEMCertificateRequestWith(name, key, func(csr *x509.CertificateRequest) error { + return compareCertSubjects(expected, &csr.Subject) }) } func testCheckPEMCertificateRequestDNSNames(name, key string, expected []string) r.TestCheckFunc { - return r.TestCheckResourceAttrWith(name, key, func(value string) error { - block, _ := pem.Decode([]byte(value)) - actual, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) - } - return compareCertDNSNames(expected, actual.DNSNames) + return testCheckPEMCertificateRequestWith(name, key, func(csr *x509.CertificateRequest) error { + return compareCertDNSNames(expected, csr.DNSNames) }) } func testCheckPEMCertificateRequestIPAddresses(name, key string, expected []net.IP) r.TestCheckFunc { - return r.TestCheckResourceAttrWith(name, key, func(value string) error { - block, _ := pem.Decode([]byte(value)) - actual, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) - } - return compareCertIPAddresses(expected, actual.IPAddresses) + return testCheckPEMCertificateRequestWith(name, key, func(csr *x509.CertificateRequest) error { + return compareCertIPAddresses(expected, csr.IPAddresses) }) } func testCheckPEMCertificateRequestURIs(name, key string, expected []*url.URL) r.TestCheckFunc { + return testCheckPEMCertificateRequestWith(name, key, func(csr *x509.CertificateRequest) error { + return compareCertURIs(expected, csr.URIs) + }) +} + +func testCheckPEMCertificateWith(name, key string, f func(csr *x509.Certificate) error) r.TestCheckFunc { return r.TestCheckResourceAttrWith(name, key, func(value string) error { block, _ := pem.Decode([]byte(value)) - actual, err := x509.ParseCertificateRequest(block.Bytes) + crt, err := x509.ParseCertificate(block.Bytes) if err != nil { - return fmt.Errorf("error parsing CSR: %s", err) + return fmt.Errorf("error parsing Certificate: %s", err) } - return compareCertURIs(expected, actual.URIs) + + return f(crt) + }) +} + +func testCheckPEMCertificateSubject(name, key string, expected *pkix.Name) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + return compareCertSubjects(expected, &crt.Subject) + }) +} + +func testCheckPEMCertificateDNSNames(name, key string, expected []string) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + return compareCertDNSNames(expected, crt.DNSNames) + }) +} + +func testCheckPEMCertificateIPAddresses(name, key string, expected []net.IP) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + return compareCertIPAddresses(expected, crt.IPAddresses) + }) +} + +func testCheckPEMCertificateURIs(name, key string, expected []*url.URL) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + return compareCertURIs(expected, crt.URIs) + }) +} + +func testCheckPEMCertificateKeyUsage(name, key string, expected x509.KeyUsage) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + if expected != crt.KeyUsage { + return fmt.Errorf("incorrect Key Usage: expected %v, got %v", expected, crt.KeyUsage) + } + return nil + }) +} + +func testCheckPEMCertificateExtKeyUsages(name, key string, expected []x509.ExtKeyUsage) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + return compareExtKeyUsages(expected, crt.ExtKeyUsage) + }) +} + +func testCheckPEMCertificateDuration(name, key string, expected time.Duration) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(cert *x509.Certificate) error { + now := time.Now() + + if cert.NotBefore.After(now) { + return fmt.Errorf("incorrect certificate validity period; begins in the future: %s", cert.NotBefore) + } + + // NOTE: 2 minutes should be plenty to cover for slow hardware that takes long to start + // the test and then get to this check. + if now.Sub(cert.NotBefore) > (2 * time.Minute) { + return fmt.Errorf("incorrect certificate validity period; begins more than 2 minutes in the past: %s", cert.NotBefore) + } + + if actual := cert.NotAfter.Sub(cert.NotBefore); actual != expected { + return fmt.Errorf("incorrect certificate validity duration: expected %s, got %s", expected, actual) + } + + return nil + }) +} + +func testCheckPEMCertificateAgainstPEMRootCA(name, key string, rootCA []byte) r.TestCheckFunc { + return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { + // Certificate verification must fail if no CA Cert Pool is provided + _, err := crt.Verify(x509.VerifyOptions{}) + if err == nil { + return fmt.Errorf("incorrectly verified certificate") + } else if !errors.Is(err, x509.UnknownAuthorityError{Cert: crt}) { + return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) + } + + // Certificate verification must fail if an empty CA Cert Pool is provided + _, err = crt.Verify(x509.VerifyOptions{Roots: x509.NewCertPool()}) + if err == nil { + return fmt.Errorf("incorrectly verified certificate") + } else if !errors.Is(err, x509.UnknownAuthorityError{Cert: crt}) { + return fmt.Errorf("incorrect verify error: expected UnknownAuthorityError, got %v", err) + } + + // Certification verification must succeed now that we are providing the correct CA Cert Pool + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(rootCA) + if _, err = crt.Verify(x509.VerifyOptions{Roots: certPool}); err != nil { + return fmt.Errorf("verify failed: %s", err) + } + + return nil }) } @@ -96,12 +192,12 @@ func compareCertSubjects(expected, actualSubject *pkix.Name) error { func compareCertDNSNames(expected, actual []string) error { if len(expected) != len(actual) { - return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + return fmt.Errorf("incorrect DNS names: expected %v, got %v", expected, actual) } for i := range expected { if !strings.EqualFold(expected[i], actual[i]) { - return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + return fmt.Errorf("incorrect DNS names: expected %v, got %v", expected, actual) } } @@ -129,7 +225,21 @@ func compareCertURIs(expected, actual []*url.URL) error { for i := range expected { if !strings.EqualFold(expected[i].String(), actual[i].String()) { - return fmt.Errorf("incorrect IP addresses: expected %v, got %v", expected, actual) + return fmt.Errorf("incorrect URIs: expected %v, got %v", expected, actual) + } + } + + return nil +} + +func compareExtKeyUsages(expected, actual []x509.ExtKeyUsage) error { + if len(expected) != len(actual) { + return fmt.Errorf("incorrect Extended Key Usages: expected %v, got %v", expected, actual) + } + + for i := range expected { + if expected[i] != actual[i] { + return fmt.Errorf("incorrect Extended Key Usages: expected %v, got %v", expected, actual) } } diff --git a/internal/provider/types.go b/internal/provider/types.go index 2bf69411..95ca765c 100644 --- a/internal/provider/types.go +++ b/internal/provider/types.go @@ -80,9 +80,10 @@ type PEMPreamble string const ( PreamblePublicKey PEMPreamble = "PUBLIC KEY" - PreamblePrivateKeyPKCS8 PEMPreamble = "PRIVATE KEY" - PreamblePrivateKeyRSA PEMPreamble = "RSA PRIVATE KEY" - PreamblePrivateKeyEC PEMPreamble = "EC PRIVATE KEY" + PreamblePrivateKeyPKCS8 PEMPreamble = "PRIVATE KEY" + PreamblePrivateKeyRSA PEMPreamble = "RSA PRIVATE KEY" + PreamblePrivateKeyEC PEMPreamble = "EC PRIVATE KEY" + PreamblePrivateKeyOpenSSH PEMPreamble = "OPENSSH PRIVATE KEY" PreambleCertificate PEMPreamble = "CERTIFICATE" PreambleCertificateRequest PEMPreamble = "CERTIFICATE REQUEST" From 566ac29283afc143cf787939e93f1fddcfbbd5cc Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Mon, 9 May 2022 18:04:58 +0100 Subject: [PATCH 8/9] Appease linter (unparam) for implementations of `TestCheckFunc` --- .golangci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index 6b74d23f..19a6f2a4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,3 +15,10 @@ linters: - tenv - unconvert - unparam + +issues: + exclude-rules: + - linters: + - unparam + text: "always receives" + path: internal/provider/test_check_func_test.go From 9a48156b8b551f7c2105761b53b7feec1edcbddb Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Mon, 9 May 2022 18:24:57 +0100 Subject: [PATCH 9/9] Use `//nolint:unparam` instead of `exclude-rules:` for very specific linter false alerts --- .golangci.yml | 7 ------- internal/provider/test_check_func_test.go | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 19a6f2a4..6b74d23f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,10 +15,3 @@ linters: - tenv - unconvert - unparam - -issues: - exclude-rules: - - linters: - - unparam - text: "always receives" - path: internal/provider/test_check_func_test.go diff --git a/internal/provider/test_check_func_test.go b/internal/provider/test_check_func_test.go index 028e7deb..9b6151b7 100644 --- a/internal/provider/test_check_func_test.go +++ b/internal/provider/test_check_func_test.go @@ -68,30 +68,35 @@ func testCheckPEMCertificateWith(name, key string, f func(csr *x509.Certificate) }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateSubject(name, key string, expected *pkix.Name) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { return compareCertSubjects(expected, &crt.Subject) }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateDNSNames(name, key string, expected []string) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { return compareCertDNSNames(expected, crt.DNSNames) }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateIPAddresses(name, key string, expected []net.IP) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { return compareCertIPAddresses(expected, crt.IPAddresses) }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateURIs(name, key string, expected []*url.URL) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { return compareCertURIs(expected, crt.URIs) }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateKeyUsage(name, key string, expected x509.KeyUsage) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { if expected != crt.KeyUsage { @@ -101,12 +106,14 @@ func testCheckPEMCertificateKeyUsage(name, key string, expected x509.KeyUsage) r }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateExtKeyUsages(name, key string, expected []x509.ExtKeyUsage) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(crt *x509.Certificate) error { return compareExtKeyUsages(expected, crt.ExtKeyUsage) }) } +//nolint:unparam // `key` parameter always receives `cert_pem` because generated PEMs attributes are called that way. func testCheckPEMCertificateDuration(name, key string, expected time.Duration) r.TestCheckFunc { return testCheckPEMCertificateWith(name, key, func(cert *x509.Certificate) error { now := time.Now()