diff --git a/.golangci.yaml b/.golangci.yaml index ff5651111..4b03a91ea 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -128,10 +128,6 @@ issues: - revive text: "exported: exported" # Test cases are self-explanatory, thus no need a docstring. - - path: test/helpers/certificate - linters: - - revive - text: "exported: exported" - path: test/integration linters: - revive diff --git a/test/helpers/certificate/certificate.go b/test/helpers/certificate/certificate.go index 0311d451c..915397a83 100644 --- a/test/helpers/certificate/certificate.go +++ b/test/helpers/certificate/certificate.go @@ -25,23 +25,26 @@ type selfSignedCertificateOptions struct { Expired bool } -type SelfSignedCertificateOption func(selfSignedCertificateOptions) selfSignedCertificateOptions +type selfSignedCertificateOption func(selfSignedCertificateOptions) selfSignedCertificateOptions -func WithCommonName(commonName string) SelfSignedCertificateOption { +// WithCommonName sets the CommonName field of the certificate. +func WithCommonName(commonName string) selfSignedCertificateOption { return func(opts selfSignedCertificateOptions) selfSignedCertificateOptions { opts.CommonName = commonName return opts } } -func WithDNSNames(dnsNames ...string) SelfSignedCertificateOption { +// WithDNSNames sets DNS names for the certificate. +func WithDNSNames(dnsNames ...string) selfSignedCertificateOption { return func(opts selfSignedCertificateOptions) selfSignedCertificateOptions { opts.DNSNames = append(opts.DNSNames, dnsNames...) return opts } } -func WithIPAdresses(ipAddresses ...string) SelfSignedCertificateOption { +// WithIPAdresses sets IP addresses for the certificate. +func WithIPAdresses(ipAddresses ...string) selfSignedCertificateOption { return func(opts selfSignedCertificateOptions) selfSignedCertificateOptions { for _, ip := range ipAddresses { opts.IPAddresses = append(opts.IPAddresses, net.ParseIP(ip)) @@ -51,14 +54,15 @@ func WithIPAdresses(ipAddresses ...string) SelfSignedCertificateOption { } // WithCATrue allows to use returned certificate to sign other certificates (uses BasicConstraints extension). -func WithCATrue() SelfSignedCertificateOption { +func WithCATrue() selfSignedCertificateOption { return func(opts selfSignedCertificateOptions) selfSignedCertificateOptions { opts.CATrue = true return opts } } -func WithAlreadyExpired() SelfSignedCertificateOption { +// WithAlreadyExpired sets the certificate to be already expired. +func WithAlreadyExpired() selfSignedCertificateOption { return func(opts selfSignedCertificateOptions) selfSignedCertificateOptions { opts.Expired = true return opts @@ -67,25 +71,21 @@ func WithAlreadyExpired() SelfSignedCertificateOption { // MustGenerateSelfSignedCert generates a tls.Certificate struct to be used in TLS client/listener configurations. // Certificate is self-signed thus returned cert can be used as CA for it. -func MustGenerateSelfSignedCert(decorators ...SelfSignedCertificateOption) tls.Certificate { +func MustGenerateSelfSignedCert(options ...selfSignedCertificateOption) tls.Certificate { // Generate a new RSA private key. privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(fmt.Sprintf("Failed to generate RSA key: %s", err)) } - options := selfSignedCertificateOptions{ - CommonName: "", - DNSNames: []string{}, - } - - for _, decorator := range decorators { - options = decorator(options) + var certOptions selfSignedCertificateOptions + for _, option := range options { + certOptions = option(certOptions) } notBefore := time.Now() notAfter := notBefore.AddDate(1, 0, 0) - if options.Expired { + if certOptions.Expired { notBefore = notBefore.AddDate(-2, 0, 0) notAfter = notAfter.AddDate(-2, 0, 0) } @@ -100,14 +100,14 @@ func MustGenerateSelfSignedCert(decorators ...SelfSignedCertificateOption) tls.C Locality: []string{"San Francisco"}, StreetAddress: []string{"150 Spear Street, Suite 1600"}, PostalCode: []string{"94105"}, - CommonName: options.CommonName, + CommonName: certOptions.CommonName, }, NotBefore: notBefore, NotAfter: notAfter, - DNSNames: options.DNSNames, - IPAddresses: options.IPAddresses, + DNSNames: certOptions.DNSNames, + IPAddresses: certOptions.IPAddresses, BasicConstraintsValid: true, - IsCA: options.CATrue, + IsCA: certOptions.CATrue, } derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &privateKey.PublicKey, privateKey) if err != nil { @@ -126,8 +126,8 @@ func MustGenerateSelfSignedCert(decorators ...SelfSignedCertificateOption) tls.C // MustGenerateSelfSignedCertPEMFormat generates self-signed certificate // and returns certificate and key in PEM format. Certificate is self-signed // thus returned cert can be used as CA for it. -func MustGenerateSelfSignedCertPEMFormat(decorators ...SelfSignedCertificateOption) (cert []byte, key []byte) { - tlsCert := MustGenerateSelfSignedCert(decorators...) +func MustGenerateSelfSignedCertPEMFormat(options ...selfSignedCertificateOption) (cert []byte, key []byte) { + tlsCert := MustGenerateSelfSignedCert(options...) certBlock := &pem.Block{ Type: "CERTIFICATE", diff --git a/test/helpers/certs.go b/test/helpers/certs.go index f14059121..63fafa716 100644 --- a/test/helpers/certs.go +++ b/test/helpers/certs.go @@ -5,14 +5,10 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" - "fmt" - "io" "math/big" - "net" "testing" "time" @@ -152,65 +148,3 @@ func TLSSecretData(t *testing.T, ca Cert, c Cert) map[string][]byte { "tls.key": c.KeyPEM.Bytes(), } } - -// ----------------------------------------------------------------------------- -// TLS Certificate test helper functions and types -// ----------------------------------------------------------------------------- - -const ( - rsaBits = 2048 - validFor = 365 * 24 * time.Hour -) - -// generateRSACert generates a basic self signed certificate valid for a year -func generateRSACert(hosts []string, keyOut, certOut io.Writer) error { - priv, err := rsa.GenerateKey(rand.Reader, rsaBits) - if err != nil { - return fmt.Errorf("failed to generate key: %w", err) - } - notBefore := time.Now() - notAfter := notBefore.Add(validFor) - - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - return fmt.Errorf("failed to generate serial number: %w", err) - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - CommonName: "default", - Organization: []string{"Acme Co"}, - }, - NotBefore: notBefore, - NotAfter: notAfter, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - for _, h := range hosts { - if ip := net.ParseIP(h); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, h) - } - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - return fmt.Errorf("failed to create certificate: %w", err) - } - - if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { - return fmt.Errorf("failed creating cert: %w", err) - } - - if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { - return fmt.Errorf("failed creating key: %w", err) - } - - return nil -} diff --git a/test/helpers/generators.go b/test/helpers/generators.go index 261eeb0c6..0827cb814 100644 --- a/test/helpers/generators.go +++ b/test/helpers/generators.go @@ -1,7 +1,6 @@ package helpers import ( - "bytes" "testing" "github.com/google/uuid" @@ -190,25 +189,3 @@ func GenerateHTTPRoute(namespace string, gatewayName, serviceName string, opts . return httpRoute } - -// MustGenerateTLSSecret generates a TLS secret to be used in tests -func MustGenerateTLSSecret(t *testing.T, namespace, secretName string, hosts []string) *corev1.Secret { - t.Helper() - - var serverKey, serverCert bytes.Buffer - require.NoError(t, generateRSACert(hosts, &serverKey, &serverCert), "failed to generate RSA certificate") - - data := map[string][]byte{ - corev1.TLSCertKey: serverCert.Bytes(), - corev1.TLSPrivateKeyKey: serverKey.Bytes(), - } - - return &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: secretName, - }, - Type: corev1.SecretTypeTLS, - Data: data, - } -} diff --git a/test/integration/test_httproute.go b/test/integration/test_httproute.go index d5607780a..95100738a 100644 --- a/test/integration/test_httproute.go +++ b/test/integration/test_httproute.go @@ -18,6 +18,7 @@ import ( operatorv1beta1 "github.com/kong/gateway-operator/api/v1beta1" testutils "github.com/kong/gateway-operator/pkg/utils/test" "github.com/kong/gateway-operator/test/helpers" + "github.com/kong/gateway-operator/test/helpers/certificate" ) func TestHTTPRoute(t *testing.T) { @@ -145,9 +146,20 @@ func TestHTTPRouteWithTLS(t *testing.T) { Namespace: namespace.Name, } - host := "integration.tests.org" + const host = "integration.tests.org" + cert, key := certificate.MustGenerateSelfSignedCertPEMFormat(certificate.WithDNSNames(host)) - secret := helpers.MustGenerateTLSSecret(t, namespace.Name, host, []string{host}) + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace.Name, + Name: host, + }, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + corev1.TLSCertKey: cert, + corev1.TLSPrivateKeyKey: key, + }, + } t.Logf("deploying Secret %s/%s", secret.Namespace, secret.Name) secret, err = GetClients().K8sClient.CoreV1().Secrets(namespace.Name).Create(GetCtx(), secret, metav1.CreateOptions{}) require.NoError(t, err)