Files
open-cluster-management/pkg/operator/certrotation/cabundle.go
Jian Qiu e810520961 🌱 Refactor code to fix lint warning (#218)
* Refactor code to fix lint warning

Signed-off-by: Jian Qiu <jqiu@redhat.com>

* enable lint for testing files

Signed-off-by: Jian Qiu <jqiu@redhat.com>

---------

Signed-off-by: Jian Qiu <jqiu@redhat.com>
2023-07-25 07:12:34 +02:00

110 lines
3.7 KiB
Go

package certrotation
import (
"context"
"crypto/x509"
"fmt"
"reflect"
"github.com/openshift/library-go/pkg/crypto"
"github.com/openshift/library-go/pkg/operator/events"
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/util/cert"
)
// CABundleRotation maintains a CA bundle config map, but adding new CA certs and removing expired old ones.
type CABundleRotation struct {
Namespace string
Name string
Lister corev1listers.ConfigMapLister
Client corev1client.ConfigMapsGetter
EventRecorder events.Recorder
}
func (c CABundleRotation) EnsureConfigMapCABundle(ctx context.Context, signingCertKeyPair *crypto.CA) ([]*x509.Certificate, error) {
// by this point we have current signing cert/key pair. We now need to make sure that the ca-bundle configmap has this cert and
// doesn't have any expired certs
originalCABundleConfigMap, err := c.Lister.ConfigMaps(c.Namespace).Get(c.Name)
if err != nil && !apierrors.IsNotFound(err) {
return nil, err
}
caBundleConfigMap := originalCABundleConfigMap.DeepCopy()
if apierrors.IsNotFound(err) {
// create an empty one
caBundleConfigMap = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: c.Namespace, Name: c.Name}}
}
if _, err = manageCABundleConfigMap(caBundleConfigMap, signingCertKeyPair.Config.Certs[0]); err != nil {
return nil, err
}
if originalCABundleConfigMap == nil || originalCABundleConfigMap.Data == nil ||
!equality.Semantic.DeepEqual(originalCABundleConfigMap.Data, caBundleConfigMap.Data) {
c.EventRecorder.Eventf("CABundleUpdateRequired", "%q in %q requires update", c.Name, c.Namespace)
actualCABundleConfigMap, _, err := resourceapply.ApplyConfigMap(ctx, c.Client, c.EventRecorder, caBundleConfigMap)
if err != nil {
return nil, err
}
caBundleConfigMap = actualCABundleConfigMap
}
caBundle := caBundleConfigMap.Data["ca-bundle.crt"]
if len(caBundle) == 0 {
return nil, fmt.Errorf("configmap/%s -n%s missing ca-bundle.crt", caBundleConfigMap.Name, caBundleConfigMap.Namespace)
}
certificates, err := cert.ParseCertsPEM([]byte(caBundle))
if err != nil {
return nil, err
}
return certificates, nil
}
// manageCABundleConfigMap adds the new certificate to the list of cabundles, eliminates duplicates, and prunes the list of expired
// certs to trust as signers
func manageCABundleConfigMap(caBundleConfigMap *corev1.ConfigMap, currentSigner *x509.Certificate) ([]*x509.Certificate, error) {
if caBundleConfigMap.Data == nil {
caBundleConfigMap.Data = map[string]string{}
}
var certificates []*x509.Certificate
caBundle := caBundleConfigMap.Data["ca-bundle.crt"]
if len(caBundle) > 0 {
var err error
certificates, err = cert.ParseCertsPEM([]byte(caBundle))
if err != nil {
return nil, err
}
}
certificates = append([]*x509.Certificate{currentSigner}, certificates...)
certificates = crypto.FilterExpiredCerts(certificates...)
var finalCertificates []*x509.Certificate
// now check for duplicates. n^2, but super simple
for i := range certificates {
found := false
for j := range finalCertificates {
if reflect.DeepEqual(certificates[i].Raw, finalCertificates[j].Raw) {
found = true
break
}
}
if !found {
finalCertificates = append(finalCertificates, certificates[i])
}
}
caBytes, err := crypto.EncodeCertificates(finalCertificates...)
if err != nil {
return nil, err
}
caBundleConfigMap.Data["ca-bundle.crt"] = string(caBytes)
return finalCertificates, nil
}