Add remote data store connections with SSL

This commit is contained in:
Tobie Morgan Hitchcock 2016-07-19 12:05:11 +01:00
parent 804fabc6c0
commit 7b03d6f05e
5 changed files with 147 additions and 7 deletions

View file

@ -45,6 +45,55 @@ func setup() {
log.Fatal("Specify a valid data store configuration path")
}
if strings.HasPrefix(opts.DB.Cert.CA, "-----") {
var err error
var doc *os.File
if doc, err = os.Create("db.ca"); err != nil {
log.Fatal("Can not decode PEM encoded CA into db.ca")
}
doc.Write([]byte(opts.DB.Cert.CA))
doc.Close()
opts.Cert.Crt = "db.ca"
}
if strings.HasPrefix(opts.DB.Cert.Crt, "-----") {
var err error
var doc *os.File
if doc, err = os.Create("db.key"); err != nil {
log.Fatal("Can not decode PEM encoded certificate into db.crt")
}
doc.Write([]byte(opts.DB.Cert.Crt))
doc.Close()
opts.Cert.Crt = "db.crt"
}
if strings.HasPrefix(opts.DB.Cert.Key, "-----") {
var err error
var doc *os.File
if doc, err = os.Create("db.crt"); err != nil {
log.Fatal("Can not decode PEM encoded private key into db.key")
}
doc.Write([]byte(opts.DB.Cert.Key))
doc.Close()
opts.Cert.Crt = "db.key"
}
if opts.DB.Cert.CA != "" || opts.DB.Cert.Crt != "" || opts.DB.Cert.Key != "" {
opts.DB.Cert.SSL = true
}
if opts.DB.Cert.CA == "" && opts.DB.Cert.SSL {
log.Fatal("Specify a valid PEM encoded CA file.")
}
if opts.DB.Cert.Crt == "" && opts.DB.Cert.SSL {
log.Fatal("Specify a valid PEM encoded certificate file.")
}
if opts.DB.Cert.Key == "" && opts.DB.Cert.SSL {
log.Fatal("Specify a valid PEM encoded private key file.")
}
// --------------------------------------------------
// Auth
// --------------------------------------------------

View file

@ -72,6 +72,9 @@ func init() {
startCmd.PersistentFlags().StringVar(&opts.DB.Base, "db-base", "", flag("db-base"))
startCmd.PersistentFlags().StringVar(&opts.DB.Path, "db-path", "", flag("db-path"))
startCmd.PersistentFlags().StringVar(&opts.DB.Cert.CA, "db-ca", "", "Path to the CA file used to connect to the remote database.")
startCmd.PersistentFlags().StringVar(&opts.DB.Cert.Crt, "db-crt", "", "Path to the certificate file used to connect to the remote database.")
startCmd.PersistentFlags().StringVar(&opts.DB.Cert.Key, "db-key", "", "Path to the private key file used to connect to the remote database.")
startCmd.PersistentFlags().IntVar(&opts.Port.Tcp, "port-tcp", 0, flag("port-tcp"))
startCmd.PersistentFlags().IntVar(&opts.Port.Web, "port-web", 0, flag("port-web"))

View file

@ -23,6 +23,12 @@ type Options struct {
Host string // Surreal host to connect to
Port string // Surreal port to connect to
Base string // Base key to use in KV stores
Cert struct {
CA string
Crt string
Key string
SSL bool
}
}
Port struct {

View file

@ -15,10 +15,15 @@
package mysql
import (
"strings"
"fmt"
"regexp"
"crypto/tls"
"crypto/x509"
"io/ioutil"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"github.com/go-sql-driver/mysql"
"github.com/abcum/surreal/cnf"
"github.com/abcum/surreal/kvs"
@ -32,9 +37,12 @@ func New(opts *cnf.Options) (ds kvs.DS, err error) {
var db *sql.DB
path := strings.TrimLeft(opts.DB.Path, "mysql://")
opts.DB.Path, err = config(opts)
if err != nil {
return
}
db, err = sql.Open("mysql", path)
db, err = sql.Open("mysql", opts.DB.Path)
if err != nil {
return
}
@ -42,3 +50,49 @@ func New(opts *cnf.Options) (ds kvs.DS, err error) {
return &DS{db: db, ck: opts.DB.Key}, err
}
func config(opts *cnf.Options) (path string, err error) {
re := regexp.MustCompile(`^mysql://` +
`((?:(?P<user>.*?)(?::(?P<passwd>.*))?@))?` +
`(?:(?:(?P<addr>[^\/]*))?)?` +
`\/(?P<dbname>.*?)` +
`(?:\?(?P<params>[^\?]*))?$`)
ma := re.FindStringSubmatch(opts.DB.Path)
if len(ma) == 0 || ma[4] == "" || ma[5] == "" {
err = fmt.Errorf("Specify a valid data store configuration path. Use the help command for further instructions.")
}
if opts.DB.Cert.SSL {
pool := x509.NewCertPool()
pem, err := ioutil.ReadFile(opts.DB.Cert.CA)
if err != nil {
err = fmt.Errorf("Could not read file %s", opts.DB.Cert.CA)
}
if ok := pool.AppendCertsFromPEM(pem); !ok {
return "", fmt.Errorf("Could not read file %s", opts.DB.Cert.CA)
}
cert := make([]tls.Certificate, 0, 1)
pair, err := tls.LoadX509KeyPair(opts.DB.Cert.Crt, opts.DB.Cert.Key)
if err != nil {
return "", err
}
cert = append(cert, pair)
mysql.RegisterTLSConfig("custom", &tls.Config{
RootCAs: pool,
Certificates: cert,
InsecureSkipVerify: true,
})
}
if opts.DB.Cert.SSL {
path += fmt.Sprintf("%stcp(%s)/%s?tls=custom", ma[1], ma[4], ma[5])
} else {
path += fmt.Sprintf("%stcp(%s)/%s", ma[1], ma[4], ma[5])
}
return
}

View file

@ -15,7 +15,8 @@
package pgsql
import (
"strings"
"fmt"
"regexp"
"database/sql"
_ "github.com/lib/pq"
@ -32,9 +33,12 @@ func New(opts *cnf.Options) (ds kvs.DS, err error) {
var db *sql.DB
path := strings.TrimLeft(opts.DB.Path, "pgsql://")
opts.DB.Path, err = config(opts)
if err != nil {
return
}
db, err = sql.Open("postgres", path)
db, err = sql.Open("postgres", opts.DB.Path)
if err != nil {
return
}
@ -42,3 +46,27 @@ func New(opts *cnf.Options) (ds kvs.DS, err error) {
return &DS{db: db, ck: opts.DB.Key}, err
}
func config(opts *cnf.Options) (path string, err error) {
re := regexp.MustCompile(`^mysql://` +
`((?:(?P<user>.*?)(?::(?P<passwd>.*))?@))?` +
`(?:(?:(?P<addr>[^\/]*))?)?` +
`\/(?P<dbname>.*?)` +
`(?:\?(?P<params>[^\?]*))?$`)
ma := re.FindStringSubmatch(opts.DB.Path)
if len(ma) == 0 || ma[4] == "" || ma[5] == "" {
err = fmt.Errorf("Specify a valid data store configuration path. Use the help command for further instructions.")
}
if opts.DB.Cert.SSL {
path += fmt.Sprintf("postgres://%s%s/%s?sslmode=verify-ca&sslrootcert=%s&sslcert=%s&sslkey=%s", ma[1], ma[4], ma[5], opts.DB.Cert.CA, opts.DB.Cert.Crt, opts.DB.Cert.Key)
} else {
path += fmt.Sprintf("postgres://%s%s/%s", ma[1], ma[4], ma[5])
}
return
}