-
Notifications
You must be signed in to change notification settings - Fork 0
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
Addresses comments on original PR #1
Changes from all commits
a2ed601
da06a69
065fe0b
eb6e54c
3f38985
34a3e8e
0768ec0
d4b222f
45d5454
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,18 @@ | ||
package physical | ||
|
||
import ( | ||
"crypto/tls" | ||
"fmt" | ||
"io/ioutil" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
log "github.com/mgutz/logxi/v1" | ||
|
||
"github.com/armon/go-metrics" | ||
"github.com/gocql/gocql" | ||
"github.com/hashicorp/vault/helper/certutil" | ||
) | ||
|
||
// CassandraBackend is a physical backend that stores data in Cassandra. | ||
|
@@ -72,6 +76,39 @@ func newCassandraBackend(conf map[string]string, logger log.Logger) (Backend, er | |
connectStart := time.Now() | ||
cluster := gocql.NewCluster(hosts...) | ||
cluster.Keyspace = keyspace | ||
|
||
cluster.ProtoVersion = 2 | ||
if protoVersionStr, ok := conf["protocol_version"]; ok { | ||
protoVersion, err := strconv.Atoi(protoVersionStr) | ||
if err != nil { | ||
return nil, fmt.Errorf("'protocol_version' must be an integer") | ||
} | ||
cluster.ProtoVersion = protoVersion | ||
} | ||
|
||
if username, ok := conf["username"]; ok { | ||
if cluster.ProtoVersion < 2 { | ||
return nil, fmt.Errorf("Authentication is not supported with protocol version < 2") | ||
} | ||
authenticator := gocql.PasswordAuthenticator{Username: username} | ||
if password, ok := conf["password"]; ok { | ||
authenticator.Password = password | ||
} | ||
cluster.Authenticator = authenticator | ||
} | ||
|
||
if connTimeoutStr, ok := conf["connection_timeout"]; ok { | ||
connectionTimeout, err := strconv.Atoi(connTimeoutStr) | ||
if err != nil { | ||
return nil, fmt.Errorf("'connection_timeout' must be an integer") | ||
} | ||
cluster.Timeout = time.Duration(connectionTimeout) * time.Second | ||
} | ||
|
||
if err := setupCassandraTLS(conf, cluster); err != nil { | ||
return nil, err | ||
} | ||
|
||
sess, err := cluster.CreateSession() | ||
if err != nil { | ||
return nil, err | ||
|
@@ -86,6 +123,84 @@ func newCassandraBackend(conf map[string]string, logger log.Logger) (Backend, er | |
return impl, nil | ||
} | ||
|
||
func setupCassandraTLS(conf map[string]string, cluster *gocql.ClusterConfig) error { | ||
tlsOnStr, ok := conf["tls"] | ||
if !ok { | ||
return nil | ||
} | ||
|
||
tlsOn, err := strconv.Atoi(tlsOnStr) | ||
if err != nil { | ||
return fmt.Errorf("'tls' must be an integer (0 or 1)") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be made a bool? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ill double check. Their config examples use ints and it seems unquoted strings for representing bools trigger parsing errors inconsistently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, interesting. In the same example there is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a bit confusing. I'll dig deeper but while trying unquoted literals in both config formats I had this same issue: hashicorp#1559 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. Let's leave it as an integer ¯_(ツ)_/¯ I think if you can add the documentation for the new config params then we should be good to submit upstream 🚀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AWESOME! 👍 |
||
} | ||
|
||
if tlsOn == 0 { | ||
return nil | ||
} | ||
|
||
var tlsConfig = &tls.Config{} | ||
if pemBundlePath, ok := conf["pem_bundle_file"]; ok { | ||
pemBundleData, err := ioutil.ReadFile(pemBundlePath) | ||
if err != nil { | ||
return fmt.Errorf("Error reading pem bundle from %s: %v", pemBundlePath, err) | ||
} | ||
pemBundle, err := certutil.ParsePEMBundle(string(pemBundleData)) | ||
if err != nil { | ||
return fmt.Errorf("Error parsing 'pem_bundle': %v", err) | ||
} | ||
tlsConfig, err = pemBundle.GetTLSConfig(certutil.TLSClient) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
if pemJSONPath, ok := conf["pem_json_file"]; ok { | ||
pemJSONData, err := ioutil.ReadFile(pemJSONPath) | ||
if err != nil { | ||
return fmt.Errorf("Error reading json bundle from %s: %v", pemJSONPath, err) | ||
} | ||
pemJSON, err := certutil.ParsePKIJSON([]byte(pemJSONData)) | ||
if err != nil { | ||
return err | ||
} | ||
tlsConfig, err = pemJSON.GetTLSConfig(certutil.TLSClient) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
|
||
if tlsSkipVerifyStr, ok := conf["tls_skip_verify"]; ok { | ||
tlsSkipVerify, err := strconv.Atoi(tlsSkipVerifyStr) | ||
if err != nil { | ||
return fmt.Errorf("'tls_skip_verify' must be an integer (0 or 1)") | ||
} | ||
if tlsSkipVerify == 0 { | ||
tlsConfig.InsecureSkipVerify = false | ||
} else { | ||
tlsConfig.InsecureSkipVerify = true | ||
} | ||
} | ||
|
||
if tlsMinVersion, ok := conf["tls_min_version"]; ok { | ||
switch tlsMinVersion { | ||
case "tls10": | ||
tlsConfig.MinVersion = tls.VersionTLS10 | ||
case "tls11": | ||
tlsConfig.MinVersion = tls.VersionTLS11 | ||
case "tls12": | ||
tlsConfig.MinVersion = tls.VersionTLS12 | ||
default: | ||
return fmt.Errorf("'tls_min_version' must be one of `tls10`, `tls11` or `tls12`") | ||
} | ||
} | ||
|
||
cluster.SslOpts = &gocql.SslOptions{ | ||
Config: *tlsConfig.Clone(), | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// bucketName sanitises a bucket name for Cassandra | ||
func (c *CassandraBackend) bucketName(name string) string { | ||
if name == "" { | ||
|
@@ -164,7 +279,6 @@ func (c *CassandraBackend) List(prefix string) ([]string, error) { | |
|
||
stmt := fmt.Sprintf(`SELECT key FROM "%s" WHERE bucket = ?`, c.table) | ||
q := c.sess.Query(stmt, c.bucketName(prefix)) | ||
q = q.Consistency(gocql.One) // List does not need such strong consistency guarantees | ||
iter := q.Iter() | ||
k, keys := "", []string{} | ||
for iter.Scan(&k) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why set this to
2
? I agree with letting users specify the version explicitly in the config, but in the case they do not, leaving it as0
which causesgocql
to try to auto-detect the version seems better.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see… is it for consistency with this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I'm all up for 0 but their comment also suggested 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Fair enough, given their goal is to unify the Cassandra connection implementations.