Database Connection Encryption deprecated

Introduction

This guide will help you to setup TLS encryption for database connections and configure it within Middleware pods running in Kubernetes.

Further reading

Prerequisites

Database

In this guide, MariaDB is used as a database. If you use an other database, please read the vendors documentation to find equal configuration.

Officially, MariaDB is shipped as a Docker image and not as a Helm chart. So, to get a Helm chart for MariaDB, we will use the MariaDB chart provided by Bitnami, see https://github.com/bitnami/charts/blob/main/bitnami/mariadb/README.md. The Bitnami chart offers a easy way to configure MariaDB, by utilizing a section called configuration. Within the section, all configuration must be set, as known from previous "installations" that used the file my.cnf.

Therefore, configuring TLS for MariaDB is as simple as this:

mariadb:
  enabled: true
  architecture: standalone
  primary:
      extraVolumes:
      - name: certs
        secret:
          secretName: certs
    extraVolumeMounts:
      - name: certs
        mountPath: /certs
    configuration: |-
      [mysqld]
      ssl_cert=/certs/server-cert.pem
      ssl_key=/certs/server-key.pem
      ssl_ca=/certs/ca-cert.pem
      require_secure_transport=ON
...

Please note that in this example, it is assumed that the actual certificates will be mounted to the MariaDB pod. Therefore, extra volume mounts to a folder containing the valid certificates are defined. The mounted certificates are then referenced in the configuration section.

Test the connection

To make sure that connections to MariaDB are now secured by TLS encryption, we can manually observe the connection. For example, use Wireshark and DBeaver from your local machine. Create a new connection within DBeaver to the MariaDB pod. Make sure to configure the connection to use TLS. Therefore, go to the SSL tab and toggle Use SSL, configure the certificates and toggle require TLS and Verify server certificate. Afterwards, configure Wireshark to observe the connection, by e.g. using the filter tcp.port == 3306 on the fitting network interface. Once everything is configured, connect to the database. Now

  • the connection should be established without any error
  • the message content is NOT readable

Configure your Middleware

Middleware pods are using the JDBC connector to connect to a database. The JDBC connector uses a Java KeyStore to manage different certificates. Therefore, we need to create keystores based on the CA and client certificates.

Currently, certificates and keystores must be passed down to Middleware pods as BASE64 decoded files. This is subject to change and might be replaced by Kubernetes internal mechanisms in the future. However, for now the following has to be done, to enable TLS protected connections between the database and the Middleware:

Create key stores

Keystores need to be created locally. Therefore, we create

  • A truststore file for the CA certificate
  • A keystore file for the client certificate

for example with:

keytool -importcert -alias MariaDBCACert -file ca-cert.pem -keystore truststore -storepass changeit
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -name "mariadbclient" -passout pass:changeit -out client-keystore.p12
keytool -importkeystore -srckeystore client-keystore.p12 -srcstoretype pkcs12 -srcstorepass changeit -destkeystore keystore -deststoretype JKS -deststorepass changeit

# Verify client certificate in key store
keytool -list -v -keystore keystore

Afterwards, the stores can be converted into BASE64

base64 --input truststore --output truststore.base64

The content of the BASE64 decoded file need to be copied into the values.yaml file.

Middleware Configuration

To configure the Middleware to use encryption towards the database, the following properties must be set within the values.yamlfile:

core-mw:
  enabled: true
  yamlFiles:
    dbconnector.yaml:
      com.mysql.jdbc:
        useSSL: true
        requireSSL: true
        verifyServerCertificate: true
        clientCertificateKeyStoreUrl: file:/opt/open-xchange/etc/mariadb-keystore
        clientCertificateKeyStorePassword: changeit
        clientCertificateKeyStoreType: JKS
        trustCertificateKeyStoreUrl: file:/opt/open-xchange/etc/mariadb-truststore
        trustCertificateKeyStorePassword: changeit
        trustCertificateKeyStoreType: JKS
  etcBinaries:
    - name: mariadb-keystore
      filename: mariadb-keystore
      b64Content: <BASE64_CONTENT_OF_THE_KEYSTORE>
    - name: mariadb-truststore
      filename: mariadb-truststore
      b64Content: <BASE64_CONTENT_OF_THE_TRUSTSTORE>

Please replace the placeholder <BASE64_CONTENT_OF_THE_KEYSTORE> with the actual content of the keystores. Read the section above for more information.

Reload properties and certificates in production

The server is capable to reload JDBC properties as well as the used certificates. To trigger a certificate rotation, the command line tool "reloadConfiguration" can be used. However, when using Kubernetes, simply overwrite the properties in the values.yaml and let Kubernetes schedule new pods with the updated configuration.

If you still want to use the command line tool, a reload will clear all unused connection instances held in the connection pools and updates the properties used to spawn new connections with the JDBC client. After that, all new connections will automatically use the updated properties. Connections that are still in use will get marked as deprecated, so that these connections will be replaced by updated ones after they finish their work.

Example

For a full working example on TLS encrypted database connections, please have a look here