Configuring TLS for MySQL Instances

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

Overview

Tanzu MySQL for Kubernetes is configured to require an encrypted connection for client communication.

The Tanzu MySQL TLS configuration provides various options:

Using the Default Provided TLS

From Tanzu MySQL 1.2.0, the MySQL Operator deploys the instances with TLS from the self-signed ClusterIssuer configured during Operator install.

By default, the Operator will create a ClusterIssuer named tanzu-sql-with-mysql-operator-ca-certificate-clusterissuer and will retrieve MySQL instance certificates issued via this resource.

To verify that your MySQL Operator is using the default settings, with no ClusterIssuer customization, use:

helm --namespace=tanzu-mysql-for-kubernetes-system get values tanzu-sql-with-mysql-operator

The output should be similar to:

USER-SUPPLIED VALUES:
null

When installing the MySQL instances using the default MySQL Operator settings, the instance secret is named with the convention ${INSTANCE_NAME}-mysql-tls. For example, if you used the default mysql.yaml provided with the release, and created an instance:

kubectl apply --filename=config/samples/mysql.yaml
mysql.with.sql.tanzu.vmware.com/mysql-sample created

the instance would be called mysql-sample and the default TLS secret would be mysql-sample-mysql-tls. To view the secret, use:

kubectl get secret mysql-sample-mysql-tls --template='{{ index .data "ca.crt" | base64decode }}'

This returns an output similar to:

-----BEGIN CERTIFICATE-----
MIIDOzCCAiOgAwIBAgIRANSXXz7zVfItmCCvv/ZmOGAwDQYJKoZIhvcNAQELBQAw
NzE1MDMGA1UEAxMsdGFuenUtc3FsLXdpdGgtbXlzcWwtb3BlcmF0b3ItY2EtY2Vy
............
-----END CERTIFICATE-----

To override the default ClusterIssuer follow the steps in Configuring a Custom TLS issuer. To explicitly configure an instance with a custom spec.tls.secret.name and TLS key pair, see Explicitly Configure a MySQL instance for TLS.

Configuring a Custom TLS Issuer

This procedure describes how to configure a custom Certificate Authority (CA) and custom certificates using cert-manager. When you complete these steps, your Tanzu MySQL Operator will use the custom CA for any MySQL instance certificates.

Prerequisites

Before you configure TLS using a custom CA authority, you must have access permissions to install or upgrade the Tanzu MySQL Operator using Helm.

IMPORTANT: Helm 3.7.x is currently not supported.

Procedure

  1. Verify that cert-manager was configured during Installing the MySQL Operator prerequisites:

    kubectl get all --namespace=cert-manager
    
  2. Create a Kubernetes Secret for the CA certificate. For example, create a my-CA-secret.yaml with values similar to:

    kind: Secret
    metadata:
        name: my-ca-certificate
        namespace: cert-manager-namespace
    data:
      tls.crt: this is a CA public key
      tls.key: this is the CA private key
    

    and apply with:

    kubectl apply -f my-CA-secret.yaml
    

    Note: The specific namespace for this secret depends on whether cert-manager was deployed with a specific --cluster-resource-namespace option. Cert-manager defaults to the namespace cert-manager to reference ClusterIssuer resources such as CA certificate keypairs. See the cert-manager docs for details.

  3. Create a CA issuer in cert-manager using a ClusterIssuer resource and associate it with the CA Secret created in step 2. For information about the cert-manager Issuer types, see Issuer Configuration in the cert-manager documentation.

    Note: The MySQL instance TLS secret requires the ca.crt key. The ACME Issuer does not provide a ca.crt key, therefore VMware does not recommend using it.

    Create a ClusterIssuer resource using a yaml file, for example my-cluster-issuer.yaml, similar to:

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
        name: my-ca-certificate-clusterissuer
    spec:
        ca:
         secretName: my-ca-certificate
    
  4. Apply the Secret using:

    kubectl apply -f my-cluster-issuer.yaml
    

    For certificate creation troubleshooting see the cert-manager documentation.

  5. For new Tanzu MySQL customers, create the MySQL Operator and set it to use the custom TLS issuer by using a command similar to:

    helm install tanzu-sql-with-mysql-operator ./tanzu-sql-with-mysql-operator/ --set=certManagerClusterIssuerName=my-ca-certificate-clusterissuer
    

    For existing Tanzu MySQL customers, update the Operator using a command similar to:

    helm update tanzu-sql-with-mysql-operator ./tanzu-sql-with-mysql-operator/ --set=certManagerClusterIssuerName=my-ca-certificate-clusterissuer
    

    Note: If you need to use more than one CA issuer, either see Explicitly Configure a MySQL instance for TLS or run another MySQL Operator in a different Kubernetes cluster.

  6. To verify the custom ClusterIssuer setup, use:

    helm --namespace=tanzu-mysql-for-kubernetes-system get values tanzu-sql-with-mysql-operator
    
    USER-SUPPLIED VALUES:
    certManagerClusterIssuerName: my-ca-certificate-clusterissuer
    

Explicitly Configure a MySQL instance for TLS

To configure a MySQL instance for TLS without using the ClusterIssuer through the Operator, 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 or certstrap.

    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.

  1. Verify that cert-manager was configured during Installing the MySQL Operator prerequisites:

    kubectl get all --namespace=cert-manager
    
  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, using the precreated secret, follow these steps:

  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
    

    where TLS-SECRET-NAME is the secret from Using the Default provided TLS or the custom configured secret in Configuring a Custom TLS Issuer or Explicitly Configure a MySQL instance for TLS.

    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 --user=<USERNAME> --password=<PASSWORD> --host=<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 --user=bn_wordpress --password=hunter2 --host=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>