Merge pull request #3028 from munnerz/pkcs8-integration-test

expcertificates: add integration test for PKCS#8 keyFormat
This commit is contained in:
jetstack-bot 2020-06-23 18:33:12 +01:00 committed by GitHub
commit d7d19d982b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -86,6 +86,7 @@ func TestIssuingController(t *testing.T) {
t.Fatal(err)
}
// Encode the private key as PKCS#1, the default format
skBytes := utilpki.EncodePKCS1PrivateKey(sk)
// Store new private key in secret
@ -221,3 +222,187 @@ func TestIssuingController(t *testing.T) {
t.Fatalf("Failed to wait for final state: %+v", crt)
}
}
func TestIssuingController_PKCS8_PrivateKey(t *testing.T) {
config, stopFn := framework.RunControlPlane(t)
defer stopFn()
// Build, instantiate and run the issuing controller.
kubeClient, factory, cmCl, cmFactory := framework.NewClients(t, config)
controllerOptions := controllerpkg.CertificateOptions{
EnableOwnerRef: true,
}
ctrl, queue, mustSync := issuing.NewController(logf.Log, kubeClient, cmCl, factory, cmFactory, framework.NewEventRecorder(t), clock.RealClock{}, controllerOptions)
c := controllerpkg.NewController(
context.Background(),
"issuing_test",
metrics.New(logf.Log),
ctrl.ProcessItem,
mustSync,
nil,
queue,
)
stopController := framework.StartInformersAndController(t, factory, cmFactory, c)
defer stopController()
ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20)
defer cancel()
var (
crtName = "testcrt"
revision = 1
namespace = "testns"
nextPrivateKeySecretName = "next-private-key-test-crt"
secretName = "test-crt-tls"
)
// Create a new private key
sk, err := utilpki.GenerateRSAPrivateKey(2048)
if err != nil {
t.Fatal(err)
}
// Encode the private key as PKCS#1, the default format
skBytesPKCS1 := utilpki.EncodePKCS1PrivateKey(sk)
skBytesPKCS8, err := utilpki.EncodePKCS8PrivateKey(sk)
if err != nil {
t.Fatal(err)
}
// Store new private key in secret
_, err = kubeClient.CoreV1().Secrets(namespace).Create(ctx, &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: nextPrivateKeySecretName,
Namespace: namespace,
},
Data: map[string][]byte{
// store PKCS#1 bytes so we can ensure they are correctly converted to
// PKCS#8 later on
corev1.TLSPrivateKeyKey: skBytesPKCS1,
},
}, metav1.CreateOptions{})
if err != nil {
t.Fatal(err)
}
// Create Certificate
crt := gen.Certificate(crtName,
gen.SetCertificateNamespace(namespace),
gen.SetCertificateDNSNames("example.com"),
gen.SetCertificateKeyAlgorithm(cmapi.RSAKeyAlgorithm),
gen.SetCertificateKeyEncoding(cmapi.PKCS8),
gen.SetCertificateKeySize(2048),
gen.SetCertificateSecretName(secretName),
gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: "testissuer"}),
)
crt, err = cmCl.CertmanagerV1alpha2().Certificates(namespace).Create(ctx, crt, metav1.CreateOptions{})
if err != nil {
t.Fatal(err)
}
// Create x509 CSR from Certificate
csr, err := utilpki.GenerateCSR(crt)
if err != nil {
t.Fatal(err)
}
// Encode CSR
csrDER, err := utilpki.EncodeCSR(csr, sk)
if err != nil {
t.Fatal(err)
}
csrPEM := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE REQUEST", Bytes: csrDER,
})
// Sign Certificate
certTemplate, err := utilpki.GenerateTemplate(crt)
if err != nil {
t.Fatal(err)
}
// Sign and encode the certificate
certPem, _, err := utilpki.SignCertificate(certTemplate, certTemplate, sk.Public(), sk)
if err != nil {
t.Fatal(err)
}
// Create CertificateRequest
req := gen.CertificateRequest(crtName,
gen.SetCertificateRequestNamespace(namespace),
gen.SetCertificateRequestCSR(csrPEM),
gen.SetCertificateRequestIssuer(crt.Spec.IssuerRef),
gen.SetCertificateRequestAnnotations(map[string]string{
cmapi.CertificateRequestRevisionAnnotationKey: fmt.Sprintf("%d", revision+1),
}),
gen.AddCertificateRequestOwnerReferences(*metav1.NewControllerRef(
crt,
cmapi.SchemeGroupVersion.WithKind("Certificate"),
)),
)
req, err = cmCl.CertmanagerV1alpha2().CertificateRequests(namespace).Create(ctx, req, metav1.CreateOptions{})
if err != nil {
t.Fatal(err)
}
// Set CertificateRequest as ready
req.Status.CA = certPem
req.Status.Certificate = certPem
apiutil.SetCertificateRequestCondition(req, cmapi.CertificateRequestConditionReady, cmmeta.ConditionTrue, cmapi.CertificateRequestReasonIssued, "")
req, err = cmCl.CertmanagerV1alpha2().CertificateRequests(namespace).UpdateStatus(ctx, req, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
// Add Issuing condition to Certificate
apiutil.SetCertificateCondition(crt, cmapi.CertificateConditionIssuing, cmmeta.ConditionTrue, "", "")
crt.Status.NextPrivateKeySecretName = &nextPrivateKeySecretName
crt.Status.Revision = &revision
crt, err = cmCl.CertmanagerV1alpha2().Certificates(namespace).UpdateStatus(ctx, crt, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
// Wait for the Certificate to have the 'Issuing' condition removed, and for
// the signed certificate, ca, and private key stored in the Secret.
err = wait.Poll(time.Millisecond*100, time.Second*5, func() (done bool, err error) {
crt, err = cmCl.CertmanagerV1alpha2().Certificates(namespace).Get(ctx, crtName, metav1.GetOptions{})
if err != nil {
t.Logf("Failed to fetch Certificate resource, retrying: %v", err)
return false, nil
}
if cond := apiutil.GetCertificateCondition(crt, cmapi.CertificateConditionIssuing); cond != nil {
t.Logf("Certificate does not have expected condition, got=%#v", cond)
return false, nil
}
if crt.Status.Revision == nil ||
*crt.Status.Revision != 2 {
t.Logf("Certificate does not have a revision of 2: %v", crt.Status.Revision)
return false, nil
}
secret, err := kubeClient.CoreV1().Secrets(namespace).Get(ctx, crt.Spec.SecretName, metav1.GetOptions{})
if err != nil {
t.Logf("Failed to fetch Secret %s/%s: %s", namespace, crt.Spec.SecretName, err)
return false, nil
}
if !bytes.Equal(secret.Data[corev1.TLSPrivateKeyKey], skBytesPKCS8) ||
!bytes.Equal(secret.Data[corev1.TLSCertKey], certPem) ||
!bytes.Equal(secret.Data[cmmeta.TLSCAKey], certPem) {
t.Logf("Contents of secret did not match expected: %+v", secret.Data)
return false, nil
}
return true, nil
})
if err != nil {
t.Fatalf("Failed to wait for final state: %+v", crt)
}
}