diff --git a/components/automate-cli/pkg/verifyserver/constants/fqdn.go b/components/automate-cli/pkg/verifyserver/constants/fqdn.go index 37a868e8294..8e4caf941bf 100644 --- a/components/automate-cli/pkg/verifyserver/constants/fqdn.go +++ b/components/automate-cli/pkg/verifyserver/constants/fqdn.go @@ -1,20 +1,25 @@ package constants const ( - FQDN_TITLE = "FQDN is reachable" - FQDN_ERROR_MESSAGE = "FQDN is not reachable" - FQDN_RESOLUTION_MESSAGE = "Ensure FQDN is reachable and mapped to load balancer.Also, ensure your Port 443 is open and load balancer is able to reach to the machine on port 443. Review security group or firewall settings." - NODE_TITLE = "Nodes are reachable" - NODE_SUCCESS_MESSAGE = "All nodes are reachable" - NODE_ERROR_MESSAGE = "%v is not reachable" - NODE_RESOLUTION_MESSAGE = "Ensure your Port 443 is open. Review security group or firewall settings." - CERTIFICATE_TITLE = "Certificate validity for FQDN" - CERTIFICATE_SUCCESS_MESSAGE = "FQDN has with valid certificates" - CERTIFICATE_ERROR_MESSAGE = "FQDN certificate is not valid." - CERTIFICATE_RESOLUTION_MESSAGE = "Generate new valid certificates and provide those." - IP_TO_HASH_FAIL_MESSAGE = "Failed to hash the IP." - DEFAULT_HTTPS_PORT = "443" - SERVER_IP_HEADER_KEY = "x-server-ip" - CHAN_RESULT_ERROR_MESSAGE = "error recieved" - MIN_NUMBER_OF_CALLS = 50 + FQDN_TITLE = "FQDN is reachable" + FQDN_ERROR_MESSAGE = "FQDN is not reachable" + FQDN_RESOLUTION_MESSAGE = "Ensure FQDN is reachable and mapped to load balancer. Also, ensure your Port 443 is open and load balancer is able to reach to the machine on port 443. Review security group or firewall settings." + CERT_CN_MISMATCH_RESOLUTION_MESSAGE = "Ensure the certificate provided is Valid. In case of self-signed certificate, make sure the DNS provided in \"subjectAltName\" matches with \"CN\" (Common Name)" + CERT_CN_MISMATCH_ERROR_PATTERN = "x509: certificate is not valid for any names, but wanted to match" + INVALID_FQDN_CERT_RESOLUTION_MESSAGE = "Ensure the certificate provided is Valid. In case of self-signed certificate, make sure the root-ca and the certificate provided in LB belongs to same CA" + INVALID_FQDN_CERT_ERROR_PATTERN = "x509: certificate signed by unknown authority" + GENERIC_FQDN_CERT_RESOLUTION_MESSAGE = "Ensure the certificate provided is Valid. Also check if the FQDN is reachable, and mapped to load balancer. Review security group or firewall settings for the load-balance." + NODE_TITLE = "Nodes are reachable" + NODE_SUCCESS_MESSAGE = "All nodes are reachable" + NODE_ERROR_MESSAGE = "%v is not reachable" + NODE_RESOLUTION_MESSAGE = "Ensure your Port 443 is open. Review security group or firewall settings of the node." + CERTIFICATE_TITLE = "Certificate validity for FQDN" + CERTIFICATE_SUCCESS_MESSAGE = "FQDN has with valid certificates" + CERTIFICATE_ERROR_MESSAGE = "FQDN certificate is not valid." + CERTIFICATE_RESOLUTION_MESSAGE = "Generate new valid certificates and provide those." + IP_TO_HASH_FAIL_MESSAGE = "Failed to hash the IP." + DEFAULT_HTTPS_PORT = "443" + SERVER_IP_HEADER_KEY = "x-server-ip" + CHAN_RESULT_ERROR_MESSAGE = "error recieved" + MIN_NUMBER_OF_CALLS = 50 ) diff --git a/components/automate-cli/pkg/verifyserver/server/api/v1/fqdn.go b/components/automate-cli/pkg/verifyserver/server/api/v1/fqdn.go index 19ea1593b70..9d47920909f 100644 --- a/components/automate-cli/pkg/verifyserver/server/api/v1/fqdn.go +++ b/components/automate-cli/pkg/verifyserver/server/api/v1/fqdn.go @@ -37,6 +37,6 @@ func (h *Handler) CheckFqdn(c *fiber.Ctx) error { return fiber.NewError(http.StatusBadRequest, "node_type should be automate or chef-infra-server, Please provide node_type.") } - res := h.FqdnService.CheckFqdnReachability(*req, constants.DEFAULT_HTTPS_PORT, time.Minute*1) + res := h.FqdnService.CheckFqdnReachability(*req, constants.DEFAULT_HTTPS_PORT, time.Second*60) return c.JSON(response.BuildSuccessResponse(res)) } diff --git a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/triggerapi.go b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/triggerapi.go index 5b4590b101f..a580b1d1c3e 100644 --- a/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/triggerapi.go +++ b/components/automate-cli/pkg/verifyserver/services/batchcheckservice/trigger/triggerapi.go @@ -121,7 +121,7 @@ func TriggerCheckAPI(endPoint, host, nodeType, method string, output chan<- mode } client := http.Client{ - Timeout: 35 * time.Second, + Timeout: 65 * time.Second, } resp, err := client.Do(req) if err != nil { diff --git a/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice.go b/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice.go index bcadd9eea69..fe530293afe 100644 --- a/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice.go +++ b/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice.go @@ -149,25 +149,45 @@ func (fq *FqdnService) MakeConcurrentCalls(url string, client *http.Client, setN return errors.New("nodes are not reachable") } -func (fq *FqdnService) triggerRequest(client *http.Client, url string) error { - res, err := client.Get(url) - if err != nil { - fq.log.Error(err.Error()) - return err - } +func (fq *FqdnService) triggerRequest(client *http.Client, url string, duration time.Duration) error { + timeout := time.After(duration) + + var fqdnError error +loop: + for { + select { + case <-timeout: + fq.log.Debugf("Stopped making API calls after %v seconds.", duration) + if fqdnError == nil { + return errors.New(constants.FQDN_ERROR_MESSAGE) + } + return fqdnError + default: + res, err := client.Get(url) + if err != nil { + fq.log.Error("Iteration logs: ", err.Error()) + fqdnError = err + time.Sleep(3 * time.Second) + continue + } + fq.log.Debug("Status Code: ", res.StatusCode) + if res.StatusCode != 200 { + fq.log.Errorf("%v is not reachable.", url) + } + if res.StatusCode == 200 { + fq.log.Debug("FQDN is reachable") + // return nil + break loop + } + } + time.Sleep(3 * time.Second) - fq.log.Debug("Status Code: ", res.StatusCode) - if res.StatusCode != 200 { - fq.log.Debugf("%v is not reachable.", url) - return errors.New("fqdn is not reachable") } - - fq.log.Debug("Fqdn is Reachable.") return nil } // fqdnReachable function will check that are we able to hit the load balancer fqdn or not. -func (fq *FqdnService) fqdnReachable(fqdn, rootCert, nodeType string, isAfterDeployment bool, port string) models.Checks { +func (fq *FqdnService) fqdnReachable(fqdn, rootCert, nodeType string, isAfterDeployment bool, port string, duration time.Duration) models.Checks { fq.log.Debug("Checking Fqdn Reachability...") client := fq.createClient(rootCert) var url string @@ -179,9 +199,17 @@ func (fq *FqdnService) fqdnReachable(fqdn, rootCert, nodeType string, isAfterDep } fq.log.Debug("URL: ", url) - err := fq.triggerRequest(client, url) + err := fq.triggerRequest(client, url, duration) if err != nil { - return createCheck(constants.FQDN_TITLE, false, "", constants.FQDN_ERROR_MESSAGE, constants.FQDN_RESOLUTION_MESSAGE) + resoultion_message := "" + if strings.Contains(err.Error(), constants.CERT_CN_MISMATCH_ERROR_PATTERN) { + resoultion_message = constants.CERT_CN_MISMATCH_RESOLUTION_MESSAGE + } else if strings.Contains(err.Error(), constants.INVALID_FQDN_CERT_ERROR_PATTERN) { + resoultion_message = constants.INVALID_FQDN_CERT_RESOLUTION_MESSAGE + } else { + resoultion_message = constants.GENERIC_FQDN_CERT_RESOLUTION_MESSAGE + } + return createCheck(constants.FQDN_TITLE, false, "", err.Error(), resoultion_message) } return createCheck(constants.FQDN_TITLE, true, constants.FQDN_TITLE, "", "") } @@ -266,7 +294,7 @@ func (fq *FqdnService) CheckFqdnReachability(req models.FqdnRequest, port string } if certificateValidityCheck { - check = fq.fqdnReachable(req.Fqdn, req.RootCert, req.NodeType, req.IsAfterDeployment, port) + check = fq.fqdnReachable(req.Fqdn, req.RootCert, req.NodeType, req.IsAfterDeployment, port, duration) } else { check = createCheck(constants.FQDN_TITLE, false, "", constants.FQDN_ERROR_MESSAGE, constants.FQDN_RESOLUTION_MESSAGE) } diff --git a/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice_test.go b/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice_test.go index feffddd44a6..58c3269a39c 100644 --- a/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice_test.go +++ b/components/automate-cli/pkg/verifyserver/services/fqdnservice/fqdnservice_test.go @@ -325,8 +325,8 @@ func TestCheckFqdnReachability(t *testing.T) { Title: constants.FQDN_TITLE, Passed: false, SuccessMsg: "", - ErrorMsg: constants.FQDN_ERROR_MESSAGE, - ResolutionMsg: constants.FQDN_RESOLUTION_MESSAGE, + ErrorMsg: "no such host", + ResolutionMsg: constants.GENERIC_FQDN_CERT_RESOLUTION_MESSAGE, }, { Title: constants.NODE_TITLE, @@ -545,8 +545,8 @@ func TestCheckFqdnReachability(t *testing.T) { Title: constants.FQDN_TITLE, Passed: false, SuccessMsg: "", - ErrorMsg: constants.FQDN_ERROR_MESSAGE, - ResolutionMsg: constants.FQDN_RESOLUTION_MESSAGE, + ErrorMsg: "no such host", + ResolutionMsg: constants.GENERIC_FQDN_CERT_RESOLUTION_MESSAGE, }, { Title: constants.NODE_TITLE, @@ -609,8 +609,8 @@ func TestCheckFqdnReachability(t *testing.T) { Title: constants.FQDN_TITLE, Passed: false, SuccessMsg: "", - ErrorMsg: constants.FQDN_ERROR_MESSAGE, - ResolutionMsg: constants.FQDN_RESOLUTION_MESSAGE, + ErrorMsg: "no such host", + ResolutionMsg: constants.GENERIC_FQDN_CERT_RESOLUTION_MESSAGE, }, { Title: constants.NODE_TITLE, @@ -713,7 +713,7 @@ func TestCheckFqdnReachability(t *testing.T) { Passed: false, SuccessMsg: "", ErrorMsg: constants.FQDN_ERROR_MESSAGE, - ResolutionMsg: constants.FQDN_RESOLUTION_MESSAGE, + ResolutionMsg: constants.GENERIC_FQDN_CERT_RESOLUTION_MESSAGE, }, { Title: constants.NODE_TITLE, @@ -731,7 +731,18 @@ func TestCheckFqdnReachability(t *testing.T) { for _, e := range tests { t.Run(e.TestName, func(t *testing.T) { res := fq.CheckFqdnReachability(e.ReqBody, e.Port, time.Second*2) - assert.Equal(t, e.ResponseBody, res) + if e.ResponseBody.Passed { + assert.Equal(t, e.ResponseBody, res) + } else { + for i := 0; i < len(e.ResponseBody.Checks); i++ { + check := e.ResponseBody.Checks[i] + if check.Passed { + assert.Contains(t, res.Checks[i].SuccessMsg, check.SuccessMsg) + } else { + assert.Contains(t, res.Checks[i].ErrorMsg, check.ErrorMsg) + } + } + } }) } } diff --git a/components/docs-chef-io/content/automate/ha_cert_selfsign.md b/components/docs-chef-io/content/automate/ha_cert_selfsign.md index bbb7054d9ac..c6a86a8961e 100644 --- a/components/docs-chef-io/content/automate/ha_cert_selfsign.md +++ b/components/docs-chef-io/content/automate/ha_cert_selfsign.md @@ -51,7 +51,7 @@ You can create a self-signed key and certificate pair with the **OpenSSL** utili echo extendedKeyUsage = clientAuth, serverAuth > client_cert_ext.cnf echo subjectAltName = DNS:chefclient >> client_cert_ext.cnf openssl genrsa -out root-ca-key.pem 2048 - openssl req -new -x509 -sha256 -key root-ca-key.pem -subj "/C=US/ST=Washington/L=Seattle/O=Chef Software Inc/CN=progress" -out root-ca.pem -days 1095 + openssl req -new -x509 -sha256 -key root-ca-key.pem -subj "/C=US/ST=Washington/L=Seattle/O=Chef Software Inc/CN=progress" -out root-ca.pem -days 1095 -addext basicConstraints=CA:TRUE # Admin cert openssl genrsa -out admin-key-temp.pem 2048 @@ -82,6 +82,12 @@ You can create a self-signed key and certificate pair with the **OpenSSL** utili {{< note >}} +To create self-signed certificate for FQDN make sure to provide proper DNS and CN value. The DNS in Subject Alternative Name should match with the CN (Comman Name) + +{{< /note >}} + +{{< note >}} + Please refer Opensearch certificate [documentation](https://opensearch.org/docs/1.2/security-plugin/configuration/tls/#x509-pem-certificates-and-pkcs-8-keys) {{< /note >}} \ No newline at end of file