diff --git a/pkg/controller/certificates/sync.go b/pkg/controller/certificates/sync.go index 978963587..64edeff42 100644 --- a/pkg/controller/certificates/sync.go +++ b/pkg/controller/certificates/sync.go @@ -77,12 +77,17 @@ func (c *Controller) Sync(ctx context.Context, crt *v1alpha1.Certificate) (err e }() // grab existing certificate and validate private key - cert, key, err := kube.SecretTLSKeyPair(c.secretLister, crtCopy.Namespace, crtCopy.Spec.SecretName) + certs, key, err := kube.SecretTLSKeyPair(c.secretLister, crtCopy.Namespace, crtCopy.Spec.SecretName) // if we don't have a certificate, we need to trigger a re-issue immediately if err != nil && !(k8sErrors.IsNotFound(err) || errors.IsInvalidData(err)) { return err } + var cert *x509.Certificate + if len(certs) > 0 { + cert = certs[0] + } + // update certificate expiry metric defer c.metrics.UpdateCertificateExpiry(crtCopy, c.secretLister) c.setCertificateStatus(crtCopy, key, cert) diff --git a/pkg/issuer/ca/issue.go b/pkg/issuer/ca/issue.go index b60d7a128..3b45640bf 100644 --- a/pkg/issuer/ca/issue.go +++ b/pkg/issuer/ca/issue.go @@ -70,7 +70,7 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu } // get a copy of the CA certificate named on the Issuer - caCert, caKey, err := kube.SecretTLSKeyPair(c.secretsLister, c.resourceNamespace, c.issuer.GetSpec().CA.SecretName) + caCerts, caKey, err := kube.SecretTLSKeyPair(c.secretsLister, c.resourceNamespace, c.issuer.GetSpec().CA.SecretName) if err != nil { glog.Errorf("Error getting signing CA for Issuer: %v", err) return nil, err @@ -83,6 +83,8 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu return nil, err } + caCert := caCerts[0] + // sign and encode the certificate certPem, _, err := pki.SignCertificate(template, caCert, signeePublicKey, caKey) if err != nil { @@ -90,6 +92,15 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu return nil, err } + // encode the chain + // TODO: replace caCerts with caCerts[1:]? + chainPem, err := pki.EncodeX509Chain(caCerts) + if err != nil { + return nil, err + } + + certPem = append(certPem, chainPem...) + // Encode output private key and CA cert ready for return keyPem, err := pki.EncodePrivateKey(signeeKey) if err != nil { @@ -98,7 +109,7 @@ func (c *CA) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.Issu } // encode the CA certificate to be bundled in the output - caPem, err := pki.EncodeX509(caCert) + caPem, err := pki.EncodeX509(caCerts[0]) if err != nil { c.Recorder.Eventf(crt, corev1.EventTypeWarning, "ErrorSigning", "Error encoding certificate: %v", err) return nil, err diff --git a/pkg/util/kube/pki.go b/pkg/util/kube/pki.go index 7fe835851..97f897a05 100644 --- a/pkg/util/kube/pki.go +++ b/pkg/util/kube/pki.go @@ -56,7 +56,7 @@ func SecretTLSKey(secretLister corelisters.SecretLister, namespace, name string) return SecretTLSKeyRef(secretLister, namespace, name, api.TLSPrivateKeyKey) } -func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string) (*x509.Certificate, error) { +func SecretTLSCertChain(secretLister corelisters.SecretLister, namespace, name string) ([]*x509.Certificate, error) { secret, err := secretLister.Secrets(namespace).Get(name) if err != nil { return nil, err @@ -64,9 +64,9 @@ func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string certBytes, ok := secret.Data[api.TLSCertKey] if !ok { - return nil, fmt.Errorf("no data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name) + return nil, errors.NewInvalidData("no data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name) } - cert, err := pki.DecodeX509CertificateBytes(certBytes) + cert, err := pki.DecodeX509CertificateChainBytes(certBytes) if err != nil { return cert, errors.NewInvalidData(err.Error()) } @@ -74,7 +74,7 @@ func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string return cert, nil } -func SecretTLSKeyPair(secretLister corelisters.SecretLister, namespace, name string) (*x509.Certificate, crypto.Signer, error) { +func SecretTLSKeyPair(secretLister corelisters.SecretLister, namespace, name string) ([]*x509.Certificate, crypto.Signer, error) { secret, err := secretLister.Secrets(namespace).Get(name) if err != nil { return nil, nil, err @@ -93,10 +93,19 @@ func SecretTLSKeyPair(secretLister corelisters.SecretLister, namespace, name str if !ok { return nil, key, errors.NewInvalidData("no certificate data for %q in secret '%s/%s'", api.TLSCertKey, namespace, name) } - cert, err := pki.DecodeX509CertificateBytes(certBytes) + cert, err := pki.DecodeX509CertificateChainBytes(certBytes) if err != nil { return nil, key, errors.NewInvalidData(err.Error()) } return cert, key, nil } + +func SecretTLSCert(secretLister corelisters.SecretLister, namespace, name string) (*x509.Certificate, error) { + certs, err := SecretTLSCertChain(secretLister, namespace, name) + if err != nil { + return nil, err + } + + return certs[0], nil +} diff --git a/pkg/util/pki/csr.go b/pkg/util/pki/csr.go index b5e3e532b..8a7597342 100644 --- a/pkg/util/pki/csr.go +++ b/pkg/util/pki/csr.go @@ -193,16 +193,6 @@ func SignCertificate(template *x509.Certificate, issuerCert *x509.Certificate, p return nil, nil, fmt.Errorf("error encoding certificate PEM: %s", err.Error()) } - // don't bundle the CA for selfsigned certificates - // TODO: better comparison method here? for now we can just compare pointers. - if issuerCert != template { - // bundle the CA - err = pem.Encode(pemBytes, &pem.Block{Type: "CERTIFICATE", Bytes: issuerCert.Raw}) - if err != nil { - return nil, nil, fmt.Errorf("error encoding issuer cetificate PEM: %s", err.Error()) - } - } - return pemBytes.Bytes(), cert, err } @@ -228,6 +218,23 @@ func EncodeX509(cert *x509.Certificate) ([]byte, error) { return caPem.Bytes(), nil } +// EncodeX509Chain will encode an *x509.Certificate chain into PEM format. +func EncodeX509Chain(certs []*x509.Certificate) ([]byte, error) { + caPem := bytes.NewBuffer([]byte{}) + for _, cert := range certs { + if bytes.Equal(cert.RawIssuer, cert.RawSubject) { + // Don't include self-signed certificate + continue + } + err := pem.Encode(caPem, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) + if err != nil { + return nil, err + } + } + + return caPem.Bytes(), nil +} + // SignatureAlgorithm will determine the appropriate signature algorithm for // the given certificate. // Adapted from https://github.com/cloudflare/cfssl/blob/master/csr/csr.go#L102 diff --git a/pkg/util/pki/parse.go b/pkg/util/pki/parse.go index 54dadcb1a..4f48f6265 100644 --- a/pkg/util/pki/parse.go +++ b/pkg/util/pki/parse.go @@ -78,18 +78,40 @@ func DecodePKCS1PrivateKeyBytes(keyBytes []byte) (*rsa.PrivateKey, error) { return key, nil } -// DecodeX509CertificateBytes will decode a PEM encoded x509 Certificate. -func DecodeX509CertificateBytes(certBytes []byte) (*x509.Certificate, error) { - // decode the tls certificate pem - block, _ := pem.Decode(certBytes) - if block == nil { - return nil, errors.NewInvalidData("error decoding cert PEM block") - } - // parse the tls certificate - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, errors.NewInvalidData("error parsing TLS certificate: %s", err.Error()) +// DecodeX509CertificateChainBytes will decode a PEM encoded x509 Certificate chain. +func DecodeX509CertificateChainBytes(certBytes []byte) ([]*x509.Certificate, error) { + certs := []*x509.Certificate{} + + var block *pem.Block + + for { + // decode the tls certificate pem + block, certBytes = pem.Decode(certBytes) + if block == nil { + break + } + + // parse the tls certificate + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, errors.NewInvalidData("error parsing TLS certificate: %s", err.Error()) + } + certs = append(certs, cert) } - return cert, nil + if len(certs) == 0 { + return nil, errors.NewInvalidData("error decoding cert PEM block") + } + + return certs, nil +} + +// DecodeX509CertificateBytes will decode a PEM encoded x509 Certificate. +func DecodeX509CertificateBytes(certBytes []byte) (*x509.Certificate, error) { + certs, err := DecodeX509CertificateChainBytes(certBytes) + if err != nil { + return nil, err + } + + return certs[0], nil } diff --git a/test/e2e/suite/issuers/ca/certificate.go b/test/e2e/suite/issuers/ca/certificate.go index 2df31e79c..6f5f5688f 100644 --- a/test/e2e/suite/issuers/ca/certificate.go +++ b/test/e2e/suite/issuers/ca/certificate.go @@ -36,13 +36,9 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() { certificateName := "test-ca-certificate" certificateSecretName := "test-ca-certificate" - BeforeEach(func() { - By("Creating a signing keypair fixture") - _, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(util.NewSigningKeypairSecret(issuerSecretName)) - Expect(err).NotTo(HaveOccurred()) - + JustBeforeEach(func() { By("Creating an Issuer") - _, err = f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerCAIssuer(issuerName, issuerSecretName)) + _, err := f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerCAIssuer(issuerName, issuerSecretName)) Expect(err).NotTo(HaveOccurred()) By("Waiting for Issuer to become Ready") err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name), @@ -60,68 +56,115 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() { f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Delete(issuerName, nil) }) - It("should generate a signed keypair", func() { - certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) - secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) + Context("when the CA is the root", func() { + BeforeEach(func() { + By("Creating a signing keypair fixture") + _, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(util.NewSigningKeypairSecret(issuerSecretName)) + Expect(err).NotTo(HaveOccurred()) + }) - By("Creating a Certificate") - _, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil)) - Expect(err).NotTo(HaveOccurred()) - By("Verifying the Certificate is valid") - err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30) - Expect(err).NotTo(HaveOccurred()) - }) - - It("should be able to obtain an ECDSA key from a RSA backed issuer", func() { - certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) - secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) - - crt := util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil) - crt.Spec.KeyAlgorithm = v1alpha1.ECDSAKeyAlgorithm - crt.Spec.KeySize = 521 - - By("Creating a Certificate") - _, err := certClient.Create(crt) - Expect(err).NotTo(HaveOccurred()) - - By("Verifying the Certificate is valid") - err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30) - Expect(err).NotTo(HaveOccurred()) - }) - - cases := []struct { - inputDuration *metav1.Duration - inputRenewBefore *metav1.Duration - expectedDuration time.Duration - label string - }{ - { - inputDuration: &metav1.Duration{time.Hour * 24 * 35}, - inputRenewBefore: nil, - expectedDuration: time.Hour * 24 * 35, - label: "35 days", - }, - { - inputDuration: nil, - inputRenewBefore: nil, - expectedDuration: time.Hour * 24 * 90, - label: "the default duration (90 days)", - }, - } - for _, v := range cases { - v := v - It("should generate a signed keypair valid for "+v.label, func() { + It("should generate a signed keypair", func() { certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) By("Creating a Certificate") - cert, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, v.inputDuration, v.inputRenewBefore)) + _, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil)) Expect(err).NotTo(HaveOccurred()) By("Verifying the Certificate is valid") - err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30) + err = util.WaitCertificateIssuedValidTLS(certClient, secretClient, certificateName, time.Second*30, true) Expect(err).NotTo(HaveOccurred()) - f.CertificateDurationValid(cert, v.expectedDuration) }) - } + It("should be able to obtain an ECDSA key from a RSA backed issuer", func() { + certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) + secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) + + crt := util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil) + crt.Spec.KeyAlgorithm = v1alpha1.ECDSAKeyAlgorithm + crt.Spec.KeySize = 521 + + By("Creating a Certificate") + _, err := certClient.Create(crt) + Expect(err).NotTo(HaveOccurred()) + + By("Verifying the Certificate is valid") + err = util.WaitCertificateIssuedValidTLS(certClient, secretClient, certificateName, time.Second*30, true) + Expect(err).NotTo(HaveOccurred()) + }) + + cases := []struct { + inputDuration *metav1.Duration + inputRenewBefore *metav1.Duration + expectedDuration time.Duration + label string + }{ + { + inputDuration: &metav1.Duration{time.Hour * 24 * 35}, + inputRenewBefore: nil, + expectedDuration: time.Hour * 24 * 35, + label: "35 days", + }, + { + inputDuration: nil, + inputRenewBefore: nil, + expectedDuration: time.Hour * 24 * 90, + label: "the default duration (90 days)", + }, + } + for _, v := range cases { + v := v + It("should generate a signed keypair valid for "+v.label, func() { + certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) + secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) + + By("Creating a Certificate") + cert, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, v.inputDuration, v.inputRenewBefore)) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the Certificate is valid") + err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30) + Expect(err).NotTo(HaveOccurred()) + f.CertificateDurationValid(cert, v.expectedDuration) + }) + } + }) + + Context("when the CA is an issuer", func() { + BeforeEach(func() { + By("Creating a signing keypair fixture") + _, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(util.NewSigningIssuer1KeypairSecret(issuerSecretName)) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should generate a signed keypair", func() { + certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) + secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) + + By("Creating a Certificate") + _, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil)) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the Certificate is valid") + err = util.WaitCertificateIssuedValidTLS(certClient, secretClient, certificateName, time.Second*30, true) + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("when the CA is a second level issuer", func() { + BeforeEach(func() { + By("Creating a signing keypair fixture") + _, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(util.NewSigningIssuer2KeypairSecret(issuerSecretName)) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should generate a signed keypair", func() { + certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name) + secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name) + + By("Creating a Certificate") + _, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil)) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the Certificate is valid") + err = util.WaitCertificateIssuedValidTLS(certClient, secretClient, certificateName, time.Second*30, true) + Expect(err).NotTo(HaveOccurred()) + }) + }) }) diff --git a/test/e2e/util/util.go b/test/e2e/util/util.go index 715b50516..75fa902a1 100644 --- a/test/e2e/util/util.go +++ b/test/e2e/util/util.go @@ -203,7 +203,7 @@ func wrapErrorWithCertificateStatusCondition(client clientset.CertificateInterfa // WaitCertificateIssuedValid waits for the given Certificate to be // 'Ready' and ensures the stored certificate is valid for the specified // domains. -func WaitCertificateIssuedValid(certClient clientset.CertificateInterface, secretClient corecs.SecretInterface, name string, timeout time.Duration) error { +func WaitCertificateIssuedValidTLS(certClient clientset.CertificateInterface, secretClient corecs.SecretInterface, name string, timeout time.Duration, validateTLS bool) error { return wait.PollImmediate(time.Second, timeout, func() (bool, error) { log.Logf("Waiting for Certificate %v to be ready", name) @@ -301,11 +301,32 @@ func WaitCertificateIssuedValid(certClient clientset.CertificateInterface, secre return false, fmt.Errorf("Expected secret to have certificate-name label with a value of %q, but got %q", certificate.Name, label) } + // Run TLS Verification + if validateTLS { + rootCertPool := x509.NewCertPool() + rootCertPool.AppendCertsFromPEM([]byte(rootCert)) + intermediateCertPool := x509.NewCertPool() + intermediateCertPool.AppendCertsFromPEM(certBytes) + opts := x509.VerifyOptions{ + DNSName: expectedDNSNames[0], + Intermediates: intermediateCertPool, + Roots: rootCertPool, + } + + if _, err := cert.Verify(opts); err != nil { + return false, err + } + } + return true, nil }, ) } +func WaitCertificateIssuedValid(certClient clientset.CertificateInterface, secretClient corecs.SecretInterface, name string, timeout time.Duration) error { + return WaitCertificateIssuedValidTLS(certClient, secretClient, name, timeout, false) +} + // WaitForCertificateToExist waits for the named certificate to exist func WaitForCertificateToExist(client clientset.CertificateInterface, name string, timeout time.Duration) error { return wait.PollImmediate(500*time.Millisecond, timeout, @@ -567,13 +588,7 @@ func NewCertManagerVaultIssuerAppRole(name, vaultURL, vaultPath, roleId, vaultSe } } -func NewSigningKeypairSecret(name string) *v1.Secret { - return &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - StringData: map[string]string{ - v1.TLSCertKey: `-----BEGIN CERTIFICATE----- +const rootCert = `-----BEGIN CERTIFICATE----- MIID4DCCAsigAwIBAgIJAJzTROInmDkQMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV BAYTAlVLMQswCQYDVQQIEwJOQTEVMBMGA1UEChMMY2VydC1tYW5hZ2VyMSAwHgYD VQQDExdjZXJ0LW1hbmFnZXIgdGVzdGluZyBDQTAeFw0xNzA5MTAxODMzNDNaFw0y @@ -595,8 +610,9 @@ H4/uvJps4SpVCB7+T/orcTjZ2ewT23mQAQg+B+iwX9VCof+fadkYOg1XD9/eaj6E 9McXID3iuCXg02RmEOwVMrTggHPwHrOGAilSaZc58cJZHmMYlT5rGrJcWS/AyXnH VOodKC004yjh7w9aSbCCbAL0tDEnhm4Jrb8cxt7pDWbdEVUeuk9LZRQtluYBnmJU kQ7ALfUfUh/RUpCV4uI6sEI3NDX2YqQbOtsBD/hNaL1F85FA ------END CERTIFICATE-----`, - v1.TLSPrivateKeyKey: `-----BEGIN RSA PRIVATE KEY----- +-----END CERTIFICATE-----` + +const rootKey = `-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAz5DYA7iEBFq/SrCOTsjiYSHlHbTUdLyzselos5cE2++Huon3 InPqMupiDoS8/Qr9srnoKnah7aKB3sY7GlXdg85zcIbQIKocymsRy/GPbEEpfTRG 1yfihUuEM+EBvQFX9Hs0Ut5bHOH6CC88jVebWotpZiphkQnlsGxhcPe091LgYYg1 @@ -622,7 +638,144 @@ jKQvgbUk9SBSBaRrvLNJ8csCgYAYnrZEnGo+ZcEHRxl+ZdSCwRkSl3SCTRiphJtD ThS+sQKBgQDh0+cVo1mfYiCkp3IQPB8QYiJ/g2/UBk6pH8ZZDZ+A5td6NveiWO1y wTEUWkX2qyz9SLxWDGOhdKqxNrLCUSYSOV/5/JQEtBm6K50ArFtrY40JP/T/5KvM tSK2ayFX1wQ3PuEmewAogy/20tWo80cr556AXA62Utl2PzLK30Db8w== ------END RSA PRIVATE KEY-----`, +-----END RSA PRIVATE KEY-----` + +func NewSigningKeypairSecret(name string) *v1.Secret { + return &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + StringData: map[string]string{ + v1.TLSCertKey: rootCert, + v1.TLSPrivateKeyKey: rootKey, + }, + } +} + +const issuer1Cert = `-----BEGIN CERTIFICATE----- +MIIDnjCCAoagAwIBAgIUCAJmM4rqnkj65/0sFRSIjXNlmGYwDQYJKoZIhvcNAQEL +BQAwUzELMAkGA1UEBhMCVUsxCzAJBgNVBAgTAk5BMRUwEwYDVQQKEwxjZXJ0LW1h +bmFnZXIxIDAeBgNVBAMTF2NlcnQtbWFuYWdlciB0ZXN0aW5nIENBMB4XDTE4MTEx +NTAwMDQwMFoXDTIzMTExNDAwMDQwMFowVzELMAkGA1UEBhMCVUsxCzAJBgNVBAgT +Ak5BMRUwEwYDVQQKEwxjZXJ0LW1hbmFnZXIxJDAiBgNVBAMTG2NlcnQtbWFuYWdl +ciB0ZXN0aW5nIElzc3VlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKubAgcLJfXspsDNNR/TO+UUy0s9DE28w4OXs7pAppe7rtK1a531M9lGg+jZPryT +PER4HeobhIk7h1iTmcVHp1mDB3IFDfKL8jKNEnsHGTcn5xY1RkFihFPphBiyGwvY +S4nGi1NubxTA+kW0Pbcf3po2NWNdntAHaMcvMEkq+NdoSEK1HACHQ8QqtqfKUxMD +XMFDmJD21/4PM6iqhDw2HPe87FY7KKdYAsMV8KnT5DIGJ6UbuarTuMzXZq0a8/aW +sto/hrBJir+CQwmNIYg41G8m1CgUz0a3FYxtvLNZweeW9+SiVl0FCiajLws0HIW5 +4RTJ44Omr2/byIB+lmV63AMCAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgGmMBIGA1Ud +EwEB/wQIMAYBAf8CAQMwHQYDVR0OBBYEFESJnTHvnJn8qIOb/JD+nw4o0yxnMB8G +A1UdIwQYMBaAFAba471n25CwNIl+rClUYSlKPOuJMA0GCSqGSIb3DQEBCwUAA4IB +AQBre0a1hD4T0W9E/yGhk6O8k11i63vhgIcMeN1/RMtgJRwIWIf3iKXAwAeIjkXZ +eGGSNWh8pC1wFvE9LIomhZLPSn+98FJ9dLfcaQXDOEyZM71OTsWQKS4NVNloHOxV +zujEujIIZ4caVbOlQWxf7lPydnXP+S7GsMU8vlOsU2RC9jN+yeuho+ZVguSC76ni +CG+k/Lzf46CMAZtRLdv9FPFttodBnodapOEgkhGwhyz/J6eLR1t9DWlxpQ1vk45H +dT3HDz1CNlF/5HzYpVBus553Z7SFh2x1umKfmTUWqmbFsslr2y4w2nkhyG2+jH+k +lh+Eve9i4q7YaO0EMlOOJMar +-----END CERTIFICATE----- +` + +const issuer1Key = `-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAq5sCBwsl9eymwM01H9M75RTLSz0MTbzDg5ezukCml7uu0rVr +nfUz2UaD6Nk+vJM8RHgd6huEiTuHWJOZxUenWYMHcgUN8ovyMo0SewcZNyfnFjVG +QWKEU+mEGLIbC9hLicaLU25vFMD6RbQ9tx/emjY1Y12e0Adoxy8wSSr412hIQrUc +AIdDxCq2p8pTEwNcwUOYkPbX/g8zqKqEPDYc97zsVjsop1gCwxXwqdPkMgYnpRu5 +qtO4zNdmrRrz9pay2j+GsEmKv4JDCY0hiDjUbybUKBTPRrcVjG28s1nB55b35KJW +XQUKJqMvCzQchbnhFMnjg6avb9vIgH6WZXrcAwIDAQABAoIBAHm3VFTSn3YzCIOw +CYItPUpa2WbgQh3RSYvIyf3NZVwyDun9K/u5s7DkxyMdE9aFSDX4TJ+ELRl5U6KL +7oFzNUvUGC/TTfU/NeaNERKaElSAxPOHjfFKgzlRZBRwH6bjH5D1dlUS+07pIZrX +IP8GZ8lRscRs3vwGhVbiLYl4JVACydgyV/Th1yJYFEOXlmHV4Kk0ce3swsXL0NUb +BFQ53RULSxLVaYy4XXF3azSUdMkalDf8DxxeFtPUSW49zp6/iOArZTNCoiGavOHo +YvtnUXjt2QK64SdjFYMyCD8EcLlMTOUtAS10lw9NwUS3JMp3u79bO2uvRwJpT+IP +Hb0Sg8ECgYEAyi41EwEE6cwNVOAZxkOgv+ejhBjKuUrhzp0vwg3Uziuy6TZPJEoA +5e/8pFuvxbfU0lGUe6CkHdpSQPO7ifsTuxYxO/ZX8DqSaCwnRp+kJUyi7Jz3Ypfk +LsVg3TMW9Hmvntz8kPTN8DJMo6W7TC0m05L5pyfvM2BpBXqYIPNLInkCgYEA2Uk8 +mnA43ME+oaqLxcqgIE1+AXeg+voH17kiuO7hVWlprxJv/b6AAjm0nxcuLcdofKJT +JgaWrwyhI676q5T/lqQn/gdJ7rwz/83WnforW7WVza2XT+aDFcwNq07vHYoeCK6B +5RJFIY4Yuk4CORXeElYipz/VyCO2mUgJfHNDs1sCgYEAkS3lBqRwtsHDwPK7D1d4 +ktTu4eg7ihpvU0IkDSCJcxKGAljxM4nAY1yU+iCsczmyJORXzv5nWthuwB1Eyav1 +Wx5wdDJMq0Aj6ZHrEheIcxA43ddI/Q881yj8iVoqXZsTtOvSoPRo/NXhmpFjkSvK ++ZpMku9mIGpWf4ysuNx7U2ECgYEAlOk+IVFbht7g/4aT99+f0cOJ4ZOMvbPxAASf +KUJ9Jz3w8cye97VAoUXO5WDLgxAwKYpNlbfaOOlc3cmjfUfFygWCavOv1W8h6+Oz +e9zhLh7KJYUcN+PwXlXT4F1ePk5TuvtthgH5Yr+xbqzblSfJY6OoaBq1dk4TbAUU +izerZBUCgYEAn28gG04dByfcyY/crwpRLNVlaA0J93v5H9E/wlEiV1PhEYTdj2S8 +PLm9ur3V+kkBSarBur9+rRil0BHvVgC9K6kwMr60JcVT+bmZi0AbPOlPZsp9OPQf +YK5kMSMSbh4t9OUtadogDGI299P6Q9leaU65XRAar96wVsz8X/XdPPc= +-----END RSA PRIVATE KEY-----` + +func NewSigningIssuer1KeypairSecret(name string) *v1.Secret { + return &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + StringData: map[string]string{ + v1.TLSCertKey: issuer1Cert + rootCert, + v1.TLSPrivateKeyKey: issuer1Key, + }, + } +} + +const issuer2Cert = `-----BEGIN CERTIFICATE----- +MIIDqjCCApKgAwIBAgIUHqm61uyYt2ICGRcZnBSjYaPonuowDQYJKoZIhvcNAQEL +BQAwVzELMAkGA1UEBhMCVUsxCzAJBgNVBAgTAk5BMRUwEwYDVQQKEwxjZXJ0LW1h +bmFnZXIxJDAiBgNVBAMTG2NlcnQtbWFuYWdlciB0ZXN0aW5nIElzc3VlcjAeFw0x +ODExMTUwMDA0MDBaFw0yMzExMTQwMDA0MDBaMF8xCzAJBgNVBAYTAlVLMQswCQYD +VQQIEwJOQTEVMBMGA1UEChMMY2VydC1tYW5hZ2VyMSwwKgYDVQQDEyNjZXJ0LW1h +bmFnZXIgdGVzdGluZyBJc3N1ZXIgTGV2ZWwgMjCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMRm1cYCcHmA7UtF3vISLiob5eh234njNp33nkFWjDsE9Zgi +CIxVb9FBd+rkKn0xkPMke79lmr1kVkmjpAZ0Y0w/IDSEX8JMJvtyuAoS79r0W+rn +dEG5GzJGLswOK0gsvGyl4i8E9a5itUkRa01OETFIiay0iwNMUYnIflm8G/Uu2Jhr +/HSyWND+KLzX5gMDsiv4HdtCsNHstdMwBr4dkiCzpi+N/b2KTggmY84KeVQVpmRc +IVoVr06uc3YTa2mlqrw3qX16d5r9DLYrrq1UT3HXB0PJvvsIjJN8eqKk33Mcbinj +VR1Ywg9QYaJHpBPPxLL0AzNG29SebRLtGvKexoUCAwEAAaNmMGQwDgYDVR0PAQH/ +BAQDAgGmMBIGA1UdEwEB/wQIMAYBAf8CAQMwHQYDVR0OBBYEFHp3C+Se1LZMcQ0B +0iycJLvwqo9lMB8GA1UdIwQYMBaAFESJnTHvnJn8qIOb/JD+nw4o0yxnMA0GCSqG +SIb3DQEBCwUAA4IBAQA/lnvr+GnMJDA+Z7MEMRAcqdIScO38LVQNO340jFMcMkmW +YTnyNoEvI4fnCon9Oz2FsFcZp90Gniu01lDLyzR+1SsfFf6zwqGVUV29hidR6BvD +VGLM6SMnbgXUd+RPvAIrHU3BuSF2sRPiw7YqzgNVZQ2dUF+Q+R+Onu5i47CwVFOd +6Dd7xr5+ECaHGyuIH/RsXLvB+2reJ5dEl3oBxiyyzY1oOkt6y4HrB8n90JWPmXIf +9oQ8T+p3PbsFkz667nbVnVCkdAKtU/ZX09S1jGVKsOKszA1qhxFcMy+wkkyHq4Jj +v+q/VgVxL5HzEw4zyKS9Y2lcwhCicMrLKIGt91fQ +-----END CERTIFICATE----- +` + +const issuer2Key = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxGbVxgJweYDtS0Xe8hIuKhvl6HbfieM2nfeeQVaMOwT1mCII +jFVv0UF36uQqfTGQ8yR7v2WavWRWSaOkBnRjTD8gNIRfwkwm+3K4ChLv2vRb6ud0 +QbkbMkYuzA4rSCy8bKXiLwT1rmK1SRFrTU4RMUiJrLSLA0xRich+Wbwb9S7YmGv8 +dLJY0P4ovNfmAwOyK/gd20Kw0ey10zAGvh2SILOmL439vYpOCCZjzgp5VBWmZFwh +WhWvTq5zdhNraaWqvDepfXp3mv0MtiuurVRPcdcHQ8m++wiMk3x6oqTfcxxuKeNV +HVjCD1BhokekE8/EsvQDM0bb1J5tEu0a8p7GhQIDAQABAoIBAFwCzV3RoL3bn8/m +8Pa5e7UwkrogjsM7lkfVTOfRUysHPMPEFfsgv5zqLfL2Z811HjI6wlq9kAvwaNhg ++KQpfKeo3z6bUX1mTdD5Qq09h+8tEa7wNi/gN5SK+ruQW8iZZMEFyfw7N5o2FjYg +GgQCcd2D3TPy9TlbVMvXCRKjJPns4PvWnjcR6YryPCluhnm6t0UEdusAj5baENU5 +95XG3e+7ZWzz4uejY778pyV/4yCfMXG9HZInkw9Uj3aNibiP/oKyF8Z0m1tAheLp +SfLH/KxC8sWW/Cn3YFAvq+3fSH3ezeaFNdQFi8L0uGA9h9ucZmKaT5jI1bM9Mj55 +Vrsg/wECgYEA7rCQ/NFLtQ6PZNSApxRdWG+67mDrWMuaHho9KB+g0vIzGoxj2+DS +iVlk4F1zVjZ5S8yjSmBm2pxF4ornUdQUs5+iKHJqeweSQenZ3Ylx10rhACfUWhZ+ +Zo/mrG30MJs2ceOaYJww1zrcjI3ktFwpZlX95J/e26gGqY8GKA8KaEECgYEA0qUp +3eWvwiTn2ztKEHZ06jNoPB1E3tAA939+W1Cy5VTDH2ZJYDE6lELTgW/7PuS6Auty +cJur3nyIJMQkb2GBqh8jgxb7huDpOkf8kAdPoD9PnmWTisF5XKO5Uv3O2t/xKQNl +pKAC9P1au3uCz8HA2ZbyLqiuXE7SKsIqQmMtbUUCgYArkAwWKDiyBcND+si0NbJH +prSuNwAdB6PMJKvOu98FQPD0wnSjN6gVKzyO+l9Hd8+xdtrCg0+iTG0wyHspYxSY +J+VXjnJCnAIkh4KcvS4Kxf7EoYBPJNXS8CaAh9zOVjWcmZaeVUNQtMx11pvMExn3 +NHCPHmJ1Inh8z76m5v/WQQKBgEeQFyYs10ZU9XQ0s1fedp/ucRYjN3efIQT0ioAJ +bY2d+2BahskoUGd4QJTz716RpGRDizCYoo5GrpYXEO3KKZwbUhxCHZfYJ0RGmpZv +9WxStgDxL2vviQShFuAMHE+dzzeI0OpZ9kc3H7EcJ/ffMl55+rNBWWNA4APozSSa +vx8lAoGBAODUjD1S1w/l+OTZWqo+bUvpC58CSioZ+gvNi4KE0h+1ZgLgE1RivQOM +UxwyspRQp2exnQ3hvCpzjhx+ji/FlhK86lspGjyZqTd+ifa/tO51+tvU217/XDtx +JypkAFhZ398YzhuqsRbFNMFnxA6QT+YFsqjT+R0vSFM8n2qptJHB +-----END RSA PRIVATE KEY-----` + +func NewSigningIssuer2KeypairSecret(name string) *v1.Secret { + return &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + StringData: map[string]string{ + v1.TLSCertKey: issuer2Cert + issuer1Cert + rootCert, + v1.TLSPrivateKeyKey: issuer2Key, }, } }