Commit ce43513e authored by jaloren's avatar jaloren Committed by Ben Kochie

Support custom CA truststore and client SSL keypair. (#255)

Per discussion in #226, there is no way to specify a custom CA that the
mysqld exporter will trust when establishing a SSL connection to a mysql
server. So if a mysql server has a custom truststore, an operator would
need to set DSN, where tls=skip-verify.

With this change, a user can define the ssl options in the mysql cnf and
then the mysqld exporter will construct a DSN and a custom TLS config
based on those options.
parent 8f657848
......@@ -102,6 +102,24 @@ The MySQL server's [data source name](http://en.wikipedia.org/wiki/Data_source_n
must be set via the `DATA_SOURCE_NAME` environment variable.
The format of this variable is described at https://github.com/go-sql-driver/mysql#dsn-data-source-name.
## Customizing Configuration for a SSL Connection
if The MySQL server supports SSL, you may need to specify a CA truststore to verify the server's chain-of-trust. You may also need to specify a SSL keypair for the client side of the SSL connection. To configure the mysqld exporter to use a custom CA certificate, add the following to the mysql cnf file:
```
ssl-ca=/path/to/ca/file
```
To specify the client SSL keypair, add the following to the cnf.
```
ssl-key=/path/to/ssl/client/key
ssl-cert=/path/to/ssl/client/cert
```
Customizing the SSL configuration is only supported in the mysql cnf file and is not supported if you set the mysql server's data source name in the environment variable DATA_SOURCE_NAME.
## Using Docker
You can deploy this exporter using the [prom/mysqld-exporter](https://registry.hub.docker.com/u/prom/mysqld-exporter/) Docker image.
......
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"os"
"path"
"github.com/go-sql-driver/mysql"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
......@@ -86,10 +90,47 @@ func parseMycnf(config interface{}) (string, error) {
} else {
dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/", user, password, host, port)
}
sslCA := cfg.Section("client").Key("ssl-ca").String()
sslCert := cfg.Section("client").Key("ssl-cert").String()
sslKey := cfg.Section("client").Key("ssl-key").String()
if sslCA != "" {
if tlsErr := customizeTLS(sslCA, sslCert, sslKey); tlsErr != nil {
tlsErr = fmt.Errorf("failed to register a custom TLS configuration for mysql dsn: %s", tlsErr)
return dsn, tlsErr
}
dsn = fmt.Sprintf("%s?tls=custom", dsn)
}
log.Debugln(dsn)
return dsn, nil
}
func customizeTLS(sslCA string, sslCert string, sslKey string) error {
var tlsCfg tls.Config
caBundle := x509.NewCertPool()
pemCA, err := ioutil.ReadFile(sslCA)
if err != nil {
return err
}
if ok := caBundle.AppendCertsFromPEM(pemCA); ok {
tlsCfg.RootCAs = caBundle
} else {
return fmt.Errorf("failed parse pem-encoded CA certificates from %s", sslCA)
}
if sslCert != "" && sslKey != "" {
certPairs := make([]tls.Certificate, 0, 1)
keypair, err := tls.LoadX509KeyPair(sslCert, sslKey)
if err != nil {
return fmt.Errorf("failed to parse pem-encoded SSL cert %s or SSL key %s: %s",
sslCert, sslKey, err)
}
certPairs = append(certPairs, keypair)
tlsCfg.Certificates = certPairs
}
mysql.RegisterTLSConfig("custom", &tlsCfg)
return nil
}
func init() {
prometheus.MustRegister(version.NewCollector("mysqld_exporter"))
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment