mirror of
https://github.com/kubevirt/containerized-data-importer.git
synced 2025-06-03 06:30:22 +00:00
221 lines
7.4 KiB
Go
221 lines
7.4 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/openshift/library-go/pkg/operator/certrotation"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"kubevirt.io/containerized-data-importer/pkg/operator/resources/cert"
|
|
cdicerts "kubevirt.io/containerized-data-importer/pkg/operator/resources/cert"
|
|
)
|
|
|
|
const testCertData = "test"
|
|
|
|
type fakeCertManager struct {
|
|
client client.Client
|
|
namespace string
|
|
}
|
|
|
|
func (tcm *fakeCertManager) Sync(certs []cdicerts.CertificateDefinition) error {
|
|
cm := &corev1.ConfigMap{}
|
|
key := client.ObjectKey{Namespace: tcm.namespace, Name: "cdi-uploadproxy-signer-bundle"}
|
|
err := tcm.client.Get(context.TODO(), key, cm)
|
|
// should exist
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cm.Data = map[string]string{
|
|
"ca-bundle.crt": testCertData,
|
|
}
|
|
return tcm.client.Update(context.TODO(), cm)
|
|
}
|
|
|
|
// creating certs is really CPU intensive so mocking out a CertManager to just create what we need
|
|
func newFakeCertManager(crClient client.Client, namespace string) CertManager {
|
|
return &fakeCertManager{client: crClient, namespace: namespace}
|
|
}
|
|
|
|
func newCertManagerForTest(client kubernetes.Interface, namespace string) CertManager {
|
|
return newCertManager(client, namespace)
|
|
}
|
|
|
|
func toSerializedCertConfig(l, r time.Duration) string {
|
|
scc := &serializedCertConfig{
|
|
Lifetime: l.String(),
|
|
Refresh: r.String(),
|
|
}
|
|
|
|
bs, err := json.Marshal(scc)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
return string(bs)
|
|
}
|
|
|
|
func getCertNotBefore(client kubernetes.Interface, namespace, name string) time.Time {
|
|
s, err := client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
val, ok := s.Annotations[certrotation.CertificateNotBeforeAnnotation]
|
|
Expect(ok).To(BeTrue())
|
|
t, err := time.Parse(time.RFC3339, val)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
return t
|
|
}
|
|
|
|
func getCertConfigAnno(client kubernetes.Interface, namespace, name string) string {
|
|
s, err := client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
val, ok := s.Annotations["operator.cdi.kubevirt.io/certConfig"]
|
|
Expect(ok).To(BeTrue())
|
|
return val
|
|
}
|
|
|
|
func checkSecret(client kubernetes.Interface, namespace, name string, exists bool) {
|
|
s, err := client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
if !exists {
|
|
Expect(errors.IsNotFound(err)).To(BeTrue())
|
|
return
|
|
}
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(s.Data["tls.crt"]).ShouldNot(BeEmpty())
|
|
Expect(s.Data["tls.crt"]).ShouldNot(BeEmpty())
|
|
}
|
|
|
|
func checkConfigMap(client kubernetes.Interface, namespace, name string, exists bool) {
|
|
cm, err := client.CoreV1().ConfigMaps(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
if !exists {
|
|
Expect(errors.IsNotFound(err)).To(BeTrue())
|
|
return
|
|
}
|
|
Expect(cm.Data["ca-bundle.crt"]).ShouldNot(BeEmpty())
|
|
}
|
|
|
|
func checkCerts(client kubernetes.Interface, namespace string, exists bool) {
|
|
checkSecret(client, namespace, "cdi-apiserver-signer", exists)
|
|
checkConfigMap(client, namespace, "cdi-apiserver-signer-bundle", exists)
|
|
checkSecret(client, namespace, "cdi-apiserver-server-cert", exists)
|
|
|
|
checkSecret(client, namespace, "cdi-uploadproxy-signer", exists)
|
|
checkConfigMap(client, namespace, "cdi-uploadproxy-signer-bundle", exists)
|
|
checkSecret(client, namespace, "cdi-uploadproxy-server-cert", exists)
|
|
|
|
checkSecret(client, namespace, "cdi-uploadserver-signer", exists)
|
|
checkConfigMap(client, namespace, "cdi-uploadserver-signer-bundle", exists)
|
|
|
|
checkSecret(client, namespace, "cdi-uploadserver-client-signer", exists)
|
|
checkConfigMap(client, namespace, "cdi-uploadserver-client-signer-bundle", exists)
|
|
checkSecret(client, namespace, "cdi-uploadserver-client-cert", exists)
|
|
}
|
|
|
|
var _ = Describe("Cert rotation tests", func() {
|
|
const namespace = "cdi"
|
|
|
|
pt := func(d time.Duration) *time.Duration {
|
|
return &d
|
|
}
|
|
|
|
Context("with clean slate", func() {
|
|
It("should create everything", func() {
|
|
client := fake.NewSimpleClientset()
|
|
cm := newCertManagerForTest(client, namespace)
|
|
|
|
ch := make(chan struct{})
|
|
cm.(*certManager).Start(ch)
|
|
|
|
checkCerts(client, namespace, false)
|
|
|
|
certs := cert.CreateCertificateDefinitions(&cert.FactoryArgs{Namespace: namespace})
|
|
err := cm.Sync(certs)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
checkCerts(client, namespace, true)
|
|
|
|
certs = cert.CreateCertificateDefinitions(&cert.FactoryArgs{Namespace: namespace})
|
|
err = cm.Sync(certs)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
checkCerts(client, namespace, true)
|
|
|
|
close(ch)
|
|
})
|
|
|
|
It("should update certs", func() {
|
|
client := fake.NewSimpleClientset()
|
|
cm := newCertManagerForTest(client, namespace)
|
|
|
|
ch := make(chan struct{})
|
|
cm.(*certManager).Start(ch)
|
|
|
|
certs := cert.CreateCertificateDefinitions(&cert.FactoryArgs{Namespace: namespace})
|
|
err := cm.Sync(certs)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
apiCA := getCertNotBefore(client, namespace, "cdi-apiserver-signer")
|
|
apiServer := getCertNotBefore(client, namespace, "cdi-apiserver-server-cert")
|
|
proxyCA := getCertNotBefore(client, namespace, "cdi-uploadproxy-signer")
|
|
proxyServer := getCertNotBefore(client, namespace, "cdi-uploadproxy-server-cert")
|
|
|
|
apiCAConfig := getCertConfigAnno(client, namespace, "cdi-apiserver-signer")
|
|
apiServerConfig := getCertConfigAnno(client, namespace, "cdi-apiserver-server-cert")
|
|
proxyCAConfig := getCertConfigAnno(client, namespace, "cdi-uploadproxy-signer")
|
|
proxyServerConfig := getCertConfigAnno(client, namespace, "cdi-uploadproxy-server-cert")
|
|
|
|
n := time.Now()
|
|
|
|
args := &cert.FactoryArgs{
|
|
Namespace: namespace,
|
|
SignerValidity: pt(50 * time.Hour),
|
|
SignerRefresh: pt(25 * time.Hour),
|
|
TargetValidity: pt(26 * time.Hour),
|
|
TargetRefresh: pt(13 * time.Hour),
|
|
}
|
|
|
|
certs = cert.CreateCertificateDefinitions(args)
|
|
err = cm.Sync(certs)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
apiCA2 := getCertNotBefore(client, namespace, "cdi-apiserver-signer")
|
|
apiServer2 := getCertNotBefore(client, namespace, "cdi-apiserver-server-cert")
|
|
proxyCA2 := getCertNotBefore(client, namespace, "cdi-uploadproxy-signer")
|
|
proxyServer2 := getCertNotBefore(client, namespace, "cdi-uploadproxy-server-cert")
|
|
|
|
Expect(apiCA2.After(n))
|
|
Expect(apiServer2.After(n))
|
|
Expect(proxyCA2.After(n))
|
|
Expect(proxyServer2.After(n))
|
|
|
|
Expect(apiCA2.After(apiCA))
|
|
Expect(apiServer2.After(apiServer))
|
|
Expect(proxyCA2.After(proxyCA))
|
|
Expect(proxyServer2.After(proxyServer))
|
|
|
|
apiCAConfig2 := getCertConfigAnno(client, namespace, "cdi-apiserver-signer")
|
|
apiServerConfig2 := getCertConfigAnno(client, namespace, "cdi-apiserver-server-cert")
|
|
proxyCAConfig2 := getCertConfigAnno(client, namespace, "cdi-uploadproxy-signer")
|
|
proxyServerConfig2 := getCertConfigAnno(client, namespace, "cdi-uploadproxy-server-cert")
|
|
|
|
Expect(apiCAConfig2).ToNot(Equal(apiCAConfig))
|
|
Expect(apiServerConfig2).ToNot(Equal(apiServerConfig))
|
|
Expect(proxyCAConfig2).ToNot(Equal(proxyCAConfig))
|
|
Expect(proxyServerConfig2).ToNot(Equal(proxyServerConfig))
|
|
|
|
scc := toSerializedCertConfig(50*time.Hour, 25*time.Hour)
|
|
scc2 := toSerializedCertConfig(26*time.Hour, 13*time.Hour)
|
|
|
|
Expect(apiCAConfig2).To(Equal(scc))
|
|
Expect(apiServerConfig2).To(Equal(scc2))
|
|
Expect(proxyCAConfig2).To(Equal(scc))
|
|
Expect(proxyServerConfig2).To(Equal(scc2))
|
|
})
|
|
})
|
|
})
|