Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable TLS client connections to Cassandra #555

Merged
merged 1 commit into from
Nov 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions cmd/flags/cassandra/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ const (
suffixSocketKeepAlive = ".socket-keep-alive"
suffixUsername = ".username"
suffixPassword = ".password"
suffixTLS = ".tls"
suffixCert = ".tls.cert"
suffixKey = ".tls.key"
suffixCA = ".tls.ca"
suffixServerName = ".tls.server-name"
suffixVerifyHost = ".tls.verify-host"
)

// TODO this should be moved next to config.Configuration struct (maybe ./flags package)
Expand Down Expand Up @@ -62,6 +68,10 @@ func NewOptions(primaryNamespace string, otherNamespaces ...string) *Options {
options := &Options{
primary: &namespaceConfig{
Configuration: config.Configuration{
TLS: config.TLS{
Enabled: false,
EnableHostVerification: true,
},
MaxRetryAttempts: 3,
Keyspace: "jaeger_v1_local",
ProtoVersion: 4,
Expand Down Expand Up @@ -129,6 +139,30 @@ func addFlags(flagSet *flag.FlagSet, nsConfig *namespaceConfig) {
nsConfig.namespace+suffixPassword,
nsConfig.Authenticator.Basic.Password,
"Password for password authentication for Cassandra")
flagSet.Bool(
nsConfig.namespace+suffixTLS,
nsConfig.TLS.Enabled,
"Enable TLS")
flagSet.String(
nsConfig.namespace+suffixCert,
nsConfig.TLS.CertPath,
"Path to TLS certificate file")
flagSet.String(
nsConfig.namespace+suffixKey,
nsConfig.TLS.KeyPath,
"Path to TLS key file")
flagSet.String(
nsConfig.namespace+suffixCA,
nsConfig.TLS.CaPath,
"Path to TLS CA file")
flagSet.String(
nsConfig.namespace+suffixServerName,
nsConfig.TLS.ServerName,
"Override the TLS server name")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. The main reason is to allow connecting to a host where the server name in the cert, or one of the SANs, differs.

e.g. you have a cert for foo.svc.cluster.local but you're connecting to just 'foo', you could set ServerName=foo.svc.cluster.local.

There is something odd in the dialer setup for jaeger at the moment which is leading to the TLS layer missing the hostname, and ServerName can be used to work around that. I'm going to poke around and see if I can make it more JustWorks in future - but there are still cases where ServerName is needed.

flagSet.Bool(
nsConfig.namespace+suffixVerifyHost,
nsConfig.TLS.EnableHostVerification,
"Enable (or disable) host key verification")
}

// InitFromViper initializes Options with properties from viper
Expand All @@ -150,6 +184,12 @@ func initFromViper(cfg *namespaceConfig, v *viper.Viper) {
cfg.SocketKeepAlive = v.GetDuration(cfg.namespace + suffixSocketKeepAlive)
cfg.Authenticator.Basic.Username = v.GetString(cfg.namespace + suffixUsername)
cfg.Authenticator.Basic.Password = v.GetString(cfg.namespace + suffixPassword)
cfg.TLS.Enabled = v.GetBool(cfg.namespace + suffixTLS)
cfg.TLS.CertPath = v.GetString(cfg.namespace + suffixCert)
cfg.TLS.KeyPath = v.GetString(cfg.namespace + suffixKey)
cfg.TLS.CaPath = v.GetString(cfg.namespace + suffixCA)
cfg.TLS.ServerName = v.GetString(cfg.namespace + suffixServerName)
cfg.TLS.EnableHostVerification = v.GetBool(cfg.namespace + suffixVerifyHost)
}

// GetPrimary returns primary configuration.
Expand Down
24 changes: 24 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ primary supported storage backends. There is ongoing work to add support for MyS

### Cassandra

Deploying Cassandra itself is out of scope for our documentation. One good
source of documentation is the
[Apache Cassandra Docs](https://cassandra.apache.org/doc/latest/)

#### Schema script

A script is provided to initialize Cassandra keyspace and schema
using Cassandra's interactive shell [`cqlsh`][cqlsh]:

Expand All @@ -106,6 +112,23 @@ where `{datacenter}` is the name used in the Cassandra configuration / network t
The script also allows overriding TTL, keyspace name, replication factor, etc.
Run the script without arguments to see the full list of recognized parameters.

#### TLS support

Jaeger supports TLS client to node connections as long as you've configured
your Cassandra cluster correctly. After verifying with e.g. `cqlsh`, you can
configure the collector and query like so:

```
docker run \
-e CASSANDRA_SERVERS=<...> \
-e CASSAMDRA_TLS=true \
-e CASSANDRA_TLS_SERVER_NAME="CN-in-certificate" \
-e CASSANDRA_TLS_KEY=<path to client key file> \
-e CASSANDRA_TLS_CERT=<path to client cert file> \
-e CASSANDRA_TLS_CA=<path to your CA cert file> \
jaegertracing/jaeger-collector
```

### ElasticSearch

ElasticSearch does not require initialization other than
Expand Down Expand Up @@ -192,6 +215,7 @@ Project [spark-dependencies](https://github.com/jaegertracing/spark-dependencies
dependency links and stores them directly to the storage.

## Configuration

All binaries accepts command line properties and environmental variables which are managed by
by [viper](https://github.com/spf13/viper) and [cobra](https://github.com/spf13/cobra).
The names of environmental properties are capital letters and characters `-` and `.` are replaced with `_`.
Expand Down
23 changes: 23 additions & 0 deletions pkg/cassandra/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package config

import (
"crypto/tls"
"fmt"
"time"

Expand All @@ -36,6 +37,7 @@ type Configuration struct {
Consistency string `yaml:"consistency"`
Port int `yaml:"port"`
Authenticator Authenticator `yaml:"authenticator"`
TLS TLS
}

// Authenticator holds the authentication properties needed to connect to a Cassandra cluster
Expand All @@ -50,6 +52,16 @@ type BasicAuthenticator struct {
Password string `yaml:"password"`
}

// TLS Config
type TLS struct {
Enabled bool
ServerName string
CertPath string
KeyPath string
CaPath string
EnableHostVerification bool
}

// ApplyDefaults copies settings from source unless its own value is non-zero.
func (c *Configuration) ApplyDefaults(source *Configuration) {
if c.ConnectionsPerHost == 0 {
Expand Down Expand Up @@ -119,6 +131,17 @@ func (c *Configuration) NewCluster() *gocql.ClusterConfig {
Password: c.Authenticator.Basic.Password,
}
}
if c.TLS.Enabled {
cluster.SslOpts = &gocql.SslOptions{
Config: tls.Config{
ServerName: c.TLS.ServerName,
},
CertPath: c.TLS.CertPath,
KeyPath: c.TLS.KeyPath,
CaPath: c.TLS.CaPath,
EnableHostVerification: c.TLS.EnableHostVerification,
}
}
return cluster
}

Expand Down