Another important aspect of security is securing and authenticating the ports used to access the database. The most common way to do this is by enabling TLS/SSL to encrypt data and authenticate the servers using user-created certificates. The process for creating the private keystore and truststore using openssl is described in the section on "Creating the TLS/SSL Certificates" in the Using VoltDB guide. This process is the same whether you are running the cluster directly on bare metal servers or in Kubernetes.
The following instructions describe creating and using TLS/SSL certificates in Privacy Enhanced Mail, or PEM, format. PEM is a text-based format that is easy to work with and is accepted by all Volt functions starting with Volt version 14.2.0 and Volt Operator 3.6.0. For earlier versions of Volt, certain functions require a JKS file instead of PEM. Please see the version 13 documentation for configuring TLS on Kubernetes for instructions on creating and using certificates acceptable to previous releases.
The following example uses YAML properties to enable TLS/SSL security, in much the same way you enable SSL encryption
on bare metal. First you must enable SSL encryption, using the cluster.config.deployment.ssl.enabled
property. Then you choose which ports will use SSL (in this example, the internal and external ports, but not XDCR). The
YAML does not include the actual content of the truststore and keystore files. The example also chooses
to have the operator authenticate the servers by setting cluster.clusterSpec.ssl.insecure
to
false.
cluster: config: deployment: ssl: enabled: true external: true internal: true clusterSpec: ssl: insecure: false
Note that the certificates themselves and associated key and trust stores are not specified in the YAML for the cluster deployment configuration. Instead, you pass the associated files to the Operator (and subsequently the server pods) in one of three ways:
Using the --set-file argument to the Helm install
Using Kubernetes secrets
Using cert-manager
The following sections describe the three methods for configuring encryption. Two additional sections describe alternate methods for configuring TLS/SSL for the Operator and VMC and how to update the certificates when they expire.
Using the example YAML file in Section 7.2, “Configuring TLS/SSL” (and calling it ssl.yaml
), we can
complete the SSL configuration by specifying the truststore and keystore files on the helm command line
with the --set-file
argument:
helm install mydb voltdb/voltdb \
--values myconfig.yaml \
--values ssl.yaml \
--set-file cluster.config.deployment.ssl.keystore.file=keystore.pem \
--set-file cluster.config.deployment.ssl.truststore.file=truststore.pem
Two important notes concerning TLS/SSL configuration:
If you enable SSL for the cluster's external interface and ports and you enable metrics, you must provide the appropriate SSL information to the Prometheus data retriever configuration so it can access the metrics port.
If you enable SSL for the cluster, you must repeat the specification of the truststore and keystore files every
time you update the configuration. Using the --reuse-values
argument on the helm
upgrade
command is not sufficient.
An alternative method is to store the key and trust stores in a Kubernetes secret. Secrets are a standard feature of Kubernetes that allow you to store sensitive information as key value pairs in a protected space. Three advantages of using a secret are:
You do not have to enter sensitive TLS/SSL information in plain text when configuring or updating your database.
The secret is used automatically for subsequent updates; you do not have to repeatedly specify the TLS/SSL files when updating the database configuration.
You can reuse the same secret for multiple database instances and services.
To use a Kubernetes secret to store the TLS/SSL information for your database, you must first create the necessary PEM files as described in the section on "Creating the TLS/SSL Certificates" in the Using VoltDB guide. Next you create your Kubernetes secret using the kubectl create secret command, specifying the key names and corresponding artifacts as arguments. For example:
$ kubectl create secret generic my-ssl-creds \ --from-file=keystore_data=keystore.pem \ --from-file=truststore_data=truststore.pem
It is critical you use the key names keystore_data and truststore_data (as well as keystore_password and truststore_password if you created a password for the certificate). If not, the Volt Operator will not be able to find them. Also, the secret must be in the same Kubernetes namespace as the Helm release you are configuring.
Once you create the secret you can use it to configure your database by not setting any of
standard SSL properties such as the cluster.config.deployment.ssl...
properties or
cluster.clusterSpec.ssl.certificateFile
. Instead, set the property
cluster.config.deployment.ssl.sslSecret.certSecretName
. Using the secret created in the preceding
example, the configuration of your database will look something like this:
cluster:
config:
deployment:
ssl:
sslSecret:
certSecretName: my-ssl-creds
Another alternative for maintaining the TLS/SSL information is to use the Kubernetes cert-manager (cert-manager.io). The cert-manager is an add-on for Kubernetes that helps you create and maintain certificates and other private information in Kubernetes. If you wish to use cert-manager for self-signed certificates, you not only use it to store the certificate and truststore, you create them with cert-manager as well. (For more detailed information concerning cert-manager, see the cert-manager documentation.)
The basic steps for storing self-signed TLS/SSL credentials in cert-manager are:
Create an issuer resource in Kubernetes that will generate and authenticate the certificate. You only need to do this once for the namespace and multiple certificate requests can use the same issuer.
Create a request for the issuer to generate the actual TLS/SSL certificate and store it in a Kubernetes secret.
Specify the resulting certificate secret in the VoltDB configuration and start your cluster.
You create the cert-manager issuer and the certificate request using YAML properties. The easiest way to do this is by typing the property declarations into a YAML file. For example, the following two YAML files create a cert-manager issuer service and request a certificate.
create-issuer.yaml
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: selfsigned-issuer namespace: mydb spec: selfSigned: {}
request-cert.yaml
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: my-ssl-certificate namespace: mydb spec: commonName: voltdb.com duration: 8766h secretName: my-ssl-creds issuerRef: name: selfsigned-issuer kind: Issuer privateKey: algorithm: RSA encoding: PKCS8 size: 2048 usages: - server auth
Three key points to note about the certificate request are:
The issuer must be in the same namespace as the database that uses the certificate.
You specify the duration of the certificate in hours. In this example, 8766 hours, or one year.
The encoding must be PKCS8
Once you create the YAML files, you can create the issuer and request the certificate:
$ kubectl apply -f create-issuer.yaml # Do only once $ kubectl apply -f request-cert.yaml
Finally, in your database configuration, you point to the secret created by the certificate request (in this case, my-ssl-creds) the same way you would for a manually created secret:
cluster:
config:
deployment:
ssl:
sslSecret:
certSecretName: my-ssl-creds
A certificate revocation list (CRL) lets you deny access to the server from certain clients based on their certificates, when using mutual TLS (mTLS). For example, say you had separate client certificates for each vendor with access to your database. If the partnership with a vendor ends, you want to now deny access to the vendor's clients by adding their certificate to the list of CRLs. Note that the CRL files must be in PEM format. See the section on Using CRLs in the Using VoltDB guide for instructions on converting files in other formats to PEM using the openssl utility.
In Kubernetes, you add CRLs to the server in one of two ways:
By specifying the CRLs, one at a time, using the --set-file
qualifier when installing the
database release. For example:
helm install mydb voltdb/voltdb \
--values myconfig.yaml \
--set-file cluster.config.deployment.ssl.crl.file.a=/etc/ssl/local/crl/crl1.pem \
--set-file cluster.config.deployment.ssl.crl.file.b=/etc/ssl/local/crl/crl2.pem \
--set-file cluster.config.deployment.ssl.crl.file.c=/etc/ssl/local/crl/crl3.pem
The last name of the cluster.config.deployment.ssl.crl.file.{name}
property can be any name you choose as long as it is unique within the set of CRL file property names.
By creating a configuration map containing the CRLs. Create a directory with one or more CRL files in it. Then
create a configuration map using the kubectl create configmap command pointing to the CRL
directory. For example, using the directory name /etc/ssl/local/crl
from the preceding example
and naming the configuration map mycrlmap:
kubectl create configmap mycrlmap --from-file /etc/ssl/local/crl
Once you create the configuration map, you can add it to the Helm configuration using the
cluster.config.deployment.ssl.crl.configName
property when installing the database release:
helm install mydb voltdb/voltdb \
--values myconfig.yaml \
--set cluster.config.deployment.ssl.crl.configName=mycrlmap
By default, when you enable TLS/SSL, the Volt Operator and the Volt Management Console (VMC) automatically use the truststore configured for the servers as their truststore for authenticating the server. In other words, you do not have to set any SSL configuration properties yourself for these two services. VMC will also use the server keystore to define its own certificate for encrypting user access to its HTTP port. This way clients and interactive users can use the same truststore to access both the servers' client ports and the VMC web console.
Of course, you can choose to explicitly identify a separate truststore for these other services and provide the associated files yourself, if you wish. But by default, configuring SSL for the server automatically configures the Operator and VMC correctly to respond to the encrypted messages.
The same is true if you enable mutual TLS (mTLS) for the cluster. In this case, the Operator and VMC use the same certificate (and truststore) as the servers by default. If you want to have these services use a distinct client certificate, you need to specify that certificate using the appropriate YAML properties for those services. For example, the following Helm command loads a separate certificate for the Volt Operator and uses the root truststore for both the server and Operator:
helm install mydb voltdb/voltdb \
--values myconfig.yaml \
--values ssl.yaml \
--set-file cluster.config.deployment.ssl.keystore.file=server.keystore.pem \
--set-file cluster.config.deployment.ssl.truststore.file=root.truststore.pem \
--set-file cluster.clusterSpec.ssl.clientCertFile=client.keystore.pem