Skip to content

Commit

Permalink
Create generic Certificate package
Browse files Browse the repository at this point in the history
Signed-off-by: ArkaSaha30 <[email protected]>
  • Loading branch information
ArkaSaha30 committed Jan 23, 2025
1 parent 4d2dce8 commit 4ae9757
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 104 deletions.
150 changes: 150 additions & 0 deletions internal/certificate/certificate_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package certificate

import (
"context"
"errors"
"fmt"
"strings"

certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
ecv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1"

Check failure on line 11 in internal/certificate/certificate_utils.go

View workflow job for this annotation

GitHub Actions / Run on Ubuntu

File is not properly formatted (goimports)
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
)

type NewCertificateManager struct {
Ctx context.Context
Client client.Client
Scheme *runtime.Scheme
EtcdCluster *ecv1alpha1.EtcdCluster
CertProvider
}

type CertProvider interface {
CertManager
}

type CertManager interface {
GetCMCertificate()
CreateCMCertificate()
}

func (c *NewCertificateManager) GetCMCertificate(tlsCertName, namespace string) (*certv1.Certificate, error) {
foundCert := &certv1.Certificate{}

err := c.Client.Get(c.Ctx, client.ObjectKey{Name: tlsCertName, Namespace: namespace}, foundCert)
if err != nil {
return nil, err
}
return foundCert, nil
}

func (c *NewCertificateManager) CreateCMCertificate(tlsCertName string) (*certv1.Certificate, error) {
certificateResource := &certv1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: tlsCertName,
Namespace: c.EtcdCluster.Namespace,
},
Spec: certv1.CertificateSpec{
SecretName: tlsCertName,
DNSNames: []string{fmt.Sprintf("%s-%d.%s.%s.svc.cluster.local", c.EtcdCluster.Name, c.EtcdCluster.Spec.Size, c.EtcdCluster.Name, c.EtcdCluster.Namespace)},
IssuerRef: cmmeta.ObjectReference{
Name: CMClusterIssuerName,
Kind: "ClusterIssuer",
},
},
}

err := c.Client.Create(c.Ctx, certificateResource)
if err != nil {
return nil, err
}
return certificateResource, nil
}

func setCertificateFuncs(c NewCertificateManager) (func(string, string) (*certv1.Certificate, error), func(string) (*certv1.Certificate, error), error) {
certProvider := c.EtcdCluster.Spec.TLS.Provider

switch certProvider {
case "cert-manager":
return c.GetCMCertificate, c.CreateCMCertificate, nil
default:
return nil, nil, errors.New("invalid certificate provider")

}
}

func ReconcileMemberCertificate(c NewCertificateManager) ([]interface{}, error) {
var certificates []interface{}
logger := log.FromContext(c.Ctx)

getCertFunc, createCertFunc, err := setCertificateFuncs(c)
if err != nil {
return nil, err
}

for members := 1; members < c.EtcdCluster.Spec.Size; members++ {

clientCertName := strings.Join([]string{c.EtcdCluster.Name, c.EtcdCluster.Spec.TLS.OperatorSecret, fmt.Sprintf("%d", members)}, "-")
logger.Info("Starting reconciliation of Client Certificate", clientCertName, c.EtcdCluster.Namespace)
clientCert, clientCertErr := getCertFunc(clientCertName, c.EtcdCluster.Namespace)
if k8serrors.IsNotFound(clientCertErr) {
clientCert, clientCertErr = createCertFunc(clientCertName)
if clientCertErr != nil {
logger.Error(clientCertErr, "failed to create Client Certificate")
}
} else {
logger.Error(clientCertErr, "failed to get Client Certificate")
}

peerCertName := strings.Join([]string{c.EtcdCluster.Name, c.EtcdCluster.Spec.TLS.Member.PeerSecret, fmt.Sprintf("%d", members)}, "-")
logger.Info("Starting reconciliation of Peer Certificate", peerCertName, c.EtcdCluster.Namespace)
peerCert, peerCertErr := getCertFunc(peerCertName, c.EtcdCluster.Namespace)
if k8serrors.IsNotFound(peerCertErr) {
peerCert, peerCertErr = createCertFunc(peerCertName)
if peerCertErr != nil {
logger.Error(peerCertErr, "failed to create Peer Certificate")
}
} else {
logger.Error(clientCertErr, "failed to get Peer Certificate")
}

certificates = append(certificates, clientCert, peerCert)
}

for _, cert := range certificates {
if cert == nil {
return certificates, errors.New("failed to create one or more certificate")
}
}
return certificates, nil
}

func ReconcileServerCertificate(c NewCertificateManager) (interface{}, error) {
logger := log.FromContext(c.Ctx)

getCertFunc, createCertFunc, err := setCertificateFuncs(c)
if err != nil {
return nil, err
}

serverCertName := strings.Join([]string{c.EtcdCluster.Name, c.EtcdCluster.Spec.TLS.Member.ServerSecret}, "-")
logger.Info("Starting reconciliation of Server Certificate", serverCertName, c.EtcdCluster.Namespace)
serverCert, serverCertErr := getCertFunc(serverCertName, c.EtcdCluster.Namespace)

Check failure on line 137 in internal/certificate/certificate_utils.go

View workflow job for this annotation

GitHub Actions / Run on Ubuntu

ineffectual assignment to serverCert (ineffassign)
if k8serrors.IsNotFound(serverCertErr) {
serverCert, serverCertErr = createCertFunc(serverCertName)
if serverCertErr != nil {
logger.Error(serverCertErr, "failed to create Server Certificate")
return nil, serverCertErr
}
} else {
logger.Error(serverCertErr, "failed to get Server Certificate")
return nil, serverCertErr
}

return serverCert, nil
}
5 changes: 5 additions & 0 deletions internal/certificate/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package certificate

const (
CMClusterIssuerName = "etcd-operator-selfsigned"
)
5 changes: 0 additions & 5 deletions internal/controller/constants.go

This file was deleted.

19 changes: 15 additions & 4 deletions internal/controller/etcdcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
cmv1 "go.etcd.io/etcd-operator/internal/certificate"

Check failure on line 25 in internal/controller/etcdcluster_controller.go

View workflow job for this annotation

GitHub Actions / Run on Ubuntu

File is not properly formatted (goimports)
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -89,12 +90,22 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)

logger.Info("Reconciling EtcdCluster", "spec", etcdCluster.Spec)

logger.Info("Reconciling EtcdCluster Server certificates", "tls", etcdCluster.Spec.TLS)
certificates, err := reconcileServerCertificate(ctx, r.Client, etcdCluster, r.Scheme, logger)
etcdCertManager := cmv1.NewCertificateManager{Ctx: ctx, Client: r.Client, Scheme: r.Scheme, EtcdCluster: etcdCluster}
logger.Info("Reconciling EtcdCluster Server certificate", "tls", etcdCluster.Spec.TLS)
serverCertificate, err := cmv1.ReconcileServerCertificate(etcdCertManager)
if err != nil {
logger.Error(err, "failed to reconcile EtcdCluster Server certificates")
logger.Error(err, "failed to reconcile EtcdCluster Server certificate")
} else {
logger.Info("Successfully reconciled EtcdCluster Server certificates", "tls", certificates)
logger.Info("Successfully reconciled EtcdCluster Server certificate", "tls", serverCertificate)
}

//needs to be reconciled along with member creation

Check failure on line 102 in internal/controller/etcdcluster_controller.go

View workflow job for this annotation

GitHub Actions / Run on Ubuntu

comment-spacings: no space between comment delimiter and comment text (revive)
logger.Info("Reconciling EtcdCluster Member certificates", "tls", etcdCluster.Spec.TLS)
memberCertificates, err := cmv1.ReconcileMemberCertificate(etcdCertManager)
if err != nil {
logger.Error(err, "failed to reconcile EtcdCluster Member certificates")
} else {
logger.Info("Successfully reconciled EtcdCluster member certificates", "tls", memberCertificates)
}

// Get the statefulsets which has the same name as the EtcdCluster resource
Expand Down
95 changes: 0 additions & 95 deletions internal/controller/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"strings"
"time"

certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
"github.com/go-logr/logr"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -404,96 +402,3 @@ func healthCheck(sts *appsv1.StatefulSet, lg klog.Logger) (*clientv3.MemberListR

return memberlistResp, healthInfos, nil
}

func reconcileMemberCertificate(ctx context.Context, c client.Client, ec *ecv1alpha1.EtcdCluster, scheme *runtime.Scheme, logger logr.Logger) ([]*certv1.Certificate, error) {
var certificates []*certv1.Certificate

clientCertName := strings.Join([]string{ec.Name, ec.Spec.TLS.OperatorSecret}, "-")
logger.Info("Starting reconciliation of Client Certificate", clientCertName, ec.Namespace)
clientCert, clientCertErr := getCertificate(ctx, c, clientCertName, ec.Namespace)
if k8serrors.IsNotFound(clientCertErr) {
clientCert, clientCertErr = createCertificate(ctx, c, clientCertName, ec, scheme)
if clientCertErr != nil {
logger.Error(clientCertErr, "failed to create Client Certificate")
}
} else {
logger.Error(clientCertErr, "failed to get Client Certificate")
}

peerCertName := strings.Join([]string{ec.Name, ec.Spec.TLS.Member.PeerSecret}, "-")
logger.Info("Starting reconciliation of Peer Certificate", peerCertName, ec.Namespace)
peerCert, peerCertErr := getCertificate(ctx, c, peerCertName, ec.Namespace)
if k8serrors.IsNotFound(peerCertErr) {
peerCert, peerCertErr = createCertificate(ctx, c, peerCertName, ec, scheme)
if peerCertErr != nil {
logger.Error(peerCertErr, "failed to create Peer Certificate")
}
} else {
logger.Error(clientCertErr, "failed to get Peer Certificate")
}

certificates = append(certificates, clientCert, peerCert)
for _, cert := range certificates {
if cert == nil {
return certificates, errors.New("failed to create one or more certificate")
}
}
return certificates, nil
}

func reconcileServerCertificate(ctx context.Context, c client.Client, ec *ecv1alpha1.EtcdCluster, scheme *runtime.Scheme, logger logr.Logger) (*certv1.Certificate, error) {

serverCertName := strings.Join([]string{ec.Name, ec.Spec.TLS.Member.ServerSecret}, "-")
logger.Info("Starting reconciliation of Server Certificate", serverCertName, ec.Namespace)
serverCert, serverCertErr := getCertificate(ctx, c, serverCertName, ec.Namespace)
if k8serrors.IsNotFound(serverCertErr) {
serverCert, serverCertErr = createCertificate(ctx, c, serverCertName, ec, scheme)
if serverCertErr != nil {
logger.Error(serverCertErr, "failed to create Server Certificate")
return nil, serverCertErr
}
} else {
logger.Error(serverCertErr, "failed to get Server Certificate")
return nil, serverCertErr
}

return serverCert, nil
}

func getCertificate(ctx context.Context, c client.Client, tlsCertName, namespace string) (*certv1.Certificate, error) {
foundCert := &certv1.Certificate{}

err := c.Get(ctx, client.ObjectKey{Name: tlsCertName, Namespace: namespace}, foundCert)
if err != nil {
return nil, err
}
return foundCert, nil
}

func createCertificate(ctx context.Context, c client.Client, tlsCertName string, ec *ecv1alpha1.EtcdCluster, scheme *runtime.Scheme) (*certv1.Certificate, error) {
owners, ownersErr := prepareOwnerReference(ec, scheme)
if ownersErr != nil {
return nil, ownersErr
}
certificateResource := &certv1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: tlsCertName,
Namespace: ec.Namespace,
OwnerReferences: owners,
},
Spec: certv1.CertificateSpec{
SecretName: tlsCertName,
DNSNames: []string{fmt.Sprintf("%s-%d.%s.%s.svc.cluster.local", ec.Name, ec.Spec.Size, ec.Name, ec.Namespace)},
IssuerRef: cmmeta.ObjectReference{
Name: CertClusterIssuerName,
Kind: "ClusterIssuer",
},
},
}

err := c.Create(ctx, certificateResource)
if err != nil {
return nil, err
}
return certificateResource, nil
}

0 comments on commit 4ae9757

Please sign in to comment.