1

I'm looking to use CouchDB with SSL and nodejs and I have just switched from self signed certificates (which were working for over a month) to a real SSL certificate and now I'm running into configuration issues. I've scattered a few questions along the way as there are quite a few pieces, but the main issue is that node and couch no longer talk.

I have nodejs running and I'm using the node-spdy extension (https://www.npmjs.org/package/spdy)

I have SSL certificates configured:

var options = {
  key: fs.readFileSync(__dirname + '/keys/spdy-key.pem'),
  cert: fs.readFileSync(__dirname + '/keys/spdy-cert.pem'),
  ca: fs.readFileSync(__dirname + '/keys/spdy-ca.pem'),
};

First question: I now have an intermediate certificate, how do I tell nodejs this?Previously my cert was self-signed so I put the csr file in the ca spot (above) and that was working. Actually, trying it today, both the csr file and the intermediate certificate seem to work in that spot, but that can't be right, hence my question. So if it's the csr, then how do I properly configure the intermediate certificate? I've seen this thread: https://stackoverflow.com/questions/19104215/node-js-express-js-chain-certificate-not-working

Next, couchdb was working with SSL when I had self-signed cert. In order to get node and couch to play nice over SSL I had to set this flag in node:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

This stopped node from quitting on error of "self-signed" certificate. Now I want to remove that flag. (Originally I got that tip from here: https://github.com/mikeal/request/issues/418)

Now to to the main issue. In CouchDB, my local.ini has:

[httpd]
;port = 5984
;bind_address = 127.0.0.1
; Options for the MochiWeb HTTP server.
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
; For more socket options, consult Erlang's module 'inet' man page.
;socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}]

; Uncomment next line to trigger basic-auth popup on unauthorized requests.
WWW-Authenticate = Basic realm="administrator"

; Uncomment next line to set the configuration modification whitelist. Only
; whitelisted values may be changed via the /_config URLs. To allow the admin
; to change this value over HTTP, remember to include {httpd,config_whitelist}
; itself. Excluding it from the list would require editing this file to update
; the whitelist.
;config_whitelist = [{httpd,config_whitelist}, {log,level}, {etc,etc}]

[httpd_global_handlers]
;_google = {couch_httpd_proxy, handle_proxy_req, <<"http://www.google.com">>}

[couch_httpd_auth]
; If you set this to true, you should also uncomment the WWW-Authenticate line
; above. If you don't configure a WWW-Authenticate header, CouchDB will send
; Basic realm="server" in order to prevent you getting logged out.
require_valid_user = true

[log]
;level = debug

[log_level_by_module]
; In this section you can specify any of the four log levels 'none', 'info',
; 'error' or 'debug' on a per-module basis. See src/*/*.erl for various
; modules.
;couch_httpd = error


[os_daemons]
; For any commands listed here, CouchDB will attempt to ensure that
; the process remains alive. Daemons should monitor their environment
; to know when to exit. This can most easily be accomplished by exiting
; when stdin is closed.
;foo = /path/to/command -with args

[daemons]
; enable SSL support by uncommenting the following line and supply the PEM's below.
; the default ssl port CouchDB listens on is 6984
httpsd = {couch_httpd, start_link, [https]}

[ssl]
cert_file = /srv/www/[appname]/keys/cert.pem
key_file = /srv/www/[appname]/keys/key.pem
;password = somepassword
; set to true to validate peer certificates
;verify_ssl_certificates = true

; Path to file containing PEM encoded CA certificates (trusted
; certificates used for verifying a peer certificate). May be omitted if
; you do not want to verify the peer.
; cacert_file = /srv/www/[appname]/keys/ca.pem
; The verification fun (optional) if not specified, the default
; verification fun will be used.
;verify_fun = {Module, VerifyFun}
; maximum peer certificate depth
ssl_certificate_max_depth = 1

Is this setup right? I followed (http://guide.couchdb.org/draft/security.html) and (http://wiki.apache.org/couchdb/How_to_enable_SSL)

However, when I connect, I get this in the node logs:

error { [Error: read ECONNRESET] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }

This is usually an error when the other side of the connection ends early on nodejs. So couchDB is exiting. And when I run curl -k -v https://127.0.0.1:6984/ to check out what's up, I get:

* About to connect() to 127.0.0.1 port 6984 (#0)
*   Trying 127.0.0.1...
* Adding handle: conn: 0x181eab0
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x181eab0) send_pipe: 1, recv_pipe: 0
* Connected to 127.0.0.1 (127.0.0.1) port 6984 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* Unknown SSL protocol error in connection to 127.0.0.1:6984 
* Closing connection 0
curl: (35) Unknown SSL protocol error in connection to 127.0.0.1:6984

This all happened after the new SSL files. I've heard that CouchDB doesn't like some of SSL configs? (See here: https://leap.se/code/issues/883#note-10)

Seems like a strange error to output if it's just permissions, but you can never be too sure. So, for the pem files - I have the permissions set to 700 on the /keys folder and 600 on the pem files. The user is a deploy user and couch runs on the couch user. So couch can't actually access these, correct? Is that the issue? If it is the solution, is the best course of action to add couchdb user to the deploy group? Is that the fix? I always like to make double sure when dealing with permissions.

Separately from that, no matter how I try, I can't seem to get couch to verify the SSL cert, so I've left that config as off. Is that a problem? I've heard that couch requires the certs to have a password for this setting to work. Is that true? (http://thinkinginsoftware.blogspot.ca/2012/12/couchdb-unknown-ssl-protocol-error-in.html) Do I even need this config to be on?

Lastly and separately, in couch.uri file it has both the http and https URLs. So it's starting up 2 instances. Can I safely remove the http URL from starting up now that I'm using SSL or does it need both?

Paul

paintedbicycle
  • 199
  • 1
  • 3
  • 15

2 Answers2

1

So, here are the answers in case anyone comes across this in their own journey:

When you're setting SSL up in node, especially with SPDY, it asks for:

var options = {
  key: fs.readFileSync(__dirname + '/keys/spdy-key.pem'),
  cert: fs.readFileSync(__dirname + '/keys/spdy-cert.pem'),
  ca: fs.readFileSync(__dirname + '/keys/spdy-ca.pem'),
};

It seems that you can use the csr (certificate signing request) as the ca in the SSL setup for self-signed certificates. However, doing that on a production server, means that the certificate chain has problems (the certificate you bought, like RapidSSL, is chained to a lower-level certificate, like GeoTrust. The chain needs to go all the way back since GeoTrust is the one trusted by the browser.) If you don't do the ca file (intermediate certificate file) it's ok in most cases - it'll say that the chain is broken in https://www.ssllabs.com/ssltest but the browsers didn't seem to care. But the correct way is to put the intermediate certificate in the ca spot.

As for node and couch, the problem definitely was permissions. I added couchdb user to the deploy usergroup but since the permissions on the key files are 600, the group still doesn't have access. In my case, I just created a self-signed certificate specially for couchDB.

That means that I have to tell node to trust it by using this config flag:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

So now couch and node talk and use SSL.

As for some of the other questions:

Basic openssl usage seems to work fine with couchdb, so no issues with certain certificate types or anything like that I've come across

I cannot seem to turn on certificate verification for couch in this setup. I just get SSL: hello: tls_handshake.erl:285:Fatal error: internal error So leaving that set to false works

It seems that you can safely remove the http server from couchdb's couch.uri file (found at /var/run/couchdb/couch.uri) and just have the https one.

Hope this helps someone out,

Paul

paintedbicycle
  • 199
  • 1
  • 3
  • 15
0

couchdb and ssl is hopeless (at least for the moment). It seems to be a bug in the underlying erlang library. I spent two days without luck. Now I try to use nginx as proxy...

andiba
  • 101
  • 2