-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Initial SSL Connection Support #705
Initial SSL Connection Support #705
Conversation
- Adding a command line option for users to enforce tls/ssl connections for the applier, inspector, and binlog reader. - The user can optionally request server certificate verification through a command line option to specify the ca cert via a file path. - Fixes an existing bug appending the timeout option to the singleton applier connection.
@@ -73,7 +73,7 @@ func (this *Applier) InitDBConnections() (err error) { | |||
if this.db, _, err = mysql.GetDB(this.migrationContext.Uuid, applierUri); err != nil { | |||
return err | |||
} | |||
singletonApplierUri := fmt.Sprintf("%s?timeout=0", applierUri) | |||
singletonApplierUri := fmt.Sprintf("%s&timeout=0", applierUri) |
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.
This was an existing bug we found when adding the tls option onto the uri. Previously, this was causing the uri to take the form of gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1?timeout=0
. The DSN parser for go-mysql-driver/mysql was then not parsing the timeout setting, but instead including that as part of the value for charset
.
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.
What if applierUri
has no query string yet?
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.
@johnlockwood-wf applierUri
has query strings from the return value of ConnectionConfig.GetDBUri both before and after this PR.
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 not use net/url
to work with urls?
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.
I rather not refactor every place where GetDBUri is currently being used to address this bug. Because we are adding the tls param into GetDBUri, we are directly impacted by this line using the wrong symbol and thus I am including the fix here to use the correct symbol.
These are not really URLs but DSNs recognized by go-my-sql/driver. While net/url.Values may have some helpful functions, I don't think the work involved in shoehorning that in is worthwhile here where each code path that hits this spot already has params set for applierUri
.
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.
go-sql-driver's Config.FormatDSN would likely be a great improvement on the manually created DSN, but I think that is something to reserve for a separate issue or PR.
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.
Agreed. Let's postpone use of FormatDNS
to a next PR.
@@ -14,6 +14,7 @@ import ( | |||
|
|||
"github.com/github/gh-ost/go/base" | |||
"github.com/github/gh-ost/go/logic" | |||
_ "github.com/go-sql-driver/mysql" |
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.
Added this to make it clear that gh-ost was registering the go-sql-driver/mysql
driver as its mysql
driver. We had some confusion previously and thought that the driver might have been coming from the siddontang/go-mysql
library referenced in the go/binlog/gomysql_reader.go
. But, the driver was in fact the go-sql-driver/mysql
, pulled in though an import statement located within github.com/outbrain/golib/sqlutils
. Hoping that adding the import directly here instead of relying on the indirect import will make it more clear for others.
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.
You made that look easy, good work
@@ -14,6 +14,7 @@ import ( | |||
|
|||
"github.com/github/gh-ost/go/base" | |||
"github.com/github/gh-ost/go/logic" | |||
_ "github.com/go-sql-driver/mysql" |
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.
Should we add a comment explaining why we're importing 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.
I don't believe so. Not use to seeing comments within import statements, and this brings the usage much closer to the standard usage described in the go-sql-driver/mysql documentation. Potentially we could move this into the one of the classes where database/sql
is being imported to exactly match the documentation, but that seems less discoverable to me than adding here in main.
I've updated the description of this PR to include some of the steps we took in testing this change against some AWS RDS instances. |
@@ -16,6 +22,7 @@ type ConnectionConfig struct { | |||
User string | |||
Password string | |||
ImpliedKey *InstanceKey | |||
tlsConfig *tls.Config |
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.
Any reason not to make this variable public since you have a simple getter down below anyway?
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.
Wanted to force callers consuming this struct to set up the TLS for the ConnectionConfig through the UseTLS
function below if they wanted to set up the tls.Config. This prevents passing around a ConnectionConfig whose tls.Config has not be registered with the mysql driver.
go/cmd/gh-ost/main.go
Outdated
@@ -54,6 +55,9 @@ func main() { | |||
flag.StringVar(&migrationContext.ConfigFile, "conf", "", "Config file") | |||
askPass := flag.Bool("ask-pass", false, "prompt for MySQL password") | |||
|
|||
flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL") | |||
flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections. Requires --ssl") |
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.
Should there be a note that these settings will apply to both the replica and master with no option to differentiate them?
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.
Thanks. I've expanded the usage statements a little to make clear that it applies to all the MySQL hosts, while trying to keep the statements concise and general enough in case someone else needs to add a master override (similar to the username and password overrides) in the future. I imagine needing to have different CA or TLS settings for the master and replicas is probably not a super common case, but something that can definitely be added in the future.
@shlomi-noach If there is anything I can add to this PR that would make review on the maintainers side easier, please let me know. Adding SSL support is a priority for us and I would like to make it as easy as possible for you. |
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.
@brandonbodnar-wk thank you! This PR is looking good. I'll run it through internal testing, though our testing will not check the introduced functionality, so more in the way of verifying nothing gets broken.
I have one further request: if you can update the docs to reflect the changes you made, we'd be most grateful.
Thanks @shlomi-noach. I've added documentation for the flags into command-line-flags.md in this latest commit. |
Thank you |
Related issue: #521
Description
This PR adds initial support for enforcing TLS/SSL connections for the databases involved in the schema changes. In this initial pass, a gh-ost user can enforce ssl be used for connections using the
--ssl
flag on the command line. If the user wishes to enforce checking validity of the database's certificate, the user can also specify a CA certificate in pem format with the--ssl-ca
option.Adding these two options is sufficient for our use case right now in connecting to AWS RDS instances. While there are plenty more options that can be specified by the native mysql client regarding ssl, this can provide a good starting point for other work by those with more complex needs.
script/cibuild
returns with no formatting errors, build errors or unit test errors.Testing
We tested this updated code against an Aurora2 cluster running a MySQL 5.7 compatible engine.
REQUIRE SSL
set.gh-ost
against the cluster, but without the new ssl options enabled. As expected we received an access denied when attempting to connect withgh-ost
.--ssl
flag, along with specifying the--ssl-ca
certificate for AWS RDS. The job executed flawlessly.