diff --git a/main.go b/main.go
index ec73ace6..3ba8454f 100644
--- a/main.go
+++ b/main.go
@@ -11,6 +11,7 @@ package main
 import (
 	"context"
 	"flag"
+	corev1 "k8s.io/api/core/v1"
 	"net/http"
 	"os"
 	"os/signal"
@@ -144,7 +145,12 @@ func main() {
 		}
 	}()
 
-	informerFactory := informers.NewSharedInformerFactory(client, 1*time.Minute)
+	informerFactory := informers.NewSharedInformerFactoryWithOptions(client, 1*time.Minute,
+		informers.WithCustomResyncConfig(
+			map[metav1.Object]time.Duration{
+				&corev1.Secret{}: 0,
+			},
+		))
 
 	// listen for interrupts or the Linux SIGTERM signal and cancel
 	// our context, which the leader election code will observe and
@@ -157,13 +163,13 @@ func main() {
 		cancel()
 	}()
 
-	ingressClassInformer, ingressInformer, serviceInformer, endpointInformer, podInformer, nodeInformer, serviceAccountInformer := setupInformers(informerFactory, ctx, classParamInformer)
+	ingressClassInformer, ingressInformer, serviceInformer, secretInformer, endpointInformer, podInformer, nodeInformer, serviceAccountInformer := setupInformers(informerFactory, ctx, classParamInformer)
 
 	server.SetupWebhookServer(ingressInformer, serviceInformer, client, ctx)
 	mux := http.NewServeMux()
 	reg, err := server.SetupMetricsServer(opts.MetricsBackend, opts.MetricsPort, mux, ctx)
 
-	run := server.SetUpControllers(opts, ingressClassInformer, ingressInformer, client, serviceInformer, endpointInformer, podInformer, nodeInformer, serviceAccountInformer, c, reg)
+	run := server.SetUpControllers(opts, ingressClassInformer, ingressInformer, client, serviceInformer, secretInformer, endpointInformer, podInformer, nodeInformer, serviceAccountInformer, c, reg)
 
 	metric.ServeMetrics(opts.MetricsPort, mux)
 	// we use the Lease lock type since edits to Leases are less common
@@ -214,7 +220,7 @@ func main() {
 	})
 }
 
-func setupInformers(informerFactory informers.SharedInformerFactory, ctx context.Context, classParamInformer ctrcache.Informer) (networkinginformers.IngressClassInformer, networkinginformers.IngressInformer, v1.ServiceInformer, v1.EndpointsInformer, v1.PodInformer, v1.NodeInformer, v1.ServiceAccountInformer) {
+func setupInformers(informerFactory informers.SharedInformerFactory, ctx context.Context, classParamInformer ctrcache.Informer) (networkinginformers.IngressClassInformer, networkinginformers.IngressInformer, v1.ServiceInformer, v1.SecretInformer, v1.EndpointsInformer, v1.PodInformer, v1.NodeInformer, v1.ServiceAccountInformer) {
 	ingressClassInformer := informerFactory.Networking().V1().IngressClasses()
 	go ingressClassInformer.Informer().Run(ctx.Done())
 
@@ -224,6 +230,9 @@ func setupInformers(informerFactory informers.SharedInformerFactory, ctx context
 	serviceInformer := informerFactory.Core().V1().Services()
 	go serviceInformer.Informer().Run(ctx.Done())
 
+	secretInformer := informerFactory.Core().V1().Secrets()
+	go secretInformer.Informer().Run(ctx.Done())
+
 	endpointInformer := informerFactory.Core().V1().Endpoints()
 	go endpointInformer.Informer().Run(ctx.Done())
 
@@ -245,6 +254,7 @@ func setupInformers(informerFactory informers.SharedInformerFactory, ctx context
 		ingressClassInformer.Informer().HasSynced,
 		ingressInformer.Informer().HasSynced,
 		serviceInformer.Informer().HasSynced,
+		secretInformer.Informer().HasSynced,
 		endpointInformer.Informer().HasSynced,
 		podInformer.Informer().HasSynced,
 		classParamInformer.HasSynced,
@@ -253,5 +263,5 @@ func setupInformers(informerFactory informers.SharedInformerFactory, ctx context
 
 		klog.Fatal("failed to sync informers")
 	}
-	return ingressClassInformer, ingressInformer, serviceInformer, endpointInformer, podInformer, nodeInformer, serviceAccountInformer
+	return ingressClassInformer, ingressInformer, serviceInformer, secretInformer, endpointInformer, podInformer, nodeInformer, serviceAccountInformer
 }
diff --git a/pkg/certificate/certificate.go b/pkg/certificate/certificate.go
index 95d596e9..61978d96 100644
--- a/pkg/certificate/certificate.go
+++ b/pkg/certificate/certificate.go
@@ -11,6 +11,7 @@ package certificate
 
 import (
 	"context"
+	"fmt"
 	"net/http"
 	"sync"
 	"time"
@@ -22,6 +23,10 @@ import (
 	"k8s.io/klog/v2"
 )
 
+const (
+	certificateServiceTimeout = 2 * time.Minute
+)
+
 type CertificatesClient struct {
 	ManagementClient   CertificateManagementInterface
 	CertificatesClient CertificateInterface
@@ -42,9 +47,9 @@ func New(managementClient CertificateManagementInterface,
 	}
 }
 
-func (certificatesClient *CertificatesClient) SetCertCache(cert *certificatesmanagement.Certificate) {
+func (certificatesClient *CertificatesClient) SetCertCache(cert *certificatesmanagement.Certificate, etag string) {
 	certificatesClient.certMu.Lock()
-	certificatesClient.CertCache[*cert.Id] = &CertCacheObj{Cert: cert, Age: time.Now()}
+	certificatesClient.CertCache[*cert.Id] = &CertCacheObj{Cert: cert, Age: time.Now(), Etag: etag}
 	certificatesClient.certMu.Unlock()
 }
 
@@ -54,9 +59,9 @@ func (certificatesClient *CertificatesClient) GetFromCertCache(certId string) *C
 	return certificatesClient.CertCache[certId]
 }
 
-func (certificatesClient *CertificatesClient) SetCaBundleCache(caBundle *certificatesmanagement.CaBundle) {
+func (certificatesClient *CertificatesClient) SetCaBundleCache(caBundle *certificatesmanagement.CaBundle, etag string) {
 	certificatesClient.caMu.Lock()
-	certificatesClient.CaBundleCache[*caBundle.Id] = &CaBundleCacheObj{CaBundle: caBundle, Age: time.Now()}
+	certificatesClient.CaBundleCache[*caBundle.Id] = &CaBundleCacheObj{CaBundle: caBundle, Age: time.Now(), Etag: etag}
 	certificatesClient.caMu.Unlock()
 }
 
@@ -67,37 +72,37 @@ func (certificatesClient *CertificatesClient) GetFromCaBundleCache(id string) *C
 }
 
 func (certificatesClient *CertificatesClient) CreateCertificate(ctx context.Context,
-	req certificatesmanagement.CreateCertificateRequest) (*certificatesmanagement.Certificate, error) {
+	req certificatesmanagement.CreateCertificateRequest) (*certificatesmanagement.Certificate, string, error) {
 	resp, err := certificatesClient.ManagementClient.CreateCertificate(ctx, req)
 	if err != nil {
 		klog.Errorf("Error creating certificate %s, %s ", *req.Name, err.Error())
-		return nil, err
+		return nil, "", err
 	}
 
-	return &resp.Certificate, nil
+	return certificatesClient.waitForActiveCertificate(ctx, *resp.Certificate.Id)
 }
 
 func (certificatesClient *CertificatesClient) CreateCaBundle(ctx context.Context,
-	req certificatesmanagement.CreateCaBundleRequest) (*certificatesmanagement.CaBundle, error) {
+	req certificatesmanagement.CreateCaBundleRequest) (*certificatesmanagement.CaBundle, string, error) {
 	resp, err := certificatesClient.ManagementClient.CreateCaBundle(ctx, req)
 	if err != nil {
 		klog.Errorf("Error creating ca bundle %s, %s ", *req.Name, err.Error())
-		return nil, err
+		return nil, "", err
 	}
 
-	return &resp.CaBundle, nil
+	return certificatesClient.waitForActiveCaBundle(ctx, *resp.CaBundle.Id)
 }
 
 func (certificatesClient *CertificatesClient) GetCertificate(ctx context.Context,
-	req certificatesmanagement.GetCertificateRequest) (*certificatesmanagement.Certificate, error) {
+	req certificatesmanagement.GetCertificateRequest) (*certificatesmanagement.Certificate, string, error) {
 	klog.Infof("Getting certificate for ocid %s ", *req.CertificateId)
 	resp, err := certificatesClient.ManagementClient.GetCertificate(ctx, req)
 	if err != nil {
 		klog.Errorf("Error getting certificate %s, %s ", *req.CertificateId, err.Error())
-		return nil, err
+		return nil, "", err
 	}
 
-	return &resp.Certificate, nil
+	return &resp.Certificate, *resp.Etag, nil
 }
 
 func (certificatesClient *CertificatesClient) ListCertificates(ctx context.Context,
@@ -112,6 +117,21 @@ func (certificatesClient *CertificatesClient) ListCertificates(ctx context.Conte
 	return &resp.CertificateCollection, resp.OpcNextPage, nil
 }
 
+func (certificatesClient *CertificatesClient) UpdateCertificate(ctx context.Context,
+	req certificatesmanagement.UpdateCertificateRequest) (*certificatesmanagement.Certificate, string, error) {
+	_, err := certificatesClient.ManagementClient.UpdateCertificate(ctx, req)
+	if err != nil {
+		if !util.IsServiceError(err, 409) {
+			klog.Errorf("Error updating certificate %s: %s", *req.CertificateId, err)
+		} else {
+			klog.Errorf("Error updating certificate %s due to 409-Conflict", *req.CertificateId)
+		}
+		return nil, "", err
+	}
+
+	return certificatesClient.waitForActiveCertificate(ctx, *req.CertificateId)
+}
+
 func (certificatesClient *CertificatesClient) ScheduleCertificateDeletion(ctx context.Context,
 	req certificatesmanagement.ScheduleCertificateDeletionRequest) error {
 	_, err := certificatesClient.ManagementClient.ScheduleCertificateDeletion(ctx, req)
@@ -122,16 +142,68 @@ func (certificatesClient *CertificatesClient) ScheduleCertificateDeletion(ctx co
 	return nil
 }
 
+func (certificatesClient *CertificatesClient) ListCertificateVersions(ctx context.Context,
+	req certificatesmanagement.ListCertificateVersionsRequest) (*certificatesmanagement.CertificateVersionCollection, *string, error) {
+	resp, err := certificatesClient.ManagementClient.ListCertificateVersions(ctx, req)
+	if err != nil {
+		klog.Errorf("Error listing certificate versions for request %s, %s ", util.PrettyPrint(req), err.Error())
+		return nil, nil, err
+	}
+
+	return &resp.CertificateVersionCollection, resp.OpcNextPage, nil
+}
+
+func (certificatesClient *CertificatesClient) ScheduleCertificateVersionDeletion(ctx context.Context,
+	req certificatesmanagement.ScheduleCertificateVersionDeletionRequest) (*certificatesmanagement.Certificate, string, error) {
+	klog.Infof("Scheduling version %d of Certificate %s for deletion", *req.CertificateVersionNumber, *req.CertificateId)
+	_, err := certificatesClient.ManagementClient.ScheduleCertificateVersionDeletion(ctx, req)
+	if err != nil {
+		klog.Errorf("Error scheduling certificate version for deletion, certificateId %s, version %d, %s ",
+			*req.CertificateId, *req.CertificateVersionNumber, err.Error())
+		return nil, "", err
+	}
+
+	return certificatesClient.waitForActiveCertificate(ctx, *req.CertificateId)
+}
+
+func (certificatesClient *CertificatesClient) waitForActiveCertificate(ctx context.Context,
+	certificateId string) (*certificatesmanagement.Certificate, string, error) {
+	timeoutCtx, cancel := context.WithTimeout(ctx, certificateServiceTimeout)
+	defer cancel()
+
+	for {
+		resp, err := certificatesClient.ManagementClient.GetCertificate(timeoutCtx, certificatesmanagement.GetCertificateRequest{
+			CertificateId: &certificateId,
+		})
+		if err != nil {
+			return nil, "", err
+		}
+
+		if resp.Certificate.LifecycleState == certificatesmanagement.CertificateLifecycleStateActive {
+			return &resp.Certificate, *resp.Etag, nil
+		}
+
+		if resp.Certificate.LifecycleState != certificatesmanagement.CertificateLifecycleStateUpdating &&
+			resp.Certificate.LifecycleState != certificatesmanagement.CertificateLifecycleStateCreating {
+			return nil, "", fmt.Errorf("certificate %s went into an unexpected state %s while updating",
+				*resp.Certificate.Id, resp.Certificate.LifecycleState)
+		}
+
+		klog.Infof("Certificate %s still not active, waiting", certificateId)
+		time.Sleep(3 * time.Second)
+	}
+}
+
 func (certificatesClient *CertificatesClient) GetCaBundle(ctx context.Context,
-	req certificatesmanagement.GetCaBundleRequest) (*certificatesmanagement.CaBundle, error) {
+	req certificatesmanagement.GetCaBundleRequest) (*certificatesmanagement.CaBundle, string, error) {
 	klog.Infof("Getting ca bundle with ocid %s ", *req.CaBundleId)
 	resp, err := certificatesClient.ManagementClient.GetCaBundle(ctx, req)
 	if err != nil {
 		klog.Errorf("Error getting certificate %s, %s ", *req.CaBundleId, err.Error())
-		return nil, err
+		return nil, "", err
 	}
 
-	return &resp.CaBundle, nil
+	return &resp.CaBundle, *resp.Etag, nil
 }
 
 func (certificatesClient *CertificatesClient) ListCaBundles(ctx context.Context,
@@ -146,6 +218,21 @@ func (certificatesClient *CertificatesClient) ListCaBundles(ctx context.Context,
 	return &resp.CaBundleCollection, nil
 }
 
+func (certificatesClient *CertificatesClient) UpdateCaBundle(ctx context.Context,
+	req certificatesmanagement.UpdateCaBundleRequest) (*certificatesmanagement.CaBundle, string, error) {
+	_, err := certificatesClient.ManagementClient.UpdateCaBundle(ctx, req)
+	if err != nil {
+		if !util.IsServiceError(err, 409) {
+			klog.Errorf("Error updating ca bundle %s: %s", *req.CaBundleId, err)
+		} else {
+			klog.Errorf("Error updating ca bundle %s due to 409-Conflict", *req.CaBundleId)
+		}
+		return nil, "", err
+	}
+
+	return certificatesClient.waitForActiveCaBundle(ctx, *req.CaBundleId)
+}
+
 func (certificatesClient *CertificatesClient) DeleteCaBundle(ctx context.Context,
 	req certificatesmanagement.DeleteCaBundleRequest) (*http.Response, error) {
 	klog.Infof("Deleting ca bundle with ocid %s ", *req.CaBundleId)
@@ -158,6 +245,34 @@ func (certificatesClient *CertificatesClient) DeleteCaBundle(ctx context.Context
 	return resp.HTTPResponse(), nil
 }
 
+func (certificatesClient *CertificatesClient) waitForActiveCaBundle(ctx context.Context,
+	caBundleId string) (*certificatesmanagement.CaBundle, string, error) {
+	timeoutCtx, cancel := context.WithTimeout(ctx, certificateServiceTimeout)
+	defer cancel()
+
+	for {
+		resp, err := certificatesClient.ManagementClient.GetCaBundle(timeoutCtx, certificatesmanagement.GetCaBundleRequest{
+			CaBundleId: &caBundleId,
+		})
+		if err != nil {
+			return nil, "", err
+		}
+
+		if resp.CaBundle.LifecycleState == certificatesmanagement.CaBundleLifecycleStateActive {
+			return &resp.CaBundle, *resp.Etag, nil
+		}
+
+		if resp.CaBundle.LifecycleState != certificatesmanagement.CaBundleLifecycleStateUpdating &&
+			resp.CaBundle.LifecycleState != certificatesmanagement.CaBundleLifecycleStateCreating {
+			return nil, "", fmt.Errorf("ca bundle %s went into an unexpected state %s while updating",
+				*resp.CaBundle.Id, resp.CaBundle.LifecycleState)
+		}
+
+		klog.Infof("cabundle %s still not active, waiting", caBundleId)
+		time.Sleep(3 * time.Second)
+	}
+}
+
 func (certificatesClient *CertificatesClient) GetCertificateBundle(ctx context.Context,
 	req certificates.GetCertificateBundleRequest) (certificates.CertificateBundle, error) {
 	klog.Infof("Getting certificate bundle for certificate ocid %s ", *req.CertificateId)
diff --git a/pkg/certificate/certificate_test.go b/pkg/certificate/certificate_test.go
index 49f3bb97..199dcadb 100644
--- a/pkg/certificate/certificate_test.go
+++ b/pkg/certificate/certificate_test.go
@@ -14,7 +14,12 @@ import (
 	ociclient "github.com/oracle/oci-native-ingress-controller/pkg/oci/client"
 )
 
-const ErrorListingCaBundle = "error listing Ca Bundles"
+const (
+	ErrorListingCaBundle = "error listing Ca Bundles"
+	errorMsg             = "no cert found"
+	namespace            = "test"
+	errorImportCert      = "errorImportCert"
+)
 
 func setup() *CertificatesClient {
 	certClient := GetCertClient()
@@ -38,7 +43,7 @@ func TestCertificatesClient_Cache(t *testing.T) {
 		OpcRetryToken:            nil,
 		RequestMetadata:          common.RequestMetadata{},
 	}
-	cert, err := client.CreateCertificate(context.TODO(), request)
+	cert, _, err := client.CreateCertificate(context.TODO(), request)
 	Expect(err).Should(BeNil())
 	Expect(cert).Should(Not(BeNil()))
 
@@ -54,7 +59,7 @@ func TestCertificatesClient_CreateCertificate(t *testing.T) {
 		OpcRetryToken:            nil,
 		RequestMetadata:          common.RequestMetadata{},
 	}
-	cert, err := client.CreateCertificate(context.TODO(), request)
+	cert, _, err := client.CreateCertificate(context.TODO(), request)
 	Expect(err).Should(BeNil())
 	Expect(cert).Should(Not(BeNil()))
 
@@ -70,7 +75,7 @@ func TestCertificatesClient_CreateCaBundle(t *testing.T) {
 		OpcRetryToken:         nil,
 		RequestMetadata:       common.RequestMetadata{},
 	}
-	cert, err := client.CreateCaBundle(context.TODO(), request)
+	cert, _, err := client.CreateCaBundle(context.TODO(), request)
 	Expect(err).Should(BeNil())
 	Expect(cert).Should(Not(BeNil()))
 
@@ -84,8 +89,9 @@ func TestCertificatesClient_GetCertificate(t *testing.T) {
 		OpcRequestId:    nil,
 		RequestMetadata: common.RequestMetadata{},
 	}
-	cert, err := client.GetCertificate(context.TODO(), request)
+	cert, etag, err := client.GetCertificate(context.TODO(), request)
 	Expect(err).Should(BeNil())
+	Expect(etag).Should(Equal("etag"))
 	Expect(cert).Should(Not(BeNil()))
 
 }
@@ -103,6 +109,61 @@ func TestCertificatesClient_ListCertificates(t *testing.T) {
 	Expect(cert).Should(Not(BeNil()))
 
 }
+
+func TestCertificatesClient_UpdateCertificate(t *testing.T) {
+	RegisterTestingT(t)
+	client := setup()
+
+	request := certificatesmanagement.UpdateCertificateRequest{
+		CertificateId:   common.String("id"),
+		RequestMetadata: common.RequestMetadata{},
+	}
+	cert, _, err := client.UpdateCertificate(context.TODO(), request)
+	Expect(err).Should(BeNil())
+	Expect(cert).Should(Not(BeNil()))
+
+	request.CertificateId = common.String("error")
+	cert, _, err = client.UpdateCertificate(context.TODO(), request)
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+}
+
+func TestCertificatesClient_ListCertificateVersions(t *testing.T) {
+	RegisterTestingT(t)
+	client := setup()
+
+	request := certificatesmanagement.ListCertificateVersionsRequest{
+		CertificateId: common.String("id"),
+		SortOrder:     certificatesmanagement.ListCertificateVersionsSortOrderDesc,
+	}
+	certVersionSummary, _, err := client.ListCertificateVersions(context.TODO(), request)
+	Expect(err).Should(BeNil())
+	Expect(certVersionSummary).ShouldNot(BeNil())
+}
+
+func TestCertificatesClient_ScheduleCertificateVersionDeletion(t *testing.T) {
+	RegisterTestingT(t)
+	client := setup()
+
+	request := certificatesmanagement.ScheduleCertificateVersionDeletionRequest{
+		CertificateId:            common.String("id"),
+		CertificateVersionNumber: common.Int64(3),
+	}
+	cert, _, err := client.ScheduleCertificateVersionDeletion(context.TODO(), request)
+	Expect(err).Should(BeNil())
+	Expect(cert).ShouldNot(BeNil())
+}
+
+func TestCertificatesClient_waitForActiveCertificate(t *testing.T) {
+	RegisterTestingT(t)
+	client := setup()
+
+	certificateId := "id"
+	cert, _, err := client.waitForActiveCertificate(context.TODO(), certificateId)
+	Expect(err).Should(BeNil())
+	Expect(cert).ShouldNot(BeNil())
+}
+
 func TestCertificatesClient_GetCaBundle(t *testing.T) {
 	RegisterTestingT(t)
 	client := setup()
@@ -112,8 +173,9 @@ func TestCertificatesClient_GetCaBundle(t *testing.T) {
 		OpcRequestId:    nil,
 		RequestMetadata: common.RequestMetadata{},
 	}
-	caBundle, err := client.GetCaBundle(context.TODO(), request)
+	caBundle, etag, err := client.GetCaBundle(context.TODO(), request)
 	Expect(err).Should(BeNil())
+	Expect(etag).Should(Equal("etag"))
 	Expect(caBundle).Should(Not(BeNil()))
 
 }
@@ -160,6 +222,24 @@ func TestCertificatesClient_ListCaBundles(t *testing.T) {
 
 }
 
+func TestCertificatesClient_UpdateCaBundle(t *testing.T) {
+	RegisterTestingT(t)
+	client := setup()
+
+	request := certificatesmanagement.UpdateCaBundleRequest{
+		CaBundleId:      common.String("id"),
+		RequestMetadata: common.RequestMetadata{},
+	}
+	cert, _, err := client.UpdateCaBundle(context.TODO(), request)
+	Expect(err).Should(BeNil())
+	Expect(cert).Should(Not(BeNil()))
+
+	request.CaBundleId = common.String("error")
+	cert, _, err = client.UpdateCaBundle(context.TODO(), request)
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+}
+
 func TestScheduleCertificateDeletion(t *testing.T) {
 	RegisterTestingT(t)
 	client := setup()
@@ -197,6 +277,16 @@ func TestDeleteCaBundle(t *testing.T) {
 	Expect(err).Should(Not(BeNil()))
 }
 
+func TestCertificatesClient_waitForActiveCaBundle(t *testing.T) {
+	RegisterTestingT(t)
+	client := setup()
+
+	certificateId := "id"
+	caBundle, _, err := client.waitForActiveCaBundle(context.TODO(), certificateId)
+	Expect(err).Should(BeNil())
+	Expect(caBundle).ShouldNot(BeNil())
+}
+
 func getDeleteCaBundleRequest(id string) certificatesmanagement.DeleteCaBundleRequest {
 	request := certificatesmanagement.DeleteCaBundleRequest{
 		CaBundleId:      &id,
@@ -215,22 +305,71 @@ type MockCertificateManagerClient struct {
 }
 
 func (m MockCertificateManagerClient) CreateCertificate(ctx context.Context, request certificatesmanagement.CreateCertificateRequest) (certificatesmanagement.CreateCertificateResponse, error) {
-	return certificatesmanagement.CreateCertificateResponse{}, nil
+	id := "id"
+	etag := "etag"
+	return certificatesmanagement.CreateCertificateResponse{
+		RawResponse: nil,
+		Certificate: certificatesmanagement.Certificate{
+			Id: &id,
+		},
+		Etag:         &etag,
+		OpcRequestId: &id,
+	}, nil
 }
 
 func (m MockCertificateManagerClient) GetCertificate(ctx context.Context, request certificatesmanagement.GetCertificateRequest) (certificatesmanagement.GetCertificateResponse, error) {
-	return certificatesmanagement.GetCertificateResponse{}, nil
+
+	if *request.CertificateId == "error" {
+		return certificatesmanagement.GetCertificateResponse{}, errors.New(errorMsg)
+	}
+	id := "id"
+	name := "cert"
+	authorityId := "authId"
+	etag := "etag"
+	var confType certificatesmanagement.CertificateConfigTypeEnum
+	if *request.CertificateId == errorImportCert {
+		name = "error"
+		confType = certificatesmanagement.CertificateConfigTypeImported
+	} else {
+		confType, _ = certificatesmanagement.GetMappingCertificateConfigTypeEnum(*request.CertificateId)
+	}
+	var number int64
+	number = 234
+	certVersionSummary := certificatesmanagement.CertificateVersionSummary{
+		VersionNumber: &number,
+	}
+	return certificatesmanagement.GetCertificateResponse{
+		RawResponse: nil,
+		Certificate: certificatesmanagement.Certificate{
+			Id:                           &id,
+			Name:                         &name,
+			ConfigType:                   confType,
+			IssuerCertificateAuthorityId: &authorityId,
+			CurrentVersion:               &certVersionSummary,
+			LifecycleState:               certificatesmanagement.CertificateLifecycleStateActive,
+		},
+		Etag:         &etag,
+		OpcRequestId: nil,
+	}, nil
 }
 
 func (m MockCertificateManagerClient) ListCertificates(ctx context.Context, request certificatesmanagement.ListCertificatesRequest) (certificatesmanagement.ListCertificatesResponse, error) {
+	id := "id"
 	return certificatesmanagement.ListCertificatesResponse{
 		RawResponse:           nil,
 		CertificateCollection: certificatesmanagement.CertificateCollection{},
-		OpcRequestId:          nil,
-		OpcNextPage:           common.String("next"),
+		OpcRequestId:          &id,
+		OpcNextPage:           &id,
 	}, nil
 }
 
+func (m MockCertificateManagerClient) UpdateCertificate(ctx context.Context, request certificatesmanagement.UpdateCertificateRequest) (certificatesmanagement.UpdateCertificateResponse, error) {
+	if *request.CertificateId == "error" {
+		return certificatesmanagement.UpdateCertificateResponse{}, errors.New("cannot find certificate")
+	}
+	return certificatesmanagement.UpdateCertificateResponse{}, nil
+}
+
 func (m MockCertificateManagerClient) ScheduleCertificateDeletion(ctx context.Context, request certificatesmanagement.ScheduleCertificateDeletionRequest) (certificatesmanagement.ScheduleCertificateDeletionResponse, error) {
 	var err error
 	if *request.CertificateId == "error" {
@@ -239,21 +378,78 @@ func (m MockCertificateManagerClient) ScheduleCertificateDeletion(ctx context.Co
 	return certificatesmanagement.ScheduleCertificateDeletionResponse{}, err
 }
 
+func (m MockCertificateManagerClient) ListCertificateVersions(ctx context.Context, request certificatesmanagement.ListCertificateVersionsRequest) (certificatesmanagement.ListCertificateVersionsResponse, error) {
+	return certificatesmanagement.ListCertificateVersionsResponse{}, nil
+}
+
+func (m MockCertificateManagerClient) ScheduleCertificateVersionDeletion(ctx context.Context, request certificatesmanagement.ScheduleCertificateVersionDeletionRequest) (certificatesmanagement.ScheduleCertificateVersionDeletionResponse, error) {
+	return certificatesmanagement.ScheduleCertificateVersionDeletionResponse{}, nil
+}
+
 func (m MockCertificateManagerClient) CreateCaBundle(ctx context.Context, request certificatesmanagement.CreateCaBundleRequest) (certificatesmanagement.CreateCaBundleResponse, error) {
-	return certificatesmanagement.CreateCaBundleResponse{}, nil
+	id := "id"
+	etag := "etag"
+	return certificatesmanagement.CreateCaBundleResponse{
+		RawResponse: nil,
+		CaBundle: certificatesmanagement.CaBundle{
+			Id: &id,
+		},
+		Etag:         &etag,
+		OpcRequestId: nil,
+	}, nil
 }
 
 func (m MockCertificateManagerClient) GetCaBundle(ctx context.Context, request certificatesmanagement.GetCaBundleRequest) (certificatesmanagement.GetCaBundleResponse, error) {
-	return certificatesmanagement.GetCaBundleResponse{}, nil
+	id := "id"
+	name := "cabundle"
+	etag := "etag"
+	return certificatesmanagement.GetCaBundleResponse{
+		RawResponse: nil,
+		CaBundle: certificatesmanagement.CaBundle{
+			Id:             &id,
+			Name:           &name,
+			LifecycleState: certificatesmanagement.CaBundleLifecycleStateActive,
+		},
+		OpcRequestId: &id,
+		Etag:         &etag,
+	}, nil
 }
 
 func (m MockCertificateManagerClient) ListCaBundles(ctx context.Context, request certificatesmanagement.ListCaBundlesRequest) (certificatesmanagement.ListCaBundlesResponse, error) {
 
-	if request.LifecycleState == certificatesmanagement.ListCaBundlesLifecycleStateActive {
+	if request.LifecycleState == certificatesmanagement.ListCaBundlesLifecycleStateDeleted {
+		err := errors.New(ErrorListingCaBundle)
+		return certificatesmanagement.ListCaBundlesResponse{}, err
+	}
+
+	if *request.Name == "error" {
 		return certificatesmanagement.ListCaBundlesResponse{}, nil
 	}
-	err := errors.New(ErrorListingCaBundle)
-	return certificatesmanagement.ListCaBundlesResponse{}, err
+
+	var items []certificatesmanagement.CaBundleSummary
+	name := "ic-oci-config"
+	id := "id"
+	item := certificatesmanagement.CaBundleSummary{
+		Id:   &id,
+		Name: &name,
+	}
+	items = append(items, item)
+
+	return certificatesmanagement.ListCaBundlesResponse{
+		RawResponse: nil,
+		CaBundleCollection: certificatesmanagement.CaBundleCollection{
+			Items: items,
+		},
+		OpcRequestId: nil,
+		OpcNextPage:  nil,
+	}, nil
+}
+
+func (m MockCertificateManagerClient) UpdateCaBundle(ctx context.Context, request certificatesmanagement.UpdateCaBundleRequest) (certificatesmanagement.UpdateCaBundleResponse, error) {
+	if *request.CaBundleId == "error" {
+		return certificatesmanagement.UpdateCaBundleResponse{}, errors.New("cannot find ca bundle")
+	}
+	return certificatesmanagement.UpdateCaBundleResponse{}, nil
 }
 
 func (m MockCertificateManagerClient) DeleteCaBundle(ctx context.Context, request certificatesmanagement.DeleteCaBundleRequest) (certificatesmanagement.DeleteCaBundleResponse, error) {
diff --git a/pkg/controllers/ingress/certificate_util.go b/pkg/controllers/ingress/certificate_util.go
new file mode 100644
index 00000000..79d30b2d
--- /dev/null
+++ b/pkg/controllers/ingress/certificate_util.go
@@ -0,0 +1,365 @@
+/*
+ *
+ * * OCI Native Ingress Controller
+ * *
+ * * Copyright (c) 2024 Oracle America, Inc. and its affiliates.
+ * * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+ *
+ */
+
+package ingress
+
+import (
+	"context"
+	"fmt"
+	"github.com/oracle/oci-go-sdk/v65/certificatesmanagement"
+	"github.com/oracle/oci-go-sdk/v65/common"
+	"github.com/oracle/oci-native-ingress-controller/pkg/certificate"
+	"github.com/oracle/oci-native-ingress-controller/pkg/util"
+	"k8s.io/klog/v2"
+	"time"
+)
+
+// Interacting with OCI Cert service, opinionated for Ingress Controller
+
+func GetCertificate(certificateId *string, certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.Certificate, string, error) {
+	certCacheObj := certificatesClient.GetFromCertCache(*certificateId)
+	if certCacheObj != nil {
+		now := time.Now()
+		if now.Sub(certCacheObj.Age).Minutes() < util.CertificateCacheMaxAgeInMinutes {
+			return certCacheObj.Cert, certCacheObj.Etag, nil
+		}
+		klog.Infof("Refreshing certificate %s", *certificateId)
+	}
+	return getCertificateBustCache(*certificateId, certificatesClient)
+}
+
+func getCertificateBustCache(certificateId string, certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.Certificate, string, error) {
+	getCertificateRequest := certificatesmanagement.GetCertificateRequest{
+		CertificateId: &certificateId,
+	}
+
+	cert, etag, err := certificatesClient.GetCertificate(context.TODO(), getCertificateRequest)
+	if err == nil {
+		certificatesClient.SetCertCache(cert, etag)
+	}
+	return cert, etag, err
+}
+
+// VerifyOrGetCertificateIdByName verifies that cert with certificateId has name certificateName
+// If not, try to find certificate with matching name
+func VerifyOrGetCertificateIdByName(certificateId string, certificateName string, compartmentId string,
+	certificatesClient *certificate.CertificatesClient) (string, error) {
+	if certificateId != "" {
+		cert, _, err := GetCertificate(&certificateId, certificatesClient)
+		if err != nil {
+			return "", err
+		}
+
+		if *cert.Name == certificateName {
+			return certificateId, nil
+		}
+	}
+
+	return FindCertificateWithName(certificateName, compartmentId, certificatesClient)
+}
+
+func FindCertificateWithName(certificateName string, compartmentId string,
+	certificatesClient *certificate.CertificatesClient) (string, error) {
+	listCertificatesRequest := certificatesmanagement.ListCertificatesRequest{
+		Name:           &certificateName,
+		CompartmentId:  &compartmentId,
+		LifecycleState: certificatesmanagement.ListCertificatesLifecycleStateActive,
+	}
+
+	klog.Infof("Searching for certificates with name %s in compartment %s.", certificateName, compartmentId)
+	listCertificates, _, err := certificatesClient.ListCertificates(context.TODO(), listCertificatesRequest)
+	if err != nil {
+		return "", err
+	}
+
+	if listCertificates.Items != nil {
+		numberOfCertificates := len(listCertificates.Items)
+		klog.Infof("Found %d certificates with name %s in compartment %s.", numberOfCertificates, certificateName, compartmentId)
+		if numberOfCertificates > 0 {
+			return *listCertificates.Items[0].Id, nil
+		}
+	}
+	klog.Infof("Found no certificates with name %s in compartment %s.", certificateName, compartmentId)
+	return "", nil
+}
+
+func CreateImportedTypeCertificate(tlsSecretData *TLSSecretData, certificateName string, compartmentId string,
+	certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.Certificate, error) {
+	configDetails := certificatesmanagement.CreateCertificateByImportingConfigDetails{
+		CertChainPem:   tlsSecretData.CaCertificateChain,
+		CertificatePem: tlsSecretData.ServerCertificate,
+		PrivateKeyPem:  tlsSecretData.PrivateKey,
+	}
+
+	certificateDetails := certificatesmanagement.CreateCertificateDetails{
+		Name:              &certificateName,
+		CertificateConfig: configDetails,
+		CompartmentId:     &compartmentId,
+		FreeformTags: map[string]string{
+			certificateHashTagKey: hashPublicTlsData(tlsSecretData),
+		},
+	}
+	createCertificateRequest := certificatesmanagement.CreateCertificateRequest{
+		CreateCertificateDetails: certificateDetails,
+		OpcRetryToken:            &certificateName,
+	}
+
+	createCertificate, etag, err := certificatesClient.CreateCertificate(context.TODO(), createCertificateRequest)
+	if err != nil {
+		return nil, err
+	}
+
+	certificatesClient.SetCertCache(createCertificate, etag)
+	klog.Infof("Created a certificate with ocid %s", *createCertificate.Id)
+	return createCertificate, nil
+}
+
+func UpdateImportedTypeCertificate(certificateId *string, tlsSecretData *TLSSecretData,
+	certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.Certificate, error) {
+	_, etag, err := GetCertificate(certificateId, certificatesClient)
+	if err != nil {
+		return nil, err
+	}
+
+	configDetails := certificatesmanagement.UpdateCertificateByImportingConfigDetails{
+		CertChainPem:   tlsSecretData.CaCertificateChain,
+		CertificatePem: tlsSecretData.ServerCertificate,
+		PrivateKeyPem:  tlsSecretData.PrivateKey,
+	}
+
+	updateCertificateDetails := certificatesmanagement.UpdateCertificateDetails{
+		CertificateConfig: configDetails,
+		FreeformTags: map[string]string{
+			certificateHashTagKey: hashPublicTlsData(tlsSecretData),
+		},
+	}
+
+	updateCertificateRequest := certificatesmanagement.UpdateCertificateRequest{
+		CertificateId:            certificateId,
+		IfMatch:                  common.String(etag),
+		UpdateCertificateDetails: updateCertificateDetails,
+	}
+
+	updateCertificate, etag, err := certificatesClient.UpdateCertificate(context.TODO(), updateCertificateRequest)
+
+	// This can happen by create/update listener calls that cause the certificate etag to change because of a new association
+	if util.IsServiceError(err, 409) {
+		klog.Infof("Update certificate returned code %d for certificate %s. Refreshing cache.", 409, *certificateId)
+		getCertificateBustCache(*certificateId, certificatesClient)
+		return nil, fmt.Errorf("unable to update certificate %s due to conflict, controller will retry later", *certificateId)
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	certificatesClient.SetCertCache(updateCertificate, etag)
+	return updateCertificate, nil
+}
+
+func ScheduleCertificateVersionDeletion(certificateId string, versionNumber int64, certificatesClient *certificate.CertificatesClient) error {
+	request := certificatesmanagement.ScheduleCertificateVersionDeletionRequest{
+		ScheduleCertificateVersionDeletionDetails: certificatesmanagement.ScheduleCertificateVersionDeletionDetails{
+			TimeOfDeletion: &common.SDKTime{
+				Time: time.Now().Add(time.Hour * 24 * 10),
+			},
+		},
+		CertificateId:            &certificateId,
+		CertificateVersionNumber: &versionNumber,
+	}
+
+	updatedCert, etag, err := certificatesClient.ScheduleCertificateVersionDeletion(context.TODO(), request)
+	if err != nil {
+		return err
+	}
+
+	certificatesClient.SetCertCache(updatedCert, etag)
+	return nil
+}
+
+func PruneCertificateVersions(certificateId string, currentVersion int64,
+	versionsToPreserveCount int, certificatesClient *certificate.CertificatesClient) error {
+	listCertificateVersionsRequest := certificatesmanagement.ListCertificateVersionsRequest{
+		CertificateId: &certificateId,
+		SortOrder:     certificatesmanagement.ListCertificateVersionsSortOrderDesc,
+	}
+
+	certificateVersionCollection, _, err := certificatesClient.ListCertificateVersions(context.TODO(), listCertificateVersionsRequest)
+	if err != nil {
+		return err
+	}
+
+	versionsToPreserveSeen := 0
+	for _, certVersionSummary := range certificateVersionCollection.Items {
+		if *certVersionSummary.VersionNumber > currentVersion {
+			continue
+		}
+
+		if (isCertificateVersionFailed(certVersionSummary.Stages) || versionsToPreserveSeen >= versionsToPreserveCount) &&
+			certVersionSummary.TimeOfDeletion == nil && !isCertificateVersionCurrent(certVersionSummary.Stages) {
+			err = ScheduleCertificateVersionDeletion(certificateId, *certVersionSummary.VersionNumber, certificatesClient)
+			if err != nil {
+				klog.Errorf("unable to delete certificate version number %d for certificate %s, skipping for now: %s",
+					*certVersionSummary.VersionNumber, certificateId, err.Error())
+			}
+			continue
+		}
+		versionsToPreserveSeen = versionsToPreserveSeen + 1
+	}
+
+	return nil
+}
+
+func isCertificateVersionFailed(certificateVersionStages []certificatesmanagement.VersionStageEnum) bool {
+	return certificateVersionStagesContainsStage(certificateVersionStages, certificatesmanagement.VersionStageFailed)
+}
+
+func isCertificateVersionCurrent(certificateVersionStages []certificatesmanagement.VersionStageEnum) bool {
+	return certificateVersionStagesContainsStage(certificateVersionStages, certificatesmanagement.VersionStageCurrent)
+}
+
+func certificateVersionStagesContainsStage(certificateVersionStages []certificatesmanagement.VersionStageEnum,
+	stage certificatesmanagement.VersionStageEnum) bool {
+	for _, value := range certificateVersionStages {
+		if stage == value {
+			return true
+		}
+	}
+	return false
+}
+
+func GetCaBundle(caBundleId string, certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.CaBundle, string, error) {
+	caBundleCacheObj := certificatesClient.GetFromCaBundleCache(caBundleId)
+	if caBundleCacheObj != nil {
+		now := time.Now()
+		if now.Sub(caBundleCacheObj.Age).Minutes() < util.CertificateCacheMaxAgeInMinutes {
+			return caBundleCacheObj.CaBundle, caBundleCacheObj.Etag, nil
+		}
+		klog.Infof("Refreshing ca bundle %s", caBundleId)
+	}
+
+	return getCaBundleBustCache(caBundleId, certificatesClient)
+}
+
+func getCaBundleBustCache(caBundleId string, certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.CaBundle, string, error) {
+	klog.Infof("Getting ca bundle for id %s.", caBundleId)
+	getCaBundleRequest := certificatesmanagement.GetCaBundleRequest{
+		CaBundleId: &caBundleId,
+	}
+
+	caBundle, etag, err := certificatesClient.GetCaBundle(context.TODO(), getCaBundleRequest)
+
+	if err == nil {
+		certificatesClient.SetCaBundleCache(caBundle, etag)
+	}
+	return caBundle, etag, err
+}
+
+// VerifyOrGetCaBundleIdByName verifies that caBundle with caBundleId has name caBundleName
+// If not, try to find ca bundle with matching name
+func VerifyOrGetCaBundleIdByName(caBundleId string, caBundleName string, compartmentId string,
+	certificatesClient *certificate.CertificatesClient) (*string, error) {
+	if caBundleId != "" {
+		caBundle, _, err := GetCaBundle(caBundleId, certificatesClient)
+		if err != nil {
+			return nil, err
+		}
+
+		if *caBundle.Name == caBundleName {
+			return &caBundleId, nil
+		}
+	}
+
+	return FindCaBundleWithName(caBundleName, compartmentId, certificatesClient)
+}
+
+func FindCaBundleWithName(certificateName string, compartmentId string,
+	certificatesClient *certificate.CertificatesClient) (*string, error) {
+	listCaBundlesRequest := certificatesmanagement.ListCaBundlesRequest{
+		Name:           &certificateName,
+		CompartmentId:  &compartmentId,
+		LifecycleState: certificatesmanagement.ListCaBundlesLifecycleStateActive,
+	}
+
+	klog.Infof("Searching for ca bundles with name %s in compartment %s.", certificateName, compartmentId)
+	listCaBundles, err := certificatesClient.ListCaBundles(context.TODO(), listCaBundlesRequest)
+	if err != nil {
+		return nil, err
+	}
+
+	if listCaBundles.Items != nil {
+		numberOfCertificates := len(listCaBundles.Items)
+		klog.Infof("Found %d bundles with name %s in compartment %s.", numberOfCertificates, certificateName, compartmentId)
+		if numberOfCertificates > 0 {
+			return listCaBundles.Items[0].Id, nil
+		}
+	}
+	klog.Infof("Found no bundles with name %s in compartment %s.", certificateName, compartmentId)
+	return nil, nil
+}
+
+func CreateCaBundle(certificateName string, compartmentId string, certificatesClient *certificate.CertificatesClient,
+	certificateContents *string) (*certificatesmanagement.CaBundle, error) {
+	caBundleDetails := certificatesmanagement.CreateCaBundleDetails{
+		Name:          &certificateName,
+		CompartmentId: &compartmentId,
+		CaBundlePem:   certificateContents,
+		FreeformTags: map[string]string{
+			caBundleHashTagKey: hashString(certificateContents),
+		},
+	}
+	createCaBundleRequest := certificatesmanagement.CreateCaBundleRequest{
+		CreateCaBundleDetails: caBundleDetails,
+		OpcRetryToken:         &certificateName,
+	}
+	createCaBundle, etag, err := certificatesClient.CreateCaBundle(context.TODO(), createCaBundleRequest)
+	if err != nil {
+		return nil, err
+	}
+
+	certificatesClient.SetCaBundleCache(createCaBundle, etag)
+	return createCaBundle, nil
+}
+
+func UpdateCaBundle(caBundleId string, certificatesClient *certificate.CertificatesClient,
+	certificateContents *string) (*certificatesmanagement.CaBundle, error) {
+	_, etag, err := GetCaBundle(caBundleId, certificatesClient)
+	if err != nil {
+		return nil, err
+	}
+
+	caBundleDetails := certificatesmanagement.UpdateCaBundleDetails{
+		CaBundlePem: certificateContents,
+		FreeformTags: map[string]string{
+			caBundleHashTagKey: hashString(certificateContents),
+		},
+	}
+
+	updateCaBundleRequest := certificatesmanagement.UpdateCaBundleRequest{
+		CaBundleId:            &caBundleId,
+		UpdateCaBundleDetails: caBundleDetails,
+		IfMatch:               &etag,
+	}
+
+	updateCaBundle, etag, err := certificatesClient.UpdateCaBundle(context.TODO(), updateCaBundleRequest)
+
+	// This can happen by create/update backend set calls that cause the certificate etag to change because of a new association
+	if util.IsServiceError(err, 409) {
+		klog.Infof("Update ca bundle returned code %d for ca bundle %s. Refreshing cache.", 409, caBundleId)
+		getCaBundleBustCache(caBundleId, certificatesClient)
+		return nil, fmt.Errorf("unable to update ca bundle %s due to conflict, controller will retry later", caBundleId)
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	certificatesClient.SetCaBundleCache(updateCaBundle, etag)
+	return updateCaBundle, nil
+}
diff --git a/pkg/controllers/ingress/certificate_util_test.go b/pkg/controllers/ingress/certificate_util_test.go
new file mode 100644
index 00000000..74c0aaca
--- /dev/null
+++ b/pkg/controllers/ingress/certificate_util_test.go
@@ -0,0 +1,318 @@
+/*
+ *
+ * * OCI Native Ingress Controller
+ * *
+ * * Copyright (c) 2024 Oracle America, Inc. and its affiliates.
+ * * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+ *
+ */
+
+package ingress
+
+import (
+	. "github.com/onsi/gomega"
+	"github.com/oracle/oci-go-sdk/v65/certificatesmanagement"
+	"github.com/oracle/oci-go-sdk/v65/common"
+	corev1 "k8s.io/api/core/v1"
+	"testing"
+)
+
+func TestGetCertificate(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	certId := "id"
+	certId2 := "id2"
+
+	certificate, etag, err := GetCertificate(&certId, mockClient.GetCertClient())
+	Expect(certificate != nil).Should(BeTrue())
+	Expect(etag).Should(Equal("etag"))
+	Expect(err).Should(BeNil())
+
+	// cache fetch
+	certificate, etag, err = GetCertificate(&certId, mockClient.GetCertClient())
+	Expect(certificate != nil).Should(BeTrue())
+	Expect(etag).Should(Equal("etag"))
+	Expect(err).Should(BeNil())
+
+	certificate, etag, err = GetCertificate(&certId2, mockClient.GetCertClient())
+	Expect(certificate != nil).Should(BeTrue())
+	Expect(etag).Should(Equal("etag"))
+	Expect(err).Should(BeNil())
+}
+
+func TestVerifyOrGetCertificateIdByName(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	id := "id"
+	name := "cert"
+	compartmentId := "compartmentId"
+	actualCertificateId, err := VerifyOrGetCertificateIdByName(id, name, compartmentId, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+	Expect(actualCertificateId).Should(Equal(id))
+
+	actualCertificateId, err = VerifyOrGetCertificateIdByName("", name, compartmentId, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+	Expect(actualCertificateId).ShouldNot(Equal(""))
+}
+
+func TestFindCertificateWithName(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	name := "name"
+	compartmentId := "compartmentId"
+	certificateId, err := FindCertificateWithName(name, compartmentId, mockClient.GetCertClient())
+	Expect(certificateId).ShouldNot(Equal(""))
+	Expect(err).Should(BeNil())
+
+	name = "nonexistent"
+	certificateId, err = FindCertificateWithName(name, compartmentId, mockClient.GetCertClient())
+	Expect(certificateId).Should(Equal(""))
+	Expect(err).Should(BeNil())
+
+	name = "error"
+	certificateId, err = FindCertificateWithName(name, compartmentId, mockClient.GetCertClient())
+	Expect(certificateId).Should(Equal(""))
+	Expect(err).ShouldNot(BeNil())
+}
+
+func TestCreateImportedTypeCertificate(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	tlsSecretData := &TLSSecretData{
+		ServerCertificate:  common.String("serverCert"),
+		CaCertificateChain: common.String("certChain"),
+		PrivateKey:         common.String("privateKey"),
+	}
+	certificateName := "name"
+	compartmentId := "compartmentId"
+	cert, err := CreateImportedTypeCertificate(tlsSecretData, certificateName, compartmentId, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+	Expect(cert).ShouldNot(BeNil())
+
+	certificateName = "error"
+	cert, err = CreateImportedTypeCertificate(tlsSecretData, certificateName, compartmentId, mockClient.GetCertClient())
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+}
+
+func TestUpdateImportedTypeCertificate(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	tlsSecretData := &TLSSecretData{
+		ServerCertificate:  common.String("serverCert"),
+		CaCertificateChain: common.String("certChain"),
+		PrivateKey:         common.String("privateKey"),
+	}
+	certificateId := common.String("id")
+	cert, err := UpdateImportedTypeCertificate(certificateId, tlsSecretData, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+	Expect(cert).ShouldNot(BeNil())
+
+	*certificateId = "conflictError"
+	cert, err = UpdateImportedTypeCertificate(certificateId, tlsSecretData, mockClient.GetCertClient())
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+
+	*certificateId = "error"
+	cert, err = UpdateImportedTypeCertificate(certificateId, tlsSecretData, mockClient.GetCertClient())
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+}
+
+func TestScheduleCertificateVersionDeletion(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	certificateId := "id"
+	versionNumber := int64(2)
+	err = ScheduleCertificateVersionDeletion(certificateId, versionNumber, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+
+	certificateId = "error"
+	err = ScheduleCertificateVersionDeletion(certificateId, versionNumber, mockClient.GetCertClient())
+	Expect(err).ShouldNot(BeNil())
+}
+
+func TestPruneCertificateVersions(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	certificateId := "id"
+	currentVersion := int64(8)
+	err = PruneCertificateVersions(certificateId, currentVersion, 5, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+
+	certificateId = "error"
+	err = PruneCertificateVersions(certificateId, currentVersion, 5, mockClient.GetCertClient())
+	Expect(err).ShouldNot(BeNil())
+}
+
+func TestIsCertificateVersionFailed(t *testing.T) {
+	RegisterTestingT(t)
+
+	certVersionStages := []certificatesmanagement.VersionStageEnum{
+		certificatesmanagement.VersionStageLatest,
+		certificatesmanagement.VersionStageCurrent,
+	}
+	Expect(isCertificateVersionFailed(certVersionStages)).Should(BeFalse())
+
+	certVersionStages = []certificatesmanagement.VersionStageEnum{
+		certificatesmanagement.VersionStageLatest,
+		certificatesmanagement.VersionStageFailed,
+	}
+	Expect(isCertificateVersionFailed(certVersionStages)).Should(BeTrue())
+}
+
+func TestIsCertificateVersionCurrent(t *testing.T) {
+	RegisterTestingT(t)
+
+	certVersionStages := []certificatesmanagement.VersionStageEnum{
+		certificatesmanagement.VersionStageLatest,
+		certificatesmanagement.VersionStageCurrent,
+	}
+	Expect(isCertificateVersionCurrent(certVersionStages)).Should(BeTrue())
+
+	certVersionStages = []certificatesmanagement.VersionStageEnum{
+		certificatesmanagement.VersionStageLatest,
+		certificatesmanagement.VersionStageFailed,
+	}
+	Expect(isCertificateVersionCurrent(certVersionStages)).Should(BeFalse())
+}
+
+func TestCertificateVersionStagesContainsStage(t *testing.T) {
+	RegisterTestingT(t)
+
+	stages := []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageLatest, certificatesmanagement.VersionStageCurrent}
+	Expect(certificateVersionStagesContainsStage(stages, certificatesmanagement.VersionStageLatest)).Should(BeTrue())
+	Expect(certificateVersionStagesContainsStage(stages, certificatesmanagement.VersionStageCurrent)).Should(BeTrue())
+	Expect(certificateVersionStagesContainsStage(stages, certificatesmanagement.VersionStageFailed)).Should(BeFalse())
+	Expect(certificateVersionStagesContainsStage(stages, certificatesmanagement.VersionStagePrevious)).Should(BeFalse())
+}
+
+func TestGetCaBundle(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	caBundleId := "id"
+	caBundleErrorId := "error"
+
+	caBundle, etag, err := GetCaBundle(caBundleId, mockClient.GetCertClient())
+	Expect(caBundle != nil).Should(BeTrue())
+	Expect(etag).Should(Equal("etag"))
+	Expect(err).Should(BeNil())
+
+	// cache fetch
+	caBundle, etag, err = GetCaBundle(caBundleId, mockClient.GetCertClient())
+	Expect(caBundle != nil).Should(BeTrue())
+	Expect(etag).Should(Equal("etag"))
+	Expect(err).Should(BeNil())
+
+	caBundle, etag, err = GetCaBundle(caBundleErrorId, mockClient.GetCertClient())
+	Expect(caBundle).Should(BeNil())
+	Expect(etag).Should(Equal(""))
+	Expect(err).ShouldNot(BeNil())
+}
+
+func TestVerifyOrGetCaBundleIdByName(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	id := "id"
+	name := "caBundle"
+	compartmentId := "compartmentId"
+	actualCaBundleId, err := VerifyOrGetCaBundleIdByName(id, name, compartmentId, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+	Expect(*actualCaBundleId).Should(Equal(id))
+
+	actualCaBundleId, err = VerifyOrGetCaBundleIdByName("", name, compartmentId, mockClient.GetCertClient())
+	Expect(err).Should(BeNil())
+	Expect(*actualCaBundleId).ShouldNot(Equal(""))
+}
+
+func TestFindCaBundleWithName(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	name := "name"
+	compartmentId := "compartmentId"
+	caBundleId, err := FindCaBundleWithName(name, compartmentId, mockClient.GetCertClient())
+	Expect(*caBundleId).ShouldNot(BeNil())
+	Expect(err).Should(BeNil())
+
+	name = "nonexistent"
+	caBundleId, err = FindCaBundleWithName(name, compartmentId, mockClient.GetCertClient())
+	Expect(caBundleId).Should(BeNil())
+	Expect(err).Should(BeNil())
+
+	name = "error"
+	caBundleId, err = FindCaBundleWithName(name, compartmentId, mockClient.GetCertClient())
+	Expect(caBundleId).Should(BeNil())
+	Expect(err).ShouldNot(BeNil())
+}
+
+func TestCreateCaBundle(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	certificatesContent := common.String("certChain")
+	caBundleName := "name"
+	compartmentId := "compartmentId"
+	cert, err := CreateCaBundle(caBundleName, compartmentId, mockClient.GetCertClient(), certificatesContent)
+	Expect(err).Should(BeNil())
+	Expect(cert).ShouldNot(BeNil())
+
+	caBundleName = "error"
+	cert, err = CreateCaBundle(caBundleName, compartmentId, mockClient.GetCertClient(), certificatesContent)
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+}
+
+func TestUpdateCaBundle(t *testing.T) {
+	RegisterTestingT(t)
+	c, _, _ := initsUtil(&corev1.SecretList{})
+	mockClient, err := c.GetClient(&MockConfigGetter{})
+	Expect(err).Should(BeNil())
+
+	certificatesContent := common.String("certChain")
+	caBundleId := "id"
+	cert, err := UpdateCaBundle(caBundleId, mockClient.GetCertClient(), certificatesContent)
+	Expect(err).Should(BeNil())
+	Expect(cert).ShouldNot(BeNil())
+
+	caBundleId = "conflictError"
+	cert, err = UpdateCaBundle(caBundleId, mockClient.GetCertClient(), certificatesContent)
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+
+	caBundleId = "error"
+	cert, err = UpdateCaBundle(caBundleId, mockClient.GetCertClient(), certificatesContent)
+	Expect(err).ShouldNot(BeNil())
+	Expect(cert).Should(BeNil())
+}
diff --git a/pkg/controllers/ingress/ingress.go b/pkg/controllers/ingress/ingress.go
index 476bf0ba..92711f9e 100644
--- a/pkg/controllers/ingress/ingress.go
+++ b/pkg/controllers/ingress/ingress.go
@@ -13,6 +13,8 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/labels"
 	coreinformers "k8s.io/client-go/informers/core/v1"
 	"reflect"
 	"time"
@@ -56,6 +58,7 @@ type Controller struct {
 	ingressLister      networkinglisters.IngressLister
 	serviceLister      corelisters.ServiceLister
 	saLister           corelisters.ServiceAccountLister
+	secretLister       corelisters.SecretLister
 	queue              workqueue.RateLimitingInterface
 	informer           networkinginformers.IngressInformer
 	client             *client.ClientProvider
@@ -65,7 +68,7 @@ type Controller struct {
 // NewController creates a new Controller.
 func NewController(controllerClass string, defaultCompartmentId string,
 	ingressClassInformer networkinginformers.IngressClassInformer, ingressInformer networkinginformers.IngressInformer,
-	saInformer coreinformers.ServiceAccountInformer, serviceLister corelisters.ServiceLister,
+	saInformer coreinformers.ServiceAccountInformer, serviceLister corelisters.ServiceLister, secretInformer coreinformers.SecretInformer,
 	client *client.ClientProvider,
 	reg *prometheus.Registry) *Controller {
 
@@ -77,6 +80,7 @@ func NewController(controllerClass string, defaultCompartmentId string,
 		informer:             ingressInformer,
 		serviceLister:        serviceLister,
 		saLister:             saInformer.Lister(),
+		secretLister:         secretInformer.Lister(),
 		client:               client,
 		queue:                workqueue.NewRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(10*time.Second, 5*time.Minute)),
 		metricsCollector:     metric.NewIngressCollector(controllerClass, reg),
@@ -90,6 +94,13 @@ func NewController(controllerClass string, defaultCompartmentId string,
 		},
 	)
 
+	secretInformer.Informer().AddEventHandler(
+		cache.ResourceEventHandlerDetailedFuncs{
+			AddFunc:    c.secretAdd,
+			UpdateFunc: c.secretUpdate,
+		},
+	)
+
 	return c
 }
 
@@ -144,6 +155,37 @@ func (c *Controller) ingressDelete(obj interface{}) {
 	c.enqueueIngress(ic)
 }
 
+func (c *Controller) secretAdd(obj interface{}, isInInitialList bool) {
+	if isInInitialList {
+		return
+	}
+	c.secretAddOrUpdate(obj)
+}
+
+func (c *Controller) secretUpdate(old, new interface{}) {
+	c.secretAddOrUpdate(new)
+}
+
+func (c *Controller) secretAddOrUpdate(obj interface{}) {
+	secret := obj.(*corev1.Secret)
+
+	ingresses, err := c.ingressLister.Ingresses(secret.Namespace).List(labels.Everything())
+	if err != nil {
+		klog.Errorf("error listing Ingresses for update of secret %s/%s: %s", secret.Namespace, secret.Name, err)
+		return
+	}
+
+	for _, ingress := range ingresses {
+		for _, tls := range ingress.Spec.TLS {
+			if tls.SecretName == secret.Name {
+				klog.V(4).Infof("updating ingress %s because of secret %s",
+					klog.KObj(ingress), klog.KObj(secret))
+				c.enqueueIngress(ingress)
+			}
+		}
+	}
+}
+
 func (c *Controller) processNextItem() bool {
 	// Wait until there is a new item in the working queue
 	key, quit := c.queue.Get()
@@ -354,7 +396,7 @@ func (c *Controller) ensureIngress(ctx context.Context, ingress *networkingv1.In
 		startBuildTime := util.GetCurrentTimeInUnixMillis()
 		klog.V(2).InfoS("creating backend set for ingress", "ingress", klog.KObj(ingress), "backendSetName", bsName)
 		artifact, artifactType := stateStore.GetTLSConfigForBackendSet(bsName)
-		backendSetSslConfig, err := GetSSLConfigForBackendSet(ingress.Namespace, artifactType, artifact, lb, bsName, c.defaultCompartmentId, wrapperClient)
+		backendSetSslConfig, err := GetSSLConfigForBackendSet(ingress.Namespace, artifactType, artifact, lb, bsName, c.defaultCompartmentId, c.secretLister, wrapperClient)
 		if err != nil {
 			return err
 		}
@@ -389,7 +431,7 @@ func (c *Controller) ensureIngress(ctx context.Context, ingress *networkingv1.In
 
 		var listenerSslConfig *ociloadbalancer.SslConfigurationDetails
 		artifact, artifactType := stateStore.GetTLSConfigForListener(port)
-		listenerSslConfig, err := GetSSLConfigForListener(ingress.Namespace, nil, artifactType, artifact, c.defaultCompartmentId, wrapperClient)
+		listenerSslConfig, err := GetSSLConfigForListener(ingress.Namespace, nil, artifactType, artifact, c.defaultCompartmentId, c.secretLister, wrapperClient)
 		if err != nil {
 			return err
 		}
@@ -516,7 +558,7 @@ func syncListener(ctx context.Context, namespace string, stateStore *state.State
 	artifact, artifactType := stateStore.GetTLSConfigForListener(int32(*listener.Port))
 	var sslConfig *ociloadbalancer.SslConfigurationDetails
 	if artifact != "" {
-		sslConfig, err = GetSSLConfigForListener(namespace, &listener, artifactType, artifact, c.defaultCompartmentId, wrapperClient)
+		sslConfig, err = GetSSLConfigForListener(namespace, &listener, artifactType, artifact, c.defaultCompartmentId, c.secretLister, wrapperClient)
 		if err != nil {
 			return err
 		}
@@ -575,7 +617,7 @@ func syncBackendSet(ctx context.Context, ingress *networkingv1.Ingress, lbID str
 
 	needsUpdate := false
 	artifact, artifactType := stateStore.GetTLSConfigForBackendSet(*bs.Name)
-	sslConfig, err := GetSSLConfigForBackendSet(ingress.Namespace, artifactType, artifact, lb, *bs.Name, c.defaultCompartmentId, wrapperClient)
+	sslConfig, err := GetSSLConfigForBackendSet(ingress.Namespace, artifactType, artifact, lb, *bs.Name, c.defaultCompartmentId, c.secretLister, wrapperClient)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/controllers/ingress/ingressPathWithTlsSecret.yaml b/pkg/controllers/ingress/ingressPathWithTlsSecret.yaml
new file mode 100644
index 00000000..09547f36
--- /dev/null
+++ b/pkg/controllers/ingress/ingressPathWithTlsSecret.yaml
@@ -0,0 +1,22 @@
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: ingress-readiness
+  namespace: default
+spec:
+  tls:
+    - hosts:
+        - foo.bar.com
+      secretName: tls-secret
+  rules:
+    - host: "foo.bar.com"
+      http:
+        paths:
+          - pathType: Exact
+            path: "/testecho1"
+            backend:
+              service:
+                name: testecho1
+                port:
+                  number: 80
\ No newline at end of file
diff --git a/pkg/controllers/ingress/ingress_test.go b/pkg/controllers/ingress/ingress_test.go
index 8e9f8a6a..511c5cbf 100644
--- a/pkg/controllers/ingress/ingress_test.go
+++ b/pkg/controllers/ingress/ingress_test.go
@@ -2,6 +2,7 @@ package ingress
 
 import (
 	"context"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	coreinformers "k8s.io/client-go/informers/core/v1"
 	"sync"
 	"testing"
@@ -27,9 +28,10 @@ import (
 const (
 	ingressPath              = "ingressPath.yaml"
 	ingressPathWithFinalizer = "ingressPathWithFinalizer.yaml"
+	ingressPathWithTlsSecret = "ingressPathWithTlsSecret.yaml"
 )
 
-func setUp(ctx context.Context, ingressClassList *networkingv1.IngressClassList, ingressList *networkingv1.IngressList, testService *v1.ServiceList) (networkinginformers.IngressClassInformer, networkinginformers.IngressInformer, coreinformers.ServiceAccountInformer, corelisters.ServiceLister, *fakeclientset.Clientset) {
+func setUp(ctx context.Context, ingressClassList *networkingv1.IngressClassList, ingressList *networkingv1.IngressList, testService *v1.ServiceList) (networkinginformers.IngressClassInformer, networkinginformers.IngressInformer, coreinformers.ServiceAccountInformer, corelisters.ServiceLister, coreinformers.SecretInformer, *fakeclientset.Clientset) {
 	fakeClient := fakeclientset.NewSimpleClientset()
 	action := "list"
 
@@ -50,12 +52,16 @@ func setUp(ctx context.Context, ingressClassList *networkingv1.IngressClassList,
 	serviceInformer := informerFactory.Core().V1().Services()
 	serviceLister := serviceInformer.Lister()
 
+	secretInformer := informerFactory.Core().V1().Secrets()
+	secretInformer.Lister()
+
 	saInformer := informerFactory.Core().V1().ServiceAccounts()
 
 	informerFactory.Start(ctx.Done())
 	cache.WaitForCacheSync(ctx.Done(), ingressClassInformer.Informer().HasSynced)
 	cache.WaitForCacheSync(ctx.Done(), ingressInformer.Informer().HasSynced)
-	return ingressClassInformer, ingressInformer, saInformer, serviceLister, fakeClient
+	cache.WaitForCacheSync(ctx.Done(), secretInformer.Informer().HasSynced)
+	return ingressClassInformer, ingressInformer, saInformer, serviceLister, secretInformer, fakeClient
 }
 
 func inits(ctx context.Context, ingressClassList *networkingv1.IngressClassList, ingressList *networkingv1.IngressList) *Controller {
@@ -78,7 +84,7 @@ func inits(ctx context.Context, ingressClassList *networkingv1.IngressClassList,
 		CaBundleCache:      map[string]*ociclient.CaBundleCacheObj{},
 	}
 
-	ingressClassInformer, ingressInformer, saInformer, serviceLister, k8client := setUp(ctx, ingressClassList, ingressList, testService)
+	ingressClassInformer, ingressInformer, saInformer, serviceLister, secretInformer, k8client := setUp(ctx, ingressClassList, ingressList, testService)
 	wrapperClient := client.NewWrapperClient(k8client, nil, loadBalancerClient, certificatesClient, nil)
 	fakeClient := &client.ClientProvider{
 		K8sClient:           k8client,
@@ -86,7 +92,7 @@ func inits(ctx context.Context, ingressClassList *networkingv1.IngressClassList,
 		Cache:               NewMockCacheStore(wrapperClient),
 	}
 	c := NewController("oci.oraclecloud.com/native-ingress-controller", "", ingressClassInformer,
-		ingressInformer, saInformer, serviceLister, fakeClient, nil)
+		ingressInformer, saInformer, serviceLister, secretInformer, fakeClient, nil)
 	return c
 }
 
@@ -192,6 +198,42 @@ func TestIngressDelete(t *testing.T) {
 	Expect(c.queue.Len()).Should(Equal(queueSize + 1))
 }
 
+func TestSecretAdd(t *testing.T) {
+	RegisterTestingT(t)
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	ingressClassList := util.GetIngressClassList()
+	ingressList := util.ReadResourceAsIngressList(ingressPathWithTlsSecret)
+	c := inits(ctx, ingressClassList, ingressList)
+	queueSize := c.queue.Len()
+	c.secretAdd(&v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "tls-secret"}}, false)
+	Expect(c.queue.Len()).Should(Equal(queueSize + 1))
+}
+
+func TestSecretAdd_IsInInitialList(t *testing.T) {
+	RegisterTestingT(t)
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	ingressClassList := util.GetIngressClassList()
+	ingressList := util.ReadResourceAsIngressList(ingressPathWithTlsSecret)
+	c := inits(ctx, ingressClassList, ingressList)
+	queueSize := c.queue.Len()
+	c.secretAdd(&v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "tls-secret"}}, true)
+	Expect(c.queue.Len()).Should(Equal(queueSize))
+}
+
+func TestSecretUpdate(t *testing.T) {
+	RegisterTestingT(t)
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	ingressClassList := util.GetIngressClassList()
+	ingressList := util.ReadResourceAsIngressList(ingressPathWithTlsSecret)
+	c := inits(ctx, ingressClassList, ingressList)
+	queueSize := c.queue.Len()
+	c.secretUpdate(nil, &v1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "tls-secret"}})
+	Expect(c.queue.Len()).Should(Equal(queueSize + 1))
+}
+
 func TestProcessNextItem(t *testing.T) {
 	RegisterTestingT(t)
 	ctx, cancel := context.WithCancel(context.Background())
diff --git a/pkg/controllers/ingress/util.go b/pkg/controllers/ingress/util.go
index 309b6cb5..8383c11b 100644
--- a/pkg/controllers/ingress/util.go
+++ b/pkg/controllers/ingress/util.go
@@ -11,24 +11,28 @@ package ingress
 
 import (
 	"context"
+	"crypto/sha256"
 	"crypto/tls"
+	"encoding/hex"
 	"encoding/pem"
 	"errors"
 	"fmt"
-	"reflect"
-	"strings"
-	"time"
-
 	"github.com/oracle/oci-go-sdk/v65/certificates"
 	"github.com/oracle/oci-go-sdk/v65/certificatesmanagement"
 	ociloadbalancer "github.com/oracle/oci-go-sdk/v65/loadbalancer"
-	"github.com/oracle/oci-native-ingress-controller/pkg/certificate"
 	"github.com/oracle/oci-native-ingress-controller/pkg/client"
 	"github.com/oracle/oci-native-ingress-controller/pkg/state"
 	"github.com/oracle/oci-native-ingress-controller/pkg/util"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/client-go/kubernetes"
+	v1 "k8s.io/client-go/listers/core/v1"
 	"k8s.io/klog/v2"
+	"reflect"
+	"strings"
+)
+
+const (
+	certificateHashTagKey              = "oci-native-ingress-controller-certificate-hash"
+	caBundleHashTagKey                 = "oci-native-ingress-controller-ca-bundle-hash"
+	certificateVersionsToPreserveCount = 5
 )
 
 func compareHealthCheckers(healthCheckerDetails *ociloadbalancer.HealthCheckerDetails, healthChecker *ociloadbalancer.HealthChecker) bool {
@@ -57,154 +61,36 @@ func compareHttpHealthCheckerAttributes(healthCheckerDetails *ociloadbalancer.He
 		reflect.DeepEqual(healthCheckerDetails.IsForcePlainText, healthChecker.IsForcePlainText)
 }
 
-// SSL UTILS
-
-func CreateImportedTypeCertificate(caCertificatesChain *string, serverCertificate *string, privateKey *string, certificateName string, compartmentId string,
-	certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.Certificate, error) {
-	configDetails := certificatesmanagement.CreateCertificateByImportingConfigDetails{
-		CertChainPem:   caCertificatesChain,
-		CertificatePem: serverCertificate,
-		PrivateKeyPem:  privateKey,
-	}
+// SSL UTIL
 
-	certificateDetails := certificatesmanagement.CreateCertificateDetails{
-		Name:              &certificateName,
-		CertificateConfig: configDetails,
-		CompartmentId:     &compartmentId,
-	}
-	createCertificateRequest := certificatesmanagement.CreateCertificateRequest{
-		CreateCertificateDetails: certificateDetails,
-		OpcRetryToken:            &certificateName,
-	}
-
-	createCertificate, err := certificatesClient.CreateCertificate(context.TODO(), createCertificateRequest)
-	if err != nil {
-		return nil, err
-	}
-
-	certificatesClient.SetCertCache(createCertificate)
-	klog.Infof("Created a certificate with ocid %s", *createCertificate.Id)
-	return createCertificate, nil
-}
-
-func GetCertificate(certificateId *string, certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.Certificate, error) {
-	certCacheObj := certificatesClient.GetFromCertCache(*certificateId)
-	if certCacheObj != nil {
-		now := time.Now()
-		if now.Sub(certCacheObj.Age).Minutes() < util.CertificateCacheMaxAgeInMinutes {
-			return certCacheObj.Cert, nil
-		}
-		klog.Infof("Refreshing certificate %s", *certificateId)
-	}
-	getCertificateRequest := certificatesmanagement.GetCertificateRequest{
-		CertificateId: certificateId,
-	}
-
-	cert, err := certificatesClient.GetCertificate(context.TODO(), getCertificateRequest)
-	if err == nil {
-		certificatesClient.SetCertCache(cert)
-	}
-	return cert, err
-}
-
-func FindCertificateWithName(certificateName string, compartmentId string,
-	certificatesClient *certificate.CertificatesClient) (*string, error) {
-	listCertificatesRequest := certificatesmanagement.ListCertificatesRequest{
-		Name:           &certificateName,
-		CompartmentId:  &compartmentId,
-		LifecycleState: certificatesmanagement.ListCertificatesLifecycleStateActive,
-	}
-
-	klog.Infof("Searching for certificates with name %s in compartment %s.", certificateName, compartmentId)
-	listCertificates, _, err := certificatesClient.ListCertificates(context.TODO(), listCertificatesRequest)
-	if err != nil {
-		return nil, err
-	}
-
-	if listCertificates.Items != nil {
-		numberOfCertificates := len(listCertificates.Items)
-		klog.Infof("Found %d certificates with name %s in compartment %s.", numberOfCertificates, certificateName, compartmentId)
-		if numberOfCertificates > 0 {
-			return listCertificates.Items[0].Id, nil
-		}
-	}
-	klog.Infof("Found no certificates with name %s in compartment %s.", certificateName, compartmentId)
-	return nil, nil
-}
-
-func FindCaBundleWithName(certificateName string, compartmentId string,
-	certificatesClient *certificate.CertificatesClient) (*string, error) {
-	listCaBundlesRequest := certificatesmanagement.ListCaBundlesRequest{
-		Name:           &certificateName,
-		CompartmentId:  &compartmentId,
-		LifecycleState: certificatesmanagement.ListCaBundlesLifecycleStateActive,
-	}
-
-	klog.Infof("Searching for ca bundles with name %s in compartment %s.", certificateName, compartmentId)
-	listCaBundles, err := certificatesClient.ListCaBundles(context.TODO(), listCaBundlesRequest)
-	if err != nil {
-		return nil, err
-	}
-
-	if listCaBundles.Items != nil {
-		numberOfCertificates := len(listCaBundles.Items)
-		klog.Infof("Found %d bundles with name %s in compartment %s.", numberOfCertificates, certificateName, compartmentId)
-		if numberOfCertificates > 0 {
-			return listCaBundles.Items[0].Id, nil
-		}
-	}
-	klog.Infof("Found no bundles with name %s in compartment %s.", certificateName, compartmentId)
-	return nil, nil
+type TLSSecretData struct {
+	// This would hold server certificate and any chain of trust.
+	CaCertificateChain *string
+	ServerCertificate  *string
+	PrivateKey         *string
 }
 
-func GetCaBundle(caBundleId string, certificatesClient *certificate.CertificatesClient) (*certificatesmanagement.CaBundle, error) {
-	caBundleCacheObj := certificatesClient.GetFromCaBundleCache(caBundleId)
-	if caBundleCacheObj != nil {
-		return caBundleCacheObj.CaBundle, nil
-	}
-
-	klog.Infof("Getting ca bundle for id %s.", caBundleId)
-	getCaBundleRequest := certificatesmanagement.GetCaBundleRequest{
-		CaBundleId: &caBundleId,
+func hashPublicTlsData(data *TLSSecretData) string {
+	concatString := ""
+	if data != nil && data.CaCertificateChain != nil {
+		concatString = concatString + *data.CaCertificateChain
 	}
-
-	caBundle, err := certificatesClient.GetCaBundle(context.TODO(), getCaBundleRequest)
-
-	if err == nil {
-		certificatesClient.SetCaBundleCache(caBundle)
+	if data != nil && data.ServerCertificate != nil {
+		concatString = concatString + *data.ServerCertificate
 	}
-	return caBundle, err
+	return hashString(&concatString)
 }
 
-func CreateCaBundle(certificateName string, compartmentId string, certificatesClient *certificate.CertificatesClient,
-	certificateContents *string) (*certificatesmanagement.CaBundle, error) {
-	caBundleDetails := certificatesmanagement.CreateCaBundleDetails{
-		Name:          &certificateName,
-		CompartmentId: &compartmentId,
-		CaBundlePem:   certificateContents,
-	}
-	createCaBundleRequest := certificatesmanagement.CreateCaBundleRequest{
-		CreateCaBundleDetails: caBundleDetails,
-		OpcRetryToken:         &certificateName,
+func hashString(data *string) string {
+	h := sha256.New()
+	if data != nil {
+		h.Write([]byte(*data))
 	}
-	createCaBundle, err := certificatesClient.CreateCaBundle(context.TODO(), createCaBundleRequest)
-	if err != nil {
-		return nil, err
-	}
-
-	certificatesClient.SetCaBundleCache(createCaBundle)
-	return createCaBundle, nil
+	return hex.EncodeToString(h.Sum(nil))
 }
 
-type TLSSecretData struct {
-	// This would hold server certificate and any chain of trust.
-	CaCertificateChain *string
-	ServerCertificate  *string
-	PrivateKey         *string
-}
-
-func getTlsSecretContent(namespace string, secretName string, client kubernetes.Interface) (*TLSSecretData, error) {
-	secret, err := client.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
+func getTlsSecretContent(namespace string, secretName string, secretLister v1.SecretLister) (*TLSSecretData, error) {
+	secret, err := secretLister.Secrets(namespace).Get(secretName)
 	if err != nil {
 		return nil, err
 	}
@@ -247,47 +133,40 @@ func splitLeafAndCaCertChain(certChainPEMBlock []byte, keyPEMBlock []byte) (stri
 	return leafCertString, caCertChainString, nil
 }
 
-func getCertificateNameFromSecret(secretName string) string {
+func getCertificateNameFromSecret(namespace string, secretName string, secretLister v1.SecretLister) (string, error) {
 	if secretName == "" {
-		return ""
+		return "", nil
+	}
+
+	secret, err := secretLister.Secrets(namespace).Get(secretName)
+	if err != nil {
+		return "", fmt.Errorf("unable to GET secret %s: %w", klog.KRef(namespace, secretName), err)
 	}
-	return fmt.Sprintf("ic-%s", secretName)
+
+	return fmt.Sprintf("oci-nic-%s", secret.UID), nil
 }
 
-func GetSSLConfigForBackendSet(namespace string, artifactType string, artifact string, lb *ociloadbalancer.LoadBalancer, bsName string, compartmentId string, client *client.WrapperClient) (*ociloadbalancer.SslConfigurationDetails, error) {
+func GetSSLConfigForBackendSet(namespace string, artifactType string, artifact string, lb *ociloadbalancer.LoadBalancer, bsName string,
+	compartmentId string, secretLister v1.SecretLister, client *client.WrapperClient) (*ociloadbalancer.SslConfigurationDetails, error) {
 	var backendSetSslConfig *ociloadbalancer.SslConfigurationDetails
-	createCaBundle := false
 	var caBundleId *string
 
 	bs, ok := lb.BackendSets[bsName]
 
 	if artifactType == state.ArtifactTypeSecret && artifact != "" {
 		klog.Infof("Secret name for backend set %s is %s", bsName, artifact)
-		if ok && bs.SslConfiguration != nil && isTrustAuthorityCaBundle(bs.SslConfiguration.TrustedCertificateAuthorityIds[0]) {
-			newCertificateName := getCertificateNameFromSecret(artifact)
-			caBundle, err := GetCaBundle(bs.SslConfiguration.TrustedCertificateAuthorityIds[0], client.GetCertClient())
-			if err != nil {
-				return nil, err
-			}
 
-			klog.Infof("Ca bundle name is %s, new certificate name is %s", *caBundle.Name, newCertificateName)
-			if *caBundle.Name != newCertificateName {
-				klog.Infof("Ca bundle for backend set %s needs update. Old name %s, New name %s", *bs.Name, *caBundle.Name, newCertificateName)
-				createCaBundle = true
-			} else {
-				caBundleId = caBundle.Id
-			}
-		} else {
-			createCaBundle = true
+		currentCaBundleId := ""
+		if ok && bs.SslConfiguration != nil && len(bs.SslConfiguration.TrustedCertificateAuthorityIds) > 0 &&
+			isTrustAuthorityCaBundle(bs.SslConfiguration.TrustedCertificateAuthorityIds[0]) {
+			currentCaBundleId = bs.SslConfiguration.TrustedCertificateAuthorityIds[0]
 		}
 
-		if createCaBundle {
-			cId, err := CreateOrGetCaBundleForBackendSet(namespace, artifact, compartmentId, client)
-			if err != nil {
-				return nil, err
-			}
-			caBundleId = cId
+		newCaBundleId, err := ensureCaBundleForBackendSet(currentCaBundleId, namespace, artifact, compartmentId, secretLister, client)
+		if err != nil {
+			return nil, err
 		}
+		caBundleId = newCaBundleId
 
 		if caBundleId != nil {
 			caBundleIds := []string{*caBundleId}
@@ -296,7 +175,7 @@ func GetSSLConfigForBackendSet(namespace string, artifactType string, artifact s
 	}
 
 	if artifactType == state.ArtifactTypeCertificate && artifact != "" {
-		cert, err := GetCertificate(&artifact, client.GetCertClient())
+		cert, _, err := GetCertificate(&artifact, client.GetCertClient())
 		if err != nil {
 			return nil, err
 		}
@@ -338,42 +217,27 @@ func GetSSLConfigForBackendSet(namespace string, artifactType string, artifact s
 	return backendSetSslConfig, nil
 }
 
-func GetSSLConfigForListener(namespace string, listener *ociloadbalancer.Listener, artifactType string, artifact string, compartmentId string, client *client.WrapperClient) (*ociloadbalancer.SslConfigurationDetails, error) {
+func GetSSLConfigForListener(namespace string, listener *ociloadbalancer.Listener, artifactType string, artifact string,
+	compartmentId string, secretLister v1.SecretLister, client *client.WrapperClient) (*ociloadbalancer.SslConfigurationDetails, error) {
 	var currentCertificateId string
 	var newCertificateId string
-	createCertificate := false
 
 	var listenerSslConfig *ociloadbalancer.SslConfigurationDetails
 
-	if listener != nil && listener.SslConfiguration != nil {
+	if listener != nil && listener.SslConfiguration != nil && len(listener.SslConfiguration.CertificateIds) > 0 {
 		currentCertificateId = listener.SslConfiguration.CertificateIds[0]
-		if state.ArtifactTypeCertificate == artifactType && currentCertificateId != artifact {
-			newCertificateId = artifact
-		} else if state.ArtifactTypeSecret == artifactType {
-			cert, err := GetCertificate(&currentCertificateId, client.GetCertClient())
-			if err != nil {
-				return nil, err
-			}
-			certificateName := getCertificateNameFromSecret(artifact)
-			if certificateName != "" && *cert.Name != certificateName {
-				createCertificate = true
-			}
-		}
-	} else {
-		if state.ArtifactTypeSecret == artifactType {
-			createCertificate = true
-		}
-		if state.ArtifactTypeCertificate == artifactType {
-			newCertificateId = artifact
-		}
 	}
 
-	if createCertificate {
-		cId, err := CreateOrGetCertificateForListener(namespace, artifact, compartmentId, client)
+	if state.ArtifactTypeCertificate == artifactType {
+		newCertificateId = artifact
+	}
+
+	if state.ArtifactTypeSecret == artifactType && artifact != "" {
+		cId, err := ensureCertificateForListener(currentCertificateId, namespace, artifact, compartmentId, secretLister, client)
 		if err != nil {
 			return nil, err
 		}
-		newCertificateId = *cId
+		newCertificateId = cId
 	}
 
 	if newCertificateId != "" {
@@ -383,48 +247,104 @@ func GetSSLConfigForListener(namespace string, listener *ociloadbalancer.Listene
 	return listenerSslConfig, nil
 }
 
-func CreateOrGetCertificateForListener(namespace string, secretName string, compartmentId string, client *client.WrapperClient) (*string, error) {
-	certificateName := getCertificateNameFromSecret(secretName)
-	certificateId, err := FindCertificateWithName(certificateName, compartmentId, client.GetCertClient())
+// ensureCertificateForListener creates/updates a certificate for Listeners, when the artifact is of type secret
+// inputCertificateId is optional, pass if trying to update a certificate, name of certificate will still be checked
+func ensureCertificateForListener(inputCertificateId string, namespace string, secretName string, compartmentId string, secretLister v1.SecretLister, client *client.WrapperClient) (string, error) {
+	certificateName, err := getCertificateNameFromSecret(namespace, secretName, secretLister)
 	if err != nil {
-		return nil, err
+		return "", err
+	}
+
+	tlsSecretData, err := getTlsSecretContent(namespace, secretName, secretLister)
+	if err != nil {
+		return "", err
+	}
+
+	certificateId, err := VerifyOrGetCertificateIdByName(inputCertificateId, certificateName, compartmentId, client.GetCertClient())
+	if err != nil {
+		return "", nil
 	}
 
-	if certificateId == nil {
-		tlsSecretData, err := getTlsSecretContent(namespace, secretName, client.GetK8Client())
+	if certificateId == "" {
+		klog.Infof("Need to create certificate for secret %s", klog.KRef(namespace, secretName))
+		createCertificate, err := CreateImportedTypeCertificate(tlsSecretData, certificateName, compartmentId, client.GetCertClient())
 		if err != nil {
-			return nil, err
+			return "", err
 		}
 
-		createCertificate, err := CreateImportedTypeCertificate(tlsSecretData.CaCertificateChain, tlsSecretData.ServerCertificate,
-			tlsSecretData.PrivateKey, certificateName, compartmentId, client.GetCertClient())
+		certificateId = *createCertificate.Id
+	} else {
+		cert, _, err := GetCertificate(&certificateId, client.GetCertClient())
 		if err != nil {
-			return nil, err
+			return "", err
 		}
 
-		certificateId = createCertificate.Id
+		if cert.FreeformTags == nil || hashPublicTlsData(tlsSecretData) != cert.FreeformTags[certificateHashTagKey] {
+			klog.Infof("Need to update certificate %s for secret %s", certificateId, klog.KRef(namespace, secretName))
+			cert, err = UpdateImportedTypeCertificate(&certificateId, tlsSecretData, client.GetCertClient())
+			if err != nil {
+				return "", err
+			}
+
+			klog.Infof("Pruning Certificate %s for stale versions", certificateId)
+			err = PruneCertificateVersions(certificateId, *cert.CurrentVersion.VersionNumber, certificateVersionsToPreserveCount, client.GetCertClient())
+			if err != nil {
+				klog.Errorf("Unable to prune certificate %s for stale versions: %s", certificateId, err.Error())
+			}
+		}
+
+		if !isCertificateCurrentVersionLatest(cert) {
+			klog.Warningf("For certificate %s, current version detected is not the latest one. "+
+				"Please update secret %s to have the latest desired details.", certificateId, klog.KRef(namespace, secretName))
+			if cert.LifecycleDetails != nil {
+				klog.Warningf("Lifecycle details for certificate %s: %s", certificateId, *cert.LifecycleDetails)
+			}
+		}
 	}
+
 	return certificateId, nil
 }
 
-func CreateOrGetCaBundleForBackendSet(namespace string, secretName string, compartmentId string, client *client.WrapperClient) (*string, error) {
-	certificateName := getCertificateNameFromSecret(secretName)
-	caBundleId, err := FindCaBundleWithName(certificateName, compartmentId, client.GetCertClient())
+func ensureCaBundleForBackendSet(inputCaBundleId string, namespace string, secretName string, compartmentId string, secretLister v1.SecretLister, client *client.WrapperClient) (*string, error) {
+	caBundleName, err := getCertificateNameFromSecret(namespace, secretName, secretLister)
+	if err != nil {
+		return nil, err
+	}
+
+	tlsSecretData, err := getTlsSecretContent(namespace, secretName, secretLister)
+	if err != nil {
+		return nil, err
+	}
+
+	caBundleId, err := VerifyOrGetCaBundleIdByName(inputCaBundleId, caBundleName, compartmentId, client.GetCertClient())
 	if err != nil {
 		return nil, err
 	}
 
 	if caBundleId == nil {
-		tlsSecretData, err := getTlsSecretContent(namespace, secretName, client.GetK8Client())
+		klog.Infof("Need to create ca bundle for secret %s", klog.KRef(namespace, secretName))
+		createCaBundle, err := CreateCaBundle(caBundleName, compartmentId, client.GetCertClient(), tlsSecretData.CaCertificateChain)
 		if err != nil {
 			return nil, err
 		}
-		createCaBundle, err := CreateCaBundle(certificateName, compartmentId, client.GetCertClient(), tlsSecretData.CaCertificateChain)
+
+		caBundleId = createCaBundle.Id
+	} else {
+		caBundle, _, err := GetCaBundle(*caBundleId, client.GetCertClient())
 		if err != nil {
 			return nil, err
 		}
-		caBundleId = createCaBundle.Id
+
+		if caBundle.FreeformTags == nil || hashString(tlsSecretData.CaCertificateChain) != caBundle.FreeformTags[caBundleHashTagKey] {
+			klog.Infof("Detected hash mismatch for ca bundle related to secret %s, will update ca bundle %s",
+				klog.KRef(namespace, secretName), *caBundle.Id)
+			_, err = UpdateCaBundle(*caBundleId, client.GetCertClient(), tlsSecretData.CaCertificateChain)
+			if err != nil {
+				return nil, err
+			}
+		}
 	}
+
 	return caBundleId, nil
 }
 
@@ -445,3 +365,12 @@ func backendSetSslConfigNeedsUpdate(calculatedConfig *ociloadbalancer.SslConfigu
 
 	return false
 }
+
+func isCertificateCurrentVersionLatest(cert *certificatesmanagement.Certificate) bool {
+	for _, stage := range cert.CurrentVersion.Stages {
+		if stage == certificatesmanagement.VersionStageLatest {
+			return true
+		}
+	}
+	return false
+}
diff --git a/pkg/controllers/ingress/util_test.go b/pkg/controllers/ingress/util_test.go
index 57f99b91..74137da8 100644
--- a/pkg/controllers/ingress/util_test.go
+++ b/pkg/controllers/ingress/util_test.go
@@ -17,6 +17,12 @@ import (
 	"crypto/x509/pkix"
 	"encoding/pem"
 	"errors"
+	"github.com/oracle/oci-native-ingress-controller/pkg/exception"
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/informers"
+	corelisters "k8s.io/client-go/listers/core/v1"
+	"k8s.io/client-go/tools/cache"
 	"math/big"
 	"net"
 	"net/http"
@@ -128,13 +134,20 @@ const (
 	errorImportCert = "errorImportCert"
 )
 
-func initsUtil() (*client.ClientProvider, ociloadbalancer.LoadBalancer) {
+func getSecretListerForSecretList(list *corev1.SecretList) corelisters.SecretLister {
 	k8client := fakeclientset.NewSimpleClientset()
-	secret := util.GetSampleCertSecret("test", "oci-cert", "chain", "cert", "key")
-	action := "get"
-	resource := "secrets"
-	obj := secret
-	util.FakeClientGetCall(k8client, action, resource, obj)
+	util.FakeClientGetCall(k8client, "list", "secrets", list)
+	informerFactory := informers.NewSharedInformerFactory(k8client, 0)
+	secretInformer := informerFactory.Core().V1().Secrets()
+	secretInformer.Lister()
+	informerFactory.Start(context.Background().Done())
+	cache.WaitForCacheSync(context.Background().Done(), secretInformer.Informer().HasSynced)
+	return secretInformer.Lister()
+}
+
+func initsUtil(secretList *corev1.SecretList) (*client.ClientProvider, ociloadbalancer.LoadBalancer, corelisters.SecretLister) {
+	k8client := fakeclientset.NewSimpleClientset()
+	secretLister := getSecretListerForSecretList(secretList)
 
 	certClient := GetCertClient()
 	certManageClient := GetCertManageClient()
@@ -201,36 +214,56 @@ func initsUtil() (*client.ClientProvider, ociloadbalancer.LoadBalancer) {
 		DefaultConfigGetter: &MockConfigGetter{},
 		Cache:               NewMockCacheStore(wrapperClient),
 	}
-	return mockClient, lb
+	return mockClient, lb, secretLister
+}
+
+func TestHashPublicTlsData(t *testing.T) {
+	RegisterTestingT(t)
+
+	tlsData := TLSSecretData{
+		CaCertificateChain: common.String("ca-cert-chain"),
+		ServerCertificate:  common.String("server-cert"),
+		PrivateKey:         common.String("server-key"),
+	}
+
+	hashedString := hashPublicTlsData(&tlsData)
+	Expect(hashedString).Should(Equal("e6920702515dc87338e84377a9d9fb985c2a7c7140c4518217831e9fbbd7cb43"))
+
+	// Ensure it is consistent
+	Expect(hashPublicTlsData(&tlsData)).Should(Equal(hashedString))
 }
 
 func TestGetSSLConfigForBackendSet(t *testing.T) {
 	RegisterTestingT(t)
-	c, lb := initsUtil()
+	c, lb, secretLister := initsUtil(&corev1.SecretList{
+		Items: []corev1.Secret{
+			*util.GetSampleCertSecret(namespace, "oci-config", "chain", "cert", "key"),
+		},
+	})
 	mockClient, err := c.GetClient(&MockConfigGetter{})
 	Expect(err).Should(BeNil())
 
-	config, err := GetSSLConfigForBackendSet(namespace, state.ArtifactTypeSecret, "oci-config", &lb, "testecho1", "", mockClient)
+	config, err := GetSSLConfigForBackendSet(namespace, state.ArtifactTypeSecret, "oci-config", &lb, "testecho1", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(config != nil).Should(BeTrue())
 
-	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, string(certificatesmanagement.CertificateConfigTypeIssuedByInternalCa), &lb, "testecho1", "", mockClient)
+	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, string(certificatesmanagement.CertificateConfigTypeIssuedByInternalCa), &lb, "testecho1", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(config != nil).Should(BeTrue())
 
-	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, string(certificatesmanagement.CertificateConfigTypeManagedExternallyIssuedByInternalCa), &lb, "testecho1", "", mockClient)
+	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, string(certificatesmanagement.CertificateConfigTypeManagedExternallyIssuedByInternalCa), &lb, "testecho1", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(config != nil).Should(BeTrue())
 
-	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, string(certificatesmanagement.CertificateConfigTypeImported), &lb, "testecho1", "", mockClient)
+	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, string(certificatesmanagement.CertificateConfigTypeImported), &lb, "testecho1", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(config != nil).Should(BeTrue())
 
 	// No ca bundle scenario
-	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, errorImportCert, &lb, "testecho1", "", mockClient)
+	config, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, errorImportCert, &lb, "testecho1", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 
-	_, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, "error", &lb, "testecho1", "", mockClient)
+	_, err = GetSSLConfigForBackendSet(namespace, state.ArtifactTypeCertificate, "error", &lb, "testecho1", "", secretLister, mockClient)
 	Expect(err).Should(Not(BeNil()))
 	Expect(err.Error()).Should(Equal(errorMsg))
 
@@ -238,19 +271,27 @@ func TestGetSSLConfigForBackendSet(t *testing.T) {
 
 func TestGetSSLConfigForListener(t *testing.T) {
 	RegisterTestingT(t)
-	c, _ := initsUtil()
+
+	secretList := &corev1.SecretList{
+		Items: []corev1.Secret{
+			*util.GetSampleCertSecret(namespace, "secret", "chain", "cert", "key"),
+			*util.GetSampleCertSecret(namespace, "secret-cert", "chain", "cert", "key"),
+		},
+	}
+
+	c, _, secretLister := initsUtil(secretList)
 	mockClient, err := c.GetClient(&MockConfigGetter{})
 	Expect(err).Should(BeNil())
 
 	//no listener for cert
-	sslConfig, err := GetSSLConfigForListener(namespace, nil, state.ArtifactTypeCertificate, "certificate", "", mockClient)
+	sslConfig, err := GetSSLConfigForListener(namespace, nil, state.ArtifactTypeCertificate, "certificate", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(sslConfig != nil).Should(BeTrue())
 	Expect(len(sslConfig.CertificateIds)).Should(Equal(1))
 	Expect(sslConfig.CertificateIds[0]).Should(Equal("certificate"))
 
 	//no listener for secret
-	sslConfig, err = GetSSLConfigForListener(namespace, nil, state.ArtifactTypeSecret, "secret", "", mockClient)
+	sslConfig, err = GetSSLConfigForListener(namespace, nil, state.ArtifactTypeSecret, "secret", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(sslConfig != nil).Should(BeTrue())
 	Expect(len(sslConfig.CertificateIds)).Should(Equal(1))
@@ -265,14 +306,14 @@ func TestGetSSLConfigForListener(t *testing.T) {
 	listener := ociloadbalancer.Listener{
 		SslConfiguration: &customSslConfig,
 	}
-	sslConfig, err = GetSSLConfigForListener(namespace, &listener, state.ArtifactTypeCertificate, "certificate", "", mockClient)
+	sslConfig, err = GetSSLConfigForListener(namespace, &listener, state.ArtifactTypeCertificate, "certificate", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(sslConfig != nil).Should(BeTrue())
 	Expect(len(sslConfig.CertificateIds)).Should(Equal(1))
 	Expect(sslConfig.CertificateIds[0]).Should(Equal("certificate"))
 
 	// Listener + secret
-	sslConfig, err = GetSSLConfigForListener(namespace, &listener, state.ArtifactTypeSecret, "secret-cert", "", mockClient)
+	sslConfig, err = GetSSLConfigForListener(namespace, &listener, state.ArtifactTypeSecret, "secret-cert", "", secretLister, mockClient)
 	Expect(err).Should(BeNil())
 	Expect(sslConfig != nil).Should(BeTrue())
 	Expect(len(sslConfig.CertificateIds)).Should(Equal(1))
@@ -280,29 +321,6 @@ func TestGetSSLConfigForListener(t *testing.T) {
 
 }
 
-func TestGetCertificate(t *testing.T) {
-	RegisterTestingT(t)
-	c, _ := initsUtil()
-	mockClient, err := c.GetClient(&MockConfigGetter{})
-	Expect(err).Should(BeNil())
-
-	certId := "id"
-	certId2 := "id2"
-
-	certificate, err := GetCertificate(&certId, mockClient.GetCertClient())
-	Expect(certificate != nil).Should(BeTrue())
-	Expect(err).Should(BeNil())
-
-	// cache fetch
-	certificate, err = GetCertificate(&certId, mockClient.GetCertClient())
-	Expect(certificate != nil).Should(BeTrue())
-	Expect(err).Should(BeNil())
-
-	certificate, err = GetCertificate(&certId2, mockClient.GetCertClient())
-	Expect(certificate != nil).Should(BeTrue())
-	Expect(err).Should(BeNil())
-}
-
 func TestGetTlsSecretContent(t *testing.T) {
 	RegisterTestingT(t)
 
@@ -313,28 +331,36 @@ func TestGetTlsSecretContent(t *testing.T) {
 	secretWithWrongChain := util.GetSampleCertSecret("test", "secretWithWrongChain", "", testCaChain+testCert, testKey)
 	secretWithoutCaCrt := util.GetSampleCertSecret("test", "secretWithoutCaCrt", "", testCert, testKey)
 
-	k8client := fakeclientset.NewSimpleClientset()
-	util.FakeClientGetCall(k8client, "get", "secrets", secretWithCaCrt)
+	secretList := &corev1.SecretList{
+		Items: []corev1.Secret{
+			*secretWithCaCrt,
+			*secretWithCorrectChain,
+			*secretWithWrongChain,
+			*secretWithoutCaCrt,
+		},
+	}
 
-	secretData1, err := getTlsSecretContent("test", "secretWithCaCrt", k8client)
+	secretLister := getSecretListerForSecretList(secretList)
+
+	secretData1, err := getTlsSecretContent("test", "secretWithCaCrt", secretLister)
 	Expect(err).ToNot(HaveOccurred())
 	Expect(*secretData1.CaCertificateChain).To(Equal(testCaChain))
 	Expect(*secretData1.ServerCertificate).To(Equal(testCert))
 	Expect(*secretData1.PrivateKey).To(Equal(testKey))
 
-	util.FakeClientGetCall(k8client, "get", "secrets", secretWithCorrectChain)
-	secretData2, err := getTlsSecretContent("test", "secretWithCorrectChain", k8client)
+	secretData2, err := getTlsSecretContent("test", "secretWithCorrectChain", secretLister)
 	Expect(err).ToNot(HaveOccurred())
 	Expect(*secretData2.CaCertificateChain).To(Equal(testCaChain))
 	Expect(*secretData2.ServerCertificate).To(Equal(testCert))
 	Expect(*secretData2.PrivateKey).To(Equal(testKey))
 
-	util.FakeClientGetCall(k8client, "get", "secrets", secretWithWrongChain)
-	_, err = getTlsSecretContent("test", "secretWithWrongChain", k8client)
+	_, err = getTlsSecretContent("test", "secretWithWrongChain", secretLister)
+	Expect(err).To(HaveOccurred())
+
+	_, err = getTlsSecretContent("test", "secretWithoutCaCrt", secretLister)
 	Expect(err).To(HaveOccurred())
 
-	util.FakeClientGetCall(k8client, "get", "secrets", secretWithoutCaCrt)
-	_, err = getTlsSecretContent("test", "secretWithoutCaCrt", k8client)
+	_, err = getTlsSecretContent("test", "nonexistent", secretLister)
 	Expect(err).To(HaveOccurred())
 }
 
@@ -395,6 +421,58 @@ func TestBackendSetSslConfigNeedsUpdate(t *testing.T) {
 	Expect(backendSetSslConfigNeedsUpdate(calculatedConfig1, backendSetWithNilSslConfig)).To(BeTrue())
 }
 
+func TestGetCertificateNameFromSecret(t *testing.T) {
+	RegisterTestingT(t)
+
+	secret := &corev1.Secret{
+		ObjectMeta: v1.ObjectMeta{
+			Name:      "secret",
+			Namespace: "namespace",
+			UID:       "uid",
+		},
+	}
+
+	secretList := &corev1.SecretList{
+		Items: []corev1.Secret{
+			*secret,
+		},
+	}
+
+	secretLister := getSecretListerForSecretList(secretList)
+
+	secretName, err := getCertificateNameFromSecret("namespace", "", secretLister)
+	Expect(err).To(BeNil())
+	Expect(secretName).To(Equal(""))
+
+	secretName, err = getCertificateNameFromSecret("namespace", "nonexistent", secretLister)
+	Expect(err).ToNot(BeNil())
+	Expect(secretName).To(Equal(""))
+
+	secretName, err = getCertificateNameFromSecret("namespace", "secret", secretLister)
+	Expect(err).To(BeNil())
+	Expect(secretName).To(Equal("oci-nic-uid"))
+}
+
+func TestIsCertificateCurrentVersionLatest(t *testing.T) {
+	RegisterTestingT(t)
+
+	cert := &certificatesmanagement.Certificate{
+		CurrentVersion: &certificatesmanagement.CertificateVersionSummary{
+			Stages: []certificatesmanagement.VersionStageEnum{
+				certificatesmanagement.VersionStageCurrent,
+				certificatesmanagement.VersionStageFailed,
+			},
+		},
+	}
+	Expect(isCertificateCurrentVersionLatest(cert)).To(BeFalse())
+
+	cert.CurrentVersion.Stages = []certificatesmanagement.VersionStageEnum{
+		certificatesmanagement.VersionStageCurrent,
+		certificatesmanagement.VersionStageLatest,
+	}
+	Expect(isCertificateCurrentVersionLatest(cert)).To(BeTrue())
+}
+
 func generateTestCertsAndKey() (string, string, string) {
 	caCert := &x509.Certificate{
 		SerialNumber: big.NewInt(1),
@@ -439,13 +517,18 @@ type MockCertificateManagerClient struct {
 }
 
 func (m MockCertificateManagerClient) CreateCertificate(ctx context.Context, request certificatesmanagement.CreateCertificateRequest) (certificatesmanagement.CreateCertificateResponse, error) {
+	if *request.Name == "error" {
+		return certificatesmanagement.CreateCertificateResponse{}, errors.New("cert create error")
+	}
+
 	id := "id"
+	etag := "etag"
 	return certificatesmanagement.CreateCertificateResponse{
 		RawResponse: nil,
 		Certificate: certificatesmanagement.Certificate{
 			Id: &id,
 		},
-		Etag:         nil,
+		Etag:         &etag,
 		OpcRequestId: &id,
 	}, nil
 }
@@ -458,9 +541,10 @@ func (m MockCertificateManagerClient) GetCertificate(ctx context.Context, reques
 	id := "id"
 	name := "cert"
 	authorityId := "authId"
+	etag := "etag"
 	var confType certificatesmanagement.CertificateConfigTypeEnum
 	if *request.CertificateId == errorImportCert {
-		name = "error"
+		name = "errorImportCert"
 		confType = certificatesmanagement.CertificateConfigTypeImported
 	} else {
 		confType, _ = certificatesmanagement.GetMappingCertificateConfigTypeEnum(*request.CertificateId)
@@ -478,22 +562,49 @@ func (m MockCertificateManagerClient) GetCertificate(ctx context.Context, reques
 			ConfigType:                   confType,
 			IssuerCertificateAuthorityId: &authorityId,
 			CurrentVersion:               &certVersionSummary,
+			LifecycleState:               certificatesmanagement.CertificateLifecycleStateActive,
 		},
-		Etag:         nil,
+		Etag:         &etag,
 		OpcRequestId: nil,
 	}, nil
 }
 
 func (m MockCertificateManagerClient) ListCertificates(ctx context.Context, request certificatesmanagement.ListCertificatesRequest) (certificatesmanagement.ListCertificatesResponse, error) {
+	if *request.Name == "error" {
+		return certificatesmanagement.ListCertificatesResponse{}, errors.New("cert list error")
+	}
+
+	if *request.Name == "nonexistent" {
+		return certificatesmanagement.ListCertificatesResponse{}, nil
+	}
+
 	id := "id"
 	return certificatesmanagement.ListCertificatesResponse{
-		RawResponse:           nil,
-		CertificateCollection: certificatesmanagement.CertificateCollection{},
-		OpcRequestId:          &id,
-		OpcNextPage:           &id,
+		RawResponse: nil,
+		CertificateCollection: certificatesmanagement.CertificateCollection{
+			Items: []certificatesmanagement.CertificateSummary{
+				{
+					Id: common.String(id),
+				},
+			},
+		},
+		OpcRequestId: &id,
+		OpcNextPage:  &id,
 	}, nil
 }
 
+func (m MockCertificateManagerClient) UpdateCertificate(ctx context.Context, request certificatesmanagement.UpdateCertificateRequest) (certificatesmanagement.UpdateCertificateResponse, error) {
+	if *request.CertificateId == "error" {
+		return certificatesmanagement.UpdateCertificateResponse{}, errors.New("cert update error")
+	}
+
+	if *request.CertificateId == "conflictError" {
+		return certificatesmanagement.UpdateCertificateResponse{}, &exception.ConflictServiceError{}
+	}
+
+	return certificatesmanagement.UpdateCertificateResponse{}, nil
+}
+
 func (m MockCertificateManagerClient) ScheduleCertificateDeletion(ctx context.Context, request certificatesmanagement.ScheduleCertificateDeletionRequest) (certificatesmanagement.ScheduleCertificateDeletionResponse, error) {
 	var err error
 	if *request.CertificateId == "error" {
@@ -502,33 +613,86 @@ func (m MockCertificateManagerClient) ScheduleCertificateDeletion(ctx context.Co
 	return certificatesmanagement.ScheduleCertificateDeletionResponse{}, err
 }
 
+func (m MockCertificateManagerClient) ListCertificateVersions(ctx context.Context, request certificatesmanagement.ListCertificateVersionsRequest) (certificatesmanagement.ListCertificateVersionsResponse, error) {
+	if *request.CertificateId == "error" {
+		return certificatesmanagement.ListCertificateVersionsResponse{}, errors.New("list cert versions error")
+	}
+
+	createCertificateVersionSummary := func(versionNumber int64, stages []certificatesmanagement.VersionStageEnum) certificatesmanagement.CertificateVersionSummary {
+		return certificatesmanagement.CertificateVersionSummary{
+			VersionNumber: common.Int64(versionNumber),
+			Stages:        stages,
+		}
+	}
+
+	return certificatesmanagement.ListCertificateVersionsResponse{
+		CertificateVersionCollection: certificatesmanagement.CertificateVersionCollection{
+			Items: []certificatesmanagement.CertificateVersionSummary{
+				createCertificateVersionSummary(int64(9), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageFailed, certificatesmanagement.VersionStageLatest}),
+				createCertificateVersionSummary(int64(8), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageCurrent}),
+				createCertificateVersionSummary(int64(7), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageFailed}),
+				createCertificateVersionSummary(int64(6), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStagePrevious}),
+				createCertificateVersionSummary(int64(5), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageDeprecated}),
+				createCertificateVersionSummary(int64(4), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageDeprecated}),
+				createCertificateVersionSummary(int64(3), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageDeprecated}),
+				createCertificateVersionSummary(int64(2), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageFailed}),
+				createCertificateVersionSummary(int64(1), []certificatesmanagement.VersionStageEnum{certificatesmanagement.VersionStageDeprecated}),
+			},
+		},
+	}, nil
+}
+
+func (m MockCertificateManagerClient) ScheduleCertificateVersionDeletion(ctx context.Context, request certificatesmanagement.ScheduleCertificateVersionDeletionRequest) (certificatesmanagement.ScheduleCertificateVersionDeletionResponse, error) {
+	if *request.CertificateId == "error" {
+		return certificatesmanagement.ScheduleCertificateVersionDeletionResponse{}, errors.New("cert version delete error")
+	}
+
+	return certificatesmanagement.ScheduleCertificateVersionDeletionResponse{}, nil
+}
+
 func (m MockCertificateManagerClient) CreateCaBundle(ctx context.Context, request certificatesmanagement.CreateCaBundleRequest) (certificatesmanagement.CreateCaBundleResponse, error) {
+	if *request.Name == "error" {
+		return certificatesmanagement.CreateCaBundleResponse{}, errors.New("caBundle create error")
+	}
+
 	id := "id"
+	etag := "etag"
 	return certificatesmanagement.CreateCaBundleResponse{
 		RawResponse: nil,
 		CaBundle: certificatesmanagement.CaBundle{
 			Id: &id,
 		},
-		Etag:         nil,
+		Etag:         &etag,
 		OpcRequestId: nil,
 	}, nil
 }
 
 func (m MockCertificateManagerClient) GetCaBundle(ctx context.Context, request certificatesmanagement.GetCaBundleRequest) (certificatesmanagement.GetCaBundleResponse, error) {
+	if *request.CaBundleId == "error" {
+		return certificatesmanagement.GetCaBundleResponse{}, errors.New("no ca bundle found")
+	}
+
 	id := "id"
 	name := "cabundle"
+	etag := "etag"
 	return certificatesmanagement.GetCaBundleResponse{
 		RawResponse: nil,
 		CaBundle: certificatesmanagement.CaBundle{
-			Id:   &id,
-			Name: &name,
+			Id:             &id,
+			Name:           &name,
+			LifecycleState: certificatesmanagement.CaBundleLifecycleStateActive,
 		},
 		OpcRequestId: &id,
+		Etag:         &etag,
 	}, nil
 }
 
 func (m MockCertificateManagerClient) ListCaBundles(ctx context.Context, request certificatesmanagement.ListCaBundlesRequest) (certificatesmanagement.ListCaBundlesResponse, error) {
 	if *request.Name == "error" {
+		return certificatesmanagement.ListCaBundlesResponse{}, errors.New("caBundle list error")
+	}
+
+	if *request.Name == "nonexistent" {
 		return certificatesmanagement.ListCaBundlesResponse{}, nil
 	}
 
@@ -551,6 +715,18 @@ func (m MockCertificateManagerClient) ListCaBundles(ctx context.Context, request
 	}, nil
 }
 
+func (m MockCertificateManagerClient) UpdateCaBundle(ctx context.Context, request certificatesmanagement.UpdateCaBundleRequest) (certificatesmanagement.UpdateCaBundleResponse, error) {
+	if *request.CaBundleId == "error" {
+		return certificatesmanagement.UpdateCaBundleResponse{}, errors.New("caBundle update error")
+	}
+
+	if *request.CaBundleId == "conflictError" {
+		return certificatesmanagement.UpdateCaBundleResponse{}, &exception.ConflictServiceError{}
+	}
+
+	return certificatesmanagement.UpdateCaBundleResponse{}, nil
+}
+
 func (m MockCertificateManagerClient) DeleteCaBundle(ctx context.Context, request certificatesmanagement.DeleteCaBundleRequest) (certificatesmanagement.DeleteCaBundleResponse, error) {
 	res := http.Response{
 		Status: "200",
diff --git a/pkg/exception/util.go b/pkg/exception/util.go
index 5ce3616d..46f13bd1 100644
--- a/pkg/exception/util.go
+++ b/pkg/exception/util.go
@@ -34,3 +34,27 @@ func (e *NotFoundServiceError) GetOpcRequestID() string {
 func (e *NotFoundServiceError) Error() string {
 	return "NotFound"
 }
+
+type ConflictServiceError struct {
+	common.ServiceError
+}
+
+func (e *ConflictServiceError) GetHTTPStatusCode() int {
+	return 409
+}
+
+func (e *ConflictServiceError) GetMessage() string {
+	return "Conflict"
+}
+
+func (e *ConflictServiceError) GetCode() string {
+	return "Conflict"
+}
+
+func (e *ConflictServiceError) GetOpcRequestID() string {
+	return "fakeopcrequestid"
+}
+
+func (e *ConflictServiceError) Error() string {
+	return "Conflict"
+}
diff --git a/pkg/loadbalancer/loadbalancer.go b/pkg/loadbalancer/loadbalancer.go
index 2712d32f..a636e667 100644
--- a/pkg/loadbalancer/loadbalancer.go
+++ b/pkg/loadbalancer/loadbalancer.go
@@ -249,7 +249,7 @@ func (lbc *LoadBalancerClient) createRoutingPolicy(
 	klog.Infof("Creating routing policy with request: %s", util.PrettyPrint(createPolicyRequest))
 	resp, err := lbc.LbClient.CreateRoutingPolicy(ctx, createPolicyRequest)
 
-	if isServiceError(err, 409) {
+	if util.IsServiceError(err, 409) {
 		klog.Infof("Create routing policy operation returned code %d for load balancer %s. Routing policy %s may be already present.", 409, lbID, policyName)
 		return nil
 	}
@@ -276,7 +276,7 @@ func (lbc *LoadBalancerClient) DeleteRoutingPolicy(
 	klog.Infof("Delete routing policy with request %s ", util.PrettyPrint(deleteRoutingPolicyRequest))
 	resp, err := lbc.LbClient.DeleteRoutingPolicy(ctx, deleteRoutingPolicyRequest)
 
-	if isServiceError(err, 404) {
+	if util.IsServiceError(err, 404) {
 		klog.Infof("Delete routing policy operation returned code %d for load balancer %s. Routing policy %s may be already deleted.", 404, lbID, policyName)
 		return nil
 	}
@@ -311,7 +311,7 @@ func (lbc *LoadBalancerClient) DeleteBackendSet(ctx context.Context, lbID string
 
 	klog.Infof("Deleting backend set with request %s", util.PrettyPrint(backendSetDeleteRequest))
 	resp, err := lbc.LbClient.DeleteBackendSet(ctx, backendSetDeleteRequest)
-	if isServiceError(err, 404) {
+	if util.IsServiceError(err, 404) {
 		// it was already deleted so nothing to do.
 		klog.Infof("Delete backend set operation returned code %d for load balancer %s. Backend set %s may be already deleted.", 404, lbID, backendSetName)
 		return nil
@@ -347,7 +347,7 @@ func (lbc *LoadBalancerClient) DeleteListener(ctx context.Context, lbID string,
 
 	klog.Infof("Deleting listener with request %s", util.PrettyPrint(deleteListenerRequest))
 	resp, err := lbc.LbClient.DeleteListener(ctx, deleteListenerRequest)
-	if isServiceError(err, 404) {
+	if util.IsServiceError(err, 404) {
 		// it was already deleted so nothing to do.
 		klog.Infof("Delete listener operation returned code %d for load balancer %s. Listener %s may be already deleted.", 404, lbID, listenerName)
 		return nil
@@ -394,7 +394,7 @@ func (lbc *LoadBalancerClient) CreateBackendSet(
 	klog.Infof("Creating backend set with request: %s", util.PrettyPrint(createBackendSetRequest))
 	resp, err := lbc.LbClient.CreateBackendSet(ctx, createBackendSetRequest)
 
-	if isServiceError(err, 409) {
+	if util.IsServiceError(err, 409) {
 		klog.Infof("Create backend set operation returned code %d for load balancer %s. Backend set %s may be already present.", 409, lbID, backendSetName)
 		return nil
 	}
@@ -714,7 +714,7 @@ func (lbc *LoadBalancerClient) CreateListener(ctx context.Context, lbID string,
 	klog.Infof("Creating listener with request %s", util.PrettyPrint(createListenerRequest))
 	resp, err := lbc.LbClient.CreateListener(ctx, createListenerRequest)
 
-	if isServiceError(err, 409) {
+	if util.IsServiceError(err, 409) {
 		klog.Infof("Create listener operation returned code %d for load balancer %s. Listener %s may be already present.", 409, lbID, listenerName)
 		return nil
 	}
@@ -752,12 +752,3 @@ func (lbc *LoadBalancerClient) waitForWorkRequest(ctx context.Context, workReque
 		time.Sleep(10 * time.Second)
 	}
 }
-
-func isServiceError(err error, statusCode int) bool {
-	svcErr, ok := common.IsServiceError(err)
-	if !ok {
-		return false
-	}
-
-	return svcErr.GetHTTPStatusCode() == statusCode
-}
diff --git a/pkg/oci/client/certificate.go b/pkg/oci/client/certificate.go
index 170da389..b824b688 100644
--- a/pkg/oci/client/certificate.go
+++ b/pkg/oci/client/certificate.go
@@ -37,11 +37,13 @@ type CertificateInterface interface {
 type CertCacheObj struct {
 	Cert *certificatesmanagement.Certificate
 	Age  time.Time
+	Etag string
 }
 
 type CaBundleCacheObj struct {
 	CaBundle *certificatesmanagement.CaBundle
 	Age      time.Time
+	Etag     string
 }
 
 type CertificateClient struct {
diff --git a/pkg/oci/client/certificatemanagement.go b/pkg/oci/client/certificatemanagement.go
index d3f33964..4ae01072 100644
--- a/pkg/oci/client/certificatemanagement.go
+++ b/pkg/oci/client/certificatemanagement.go
@@ -10,10 +10,14 @@ type CertificateManagementInterface interface {
 	CreateCertificate(ctx context.Context, request certificatesmanagement.CreateCertificateRequest) (certificatesmanagement.CreateCertificateResponse, error)
 	GetCertificate(ctx context.Context, request certificatesmanagement.GetCertificateRequest) (certificatesmanagement.GetCertificateResponse, error)
 	ListCertificates(ctx context.Context, request certificatesmanagement.ListCertificatesRequest) (certificatesmanagement.ListCertificatesResponse, error)
+	UpdateCertificate(ctx context.Context, request certificatesmanagement.UpdateCertificateRequest) (certificatesmanagement.UpdateCertificateResponse, error)
 	ScheduleCertificateDeletion(ctx context.Context, request certificatesmanagement.ScheduleCertificateDeletionRequest) (certificatesmanagement.ScheduleCertificateDeletionResponse, error)
+	ListCertificateVersions(ctx context.Context, request certificatesmanagement.ListCertificateVersionsRequest) (certificatesmanagement.ListCertificateVersionsResponse, error)
+	ScheduleCertificateVersionDeletion(ctx context.Context, request certificatesmanagement.ScheduleCertificateVersionDeletionRequest) (certificatesmanagement.ScheduleCertificateVersionDeletionResponse, error)
 	CreateCaBundle(ctx context.Context, request certificatesmanagement.CreateCaBundleRequest) (certificatesmanagement.CreateCaBundleResponse, error)
 	GetCaBundle(ctx context.Context, request certificatesmanagement.GetCaBundleRequest) (certificatesmanagement.GetCaBundleResponse, error)
 	ListCaBundles(ctx context.Context, request certificatesmanagement.ListCaBundlesRequest) (certificatesmanagement.ListCaBundlesResponse, error)
+	UpdateCaBundle(ctx context.Context, request certificatesmanagement.UpdateCaBundleRequest) (certificatesmanagement.UpdateCaBundleResponse, error)
 	DeleteCaBundle(ctx context.Context, request certificatesmanagement.DeleteCaBundleRequest) (certificatesmanagement.DeleteCaBundleResponse, error)
 }
 
@@ -42,11 +46,26 @@ func (client CertificateManagementClient) ListCertificates(ctx context.Context,
 	return client.managementClient.ListCertificates(ctx, request)
 }
 
+func (client CertificateManagementClient) UpdateCertificate(ctx context.Context,
+	request certificatesmanagement.UpdateCertificateRequest) (certificatesmanagement.UpdateCertificateResponse, error) {
+	return client.managementClient.UpdateCertificate(ctx, request)
+}
+
 func (client CertificateManagementClient) ScheduleCertificateDeletion(ctx context.Context,
 	request certificatesmanagement.ScheduleCertificateDeletionRequest) (certificatesmanagement.ScheduleCertificateDeletionResponse, error) {
 	return client.managementClient.ScheduleCertificateDeletion(ctx, request)
 }
 
+func (client CertificateManagementClient) ListCertificateVersions(ctx context.Context,
+	request certificatesmanagement.ListCertificateVersionsRequest) (certificatesmanagement.ListCertificateVersionsResponse, error) {
+	return client.managementClient.ListCertificateVersions(ctx, request)
+}
+
+func (client CertificateManagementClient) ScheduleCertificateVersionDeletion(ctx context.Context,
+	request certificatesmanagement.ScheduleCertificateVersionDeletionRequest) (certificatesmanagement.ScheduleCertificateVersionDeletionResponse, error) {
+	return client.managementClient.ScheduleCertificateVersionDeletion(ctx, request)
+}
+
 func (client CertificateManagementClient) CreateCaBundle(ctx context.Context,
 	request certificatesmanagement.CreateCaBundleRequest) (certificatesmanagement.CreateCaBundleResponse, error) {
 	return client.managementClient.CreateCaBundle(ctx, request)
@@ -62,6 +81,11 @@ func (client CertificateManagementClient) ListCaBundles(ctx context.Context,
 	return client.managementClient.ListCaBundles(ctx, request)
 }
 
+func (client CertificateManagementClient) UpdateCaBundle(ctx context.Context,
+	request certificatesmanagement.UpdateCaBundleRequest) (certificatesmanagement.UpdateCaBundleResponse, error) {
+	return client.managementClient.UpdateCaBundle(ctx, request)
+}
+
 func (client CertificateManagementClient) DeleteCaBundle(ctx context.Context,
 	request certificatesmanagement.DeleteCaBundleRequest) (certificatesmanagement.DeleteCaBundleResponse, error) {
 	return client.managementClient.DeleteCaBundle(ctx, request)
diff --git a/pkg/server/server.go b/pkg/server/server.go
index 6d742ff9..1c5a72f1 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -58,9 +58,9 @@ func BuildConfig(kubeconfig string) (*rest.Config, error) {
 }
 
 func SetUpControllers(opts types.IngressOpts, ingressClassInformer networkinginformers.IngressClassInformer,
-	ingressInformer networkinginformers.IngressInformer, k8client kubernetes.Interface,
-	serviceInformer v1.ServiceInformer, endpointInformer v1.EndpointsInformer, podInformer v1.PodInformer, nodeInformer v1.NodeInformer, serviceAccountInformer v1.ServiceAccountInformer, c ctrcache.Cache,
-	reg *prometheus.Registry) func(ctx context.Context) {
+	ingressInformer networkinginformers.IngressInformer, k8client kubernetes.Interface, serviceInformer v1.ServiceInformer, secretInformer v1.SecretInformer,
+	endpointInformer v1.EndpointsInformer, podInformer v1.PodInformer, nodeInformer v1.NodeInformer, serviceAccountInformer v1.ServiceAccountInformer,
+	c ctrcache.Cache, reg *prometheus.Registry) func(ctx context.Context) {
 	return func(ctx context.Context) {
 		klog.Info("Controller loop...")
 
@@ -82,6 +82,7 @@ func SetUpControllers(opts types.IngressOpts, ingressClassInformer networkinginf
 			ingressInformer,
 			serviceAccountInformer,
 			serviceInformer.Lister(),
+			secretInformer,
 			client,
 			reg,
 		)
diff --git a/pkg/util/util.go b/pkg/util/util.go
index bb73bd31..01f51764 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -828,3 +828,12 @@ func IsIngressProtocolTCP(ingress *networkingv1.Ingress) bool {
 func StringSlicesHaveSameElements(s1 []string, s2 []string) bool {
 	return sets.New(s1...).Equal(sets.New(s2...))
 }
+
+func IsServiceError(err error, statusCode int) bool {
+	svcErr, ok := common.IsServiceError(err)
+	if !ok {
+		return false
+	}
+
+	return svcErr.GetHTTPStatusCode() == statusCode
+}