Configuring TLS for MySQL Instances

Page last updated:

This topic describes how to configure TLS for a MySQL instance.

Overview

Tanzu MySQL for Kubernetes is configured to require an encrypted connection, and client connections cannot fall back to use an unencrypted connection. By default, the MySQL server uses a self-signed certificate. Clients can connect to the MySQL server, but they cannot verify the connection.

To verify the connection to the MySQL server, the MySQL instance can be configured with a TLS certificate and private key.

To configure a MySQL instance for TLS, you must first create a TLS Secret in the same namespace as the MySQL instance. There are several ways to create the Secret. This topic describes two methods:

After creating the secret, you add the name of the secret to your copy of the mysql.yaml file, and configure the instance with the updated file, as described in Configure MySQL for TLS below.

For general information about TLS secrets, see the Kubernetes documentation.

Prerequisites

Before you configure TLS for a MySQL instance, you must have:

  • Access and permissions to the MySQL instance.

  • The Kubernetes Command Line Interface (kubectl) installed: For more information, see the Kubernetes documentation.

Create the TLS Secret Manually

This procedure describes how to create the TLS Secret using kubectl. To create the TLS Secret using cert-manager instead, see Create TLS Secret with cert-manager below.

  1. Generate a certificate and private key using a certificate manager, such as OpenSSL, certstrap, or Let’s Encrypt.

    When creating the certificate, supply the server hostname for the subject alternative names (SANs). The server hostname is the DNS name that you use when connecting your app to the MySQL instance:

    • If your apps are deployed in the same Kubernetes cluster as your instance:
      The hostname is INSTANCE-NAME.DEVELOPMENT-NAMESPACE, for example, mysql-sample.my-namespace.
    • If your app is deployed outside the Kubernetes cluster and you have configured the MySQL spec.serviceType as LoadBalancer:
      The hostname is the external DNS name of the load balancer. See Access the MySQL Server from an External IP Address in Accessing MySQL Instances.
  2. Create the TLS Secret by running:

    kubectl -n DEVELOPMENT-NAMESPACE create secret generic TLS-SECRET-NAME \
      --type kubernetes.io/tls \
      --from-file=tls.crt=PATH-TO-CERTIFICATE \
      --from-file=tls.key=PATH-TO-PRIVATE-KEY \
      --from-file=ca.crt=PATH-TO-CERTIFICATE-AUTHORITY
    

    Where:

    • DEVELOPMENT-NAMESPACE is the namespace for the MySQL instance.
    • TLS-SECRET-NAME is the name you choose for the TLS Secret.
    • PATH-TO-CERTIFICATE is the file path to the certificate created in the step above.
    • PATH-TO-PRIVATE-KEY is the file path to the private key created in the step above.
    • PATH-TO-CERTIFICATE-AUTHORITY is the file path to the certificate authority that signed the certificate.

    For example:

      $ kubectl -n my-namespace create secret generic mysql-tls-secret \
          --type kubernetes.io/tls \
          --from-file=tls.crt=/path/server.crt \
          --from-file=tls.key=/path/server.key \
          --from-file=ca.crt=/path/server_ca.crt
    

After completing the steps above, you add the secret to the instance by following the instructions in Configure MySQL for TLS below.

Create TLS Secret with cert-manager

This procedure describes how to create the TLS Secret using cert-manager.

To create the TLS Secret through the kubectl instead, see Create the TLS Secret Manually above.

Prerequisite: Before you install cert-manager, you must have the Helm v3 command-line tool installed. For information about installing Helm, see the Helm documentation.

  1. Install cert-manager on your Kubernetes cluster by running these commands:

    kubectl create namespace cert-manager
    helm repo add jetstack https://charts.jetstack.io
    helm repo update
    helm install cert-manager jetstack/cert-manager \
    --namespace cert-manager --version v1.0.2 --set installCRDs=true
    
  2. Use cert-manager to create either a cluster-wide ClusterIssuer resource or a namespace-local Issuer resource in the same namespace as your MySQL instance.

    For information about the Issuer types, see the cert-manager documentation.

    Note: Because the MySQL instance requires that the TLS secret include the ca.crt key, VMware does not recommend the ACME Issuer.

  3. Choose and record a name for the TLS secret name, for example, mysql-tls-secret. Use this name as the spec.secretName when you create the Certificate resource below.

  4. Create a certificate request YAML. For instructions, see the cert-manager documentation. The following table suggests values for the YAML parameters.

    Enter: As this parameter in the YAML:
    your TLS secret name from step 3 above, for example, mysql-tls-secret spec.secretName
    the name of your ClusterIssuer or Issuer created in step 2 above spec.issuerRef.name
    the DNS name or the fully qualified DNS name that you use to connect to apps deployed in the same Kubernetes cluster as the MySQL instance:
    • INSTANCE-NAME.DEVELOPMENT-NAMESPACE, for example, mysql-sample.my-namespace
    • INSTANCE-NAME.DEVELOPMENT-NAMESPACE.svc.CLUSTER-DOMAIN, for example, mysql-sample.my-namespace.svc.cluster.local
      . The default CLUSTER-DOMAIN is cluster.local.
    spec.dnsNames
    the external IP address of the load balancer that you use to connect to apps deployed outside the cluster. To find the address, see step 4 of Access the MySQL Server from an External IP Address. spec.ipAddresses
    any additional DNS names that clients use to access the MySQL instance through a TLS connection spec.dnsNames
    any additional URIs that clients use to access the MySQL instance through a TLS connection you might have configured to access your MySQL spec.uris
    any additional IP addresses that clients use to access the MySQL instance through a TLS connection spec.ipAddresses

    For information about troubleshooting certificate creation, see the cert-manager documentation.

  5. Verify that the TLS secret created has the ca.crt key by running:

    kubectl -n DEVELOPMENT-NAMESPACE get secret TLS-SECRET-NAME -o jsonpath="{.data['ca\.crt']}"
    

    Where:

    • DEVELOPMENT-NAMESPACE is the namespace for the MySQL instance.
    • TLS-SECRET-NAME is the name you chose for the TLS Secret.

    For example:

    $ kubectl -n my-namespace get secret mysql-tls-secret -o jsonpath="{.data['ca\.crt']}"  

Configure MySQL for TLS

To configure TLS for the MySQL instance:

  1. In your copy of the mysql.yaml for the MySQL instance, specify spec.tls.secret.name as the name of the TLS Secret created in the namespace.

  2. Create or update the MySQL instance by running:

    kubectl apply -f FILENAME -n DEVELOPMENT-NAMESPACE
    

    Where:

    • FILENAME is the name of the configuration file for your MySQL resource.
    • DEVELOPMENT-NAMESPACE is the namespace for the MySQL instance.

Connect to a Load-Balanced MySQL Instance over TLS

This section shows how to connect to a MySQL instance configured with a load balancing service, spec.serviceType.LoadBalancer, from an off-cluster machine running the MySQL command-line client.

In the procedure below, you give the client the certificate of the CA that signed the MySQL TLS certificate. The client uses this CA to authenticate the MySQL server-provided TLS certificate.

To connect the MySQL command-line client to the MySQL instance over TLS:

  1. Obtain the certificate of the CA that signed the MySQL server’s TLS certificate.

    The CA certificate is stored in the TLS secrets ca.crt field, base64 encoded. Save that certificate to a local file ca.crt by running:

    kubectl -n DEVELOPMENT-NAMESPACE get secret TLS-SECRET-NAME -o jsonpath="{.data['ca\.crt']}" | base64 -d > ca.crt
    

    For example:

    $ kubectl -n my-namespace get secret mysql-tls-secret -o jsonpath="{.data['ca\.crt']}" | base64 -d > ca.crt
    
  2. Create a MySQL username and password to test your connection with. You need to connect as a non-root user because MySQL instances prohibit root connection from remote machines.

    For an example of creating a database, user, and password for connection testing, see Connecting Apps to MySQL Instances.

  3. Obtain the IP address that your MySQL instance is listening on for connections. Load-balanced instances expose their IP address through their status.loadBalancer.ingress property:

    kubectl get service INSTANCE-NAME -o jsonpath={.status.loadBalancer.ingress[].ip}
    
  4. Connect your local MySQL command-line client to your MySQL instance by running:

    mysql -u USERNAME -pPASSWORD -h IP_ADDRESS --ssl-mode=VERIFY_CA --ssl-ca=CA-CERTPATH
    

    Where:

    • USERNAME is the username you created above, for example, bn_wordpress.
    • PASSWORD is the password for the user you created above, for example, hunter2.
    • IP-ADDRESS is the external IP address from step 3 above.
    • CA-CERTPATH is the pathname to the certificate file saved in step 1 above, for example, ./ca.crt.

    For example:

    $ mysql -u bn_wordpress -phunter2 -h 192.168.64.200 --ssl-mode=VERIFY_CA --ssl-ca=./ca.crt 
    mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 7 ... Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    mysql>