Search code examples
node.jssslneo4jssl-certificatekubernetes-helm

Ne4j community in AKS cluster doesn't see the Certificate as valid anymore dough it has been renewed


I have a Node.js server which uses MongoDb and Neo4j in a AKS Cluster all deployed via Helm Charts. I have A Certificate issued by Let's Encrypt which is used both for the server and for Neo4j bolt connection. I deployed the cluster in February and it all worked fine, but now when writing to Neo4j it throws the Failed to connect to server error with the Socket responded with: CERT_HAS_EXPIRED reason and Browser does not connect to the db.

Neo4jError: Failed to connect to server. Please ensure that your database is listening on the correct host and port and that you have compatible encryption settings both on Neo4j server and driver. Note that the default encryption setting has changed in Neo4j 4.0. Caused by: Server certificate is not trusted. If you trust the database you are connecting to, use TRUST_CUSTOM_CA_SIGNED_CERTIFICATES and add the signing certificate, or the server certificate, to the list of certificates trusted by this driver using `neo4j.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This  is a security measure to protect against man-in-the-middle attacks. If you are just trying  Neo4j out and are not concerned about encryption, simply disable it using `encrypted="ENCRYPTION_OFF"` in the driver options. Socket responded with: CERT_HAS_EXPIRED
0|server  |     at new Neo4jError (/usr/app/node_modules/neo4j-driver-core/lib/error.js:77:16)
0|server  |     at newError (/usr/app/node_modules/neo4j-driver-core/lib/error.js:113:12)
0|server  |     at NodeChannel._handleConnectionError (/usr/app/node_modules/neo4j-driver-bolt-connection/lib/channel/node/node-channel.js:227:56)
0|server  |     at TLSSocket.<anonymous> (/usr/app/node_modules/neo4j-driver-bolt-connection/lib/channel/node/node-channel.js:69:17)
0|server  |     at Object.onceWrapper (node:events:641:28)
0|server  |     at TLSSocket.emit (node:events:527:28)
0|server  |     at TLSSocket.onConnectSecure (node:_tls_wrap:1564:10)
0|server  |     at TLSSocket.emit (node:events:527:28)
0|server  |     at TLSSocket._finishInit (node:_tls_wrap:945:8)
0|server  |     at ssl.onhandshakedone (node:_tls_wrap:726:12) {
0|server  |   constructor: [Function: Neo4jError] { isRetriable: [Function (anonymous)] },
0|server  |   code: 'ServiceUnavailable',
0|server  |   retriable: true
0|server  | }

The certificate has been renewed in April and my guess is that Neo4j just stuck with the first certificate, is it possible?

this is the Certificate

Name:         tls-certificate
Namespace:    default
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: cluster
              meta.helm.sh/release-namespace: default
API Version:  cert-manager.io/v1
Kind:         Certificate
Metadata:
  Creation Timestamp:  2023-02-15T15:25:52Z
  Generation:          1
  Managed Fields:
    API Version:  cert-manager.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:meta.helm.sh/release-name:
          f:meta.helm.sh/release-namespace:
        f:labels:
          .:
          f:app.kubernetes.io/managed-by:
      f:spec:
        .:
        f:dnsNames:
        f:issuerRef:
          .:
          f:kind:
          f:name:
        f:secretName:
    Manager:      helm
    Operation:    Update
    Time:         2023-02-15T15:25:52Z
    API Version:  cert-manager.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:status:
        f:revision:
    Manager:      cert-manager-certificates-issuing
    Operation:    Update
    Subresource:  status
    Time:         2023-04-16T14:27:13Z
    API Version:  cert-manager.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:status:
        .:
        f:conditions:
          .:
          k:{"type":"Ready"}:
            .:
            f:lastTransitionTime:
            f:message:
            f:observedGeneration:
            f:reason:
            f:status:
            f:type:
        f:notAfter:
        f:notBefore:
        f:renewalTime:
    Manager:         cert-manager-certificates-readiness
    Operation:       Update
    Subresource:     status
    Time:            2023-04-16T14:27:13Z
  Resource Version:  20023818
  UID:               9edc761c-9382-4597-8048-ec5e85d0871d
Spec:
  Dns Names:
    xxx.westeurope.cloudapp.azure.com
  Issuer Ref:
    Kind:       ClusterIssuer
    Name:       letsencrypt-issuer
  Secret Name:  tls-secret
Status:
  Conditions:
    Last Transition Time:  2023-02-15T15:26:48Z
    Message:               Certificate is up to date and has not expired
    Observed Generation:   1
    Reason:                Ready
    Status:                True
    Type:                  Ready
  Not After:               2023-07-15T13:27:11Z
  Not Before:              2023-04-16T13:27:12Z
  Renewal Time:            2023-06-15T13:27:11Z
  Revision:                2
Events:                    <none>

Now looking at the message

use TRUST_CUSTOM_CA_SIGNED_CERTIFICATES and add the signing certificate, or the server certificate, to the list of certificates trusted by this driver using `neo4j.driver(.., { trustedCertificates:['path/to/certificate.crt']})

I see that I haven't placed the certificate in the array of trusted certificates but only used the secret that the Certificate creates.

Neo4 ssl settings in the Neo4j Chart's Values :

  ssl:
    # setting per "connector" matching neo4j config
    bolt:
      privateKey:
        secretName: tls-secret
        subPath: tls.key
      publicCertificate:
        secretName: tls-secret
        subPath: tls.crt
      trustedCerts:
        sources: []
      revokedCerts:
        sources: []

After scaling down Neo4j cluster to 0 replicas and up to 1 replicas it all start working again as expected, but how do I set it up in order to make this automatic? I don't see any TRUST_CUSTOM_CA_SIGNED_CERTIFICATES parameter in the Neo4j Chart's Values. Also what would the path/to/certificate.crt be? Should I just add the name of the Certificate in the trustedCerts.sources array like sources: [tls-certificate]?

Many thanks.


Solution

  • Assuming you are using the helm charts https://github.com/neo4j/helm-charts you will need to refresh the secrets you created with the certs, and then either roll your cluster, or in your case, scale to 0 and then back up to pick up the secret. At this time (Neo4j 5.8.0) Certs are only picked up at startup. See https://neo4j.com/docs/operations-manual/current/kubernetes/configuration/#configure-ssl