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

Connect to rethinkdb with a custom certificate #116

Merged
merged 3 commits into from
Jun 23, 2016
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
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")
}