Skip to content

Commit

Permalink
cmd: connect to rethinkdb with custom root certificate (#116)
Browse files Browse the repository at this point in the history
* Connect to rethinkdb with a custom certificate

Signed-off-by: Matteo Suppo <matteo.suppo@gmail.com>

* Test importRethinkDBRootCA

Signed-off-by: Matteo Suppo <matteo.suppo@gmail.com>

* Move backend_connections tests

Signed-off-by: Matteo Suppo <matteo.suppo@gmail.com>
  • Loading branch information
matteosuppo authored and Aeneas committed Jun 23, 2016
1 parent 5b44457 commit 74432b0
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 5 deletions.
10 changes: 7 additions & 3 deletions cmd/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ This command supports the following environment variables:
- HTTPS_TLS_CERT_PATH: The path to the TLS certificate (pem encoded).
- HTTPS_TLS_KEY_PATH: The path to the TLS private key (pem encoded).
- HTTPS_TLS_CERT: A pem encoded TLS certificate passed as string. Can be used instead of TLS_CERT_PATH.
- HTTPS_TLS_KEY: A pem encoded TLS key passed as string. Can be used instead of TLS_KEY_PATH.
- HTTPS_TLS_CERT: A pem encoded TLS certificate passed as string. Can be used instead of HTTPS_TLS_CERT_PATH.
- HTTPS_TLS_KEY: A pem encoded TLS key passed as string. Can be used instead of HTTPS_TLS_KEY_PATH.
- RETHINK_TLS_CERT_PATH: The path to the TLS certificate (pem encoded) used to connect to rethinkdb.
- RETHINK_TLS_CERT: A pem encoded TLS certificate passed as string. Can be used instead of RETHINK_TLS_CERT_PATH.
- HYDRA_PROFILING: Set "HYDRA_PROFILING=1" to enable profiling.
`,
Expand All @@ -67,7 +70,8 @@ func init() {
hostCmd.Flags().Bool("force-dangerous-http", false, "Disable HTTP/2 over TLS (HTTPS) and serve HTTP instead. Never use this in production.")
hostCmd.Flags().Bool("dangerous-auto-logon", false, "Stores the root credentials in ~/.hydra.yml. Do not use in production.")
hostCmd.Flags().String("https-tls-key-path", "", "Path to the key file for HTTP/2 over TLS (https). You can set HTTPS_TLS_KEY_PATH or HTTPS_TLS_KEY instead.")
hostCmd.Flags().String("https-tls-cert-path", "", "Path to the certificate file for HTTP/2 over TLS (https). You can set HTTPS_TLS_KEY_PATH or HTTPS_TLS_KEY instead.")
hostCmd.Flags().String("https-tls-cert-path", "", "Path to the certificate file for HTTP/2 over TLS (https). You can set HTTPS_TLS_CERT_PATH or HTTPS_TLS_CERT instead.")
hostCmd.Flags().String("rethink-tls-cert-path", "", "Path to the certificate file to connect to rethinkdb over TLS (https). You can set RETHINK_TLS_CERT_PATH or RETHINK_TLS_CERT instead.")
}

func runHostCmd(cmd *cobra.Command, args []string) {
Expand Down
42 changes: 40 additions & 2 deletions config/backend_connections.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package config

import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"net/url"

"time"

"github.com/Sirupsen/logrus"
"github.com/go-errors/errors"
"github.com/ory-am/hydra/pkg"
"github.com/spf13/viper"
r "gopkg.in/dancannon/gorethink.v2"
)

Expand All @@ -33,11 +37,16 @@ func (c *RethinkDBConnection) GetSession() *r.Session {

if err := pkg.Retry(time.Second*15, time.Minute*2, func() error {
logrus.Infof("Connecting with RethinkDB: %s (%s) (%s)", c.URL.String(), c.URL.Host, database)
if c.session, err = r.Connect(r.ConnectOpts{

options := r.ConnectOpts{
Address: c.URL.Host,
Username: username,
Password: password,
}); err != nil {
}

importRethinkDBRootCA(&options)

if c.session, err = r.Connect(options); err != nil {
return errors.Errorf("Could not connect to RethinkDB: %s", err)
}

Expand All @@ -61,6 +70,35 @@ func (c *RethinkDBConnection) GetSession() *r.Session {
return c.session
}

// importRethinkDBRootCA checks for the configuration values RETHINK_TLS_CERT_PATH
// or RETHINK_TLS_CERT and adds the certificate to the connect options
func importRethinkDBRootCA(opts *r.ConnectOpts) {
var cert []byte
certPath := viper.GetString("RETHINK_TLS_CERT_PATH")
if certPath != "" {
var err error
cert, err = ioutil.ReadFile(certPath)
if err != nil {
logrus.Warningf("Could not read rethinkdb certificate: %s", err)
return
}
}

certString := viper.GetString("RETHINK_TLS_CERT")
if certString != "" {
cert = []byte(certString)
}

if cert != nil {
roots := x509.NewCertPool()
roots.AppendCertsFromPEM(cert)
opts.TLSConfig = &tls.Config{
RootCAs: roots,
}
logrus.Warnln("Loaded self-signed certificate for rethinkdb")
}
}

func (c *RethinkDBConnection) CreateTableIfNotExists(table string) {
if _, err := r.TableList().Contains(table).Do(func(e r.Term) r.Term {
return r.Branch(
Expand Down
84 changes: 84 additions & 0 deletions config/backend_connections_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package config

import (
"io/ioutil"
"os"
"testing"

"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

r "gopkg.in/dancannon/gorethink.v2"
)

var cert1 = `-----BEGIN CERTIFICATE-----
MIIB/zCCAamgAwIBAgIJAPKYmr9KduB0MA0GCSqGSIb3DQEBCwUAMFsxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtMb3MgQW5nZWxl
czEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE2MDYyMzEx
NTM0NloXDTI2MDYyMTExNTM0NlowWzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
bGlmb3JuaWExFDASBgNVBAcMC0xvcyBBbmdlbGVzMSEwHwYDVQQKDBhJbnRlcm5l
dCBXaWRnaXRzIFB0eSBMdGQwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA29Rsxzzh
ZkN6b1UZ8eQJcJBLsSxEDJPdHaztJbL1azYr+pdSCBx7QGL+8odxC6Vur9Y3keZl
fkUza9YoKTxUpwIDAQABo1AwTjAdBgNVHQ4EFgQUMlXwDvfVUxBftSsr3Hl9HMDo
tY0wHwYDVR0jBBgwFoAUMlXwDvfVUxBftSsr3Hl9HMDotY0wDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAANBAIPOzp8x4rS0sOFfUaXacKgFBm7wh+ski5P35chZ
0BZAXTka0jqHhLRo+qsD/mNGQWwUkDbtLSkMZVxxO5HMJXg=
-----END CERTIFICATE-----`

var cert2 = `-----BEGIN CERTIFICATE-----
MIIB/TCCAaegAwIBAgIJAPywvLC/ldr6MA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRMwEQYDVQQHDApXYXNoaW5ndG9u
MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwNjIzMTE1
NDI3WhcNMjYwNjIxMTE1NDI3WjBaMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz
aGluZ3RvbjETMBEGA1UEBwwKV2FzaGluZ3RvbjEhMB8GA1UECgwYSW50ZXJuZXQg
V2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMMXumS376Qp
yK/Jaa83MOcyIGwrmLxuu0vKWQU5u1USSuFGGnIQ08YhBcklQI8+t4aJY+hCsfDx
5PKNIX8SxNsCAwEAAaNQME4wHQYDVR0OBBYEFF6FjQx8T3JOU46GAdGNQ7UWDQEj
MB8GA1UdIwQYMBaAFF6FjQx8T3JOU46GAdGNQ7UWDQEjMAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQELBQADQQC4aXmUbyBiVaXWnkKCGzbf5Uxs6y3td+togd1La1mn
d9ahfgeVHNG0Dz9VJu2LA3aB4pAWPlbxd2m0frzK1Sx4
-----END CERTIFICATE-----`

var TestImportRethinkDBRootCAData = []struct {
Name string
EnvKey string
EnvValue string
Cert string
}{
{"Without Certificate", "", "", ""},
{"Certificate string 1", "RETHINK_TLS_CERT", cert1, cert1},
{"Certificate string 2", "RETHINK_TLS_CERT", cert2, cert2},
{"Certificate path 1", "RETHINK_TLS_CERT_PATH", "cert1.pem", cert1},
{"Certificate path 2", "RETHINK_TLS_CERT_PATH", "cert2.pem", cert2},
}

func TestImportRethinkDBRootCA(t *testing.T) {
ioutil.WriteFile("cert1.pem", []byte(cert1), 0644)
ioutil.WriteFile("cert2.pem", []byte(cert2), 0644)

for _, test := range TestImportRethinkDBRootCAData {
viper.Reset()
if test.EnvKey != "" {
viper.Set(test.EnvKey, test.EnvValue)
}

opts := r.ConnectOpts{}

importRethinkDBRootCA(&opts)

if test.Cert != "" {
require.NotNil(t, opts.TLSConfig, test.Name)

// We try to add the same certificate twice to see if it has added the correct one
assert.Equal(t, 1, len(opts.TLSConfig.RootCAs.Subjects()), test.Name)
opts.TLSConfig.RootCAs.AppendCertsFromPEM([]byte(test.Cert))
assert.Equal(t, 1, len(opts.TLSConfig.RootCAs.Subjects()), test.Name)
}
}

// Cleanup
viper.Reset()
os.Remove("cert1.pem")
os.Remove("cert2.pem")
}

0 comments on commit 74432b0

Please sign in to comment.