Repository: chef/automate
Pull request #8005 (2023-06-28 10:30:49)

CertByIp validation and validate common private and public keys when …
…CertByIp is empty

### :nut_and_bolt: Description: What code changed, and why?

<!-- /!\ Please ensure that you are NOT disclosing any customer information without their consent /!\ -->

### :chains: Related Resources

### :+1: Definition of Done

### :athletic_shoe: How to Build and Test the Change

### :white_check_mark: Checklist

**All PRs** must tick these:

- [ ] I have read the [CONTRIBUTING document](https://github.com/chef/automate/blob/master/CONTRIBUTING.md).
- [ ] All commits signed-off for the [Developer Certification of Origin](https://github.com/chef/chef/blob/master/CONTRIBUTING.md#developer-certification-of-origin-dco).

With occasional exceptions, all PRs **from Progress employees** must tick these:

- [ ] Is the code clear? *(complicated code or lots of comments--subdivide and use well-named methods, meaningful variable names, etc.)*
- [ ] Consistency checked? *(user notifications, user prompts, visual patterns, code patterns, variable names)*
- [ ] Repeated code blocks eliminated? *(adapt and reuse existing components, blocks, functions, etc.)*
- [ ] Spelling, grammar, typos checked? *(at a minimum use `make spell` in any component directory)*
- [ ] Code well-formatted? *(indents, line breaks, etc. improve rather than hinder readability)*

All PRs **from Progress employees** should tick these if appropriate:

- [ ] Tests added/updated? (all new code needs new tests)
- [ ] Docs added/updated? (all customer-facing changes)

*Please add a note next to any checkbox above if you are NOT ticking it.*

### :camera: Screenshots, if applicable
![Screenshot 2023-06-28 at 8 33 33 PM](https://github.com/chef/automate/assets/36985548/24a866ca-ee19-4e6d-95bb-3680a125a05b)


sonarqube-for-infrastructure-prod[bot]: **SonarQube Quality Gate**

[![Quality Gate failed](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005)

[![Failed condition](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/FailedConditionIcon-16px.png 'Failed condition')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005) [![72.4%](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/CoverageChart/60-16px.png '72.4%')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005) 72.4% Coverage on New Code (is less than 80%)  

[See analysis details on SonarQube](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005)


sonarqube-for-infrastructure-prod[bot]: **SonarQube Quality Gate**

[![Quality Gate failed](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005)

[![Failed condition](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/FailedConditionIcon-16px.png 'Failed condition')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005) [![63.6%](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/CoverageChart/60-16px.png '63.6%')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005) 63.6% Coverage on New Code (is less than 80%)  

[See analysis details on SonarQube](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005)


sonarqube-for-infrastructure-prod[bot]: **SonarQube Quality Gate**

[![Quality Gate failed](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005)

[![Failed condition](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/FailedConditionIcon-16px.png 'Failed condition')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005) [![63.6%](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/CoverageChart/60-16px.png '63.6%')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005) 63.6% Coverage on New Code (is less than 80%)  

[See analysis details on SonarQube](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8005)



Patch:
diff --git a/VERSION b/VERSION
index 113ec2733..0cb646ace 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-4.7.119
\ No newline at end of file
+4.7.126
\ No newline at end of file
diff --git a/components/automate-backend-deployment/habitat/plan.sh b/components/automate-backend-deployment/habitat/plan.sh
index ac1dbf5e0..821f55cb1 100644
--- a/components/automate-backend-deployment/habitat/plan.sh
+++ b/components/automate-backend-deployment/habitat/plan.sh
@@ -112,4 +112,4 @@ do_install() {
 
 do_strip() {
   return 0
-}
\ No newline at end of file
+}
diff --git a/components/automate-cli/cmd/chef-automate/certRotate.go b/components/automate-cli/cmd/chef-automate/certRotate.go
index 80193f02b..c9a940fd4 100644
--- a/components/automate-cli/cmd/chef-automate/certRotate.go
+++ b/components/automate-cli/cmd/chef-automate/certRotate.go
@@ -31,13 +31,6 @@ const (
 		cert = """%v"""
 		key = """%v"""`
 
-	CHEFSERVER_ROOTCA_CONFIG = `
-	[cs_nginx.v1.sys.ngx.http]
-		ssl_verify_depth = 6
-	[global.v1.external.automate.ssl]
-		server_name = "https://%v"
-		root_cert = """%v"""`
-
 	POSTGRES_CONFIG = `
 	[ssl]
 		enable = true
@@ -290,20 +283,6 @@ func (c *certRotateFlow) certRotateFrontend(sshUtil SSHUtil, certs *certificates
 		return err
 	}
 
-	// ignore root-ca when node flag is provided
-	if flagsObj.node != "" {
-		return nil
-	}
-
-	// If we pass root-ca flag in automate then we need to update root-ca in the ChefServer to maintain the connection
-	if flagsObj.automate {
-		skipIpsList := c.getFrontEndIpsForSkippingRootCAPatching(AUTOMATE, certs.rootCA, infra, currentCertsInfo)
-		c.skipMessagePrinter(CHEF_SERVER, SKIP_FRONT_END_IPS_MSG_A2, "", skipIpsList)
-		err = c.patchRootCAinCS(sshUtil, certs.rootCA, timestamp, infra, flagsObj, skipIpsList)
-		if err != nil {
-			return err
-		}
-	}
 	return nil
 }
 
@@ -561,42 +540,6 @@ func (c *certRotateFlow) patchConfig(param *patchFnParameters) error {
 	return nil
 }
 
-// patchRootCAinCS will rotate the root-ca in the ChefServer to maintain the connection.
-func (c *certRotateFlow) patchRootCAinCS(sshUtil SSHUtil, rootCA, timestamp string, infra *AutomateHAInfraDetails, flagsObj *certRotateFlags, skipIpsList []string) error {
-
-	fileName := "rotate-root_CA.toml"
-	remoteService := CHEF_SERVER
-	cmd := `sudo chef-automate config show | grep fqdn | awk '{print $3}' | tr -d '"'`
-	ips := c.getIps(remoteService, infra)
-	if len(ips) == 0 {
-		return errors.New(fmt.Sprintf("No %s IPs are found", remoteService))
-	}
-	sshUtil.getSSHConfig().hostIP = ips[0]
-	fqdn, err := sshUtil.connectAndExecuteCommandOnRemote(cmd, true)
-	if err != nil {
-		return err
-	}
-
-	config := fmt.Sprintf(CHEFSERVER_ROOTCA_CONFIG, strings.TrimSpace(string(fqdn)), rootCA)
-
-	patchFnParam := &patchFnParameters{
-		sshUtil:       sshUtil,
-		config:        config,
-		fileName:      fileName,
-		timestamp:     timestamp,
-		remoteService: remoteService,
-		infra:         infra,
-		flagsObj:      flagsObj,
-		skipIpsList:   skipIpsList,
-	}
-
-	err = c.patchConfig(patchFnParam)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
 // copyAndExecute will copy the toml file to each required node and then execute the set of commands.
 func (c *certRotateFlow) copyAndExecute(ips []string, sshUtil SSHUtil, timestamp string, remoteService string, fileName string, scriptCommands string, flagsObj *certRotateFlags) error {
 
@@ -691,7 +634,7 @@ func (c *certRotateFlow) getAllIPs(infra *AutomateHAInfraDetails) []string {
 func (c *certRotateFlow) getFilteredIps(serviceIps, skipIpsList []string) []string {
 	filteredIps := []string{}
 	for _, ip := range serviceIps {
-		if stringutils.SliceContains(skipIpsList, ip) == false {
+		if !stringutils.SliceContains(skipIpsList, ip) {
 			filteredIps = append(filteredIps, ip)
 		}
 	}
@@ -703,9 +646,6 @@ func (c *certRotateFlow) compareCurrentCertsWithNewCerts(remoteService string, n
 	skipIpsList := []string{}
 	isCertsSame := true
 	if remoteService == AUTOMATE {
-		if flagsObj.node == "" {
-			isCertsSame = strings.TrimSpace(currentCertsInfo.AutomateRootCert) == newCerts.rootCA
-		}
 		skipIpsList = c.comparePublicCertAndPrivateCert(newCerts, currentCertsInfo.AutomateCertsByIP, isCertsSame, flagsObj)
 		return skipIpsList
 	}
@@ -860,8 +800,8 @@ func (c *certRotateFlow) getCerts(infra *AutomateHAInfraDetails, flagsObj *certR
 		return nil, errors.New("Please provide the valid certificate for public-cert")
 	}
 
-	// Root CA is mandatory for A2, PG and OS nodes. But root CA is ignored when node flag is provided
-	if flagsObj.automate || flagsObj.postgres || flagsObj.opensearch {
+	// Root CA is mandatory for PG and OS nodes. But root CA is ignored when node flag is provided
+	if flagsObj.postgres || flagsObj.opensearch {
 		if rootCaPath == "" && flagsObj.node == "" {
 			return nil, errors.New("Please provide root-ca flag")
 		}
diff --git a/components/automate-cli/cmd/chef-automate/verify.go b/components/automate-cli/cmd/chef-automate/verify.go
index d9cea663e..ddc64c23a 100644
--- a/components/automate-cli/cmd/chef-automate/verify.go
+++ b/components/automate-cli/cmd/chef-automate/verify.go
@@ -311,9 +311,13 @@ func (v *verifyCmdFlow) RunVerify(config string) error {
 		v.postgresqlIPs = configDetails.PostgresqlIps
 		v.opensearchIPs = configDetails.OpensearchIps
 
-		batchCheckConfig.ExternalOS.OSRoleArn = configDetails.OsSnapshotRoleArn
-		batchCheckConfig.ExternalOS.OsSnapshotUserAccessKeyId = configDetails.OsSnapshotUserID
-		batchCheckConfig.ExternalOS.OsSnapshotUserAccessKeySecret = configDetails.OsSnapshotUserSecret
+		if v.Config.Aws.Config.SetupManagedServices {
+			batchCheckConfig.ExternalOS = &models.ExternalOS{
+				OSRoleArn:                     configDetails.OsSnapshotRoleArn,
+				OsSnapshotUserAccessKeyId:     configDetails.OsSnapshotUserID,
+				OsSnapshotUserAccessKeySecret: configDetails.OsSnapshotUserSecret,
+			}
+		}
 		// assign ip's to models.Hardware
 		batchCheckHardware := batchCheckConfig.Hardware
 		batchCheckHardware.AutomateNodeIps = configDetails.AutomateIps
diff --git a/components/automate-cli/pkg/verifyserver/models/batchcheck.go b/components/automate-cli/pkg/verifyserver/models/batchcheck.go
index a3147f1ba..d5124ec02 100644
--- a/components/automate-cli/pkg/verifyserver/models/batchcheck.go
+++ b/components/automate-cli/pkg/verifyserver/models/batchcheck.go
@@ -87,6 +87,7 @@ type Config struct {
 	SSHUser         *SSHUser       `json:"ssh_user"`
 	Arch            string         `json:"arch"`
 	Backup          *Backup        `json:"backup"`
+	ExternalDbType  string         `json:"external_db_type"`
 	Hardware        *Hardware      `json:"hardware"`
 	Certificate     []*Certificate `json:"certificate"`
 	ExternalOS      *ExternalOS    `json:"external_opensearch"`
@@ -100,8 +101,6 @@ func NewConfig() *Config {
 		Hardware:    &Hardware{},
 		Certificate: []*Certificate{},
 		SSHUser:     &SSHUser{},
-		ExternalOS:  &ExternalOS{},
-		ExternalPG:  &ExternalPG{},
 	}
 }
 
@@ -324,23 +323,26 @@ func (c *Config) populateAwsCerts(haConfig *config.HaDeployConfig) {
 
 func (c *Config) populateAwsManagedServicesConfig(haConfig *config.HaDeployConfig) {
 	awsManagedServicesConfig := haConfig.Aws.Config
+	if c.ExternalPG == nil {
+		c.ExternalPG = &ExternalPG{}
+	}
+
 	c.ExternalPG.PGDbUserName = awsManagedServicesConfig.ManagedRdsDbuserUsername
 	c.ExternalPG.PGDbUserPassword = awsManagedServicesConfig.ManagedRdsDbuserPassword
 	c.ExternalPG.PGInstanceURL = awsManagedServicesConfig.ManagedRdsInstanceURL
-
-	// pg root-ca might be nil in pre deploy state
 	c.ExternalPG.PGRootCert = awsManagedServicesConfig.ManagedRdsCertificate
 	c.ExternalPG.PGSuperuserName = awsManagedServicesConfig.ManagedRdsSuperuserUsername
 	c.ExternalPG.PGSuperuserPassword = awsManagedServicesConfig.ManagedRdsSuperuserPassword
 
+	if c.ExternalOS == nil {
+		c.ExternalOS = &ExternalOS{}
+	}
+
 	c.ExternalOS.OSDomainName = awsManagedServicesConfig.ManagedOpensearchDomainName
 	c.ExternalOS.OSDomainURL = awsManagedServicesConfig.ManagedOpensearchDomainURL
-
-	// os root-ca might be nil in pre deploy state
 	c.ExternalOS.OSCert = awsManagedServicesConfig.ManagedOpensearchCertificate
 	c.ExternalOS.OSUserPassword = awsManagedServicesConfig.ManagedOpensearchUserPassword
 	c.ExternalOS.OSUsername = awsManagedServicesConfig.ManagedOpensearchUsername
-	c.ExternalOS.OSRoleArn = awsManagedServicesConfig.AwsOsSnapshotRoleArn
 }
 
 func (c *Config) populateExistingInfraCommonConfig(haConfig *config.HaDeployConfig) {
@@ -377,21 +379,26 @@ func addCertificatesInConfig(fqdn, rootCA, nodeType string) *Certificate {
 }
 
 func (c *Config) populateExternalDbConfig(haConfig *config.HaDeployConfig) {
+	c.ExternalDbType = haConfig.External.Database.Type
 	externalPgConfig := haConfig.External.Database.PostgreSQL
+	if c.ExternalPG == nil {
+		c.ExternalPG = &ExternalPG{}
+	}
 	c.ExternalPG.PGDbUserName = externalPgConfig.DbuserUsername
 	c.ExternalPG.PGDbUserPassword = externalPgConfig.DbuserPassword
 	c.ExternalPG.PGInstanceURL = externalPgConfig.InstanceURL
-
-	// pg root-ca might be nil in pre deploy state
 	c.ExternalPG.PGRootCert = externalPgConfig.PostgresqlRootCert
 	c.ExternalPG.PGSuperuserName = externalPgConfig.SuperuserUsername
 	c.ExternalPG.PGSuperuserPassword = externalPgConfig.SuperuserPassword
 
 	externalOsConfig := haConfig.External.Database.OpenSearch
+
+	if c.ExternalOS == nil {
+		c.ExternalOS = &ExternalOS{}
+	}
+
 	c.ExternalOS.OSDomainName = externalOsConfig.OpensearchDomainName
 	c.ExternalOS.OSDomainURL = externalOsConfig.OpensearchDomainURL
-
-	// os root-ca might be nil in pre deploy state
 	c.ExternalOS.OSCert = externalOsConfig.OpensearchRootCert
 	c.ExternalOS.OSUserPassword = externalOsConfig.OpensearchUserPassword
 	c.ExternalOS.OSUsername = externalOsConfig.OpensearchUsername
diff --git a/components/automate-cli/pkg/verifyserver/models/nfsmount.go b/components/automate-cli/pkg/verifyserver/models/nfsmount.go
index 3c2f1b36d..bdc994492 100644
--- a/components/automate-cli/pkg/verifyserver/models/nfsmount.go
+++ b/components/automate-cli/pkg/verifyserver/models/nfsmount.go
@@ -1,6 +1,7 @@
 package models
 
 type NFSMountRequest struct {
+	ExternalDbType         string   `json:"external_db_type"`
 	AutomateNodeIPs        []string `json:"automate_node_ips"`
 	ChefInfraServerNodeIPs []string `json:"chef_infra_server_node_ips"`
 	PostgresqlNodeIPs      []string `json:"postgresql_node_ips"`
diff --git a/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount.go b/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount.go
index 294895895..7da6b6e46 100644
--- a/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount.go
+++ b/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount.go
@@ -14,10 +14,16 @@ func (h *Handler) NFSMount(c *fiber.Ctx) error {
 		h.Logger.Error(err.Error())
 		return fiber.NewError(http.StatusBadRequest, "Invalid Body Request")
 	}
-	if len(reqBody.AutomateNodeIPs) == 0 || len(reqBody.ChefInfraServerNodeIPs) == 0 || len(reqBody.PostgresqlNodeIPs) == 0 || len(reqBody.OpensearchNodeIPs) == 0 {
-		return fiber.NewError(http.StatusBadRequest, "AutomateNodeIPs, ChefInfraServerNodeIPs, PostgresqlNodeIPs or OpensearchNodeIPs cannot be empty")
-	}
 
+	if reqBody.ExternalDbType == "self-managed" {
+		if len(reqBody.AutomateNodeIPs) == 0 || len(reqBody.ChefInfraServerNodeIPs) == 0 {
+			return fiber.NewError(http.StatusBadRequest, "AutomateNodeIPs or ChefInfraServerNodeIPs cannot be empty")
+		}
+	} else {
+		if len(reqBody.AutomateNodeIPs) == 0 || len(reqBody.ChefInfraServerNodeIPs) == 0 || len(reqBody.PostgresqlNodeIPs) == 0 || len(reqBody.OpensearchNodeIPs) == 0 {
+			return fiber.NewError(http.StatusBadRequest, "AutomateNodeIPs, ChefInfraServerNodeIPs, PostgresqlNodeIPs or OpensearchNodeIPs cannot be empty")
+		}
+	}
 	if reqBody.MountLocation == "" {
 		return fiber.NewError(http.StatusBadRequest, "Mount Location cannot be empty")
 	}
diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck.go
index 12d6109e5..ae58326f4 100644
--- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck.go
+++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck.go
@@ -40,6 +40,7 @@ func (nbc *NfsBackupConfigCheck) Run(config *models.Config) []models.CheckTrigge
 	}
 
 	nfsMountReq := models.NFSMountRequest{
+		ExternalDbType:         config.ExternalDbType,
 		AutomateNodeIPs:        config.Hardware.AutomateNodeIps,
 		ChefInfraServerNodeIPs: config.Hardware.ChefInfraServerNodeIps,
 		PostgresqlNodeIPs:      config.Hardware.PostgresqlNodeIps,
diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck.go
index 904000ae7..42cb0a749 100644
--- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck.go
+++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck.go
@@ -27,7 +27,7 @@ func NewOpensearchS3BucketAccessCheck(log logger.Logger, port string) *Opensearc
 func (osb *OpensearchS3BucketAccessCheck) Run(config *models.Config) []models.CheckTriggerResponse {
 	if config.ExternalOS == nil || config.Backup.ObjectStorage == nil {
 		return []models.CheckTriggerResponse{
-			trigger.SkippedTriggerCheckResp(constants.UNKNOWN_HOST, constants.AWS_OPENSEARCH_S3_BUCKET_ACCESS, constants.OPENSEARCH),
+			trigger.SkippedTriggerCheckResp("-", constants.AWS_OPENSEARCH_S3_BUCKET_ACCESS, constants.OPENSEARCH),
 		}
 	}
 
diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger.go
index 01edcb5f2..9174d0eed 100644
--- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger.go
+++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger.go
@@ -23,12 +23,16 @@ func NewS3BackupConfigCheck(log logger.Logger, port string) *S3BackupConfigCheck
 }
 
 func (svc *S3BackupConfigCheck) Run(config *models.Config) []models.CheckTriggerResponse {
-	if config.Hardware == nil || config.Backup.ObjectStorage == nil {
+	if config.Hardware == nil {
 		return []models.CheckTriggerResponse{
-			trigger.SkippedTriggerCheckResp(constants.UNKNOWN_HOST, constants.S3_BACKUP_CONFIG, constants.AUTOMATE),
+			trigger.SkippedTriggerCheckResp("-", constants.S3_BACKUP_CONFIG, constants.AUTOMATE),
 		}
 	}
 
+	if config.Backup.ObjectStorage == nil {
+		return s3ConfigSkippedResponse(config, constants.S3_BACKUP_CONFIG)
+	}
+
 	if isObjectStorage(config.Backup) {
 		return emptyResp(config, constants.S3_BACKUP_CONFIG)
 	}
@@ -37,6 +41,20 @@ func (svc *S3BackupConfigCheck) Run(config *models.Config) []models.CheckTrigger
 	return runCheckForS3Config(config.Hardware.AutomateNodeIps, svc.log, svc.port, http.MethodPost, req)
 }
 
+func s3ConfigSkippedResponse(config *models.Config, checkType string) []models.CheckTriggerResponse {
+	var triggerResps []models.CheckTriggerResponse
+
+	for _, ip := range config.Hardware.AutomateNodeIps {
+		triggerResps = append(triggerResps, trigger.SkippedTriggerCheckResp(ip, checkType, constants.AUTOMATE))
+	}
+
+	for _, ip := range config.Hardware.ChefInfraServerNodeIps {
+		triggerResps = append(triggerResps, trigger.SkippedTriggerCheckResp(ip, checkType, constants.CHEF_INFRA_SERVER))
+	}
+
+	return triggerResps
+}
+
 func (ss *S3BackupConfigCheck) GetPortsForMockServer() map[string]map[string][]int {
 	nodeTypePortMap := make(map[string]map[string][]int)
 	return nodeTypePortMap
diff --git a/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation.go b/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation.go
index d5f1b1e6b..a9d528f36 100644
--- a/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation.go
+++ b/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation.go
@@ -152,12 +152,7 @@ func (vc *ValidateCertificateService) validateKeyFormat(privateKeys map[string]s
 		}
 
 		// this is for checking that our private keys are of PKCS8 format or not.
-		_, err := x509.ParsePKCS8PrivateKey(block.Bytes)
-		if err != nil {
-			vc.log.Debugf("%s is not in PKCS8 format", key)
-			invalidFormatKeys += key + ", "
-			continue
-		}
+
 	}
 
 	if invalidFormatKeys == "" {
diff --git a/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice.go b/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice.go
index fa8896155..654bb1f26 100644
--- a/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice.go
+++ b/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice.go
@@ -9,8 +9,6 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/gofiber/fiber/v2"
-
 	"github.com/chef/automate/components/automate-cli/pkg/verifyserver/constants"
 	"github.com/chef/automate/components/automate-cli/pkg/verifyserver/models"
 	"github.com/chef/automate/components/automate-cli/pkg/verifyserver/response"
@@ -188,7 +186,8 @@ func prepareMountResp(ip, nodeType, mountLocation string, mountLocResp *models.N
 	node.NodeType = nodeType
 
 	if err != nil {
-		node.Error = fiber.NewError(http.StatusBadRequest, err.Error())
+		checkList := createCheck("NFS mount", false, "", "NFS mount location not found", "NFS volume should be mounted on "+mountLocation)
+		node.CheckList = append(node.CheckList, checkList)
 		return node
 	}
 	checkMount(mountLocation, &node, mountLocResp)
diff --git a/components/docs-chef-io/content/automate/ha_cert_rotation.md b/components/docs-chef-io/content/automate/ha_cert_rotation.md
index 650d3df71..c44fc5714 100644
--- a/components/docs-chef-io/content/automate/ha_cert_rotation.md
+++ b/components/docs-chef-io/content/automate/ha_cert_rotation.md
@@ -41,7 +41,7 @@ If you want to rotate certificates of the entire cluster, then you can follow th
 
 - To rotate certificates of automate cluster:
 
-`chef-automate cert-rotate --public-cert <path of public certificate of automate node> --private-cert <path of private certificate of automate node> --root-ca <path of root certificate of automate load balancer> --a2`
+`chef-automate cert-rotate --public-cert <path of public certificate of automate node> --private-cert <path of private certificate of automate node> --a2`
 
 You can also use `--automate` or `-a` instead of a2 flag
 
@@ -95,3 +95,24 @@ You can also use `--opensearch` or `-o` instead of the os flag
 
 {{< note >}} Since admin-cert and admin-key are common in all nodes, So if you want to rotate admin-cert and admin-key, you must first run this open search cluster command: 
 `chef-automate cert-rotate --public-cert <path of public certificate> --private-cert <path of private certificate> --root-ca <path of root certificate> --admin-cert <path of admin certificate> --admin-key <path of admin key> --os`{{< /note >}}
+
+
+### Rotate Automate Load Balancer Root CA
+
+To rotate the Automate Load balancer root certificate: 
+
+1. Create a root_ca.toml file with the following content. Replace server_name with Automate Fqdn and root_cert with Automate Load balancer root certificate. 
+
+    ```toml
+    [cs_nginx.v1.sys.ngx.http]
+      ssl_verify_depth = 6
+    [global.v1.external.automate.ssl]
+      server_name = "https://<automatefqdn.example.com>"
+      root_cert = """<Root_CA_Content>"""
+    ```
+
+1. Run the following command to apply your configuration on Chef-Server from bastion:
+
+    ```shell
+    chef-automate config patch root_ca.toml --cs
+    ```
diff --git a/lib/config/hadeployconfigverify.go b/lib/config/hadeployconfigverify.go
index b19c5c665..434e93556 100644
--- a/lib/config/hadeployconfigverify.go
+++ b/lib/config/hadeployconfigverify.go
@@ -206,7 +206,7 @@ func (c *HaDeployConfig) verifyAutomateSettings() error {
 		errorList.PushBack(err)
 	}
 	if automateSettings.EnableCustomCerts {
-		if err := validateAutomateCerts(automateSettings); err != nil {
+		if err := validateAutomateCerts(c); err != nil {
 			errorList.PushBack(err)
 		}
 		if c.IsExistingInfra() {
@@ -227,7 +227,7 @@ func (c *HaDeployConfig) verifyChefServerSettings() error {
 		errorList.PushBack(err)
 	}
 	if chefServerSettings.EnableCustomCerts {
-		if err := validateChefServerCerts(chefServerSettings); err != nil {
+		if err := validateChefServerCerts(c); err != nil {
 			errorList.PushBack(err)
 		}
 		if c.IsExistingInfra() {
@@ -248,7 +248,7 @@ func (c *HaDeployConfig) verifyOpensearchSettings() error {
 		errorList.PushBack(err)
 	}
 	if opensearchSettings.EnableCustomCerts {
-		if err := validateOpensearchCerts(opensearchSettings); err != nil {
+		if err := validateOpensearchCerts(c); err != nil {
 			errorList.PushBack(err)
 		}
 		if c.IsExistingInfra() {
@@ -269,7 +269,7 @@ func (c *HaDeployConfig) verifyPostgresqlSettings() error {
 		errorList.PushBack(err)
 	}
 	if postgresqlSettings.EnableCustomCerts {
-		if err := validatePostgresqlCerts(postgresqlSettings); err != nil {
+		if err := validatePostgresqlCerts(c); err != nil {
 			errorList.PushBack(err)
 		}
 		if c.IsExistingInfra() {
diff --git a/lib/config/helper.go b/lib/config/helper.go
index 860cd4209..837a12518 100644
--- a/lib/config/helper.go
+++ b/lib/config/helper.go
@@ -16,6 +16,11 @@ import (
 	"github.com/chef/automate/components/local-user-service/password"
 )
 
+var (
+	returnErrorPublicKeyMsg = "cannot find public key for ip %s"
+	returnErrorPrivetKeyMsg = "cannot find private key for ip %s"
+)
+
 type keydetails struct {
 	key      string
 	certtype string
@@ -191,30 +196,72 @@ func validateAutomateAdminPassword(automateSettings *ConfigAutomateSettings) err
 	return nil
 }
 
-func validateAutomateCerts(automateSettings *ConfigAutomateSettings) error {
-	if len(strings.TrimSpace(automateSettings.FqdnRootCA)) < 1 ||
-		len(strings.TrimSpace(automateSettings.PrivateKey)) < 1 ||
-		len(strings.TrimSpace(automateSettings.PublicKey)) < 1 {
-		return fmt.Errorf("automate root_ca and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+func validateAutomateCerts(depConfig *HaDeployConfig) error {
+	// If CertByIp is available validate it is available for all the nodes.
+	if depConfig.Automate.Config.CertsByIP == nil || len(*depConfig.Automate.Config.CertsByIP) == 0 {
+		if len(strings.TrimSpace(depConfig.Automate.Config.PrivateKey)) < 1 ||
+			len(strings.TrimSpace(depConfig.Automate.Config.PublicKey)) < 1 {
+			return fmt.Errorf("automate root_ca and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+		}
+
+		return checkCertValid([]keydetails{
+			{key: depConfig.Automate.Config.PrivateKey, certtype: PRIVATE_KEY, svc: AUTOMATE},
+			{key: depConfig.Automate.Config.PublicKey, certtype: PUBLIC_KEY, svc: AUTOMATE},
+		})
 	}
 
-	return checkCertValid([]keydetails{
-		{key: automateSettings.FqdnRootCA, certtype: ROOT_CA, svc: AUTOMATE},
-		{key: automateSettings.PrivateKey, certtype: PRIVATE_KEY, svc: AUTOMATE},
-		{key: automateSettings.PublicKey, certtype: PUBLIC_KEY, svc: AUTOMATE},
-	})
+	// If CertByIp available then check it's availabe for all the nodes
+	for _, v := range *depConfig.Automate.Config.CertsByIP {
+		if v.PrivateKey == "" {
+			return fmt.Errorf(returnErrorPrivetKeyMsg, v.IP)
+		}
+		if v.PublicKey == "" {
+			return fmt.Errorf(returnErrorPublicKeyMsg, v.IP)
+		}
+
+		if err := checkCertValid([]keydetails{
+			{key: v.PrivateKey, certtype: PRIVATE_KEY, svc: AUTOMATE},
+			{key: v.PublicKey, certtype: PUBLIC_KEY, svc: AUTOMATE},
+		}); err != nil {
+			return err
+		}
+	}
+
+	return nil
 }
 
-func validateChefServerCerts(chefServerSettings *ConfigSettings) error {
-	if len(strings.TrimSpace(chefServerSettings.PrivateKey)) < 1 ||
-		len(strings.TrimSpace(chefServerSettings.PublicKey)) < 1 {
-		return fmt.Errorf("chefServer public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+func validateChefServerCerts(depConfig *HaDeployConfig) error {
+	// If CertByIp is available validate it is available for all the nodes.
+	if depConfig.ChefServer.Config.CertsByIP == nil || len(*depConfig.ChefServer.Config.CertsByIP) == 0 {
+		if len(strings.TrimSpace(depConfig.ChefServer.Config.PrivateKey)) < 1 ||
+			len(strings.TrimSpace(depConfig.ChefServer.Config.PublicKey)) < 1 {
+			return fmt.Errorf("chefServer public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+		}
+
+		return checkCertValid([]keydetails{
+			{key: depConfig.ChefServer.Config.PrivateKey, certtype: PRIVATE_KEY, svc: CHEFSERVER},
+			{key: depConfig.ChefServer.Config.PublicKey, certtype: PUBLIC_KEY, svc: CHEFSERVER},
+		})
+	}
+
+	// If CertByIp available then check it's availabe for all the nodes
+	for _, v := range *depConfig.ChefServer.Config.CertsByIP {
+		if v.PrivateKey == "" {
+			return fmt.Errorf(returnErrorPrivetKeyMsg, v.IP)
+		}
+		if v.PublicKey == "" {
+			return fmt.Errorf(returnErrorPublicKeyMsg, v.IP)
+		}
+
+		if err := checkCertValid([]keydetails{
+			{key: v.PrivateKey, certtype: PRIVATE_KEY, svc: CHEFSERVER},
+			{key: v.PublicKey, certtype: PUBLIC_KEY, svc: CHEFSERVER},
+		}); err != nil {
+			return err
+		}
 	}
 
-	return checkCertValid([]keydetails{
-		{key: chefServerSettings.PrivateKey, certtype: PRIVATE_KEY, svc: CHEFSERVER},
-		{key: chefServerSettings.PublicKey, certtype: PUBLIC_KEY, svc: CHEFSERVER},
-	})
+	return nil
 }
 
 func checkCertValid(keys []keydetails) error {
@@ -249,36 +296,95 @@ func validateRootCACertificate(certBytes []byte, svc string) error {
 	return nil
 }
 
-func validatePostgresqlCerts(postgresqlSettings *ConfigSettings) error {
-	if len(strings.TrimSpace(postgresqlSettings.RootCA)) < 1 ||
-		len(strings.TrimSpace(postgresqlSettings.PrivateKey)) < 1 ||
-		len(strings.TrimSpace(postgresqlSettings.PublicKey)) < 1 {
-		return fmt.Errorf("postgresql root_ca and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+func validatePostgresqlCerts(depConfig *HaDeployConfig) error {
+	if depConfig.Postgresql.Config.CertsByIP == nil || len(*depConfig.Postgresql.Config.CertsByIP) == 0 {
+		if len(strings.TrimSpace(depConfig.Postgresql.Config.RootCA)) < 1 ||
+			len(strings.TrimSpace(depConfig.Postgresql.Config.PrivateKey)) < 1 ||
+			len(strings.TrimSpace(depConfig.Postgresql.Config.PublicKey)) < 1 {
+			return fmt.Errorf("postgresql root_ca and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+		}
+
+		return checkCertValid([]keydetails{
+			{key: depConfig.Postgresql.Config.RootCA, certtype: ROOT_CA, svc: POSTGRESQL},
+			{key: depConfig.Postgresql.Config.PrivateKey, certtype: PRIVATE_KEY, svc: POSTGRESQL},
+			{key: depConfig.Postgresql.Config.PublicKey, certtype: PUBLIC_KEY, svc: POSTGRESQL},
+		})
 	}
 
-	return checkCertValid([]keydetails{
-		{key: postgresqlSettings.RootCA, certtype: ROOT_CA, svc: POSTGRESQL},
-		{key: postgresqlSettings.PrivateKey, certtype: PRIVATE_KEY, svc: POSTGRESQL},
-		{key: postgresqlSettings.PublicKey, certtype: PUBLIC_KEY, svc: POSTGRESQL},
-	})
+	if depConfig.Postgresql.Config.RootCA == "" {
+		return fmt.Errorf("cannot find root_ca for ip for PostgresSQL")
+	}
+
+	// If CertByIp available then check it's availabe for all the nodes
+	for _, v := range *depConfig.Postgresql.Config.CertsByIP {
+		if v.PrivateKey == "" {
+			return fmt.Errorf(returnErrorPrivetKeyMsg, v.IP)
+		}
+
+		if v.PublicKey == "" {
+			return fmt.Errorf(returnErrorPublicKeyMsg, v.IP)
+		}
+
+		if err := checkCertValid([]keydetails{
+			{key: depConfig.Postgresql.Config.RootCA, certtype: ROOT_CA, svc: POSTGRESQL},
+			{key: v.PrivateKey, certtype: PRIVATE_KEY, svc: POSTGRESQL},
+			{key: v.PublicKey, certtype: PUBLIC_KEY, svc: POSTGRESQL},
+		}); err != nil {
+			return err
+		}
+
+	}
+
+	return nil
 }
 
-func validateOpensearchCerts(opensearchSettings *ConfigOpensearchSettings) error {
-	if len(strings.TrimSpace(opensearchSettings.RootCA)) < 1 ||
-		len(strings.TrimSpace(opensearchSettings.AdminKey)) < 1 ||
-		len(strings.TrimSpace(opensearchSettings.AdminCert)) < 1 ||
-		len(strings.TrimSpace(opensearchSettings.PrivateKey)) < 1 ||
-		len(strings.TrimSpace(opensearchSettings.PublicKey)) < 1 {
+func validateOpensearchCerts(depConfig *HaDeployConfig) error {
+	if depConfig.Opensearch.Config.CertsByIP == nil || len(*depConfig.Opensearch.Config.CertsByIP) == 0 {
+		if len(strings.TrimSpace(depConfig.Opensearch.Config.RootCA)) < 1 ||
+			len(strings.TrimSpace(depConfig.Opensearch.Config.AdminKey)) < 1 ||
+			len(strings.TrimSpace(depConfig.Opensearch.Config.AdminCert)) < 1 ||
+			len(strings.TrimSpace(depConfig.Opensearch.Config.PrivateKey)) < 1 ||
+			len(strings.TrimSpace(depConfig.Opensearch.Config.PublicKey)) < 1 {
+			return fmt.Errorf("opensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
+		}
+
+		return checkCertValid([]keydetails{
+			{key: depConfig.Opensearch.Config.RootCA, certtype: ROOT_CA, svc: OPENSEARCH},
+			{key: depConfig.Opensearch.Config.AdminKey, certtype: ADMIN_KEY, svc: OPENSEARCH},
+			{key: depConfig.Opensearch.Config.AdminCert, certtype: ADMIN_CERT, svc: OPENSEARCH},
+			{key: depConfig.Opensearch.Config.PrivateKey, certtype: PRIVATE_KEY, svc: OPENSEARCH},
+			{key: depConfig.Opensearch.Config.PublicKey, certtype: PUBLIC_KEY, svc: OPENSEARCH},
+		})
+	}
+
+	if len(strings.TrimSpace(depConfig.Opensearch.Config.RootCA)) < 1 ||
+		len(strings.TrimSpace(depConfig.Opensearch.Config.AdminKey)) < 1 ||
+		len(strings.TrimSpace(depConfig.Opensearch.Config.AdminCert)) < 1 {
 		return fmt.Errorf("opensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false")
 	}
 
-	return checkCertValid([]keydetails{
-		{key: opensearchSettings.RootCA, certtype: ROOT_CA, svc: OPENSEARCH},
-		{key: opensearchSettings.AdminKey, certtype: ADMIN_KEY, svc: OPENSEARCH},
-		{key: opensearchSettings.AdminCert, certtype: ADMIN_CERT, svc: OPENSEARCH},
-		{key: opensearchSettings.PrivateKey, certtype: PRIVATE_KEY, svc: OPENSEARCH},
-		{key: opensearchSettings.PublicKey, certtype: PUBLIC_KEY, svc: OPENSEARCH},
-	})
+	// If CertByIp available then check it's availabe for all the nodes
+	for _, v := range *depConfig.Opensearch.Config.CertsByIP {
+		if v.PrivateKey == "" {
+			return fmt.Errorf(returnErrorPrivetKeyMsg, v.IP)
+		}
+		if v.PublicKey == "" {
+			return fmt.Errorf(returnErrorPublicKeyMsg, v.IP)
+		}
+
+		if err := checkCertValid([]keydetails{
+			{key: depConfig.Opensearch.Config.RootCA, certtype: ROOT_CA, svc: OPENSEARCH},
+			{key: depConfig.Opensearch.Config.AdminKey, certtype: ADMIN_KEY, svc: OPENSEARCH},
+			{key: depConfig.Opensearch.Config.AdminCert, certtype: ROOT_CA, svc: OPENSEARCH},
+			{key: v.PrivateKey, certtype: PRIVATE_KEY, svc: OPENSEARCH},
+			{key: v.PublicKey, certtype: PUBLIC_KEY, svc: OPENSEARCH},
+		}); err != nil {
+			return err
+		}
+
+	}
+
+	return nil
 }
 
 func validateIPList(ipList []string, prefix string) error {


Test patch:
diff --git a/components/automate-cli/cmd/chef-automate/certRotate_test.go b/components/automate-cli/cmd/chef-automate/certRotate_test.go
index 4c3b58ec9..cde597978 100644
--- a/components/automate-cli/cmd/chef-automate/certRotate_test.go
+++ b/components/automate-cli/cmd/chef-automate/certRotate_test.go
@@ -260,9 +260,8 @@ func TestGetCerts(t *testing.T) {
 				automate:        true,
 				privateCertPath: ValidCertPath,
 				publicCertPath:  ValidCertPath,
-				rootCAPath:      ValidCertPath,
 			},
-			rootCaWant:      FileContent,
+			rootCaWant:      "",
 			publicCertWant:  FileContent,
 			privateCertWant: FileContent,
 			adminCertWant:   "",
@@ -349,26 +348,11 @@ func TestGetCerts(t *testing.T) {
 				publicCertPath:  ValidCertPath,
 			},
 			rootCaWant:      "",
-			publicCertWant:  "",
-			privateCertWant: "",
-			adminCertWant:   "",
-			adminKeyWant:    "",
-			isError:         true,
-		},
-		{
-			testCaseDescription: "All paths given but root-ca path is invalid(file not exist) flag is automate service",
-			flagsObj: certRotateFlags{
-				automate:        true,
-				privateCertPath: ValidCertPath,
-				publicCertPath:  ValidCertPath,
-				rootCAPath:      "./xyx-cert.go",
-			},
-			rootCaWant:      "",
-			publicCertWant:  "",
-			privateCertWant: "",
+			publicCertWant:  FileContent,
+			privateCertWant: FileContent,
 			adminCertWant:   "",
 			adminKeyWant:    "",
-			isError:         true,
+			isError:         false,
 		},
 		{
 			testCaseDescription: "Some mandatory path not given and flag is opensearch service",
diff --git a/components/automate-cli/pkg/verifyserver/models/batchcheck_test.go b/components/automate-cli/pkg/verifyserver/models/batchcheck_test.go
index 4a5d29526..aca4d2b7a 100644
--- a/components/automate-cli/pkg/verifyserver/models/batchcheck_test.go
+++ b/components/automate-cli/pkg/verifyserver/models/batchcheck_test.go
@@ -343,7 +343,7 @@ func TestPopulateWith(t *testing.T) {
 			filePath: "./testdata/InvalidHaOnPrem.toml",
 			want:     &Config{},
 			wantErr:  true,
-			err:      errors.New("invalid or empty: ssh_user\ninvalid or empty: ssh_key_file\nautomate private ip 1324.2534.1is not valid\ninvalid or empty: chef_server_private_ips\ninvalid or empty: opensearch_private_ips\ninvalid or empty: postgresql_private_ips\nurl should not include the protocol (http:// or https://): automate fqdn\nempty value: automate instance_count\ninvalid value 'automate.toml' for field 'config_file'. Expected values are: configs/automate.toml\ninvalid format. Failed to decode root_ca for automate\ninvalid format. Failed to decode private_key for automate\ninvalid format. Failed to decode public_key for automate\ninvalid format. Failed to decode private_key for automate ip\ninvalid format. Failed to decode public_key for automate ip\ninvalid value 'chef server instance_count' for field 'two'\ninvalid format. Failed to decode private_key for chef-infra-server\ninvalid format. Failed to decode public_key for chef-infra-server\ninvalid format. Failed to decode private_key for chef server ip\ninvalid format. Failed to decode public_key for chef server ip\nempty value: opensearch instance_count\nopensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false\nopensearch ippublic_key and/or private_key are missing in certs_by_ip. Otherwise set enable_custom_certs to false\nempty value: postgresql instance_count\ninvalid format. Failed to decode root_ca for postgresql\ninvalid format. Failed to decode private_key for postgresql\ninvalid format. Failed to decode public_key for postgresql\npostgresql ip 0.0.1 for certs is not valid\ninvalid format. Failed to decode private_key for postgresql ip\ninvalid format. Failed to decode public_key for postgresql ip"),
+			err:      errors.New("invalid or empty: ssh_user\ninvalid or empty: ssh_key_file\nautomate private ip 1324.2534.1is not valid\ninvalid or empty: chef_server_private_ips\ninvalid or empty: opensearch_private_ips\ninvalid or empty: postgresql_private_ips\nurl should not include the protocol (http:// or https://): automate fqdn\nempty value: automate instance_count\ninvalid value 'automate.toml' for field 'config_file'. Expected values are: configs/automate.toml\ninvalid format. Failed to decode private_key for automate\ninvalid format. Failed to decode public_key for automate\ninvalid format. Failed to decode private_key for automate ip\ninvalid format. Failed to decode public_key for automate ip\ninvalid value 'chef server instance_count' for field 'two'\ninvalid format. Failed to decode private_key for chef-infra-server\ninvalid format. Failed to decode public_key for chef-infra-server\ninvalid format. Failed to decode private_key for chef server ip\ninvalid format. Failed to decode public_key for chef server ip\nempty value: opensearch instance_count\nopensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false\nopensearch ippublic_key and/or private_key are missing in certs_by_ip. Otherwise set enable_custom_certs to false\nempty value: postgresql instance_count\ninvalid format. Failed to decode root_ca for postgresql\ninvalid format. Failed to decode private_key for postgresql\ninvalid format. Failed to decode public_key for postgresql\npostgresql ip 0.0.1 for certs is not valid\ninvalid format. Failed to decode private_key for postgresql ip\ninvalid format. Failed to decode public_key for postgresql ip"),
 		},
 		{
 			name:     "PopulateWith OnPrem Db Aws Managed Config",
diff --git a/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount_test.go b/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount_test.go
index bf70b3a48..19b6e3885 100644
--- a/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount_test.go
+++ b/components/automate-cli/pkg/verifyserver/server/api/v1/nfsmount_test.go
@@ -519,6 +519,7 @@ func TestNFSMount(t *testing.T) {
 				]
 			}`,
 			RequestBody: `{
+				"external_db_type":"",
 				"automate_node_ips": [
 					"localhost",
 					"localhost"
@@ -554,7 +555,7 @@ func TestNFSMount(t *testing.T) {
 			RequestBody: "Invalid Body",
 		},
 		{
-			TestName:     "Not Given all the required IPs",
+			TestName:     "Not Given all the required IPs in On-Prem chef managed",
 			ExpectedCode: 400,
 			ExpectedBody: `{
 				"status": "FAILED",
@@ -565,6 +566,23 @@ func TestNFSMount(t *testing.T) {
 				}
 			}`,
 			RequestBody: `{
+				"external_db_type":"",
+				"automate_node_ips": []
+			}`,
+		},
+		{
+			TestName:     "Not Given all the required IPs in On-Prem self managed",
+			ExpectedCode: 400,
+			ExpectedBody: `{
+				"status": "FAILED",
+				"result": null,
+				"error": {
+					"code": 400,
+					"message": "AutomateNodeIPs or ChefInfraServerNodeIPs cannot be empty"
+				}
+			}`,
+			RequestBody: `{
+				"external_db_type":"self-managed",
 				"automate_node_ips": []
 			}`,
 		},
diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck_test.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck_test.go
index 2c6b1c382..047fb4572 100644
--- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck_test.go
+++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/nfsmountbackupchecktrigger/nfsmountbackupcheck_test.go
@@ -29,6 +29,7 @@ var (
 
 const (
 	mountLocation = "test-mount"
+	TYPE          = "self-managed"
 
 	nfsMountResponse = `{
 		"status": "SUCCESS",
@@ -635,7 +636,8 @@ func TestNfsBackupConfigCheck_Run(t *testing.T) {
 			name: "Passed Response for chef-server,automate,opensearch and postgresql",
 			args: args{
 				config: &models.Config{
-					Hardware: hardware,
+					ExternalDbType: TYPE,
+					Hardware:       hardware,
 					Backup: &models.Backup{
 						FileSystem: &models.FileSystem{
 							MountLocation: mountLocation,
@@ -654,7 +656,8 @@ func TestNfsBackupConfigCheck_Run(t *testing.T) {
 			name: "Failure Mount Response for chef-server,automate,opensearch and postgresql",
 			args: args{
 				config: &models.Config{
-					Hardware: hardware,
+					ExternalDbType: TYPE,
+					Hardware:       hardware,
 					Backup: &models.Backup{
 						FileSystem: &models.FileSystem{
 							MountLocation: mountLocation,
@@ -674,7 +677,8 @@ func TestNfsBackupConfigCheck_Run(t *testing.T) {
 			name: "Recived Internal Server Error From the API",
 			args: args{
 				config: &models.Config{
-					Hardware: hardware,
+					ExternalDbType: TYPE,
+					Hardware:       hardware,
 					Backup: &models.Backup{
 						FileSystem: &models.FileSystem{
 							MountLocation: mountLocation,
@@ -693,7 +697,8 @@ func TestNfsBackupConfigCheck_Run(t *testing.T) {
 			name: "Invalid Response from service",
 			args: args{
 				config: &models.Config{
-					Hardware: hardware,
+					ExternalDbType: TYPE,
+					Hardware:       hardware,
 					Backup: &models.Backup{
 						FileSystem: &models.FileSystem{
 							MountLocation: mountLocation,
@@ -713,6 +718,7 @@ func TestNfsBackupConfigCheck_Run(t *testing.T) {
 			name: "Checking for Same Front end Nodes",
 			args: args{
 				config: &models.Config{
+					ExternalDbType: TYPE,
 					Hardware: &models.Hardware{
 						AutomateNodeIps:        hardware.AutomateNodeIps,
 						ChefInfraServerNodeIps: hardware.AutomateNodeIps,
@@ -732,6 +738,7 @@ func TestNfsBackupConfigCheck_Run(t *testing.T) {
 			httpStatusCode:        http.StatusOK,
 			isError:               false,
 			wantRequest: models.NFSMountRequest{
+				ExternalDbType:         TYPE,
 				AutomateNodeIPs:        hardware.AutomateNodeIps,
 				ChefInfraServerNodeIPs: hardware.AutomateNodeIps,
 				PostgresqlNodeIPs:      hardware.PostgresqlNodeIps,
@@ -820,6 +827,7 @@ func createDummyServer(t *testing.T, requiredStatusCode int, isPassed bool, pars
 
 func getRequest() models.NFSMountRequest {
 	return models.NFSMountRequest{
+		ExternalDbType:         TYPE,
 		AutomateNodeIPs:        hardware.AutomateNodeIps,
 		ChefInfraServerNodeIPs: hardware.ChefInfraServerNodeIps,
 		PostgresqlNodeIPs:      hardware.PostgresqlNodeIps,
diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck_test.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck_test.go
index 0e9e14cb7..7f76416bd 100644
--- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck_test.go
+++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/opensearchs3bucketaccesschecktrigger/opensearchs3bucketaccesscheck_test.go
@@ -226,7 +226,7 @@ func TestOpensearchS3BucketAccessCheck_Run(t *testing.T) {
 			} else {
 				if tt.name == "Nil OS and Object storage" {
 					assert.Len(t, got, 1)
-					assert.Equal(t, constants.UNKNOWN_HOST, got[0].Host)
+					assert.Equal(t, "-", got[0].Host)
 					assert.Equal(t, constants.OPENSEARCH, got[0].NodeType)
 					assert.Equal(t, constants.AWS_OPENSEARCH_S3_BUCKET_ACCESS, got[0].CheckType)
 					assert.True(t, got[0].Result.Skipped)
diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger_test.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger_test.go
index 66fca2eb2..5c4ff7e25 100644
--- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger_test.go
+++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/s3backupchecktrigger/s3backupconfigchecktrigger_test.go
@@ -339,7 +339,7 @@ func TestRunS3BackupCheck(t *testing.T) {
 		got := svc.Run(config)
 
 		assert.Len(t, got, 1)
-		assert.Equal(t, constants.UNKNOWN_HOST, got[0].Host)
+		assert.Equal(t, "-", got[0].Host)
 		assert.Equal(t, constants.AUTOMATE, got[0].NodeType)
 		assert.Equal(t, constants.S3_BACKUP_CONFIG, got[0].CheckType)
 		assert.True(t, got[0].Result.Skipped)
diff --git a/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation_test.go b/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation_test.go
index 1f8f2356d..4a9c88cce 100644
--- a/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation_test.go
+++ b/components/automate-cli/pkg/verifyserver/services/certificatevalidation/certificatevalidation_test.go
@@ -550,49 +550,7 @@ func TestCertificateValidation(t *testing.T) {
 				},
 			},
 		},
-		{
-			TestName: "Private Key is not in PKCS8 format",
-			ReqBody: models.CertificateCheckRequest{
-				RootCertificate:  ROOT_CERTIFICATE,
-				PrivateKey:       INVALID_KEY_FORMAT,
-				NodeCertificate:  NODE_CERTIFICATE,
-				AdminPrivateKey:  ADMIN_PRIVATE_KEY,
-				AdminCertificate: ADMIN_CERTIFICATE,
-			},
-			ExpectedResBody: models.CertificateCheckResponse{
-				Passed: false,
-				Checks: []models.Checks{
-					{
-						Title:         constants.CERTIFICATE_EXPIRY_TITLE,
-						Passed:        true,
-						SuccessMsg:    constants.CERTIFICATE_EXPIRY_SUCCESS_MESSAGE,
-						ErrorMsg:      "",
-						ResolutionMsg: "",
-					},
-					{
-						Title:         constants.CERTIFICATE_FORMAT_TITLE,
-						Passed:        true,
-						SuccessMsg:    constants.CERTIFICATE_FORMAT_SUCCESS_MESSAGE,
-						ErrorMsg:      "",
-						ResolutionMsg: "",
-					},
-					{
-						Title:         constants.KEY_FORMAT_TITLE,
-						Passed:        false,
-						SuccessMsg:    "",
-						ErrorMsg:      fmt.Sprintf(constants.KEY_FORMAT_ERROR_MESSAGE, constants.NODE_KEY),
-						ResolutionMsg: fmt.Sprintf(constants.KEY_FORMAT_RESOLUTION_MESSAGE, constants.NODE_KEY),
-					},
-					{
-						Title:         constants.CERTIFICATE_ALGORITHM_TITLE,
-						Passed:        true,
-						SuccessMsg:    constants.CERTIFICATE_ALGORITHM_SUCCESS_MESSAGE,
-						ErrorMsg:      "",
-						ResolutionMsg: "",
-					},
-				},
-			},
-		},
+
 		{
 			TestName: "There is no root certificate",
 			ReqBody: models.CertificateCheckRequest{
diff --git a/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice_test.go b/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice_test.go
index 3f65a1f3b..1b33d3bb3 100644
--- a/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice_test.go
+++ b/components/automate-cli/pkg/verifyserver/services/nfsmountservice/nfsmountservice_test.go
@@ -348,21 +348,27 @@ func TestGetNFSMountDetails(t *testing.T) {
 			Response: []models.NFSMountResponse{
 				{IP: "localhost", NodeType: "automate", CheckList: []models.Checks{
 					{Passed: true},
-					{Passed: true},
+					{Passed: false},
+				}, Error: nil},
+				{IP: "192.168.54.34", NodeType: "automate", CheckList: []models.Checks{
+					{Passed: false},
+					{Passed: false},
 				}, Error: nil},
-				{IP: "192.168.54.34", NodeType: "automate", CheckList: nil, Error: errors.New("")},
 				{IP: "localhost", NodeType: "chef-infra-server", CheckList: []models.Checks{
 					{Passed: true},
-					{Passed: true},
+					{Passed: false},
+				}, Error: nil},
+				{IP: "anything.com", NodeType: "postgresql", CheckList: []models.Checks{
+					{Passed: false},
+					{Passed: false},
 				}, Error: nil},
-				{IP: "anything.com", NodeType: "postgresql", CheckList: nil, Error: errors.New("")},
 				{IP: "localhost", NodeType: "postgresql", CheckList: []models.Checks{
 					{Passed: true},
-					{Passed: true},
+					{Passed: false},
 				}, Error: nil},
 				{IP: "localhost", NodeType: "opensearch", CheckList: []models.Checks{
 					{Passed: true},
-					{Passed: true},
+					{Passed: false},
 				}, Error: nil},
 			},
 		},
diff --git a/lib/config/hadeployconfigverify_test.go b/lib/config/hadeployconfigverify_test.go
index 47d348eac..d905371cd 100644
--- a/lib/config/hadeployconfigverify_test.go
+++ b/lib/config/hadeployconfigverify_test.go
@@ -33,7 +33,7 @@ func TestParseAndVerify(t *testing.T) {
 			name:    "Verify OnPrem Config",
 			args:    args{configFile: "./testdata/HaOnPrem.toml"},
 			wantErr: true,
-			err:     errors.New("invalid or empty: ssh_user\ninvalid or empty: ssh_key_file\nautomate private ip 1324.2534.1is not valid\ninvalid or empty: chef_server_private_ips\ninvalid or empty: opensearch_private_ips\ninvalid or empty: postgresql_private_ips\nurl should not include the protocol (http:// or https://): automate fqdn\nempty value: automate instance_count\ninvalid value 'automate.toml' for field 'config_file'. Expected values are: configs/automate.toml\ninvalid format. Failed to decode root_ca for automate\ninvalid format. Failed to decode private_key for automate\ninvalid format. Failed to decode public_key for automate\ninvalid format. Failed to decode private_key for automate ip\ninvalid format. Failed to decode public_key for automate ip\ninvalid value 'chef server instance_count' for field 'two'\ninvalid format. Failed to decode private_key for chef-infra-server\ninvalid format. Failed to decode public_key for chef-infra-server\ninvalid format. Failed to decode private_key for chef server ip\ninvalid format. Failed to decode public_key for chef server ip\nempty value: opensearch instance_count\nopensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false\nopensearch ippublic_key and/or private_key are missing in certs_by_ip. Otherwise set enable_custom_certs to false\nempty value: postgresql instance_count\ninvalid format. Failed to decode root_ca for postgresql\ninvalid format. Failed to decode private_key for postgresql\ninvalid format. Failed to decode public_key for postgresql\npostgresql ip 0.0.1 for certs is not valid\ninvalid format. Failed to decode private_key for postgresql ip\ninvalid format. Failed to decode public_key for postgresql ip"),
+			err:     errors.New("invalid or empty: ssh_user\ninvalid or empty: ssh_key_file\nautomate private ip 1324.2534.1is not valid\ninvalid or empty: chef_server_private_ips\ninvalid or empty: opensearch_private_ips\ninvalid or empty: postgresql_private_ips\nurl should not include the protocol (http:// or https://): automate fqdn\nempty value: automate instance_count\ninvalid value 'automate.toml' for field 'config_file'. Expected values are: configs/automate.toml\ninvalid format. Failed to decode private_key for automate\ninvalid format. Failed to decode public_key for automate\ninvalid format. Failed to decode private_key for automate ip\ninvalid format. Failed to decode public_key for automate ip\ninvalid value 'chef server instance_count' for field 'two'\ninvalid format. Failed to decode private_key for chef-infra-server\ninvalid format. Failed to decode public_key for chef-infra-server\ninvalid format. Failed to decode private_key for chef server ip\ninvalid format. Failed to decode public_key for chef server ip\nempty value: opensearch instance_count\nopensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false\nopensearch ippublic_key and/or private_key are missing in certs_by_ip. Otherwise set enable_custom_certs to false\nempty value: postgresql instance_count\ninvalid format. Failed to decode root_ca for postgresql\ninvalid format. Failed to decode private_key for postgresql\ninvalid format. Failed to decode public_key for postgresql\npostgresql ip 0.0.1 for certs is not valid\ninvalid format. Failed to decode private_key for postgresql ip\ninvalid format. Failed to decode public_key for postgresql ip"),
 		},
 		{
 			name:    "Verify OnPrem Db Self-Managed Config",
diff --git a/lib/config/helper_test.go b/lib/config/helper_test.go
index 9fca0c043..c7bf12f1a 100644
--- a/lib/config/helper_test.go
+++ b/lib/config/helper_test.go
@@ -10,6 +10,8 @@ import (
 	"math/big"
 	"testing"
 	"time"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestValidateStringBasedBoolean(t *testing.T) {
@@ -426,3 +428,554 @@ func generateExpiredCert() []byte {
 	derBytes, _ := x509.CreateCertificate(rand.Reader, template, template, &publicKey, privateKey)
 	return derBytes
 }
+
+const (
+	PublicKey  = "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIUMUG0kbGT5s8Vo415aNfii81CzRcwDQYJKoZIhvcNAQEL\nBQAwZTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM\nB1NlYXR0bGUxGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApj\naGVmcm9vdGNhMB4XDTIyMDYwMTA3MzMwMFoXDTI1MDUzMTA3MzMwMFowZTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx\nGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApjaGVmcm9vdGNh\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4aKz6j+Otgeg+oZSsHtq\nz5Phyb2cWr+CdbLb2qZA9ZDcCjEzkxvuvI6QBScF9feVk7YVXg59DXlHJRP7AHx5\nnG5iQmND0jUUQGjyZfKTWO8Z9F8D/w0HAFOk4LTvVR/AAC6f9PpxjaydfSzkh5cc\nNxeotjlkYUgh6D7fFma9gRtjX4a36miA5FqCv0Lkwrk9tXHdDk6skdjBvCS0URnq\nzDfyTcK7R/L/iaGYtY43c8tB8eHKwK+ZQ2fR4V90YI3xkbkwr6j0efZyU2Kp/03r\n2nDtFQXHwwuj6Sg465DJB9MQ01IbR30NUjJiFGOJaxdRlhsEeWWNL8BELQuGpJe9\nVQIDAQABo1MwUTAdBgNVHQ4EFgQU3XAfDSRK1wCTf0wiDjlR4m06FCQwHwYDVR0j\nBBgwFoAU3XAfDSRK1wCTf0wiDjlR4m06FCQwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAQEAVTiFfpOzYfXzQxTrl4VxctdQJI52jPjWP55PmK/IO7sb\nn/DKzRNnvn7mN3EDGmshh5i76/hoGA09pK4SdAwJl2QIRJSu3ChH4QCf7n/iIYww\nSxhpOp9QtJA5Cyu4MoemK49Lld/7xf3Qdt1pOgEMz4AGLt2uwS5SdmR4OkSPHqt0\nQq/lgSoiawVOd0UE+5Ocu5S472du/REcVS4KkQdkzZaw9Q7OGIN9G0X0wb0V3UZs\nR2XuApUUaGOl0s0a1uNMv3WkyOrCGS3JkIem6+R59pfliaz6FPcQD+0oXI2gjG3c\nH4VFwOis/oT/2FwYM89j7XZPDpRfUUGMHD53W7YPHA==\n-----END CERTIFICATE-----"
+	PrivateKey = "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIUMUG0kbGT5s8Vo415aNfii81CzRcwDQYJKoZIhvcNAQEL\nBQAwZTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM\nB1NlYXR0bGUxGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApj\naGVmcm9vdGNhMB4XDTIyMDYwMTA3MzMwMFoXDTI1MDUzMTA3MzMwMFowZTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx\nGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApjaGVmcm9vdGNh\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4aKz6j+Otgeg+oZSsHtq\nz5Phyb2cWr+CdbLb2qZA9ZDcCjEzkxvuvI6QBScF9feVk7YVXg59DXlHJRP7AHx5\nnG5iQmND0jUUQGjyZfKTWO8Z9F8D/w0HAFOk4LTvVR/AAC6f9PpxjaydfSzkh5cc\nNxeotjlkYUgh6D7fFma9gRtjX4a36miA5FqCv0Lkwrk9tXHdDk6skdjBvCS0URnq\nzDfyTcK7R/L/iaGYtY43c8tB8eHKwK+ZQ2fR4V90YI3xkbkwr6j0efZyU2Kp/03r\n2nDtFQXHwwuj6Sg465DJB9MQ01IbR30NUjJiFGOJaxdRlhsEeWWNL8BELQuGpJe9\nVQIDAQABo1MwUTAdBgNVHQ4EFgQU3XAfDSRK1wCTf0wiDjlR4m06FCQwHwYDVR0j\nBBgwFoAU3XAfDSRK1wCTf0wiDjlR4m06FCQwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAQEAVTiFfpOzYfXzQxTrl4VxctdQJI52jPjWP55PmK/IO7sb\nn/DKzRNnvn7mN3EDGmshh5i76/hoGA09pK4SdAwJl2QIRJSu3ChH4QCf7n/iIYww\nSxhpOp9QtJA5Cyu4MoemK49Lld/7xf3Qdt1pOgEMz4AGLt2uwS5SdmR4OkSPHqt0\nQq/lgSoiawVOd0UE+5Ocu5S472du/REcVS4KkQdkzZaw9Q7OGIN9G0X0wb0V3UZs\nR2XuApUUaGOl0s0a1uNMv3WkyOrCGS3JkIem6+R59pfliaz6FPcQD+0oXI2gjG3c\nH4VFwOis/oT/2FwYM89j7XZPDpRfUUGMHD53W7YPHA==\n-----END CERTIFICATE-----"
+	RootCa     = "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIUMUG0kbGT5s8Vo415aNfii81CzRcwDQYJKoZIhvcNAQEL\nBQAwZTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM\nB1NlYXR0bGUxGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApj\naGVmcm9vdGNhMB4XDTIyMDYwMTA3MzMwMFoXDTI1MDUzMTA3MzMwMFowZTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx\nGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApjaGVmcm9vdGNh\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4aKz6j+Otgeg+oZSsHtq\nz5Phyb2cWr+CdbLb2qZA9ZDcCjEzkxvuvI6QBScF9feVk7YVXg59DXlHJRP7AHx5\nnG5iQmND0jUUQGjyZfKTWO8Z9F8D/w0HAFOk4LTvVR/AAC6f9PpxjaydfSzkh5cc\nNxeotjlkYUgh6D7fFma9gRtjX4a36miA5FqCv0Lkwrk9tXHdDk6skdjBvCS0URnq\nzDfyTcK7R/L/iaGYtY43c8tB8eHKwK+ZQ2fR4V90YI3xkbkwr6j0efZyU2Kp/03r\n2nDtFQXHwwuj6Sg465DJB9MQ01IbR30NUjJiFGOJaxdRlhsEeWWNL8BELQuGpJe9\nVQIDAQABo1MwUTAdBgNVHQ4EFgQU3XAfDSRK1wCTf0wiDjlR4m06FCQwHwYDVR0j\nBBgwFoAU3XAfDSRK1wCTf0wiDjlR4m06FCQwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAQEAVTiFfpOzYfXzQxTrl4VxctdQJI52jPjWP55PmK/IO7sb\nn/DKzRNnvn7mN3EDGmshh5i76/hoGA09pK4SdAwJl2QIRJSu3ChH4QCf7n/iIYww\nSxhpOp9QtJA5Cyu4MoemK49Lld/7xf3Qdt1pOgEMz4AGLt2uwS5SdmR4OkSPHqt0\nQq/lgSoiawVOd0UE+5Ocu5S472du/REcVS4KkQdkzZaw9Q7OGIN9G0X0wb0V3UZs\nR2XuApUUaGOl0s0a1uNMv3WkyOrCGS3JkIem6+R59pfliaz6FPcQD+0oXI2gjG3c\nH4VFwOis/oT/2FwYM89j7XZPDpRfUUGMHD53W7YPHA==\n-----END CERTIFICATE-----"
+	AdminCert  = "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIUMUG0kbGT5s8Vo415aNfii81CzRcwDQYJKoZIhvcNAQEL\nBQAwZTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM\nB1NlYXR0bGUxGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApj\naGVmcm9vdGNhMB4XDTIyMDYwMTA3MzMwMFoXDTI1MDUzMTA3MzMwMFowZTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx\nGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApjaGVmcm9vdGNh\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4aKz6j+Otgeg+oZSsHtq\nz5Phyb2cWr+CdbLb2qZA9ZDcCjEzkxvuvI6QBScF9feVk7YVXg59DXlHJRP7AHx5\nnG5iQmND0jUUQGjyZfKTWO8Z9F8D/w0HAFOk4LTvVR/AAC6f9PpxjaydfSzkh5cc\nNxeotjlkYUgh6D7fFma9gRtjX4a36miA5FqCv0Lkwrk9tXHdDk6skdjBvCS0URnq\nzDfyTcK7R/L/iaGYtY43c8tB8eHKwK+ZQ2fR4V90YI3xkbkwr6j0efZyU2Kp/03r\n2nDtFQXHwwuj6Sg465DJB9MQ01IbR30NUjJiFGOJaxdRlhsEeWWNL8BELQuGpJe9\nVQIDAQABo1MwUTAdBgNVHQ4EFgQU3XAfDSRK1wCTf0wiDjlR4m06FCQwHwYDVR0j\nBBgwFoAU3XAfDSRK1wCTf0wiDjlR4m06FCQwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAQEAVTiFfpOzYfXzQxTrl4VxctdQJI52jPjWP55PmK/IO7sb\nn/DKzRNnvn7mN3EDGmshh5i76/hoGA09pK4SdAwJl2QIRJSu3ChH4QCf7n/iIYww\nSxhpOp9QtJA5Cyu4MoemK49Lld/7xf3Qdt1pOgEMz4AGLt2uwS5SdmR4OkSPHqt0\nQq/lgSoiawVOd0UE+5Ocu5S472du/REcVS4KkQdkzZaw9Q7OGIN9G0X0wb0V3UZs\nR2XuApUUaGOl0s0a1uNMv3WkyOrCGS3JkIem6+R59pfliaz6FPcQD+0oXI2gjG3c\nH4VFwOis/oT/2FwYM89j7XZPDpRfUUGMHD53W7YPHA==\n-----END CERTIFICATE-----"
+	AdminKey   = "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIUMUG0kbGT5s8Vo415aNfii81CzRcwDQYJKoZIhvcNAQEL\nBQAwZTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM\nB1NlYXR0bGUxGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApj\naGVmcm9vdGNhMB4XDTIyMDYwMTA3MzMwMFoXDTI1MDUzMTA3MzMwMFowZTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx\nGjAYBgNVBAoMEUNoZWYgU29mdHdhcmUgSW5jMRMwEQYDVQQDDApjaGVmcm9vdGNh\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4aKz6j+Otgeg+oZSsHtq\nz5Phyb2cWr+CdbLb2qZA9ZDcCjEzkxvuvI6QBScF9feVk7YVXg59DXlHJRP7AHx5\nnG5iQmND0jUUQGjyZfKTWO8Z9F8D/w0HAFOk4LTvVR/AAC6f9PpxjaydfSzkh5cc\nNxeotjlkYUgh6D7fFma9gRtjX4a36miA5FqCv0Lkwrk9tXHdDk6skdjBvCS0URnq\nzDfyTcK7R/L/iaGYtY43c8tB8eHKwK+ZQ2fR4V90YI3xkbkwr6j0efZyU2Kp/03r\n2nDtFQXHwwuj6Sg465DJB9MQ01IbR30NUjJiFGOJaxdRlhsEeWWNL8BELQuGpJe9\nVQIDAQABo1MwUTAdBgNVHQ4EFgQU3XAfDSRK1wCTf0wiDjlR4m06FCQwHwYDVR0j\nBBgwFoAU3XAfDSRK1wCTf0wiDjlR4m06FCQwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAQEAVTiFfpOzYfXzQxTrl4VxctdQJI52jPjWP55PmK/IO7sb\nn/DKzRNnvn7mN3EDGmshh5i76/hoGA09pK4SdAwJl2QIRJSu3ChH4QCf7n/iIYww\nSxhpOp9QtJA5Cyu4MoemK49Lld/7xf3Qdt1pOgEMz4AGLt2uwS5SdmR4OkSPHqt0\nQq/lgSoiawVOd0UE+5Ocu5S472du/REcVS4KkQdkzZaw9Q7OGIN9G0X0wb0V3UZs\nR2XuApUUaGOl0s0a1uNMv3WkyOrCGS3JkIem6+R59pfliaz6FPcQD+0oXI2gjG3c\nH4VFwOis/oT/2FwYM89j7XZPDpRfUUGMHD53W7YPHA==\n-----END CERTIFICATE-----"
+
+	DummyPublicKey  = "DummyPublicKey"
+	DummyPrivateKey = "DummyPrivateKey"
+)
+
+func Test_validateAutomateCerts(t *testing.T) {
+	t.Run("NIL CERTByIP", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Automate: &AutomateSettings{
+				Config: &ConfigAutomateSettings{
+					CertsByIP: nil,
+				},
+			},
+		}
+
+		expectedErr := "automate root_ca and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false"
+		err := validateAutomateCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("Invalid common Certs", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Automate: &AutomateSettings{
+				Config: &ConfigAutomateSettings{
+					CertsByIP:  nil,
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode private_key for automate\ninvalid format. Failed to decode public_key for automate"
+		err := validateAutomateCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Automate: &AutomateSettings{
+				Config: &ConfigAutomateSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP: "10.10.10.10",
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "cannot find private key for ip 10.10.10.10"
+		err := validateAutomateCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Automate: &AutomateSettings{
+				Config: &ConfigAutomateSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: DummyPrivateKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "cannot find public key for ip 10.10.10.11"
+		err := validateAutomateCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No CertByIP validate", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Automate: &AutomateSettings{
+				Config: &ConfigAutomateSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: DummyPrivateKey,
+							PublicKey:  DummyPublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode private_key for automate\ninvalid format. Failed to decode public_key for automate"
+		err := validateAutomateCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("NO Error", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Automate: &AutomateSettings{
+				Config: &ConfigAutomateSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: PrivateKey,
+							PublicKey:  PublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		err := validateAutomateCerts(depConfig)
+		assert.NoError(t, err)
+	})
+}
+
+func Test_validateChefServerCerts(t *testing.T) {
+	t.Run("NIL CERTByIP", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			ChefServer: &ChefServerSettings{
+				Config: &ConfigSettings{
+					CertsByIP: nil,
+				},
+			},
+		}
+
+		expectedErr := "chefServer public_key and/or private_key are missing. Otherwise set enable_custom_certs to false"
+		err := validateChefServerCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("Invalid common Certs", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			ChefServer: &ChefServerSettings{
+				Config: &ConfigSettings{
+					CertsByIP:  nil,
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode private_key for chef-infra-server\ninvalid format. Failed to decode public_key for chef-infra-server"
+		err := validateChefServerCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			ChefServer: &ChefServerSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP: "10.10.10.10",
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "cannot find private key for ip 10.10.10.10"
+		err := validateChefServerCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			ChefServer: &ChefServerSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: "-----PK-----",
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "cannot find public key for ip 10.10.10.11"
+		err := validateChefServerCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No CertByIP validate", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			ChefServer: &ChefServerSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: DummyPrivateKey,
+							PublicKey:  DummyPublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode private_key for chef-infra-server\ninvalid format. Failed to decode public_key for chef-infra-server"
+		err := validateChefServerCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("NO Error", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			ChefServer: &ChefServerSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: PrivateKey,
+							PublicKey:  PublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+				},
+			},
+		}
+
+		err := validateChefServerCerts(depConfig)
+		assert.NoError(t, err)
+	})
+}
+
+func Test_validatePostgresqlCerts(t *testing.T) {
+	t.Run("NIL CERTByIP", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{},
+			},
+		}
+
+		expectedErr := "postgresql root_ca and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false"
+		err := validatePostgresqlCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("Invalid common Certs", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{
+					CertsByIP:  nil,
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+					RootCA:     "dummy_root_cert",
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode root_ca for postgresql\ninvalid format. Failed to decode private_key for postgresql\ninvalid format. Failed to decode public_key for postgresql"
+		err := validatePostgresqlCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP: "10.10.10.10",
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+					RootCA:     "-----ROOTCA KEY-----",
+				},
+			},
+		}
+
+		expectedErr := "cannot find private key for ip 10.10.10.10"
+		err := validatePostgresqlCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: DummyPrivateKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+					RootCA:     "-----ROOTCA KEY-----",
+				},
+			},
+		}
+
+		expectedErr := "cannot find public key for ip 10.10.10.11"
+		err := validatePostgresqlCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No CertByIP validate", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: DummyPrivateKey,
+							PublicKey:  DummyPublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+					RootCA:     "-----ROOTCA KEY-----",
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode root_ca for postgresql\ninvalid format. Failed to decode private_key for postgresql\ninvalid format. Failed to decode public_key for postgresql"
+		err := validatePostgresqlCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("NO Error", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: PrivateKey,
+							PublicKey:  PublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+					RootCA:     RootCa,
+				},
+			},
+		}
+
+		err := validatePostgresqlCerts(depConfig)
+		assert.NoError(t, err)
+	})
+
+	t.Run("RootCert Error", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Postgresql: &PostgresqlSettings{
+				Config: &ConfigSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: PrivateKey,
+							PublicKey:  PublicKey,
+						},
+					},
+					PrivateKey: DummyPrivateKey,
+					PublicKey:  DummyPublicKey,
+					RootCA:     "",
+				},
+			},
+		}
+
+		expectedErr := "cannot find root_ca for ip for PostgresSQL"
+		err := validatePostgresqlCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+}
+
+func Test_validateOpensearchCerts(t *testing.T) {
+	t.Run("NIL CERTByIP", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{},
+			},
+		}
+
+		expectedErr := "opensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false"
+		err := validateOpensearchCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("Invalid common Certs", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{
+					CertsByIP:  nil,
+					PrivateKey: "-----PRIVATE KEY-----",
+					PublicKey:  "-----PUBLIC KEY-----",
+					RootCA:     "dummy_root_cert",
+					AdminCert:  "admin key",
+					AdminKey:   "admin key",
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode root_ca for opensearch\ninvalid format. Failed to decode admin_key for opensearch\ninvalid format. Failed to decode admin_cert for opensearch\ninvalid format. Failed to decode private_key for opensearch\ninvalid format. Failed to decode public_key for opensearch"
+		err := validateOpensearchCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No CertByIP validate", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: "-----PRIVATE2 KEY-----",
+							PublicKey:  "-----PRIVATE2sdsf KEY-----",
+						},
+					},
+					PrivateKey: "-----PRIVATE1 KEY-----",
+					PublicKey:  "-----PUBLIC1 KEY-----",
+					RootCA:     "-----ROOTCA KEY-----",
+					AdminCert:  "admin cer",
+					AdminKey:   "admin key",
+				},
+			},
+		}
+
+		expectedErr := "invalid format. Failed to decode root_ca for opensearch\ninvalid format. Failed to decode admin_key for opensearch\ninvalid format. Failed to decode root_ca for opensearch\ninvalid format. Failed to decode private_key for opensearch\ninvalid format. Failed to decode public_key for opensearch"
+		err := validateOpensearchCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("NO Error", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: PrivateKey,
+							PublicKey:  PublicKey,
+						},
+					},
+					PrivateKey: "-----PRIVATE1 KEY-----",
+					PublicKey:  "-----PUBLIC1 KEY-----",
+					RootCA:     RootCa,
+					AdminCert:  AdminCert,
+					AdminKey:   AdminKey,
+				},
+			},
+		}
+
+		err := validateOpensearchCerts(depConfig)
+		assert.NoError(t, err)
+	})
+
+	t.Run("RootCert Error", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.11",
+							PrivateKey: PrivateKey,
+							PublicKey:  PublicKey,
+						},
+					},
+					PrivateKey: "-----PRIVATE1 KEY-----",
+					PublicKey:  "-----PUBLIC1 KEY-----",
+					RootCA:     "",
+				},
+			},
+		}
+
+		expectedErr := "opensearch root_ca and/or admin_key and/or admin_cert and/or public_key and/or private_key are missing. Otherwise set enable_custom_certs to false"
+		err := validateOpensearchCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+
+	t.Run("No private key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP: "10.10.10.10",
+						},
+					},
+					RootCA:    "root ca",
+					AdminCert: "admin cert",
+					AdminKey:  "admin  key",
+				},
+			},
+		}
+
+		expectedErr := "cannot find private key for ip 10.10.10.10"
+		err := validateOpensearchCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+	t.Run("No Public key", func(t *testing.T) {
+		depConfig := &HaDeployConfig{
+			Opensearch: &OpensearchSettings{
+				Config: &ConfigOpensearchSettings{
+					CertsByIP: &[]CertByIP{
+						{
+							IP:         "10.10.10.10",
+							PrivateKey: "private key",
+						},
+					},
+					RootCA:    "root ca",
+					AdminCert: "admin cert",
+					AdminKey:  "admin  key",
+				},
+			},
+		}
+
+		expectedErr := "cannot find public key for ip 10.10.10.10"
+		err := validateOpensearchCerts(depConfig)
+		assert.Error(t, err)
+		assert.EqualError(t, err, expectedErr)
+	})
+}