Skip to content

Commit bea3c32

Browse files
committed
Add reconciler logic for client certificate
This commit will add reconciler logic for creating client certificate to communicate with the etcdCluster Signed-off-by: ArkaSaha30 <[email protected]>
1 parent 9e3cc27 commit bea3c32

File tree

5 files changed

+129
-2
lines changed

5 files changed

+129
-2
lines changed

cmd/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"flag"
2222
"os"
2323

24+
certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
2425
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
2526
// to ensure that exec-entrypoint and run can make use of them.
2627
_ "k8s.io/client-go/plugin/pkg/client/auth"
@@ -49,6 +50,8 @@ func init() {
4950
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
5051

5152
utilruntime.Must(operatorv1alpha1.AddToScheme(scheme))
53+
54+
utilruntime.Must(certv1.AddToScheme(scheme))
5255
// +kubebuilder:scaffold:scheme
5356
}
5457

config/rbac/role.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ rules:
3939
- patch
4040
- update
4141
- watch
42+
- apiGroups:
43+
- cert-manager.io
44+
resources:
45+
- certificates
46+
verbs:
47+
- create
48+
- delete
49+
- get
50+
- list
51+
- update
52+
- watch
53+
- apiGroups:
54+
- cert-manager.io
55+
resources:
56+
- clusterissuers
57+
- issuers
58+
verbs:
59+
- get
60+
- list
61+
- watch
4262
- apiGroups:
4363
- operator.etcd.io
4464
resources:

config/samples/operator_v1alpha1_etcdcluster.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ metadata:
88
spec:
99
version: v3.5.21
1010
size: 3
11+
tls:
12+
provider: "cert-manager"
13+
providerCfg:
14+
certManagerCfg:
15+
commonName: "etcd-operator-system"
16+
validityDuration: "90h"
17+
issuerName: "selfsigned"
18+
issuerKind: "ClusterIssuer"

internal/controller/etcdcluster_controller.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"time"
2323

24+
certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
2425
appsv1 "k8s.io/api/apps/v1"
2526
corev1 "k8s.io/api/core/v1"
2627
"k8s.io/apimachinery/pkg/api/errors"
@@ -30,9 +31,10 @@ import (
3031
"sigs.k8s.io/controller-runtime/pkg/client"
3132
"sigs.k8s.io/controller-runtime/pkg/log"
3233

34+
clientv3 "go.etcd.io/etcd/client/v3"
35+
3336
ecv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1"
3437
"go.etcd.io/etcd-operator/internal/etcdutils"
35-
clientv3 "go.etcd.io/etcd/client/v3"
3638
)
3739

3840
const (
@@ -53,6 +55,9 @@ type EtcdClusterReconciler struct {
5355
// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete
5456
// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch;delete
5557
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch;get;list;update
58+
// +kubebuilder:rbac:groups="cert-manager.io",resources=certificates,verbs=create;get;list;update;delete;watch
59+
// +kubebuilder:rbac:groups="cert-manager.io",resources=clusterissuers,verbs=get;list;watch
60+
// +kubebuilder:rbac:groups="cert-manager.io",resources=issuers,verbs=get;list;watch
5661

5762
// Reconcile is part of the main kubernetes reconciliation loop which aims to
5863
// move the current state of the cluster closer to the desired state.
@@ -78,6 +83,13 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
7883
return ctrl.Result{}, err
7984
}
8085

86+
// Create Client Certificate for etcd-operator to communicate with the etcdClusterAdd commentMore actions
87+
clientCertErr := r.checkClientCertificate(etcdCluster, ctx)
88+
if clientCertErr != nil {
89+
logger.Info("Error creating Client Certificate")
90+
return ctrl.Result{}, clientCertErr
91+
}
92+
8193
logger.Info("Reconciling EtcdCluster", "spec", etcdCluster.Spec)
8294

8395
// Get the statefulsets which has the same name as the EtcdCluster resource
@@ -258,5 +270,6 @@ func (r *EtcdClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
258270
Owns(&appsv1.StatefulSet{}).
259271
Owns(&corev1.Service{}).
260272
Owns(&corev1.ConfigMap{}).
273+
Owns(&certv1.Certificate{}).
261274
Complete(r)
262275
}

internal/controller/utils.go

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"log"
8+
"net"
79
"slices"
810
"strconv"
911
"strings"
@@ -24,9 +26,12 @@ import (
2426
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2527
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2628

29+
clientv3 "go.etcd.io/etcd/client/v3"
30+
2731
ecv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1"
2832
"go.etcd.io/etcd-operator/internal/etcdutils"
29-
clientv3 "go.etcd.io/etcd/client/v3"
33+
"go.etcd.io/etcd-operator/pkg/certificate"
34+
certInterface "go.etcd.io/etcd-operator/pkg/certificate/interfaces"
3035
)
3136

3237
const (
@@ -522,3 +527,81 @@ func healthCheck(sts *appsv1.StatefulSet, lg klog.Logger) (*clientv3.MemberListR
522527

523528
return memberlistResp, healthInfos, nil
524529
}
530+
531+
func createCMCertificateConfig(ec *ecv1alpha1.ProviderCertManagerConfig) *certInterface.Config {
532+
duration, err := time.ParseDuration(ec.ValidityDuration)
533+
if err != nil {
534+
log.Printf("Failed to parse ValidityDuration: %s", err)
535+
}
536+
config := &certInterface.Config{
537+
CommonName: ec.CommonName,
538+
Organization: ec.Organization,
539+
ValidityDuration: duration,
540+
AltNames: certInterface.AltNames{
541+
DNSNames: ec.AltNames.DNSNames,
542+
IPs: make([]net.IP, len(ec.AltNames.DNSNames)),
543+
},
544+
ExtraConfig: map[string]any{
545+
"issuerName": ec.IssuerName,
546+
"issuerKind": ec.IssuerKind,
547+
},
548+
}
549+
return config
550+
}
551+
552+
func createAutoCertificateConfig(ec *ecv1alpha1.ProviderAutoConfig) *certInterface.Config {
553+
// TODO
554+
config := &certInterface.Config{}
555+
return config
556+
}
557+
558+
func (r *EtcdClusterReconciler) createCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context, podName, podNamespace, certType string) error {
559+
certName := fmt.Sprintf("%s-%s-tls", podName, certType)
560+
// cert, certErr := certificate.NewProvider(certificate.ProviderType(ec.Spec.TLS.Provider))
561+
cert, certErr := certificate.NewProvider(certificate.ProviderType(ec.Spec.TLS.Provider), r.Client)
562+
if certErr != nil {
563+
// TODO: instead of error, set default autoConfig
564+
return certErr
565+
}
566+
_, getCertError := cert.GetCertificateConfig(ctx, certName, podNamespace)
567+
if getCertError != nil {
568+
if k8serrors.IsNotFound(getCertError) {
569+
log.Println("Creating Client Certificate for etcd-operator to communicate with the etcdCluster")
570+
switch {
571+
case ec.Spec.TLS.ProviderCfg.AutoCfg != nil:
572+
cmConfig := createAutoCertificateConfig(ec.Spec.TLS.ProviderCfg.AutoCfg)
573+
createCertErr := cert.EnsureCertificateSecret(ctx, certName, podNamespace, cmConfig)
574+
if createCertErr != nil {
575+
log.Printf("Error creating certificate: %s", createCertErr)
576+
}
577+
return nil
578+
case ec.Spec.TLS.ProviderCfg.CertManagerCfg != nil:
579+
cmConfig := createCMCertificateConfig(ec.Spec.TLS.ProviderCfg.CertManagerCfg)
580+
createCertErr := cert.EnsureCertificateSecret(ctx, certName, podNamespace, cmConfig)
581+
if createCertErr != nil {
582+
log.Printf("Error creating certificate: %s", createCertErr)
583+
}
584+
return nil
585+
default:
586+
if ec.Spec.TLS.ProviderCfg.AutoCfg == nil {
587+
// TODO: instead of error, set default autoConfig which will be applied if Provider/ProviderConfig is not set
588+
return errors.New("default autoCertificate config not defined")
589+
}
590+
cmConfig := createAutoCertificateConfig(ec.Spec.TLS.ProviderCfg.AutoCfg)
591+
createCertErr := cert.EnsureCertificateSecret(ctx, certName, podNamespace, cmConfig)
592+
log.Printf("Error creating certificate, maybe already present: %s", createCertErr)
593+
return nil
594+
}
595+
} else {
596+
log.Printf("Error getting certificate")
597+
return getCertError
598+
}
599+
}
600+
601+
return nil
602+
}
603+
604+
func (r *EtcdClusterReconciler) checkClientCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context) error {
605+
createClientCertErr := r.createCertificate(ec, ctx, ec.Name, ec.Namespace, "client")
606+
return createClientCertErr
607+
}

0 commit comments

Comments
 (0)