Today I have tried to connect my Java application, running in a managed DigitalOcean Kubernetes cluster, to a managed DigitalOcean MySQL instance and I have run into some warnings regarding the connection in the application’s logs.

The suggested connection string on the DigitalOcean admin page looks like this:
jdbc:mysql://[url]:[port]/[dbname]?ssl-mode=REQUIRED

If we use ssl-mode=REQUIRED but do not verify the sql server’s certificate, we will get the following warnings in the application’s logs:

Sun Mar 08 12:10:01 CET 2020 WARN: Establishing SSL connection without server's identity verification is not recommended.
According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. 
For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. 
You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

The following guide will enable server certificate validation for the connection. We will get rid of the warnings in the logs and connect to the MySQL server in a more secure way.

Prerequisites

  • a working Kubernetes cluster (this guide was tested on 1.16)
  • kubectl configured and context set to cluster
  • JDK installed on the machine
  • a MySQL instance with a server certificate available
  • a Java application running in the cluster for testing

1. Acquire the server certificate

I am using a managed DigitalOcean MySQL instance so I can download the certificate from the DigitalOcean admin panel. Save the certificate to a folder.

Downloading certificate

2. Create a Java truststore

Create a truststore by issuing the following command in the directory where the server certificate is saved:
keytool -importcert -alias MySQLCACert -file [certificate-filename] -keystore truststore -storepass [your-password]

Answer yes to the following question. You should see a confirmation that the certificate has been added to the keystore.

...(certificate details)...
Trust this certificate? [no]:  yes
Certificate was added to keystore

3. Create a Kubernetes secret from the truststore

Issue the following command in the directory where the truststore was created, to create a Kubernetes secret from the truststore:
kubectl create secret -n [namespace] generic db-certificate --from-file truststore

4. Mount the truststore to the application’s pods

Add a volume and a volumeMount entry to the application’s deployment. This way the truststore file will be available for your application in the db-certs directory in the root of your pod’s file-system.

apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  replicas: 1
  selector:
    ...
  template:
    ...
    spec:
      containers:
        - name: container-name
          image: your-image
          volumeMounts:
            - mountPath: "/db-certs"
              name: db-truststore
              readOnly: true
      ...
      volumes:
        - name: db-truststore
          secret:
            secretName: db-certificate

5. Update the application’s connection string

Add the useSSL, trustCertificateKeyStoreUrl, trustCertificateKeyStorePassword parameters to the connection string, than the connection string should look something like this:

jdbc:mysql://[url]:[port]/[dbname]?useSSL=true&trustCertificateKeyStoreUrl=file:/db-certs/truststore&trustCertificateKeyStorePassword=[your-password]