Merge pull request #3028 from munnerz/pkcs8-integration-test
expcertificates: add integration test for PKCS#8 keyFormat
This commit is contained in:
commit
d7d19d982b
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user