我希望将 CouchDB 与 SSL 和 nodejs 结合使用,我刚刚从自签名证书(已使用了一个多月)切换到真正的 SSL 证书,现在遇到了配置问题。由于问题比较多,我在此过程中提出了一些问题,但主要问题是 node 和 Couch 不再通信。
我正在运行 nodejs,并且正在使用 node-spdy 扩展(https://www.npmjs.org/package/spdy)
我已经配置了 SSL 证书:
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'),
};
第一个问题:我现在有一个中间证书,我该如何告诉 nodejs?以前我的证书是自签名的,所以我把 csr 文件放在 ca 位置(上面),这样就可以了。实际上,今天尝试了一下,csr 文件和中间证书似乎都可以在那个位置工作,但这不可能是正确的,因此我提出了这个问题。所以如果是 csr,那么我该如何正确配置中间证书?我看过这个帖子:https://stackoverflow.com/questions/19104215/node-js-express-js-chain-certificate-not-working
接下来,当我拥有自签名证书时,couchdb 正在使用 SSL。为了让 node 和 couch 通过 SSL 顺利运行,我必须在 node 中设置此标志:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
这阻止了节点因“自签名”证书错误而退出。现在我想删除该标志。(最初我从这里得到这个提示:https://github.com/mikeal/request/issues/418)
现在来谈谈主要问题。在 CouchDB 中,我的 local.ini 有:
[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
这个设置对吗?我按照(http://guide.couchdb.org/draft/security.html) 和 (http://wiki.apache.org/couchdb/How_to_enable_SSL)
但是,当我连接时,我在节点日志中收到以下信息:
error { [Error: read ECONNRESET] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }
这通常是在连接另一端在 nodejs 上提前结束时出现的错误。因此,couchDB 正在退出。当我运行curl -k -v https://127.0.0.1:6984/
以检查发生了什么时,我得到了:
* 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
这一切都发生在新的 SSL 文件之后。我听说 CouchDB 不喜欢某些 SSL 配置?(参见此处:https://leap.se/code/issues/883#note-10)
如果只是权限问题,输出的错误似乎有点奇怪,但你永远不能太确定。因此,对于 pem 文件 - 我将 /keys 文件夹的权限设置为 700,将 pem 文件的权限设置为 600。用户是 deploy 用户,couch 以 couch 用户身份运行。因此,couch 实际上无法访问这些文件,对吗?这是问题所在吗?如果这是解决方案,最好的做法是将 couchdb 用户添加到 deploy 组吗?这是解决办法吗?在处理权限问题时,我总是喜欢再三确认。
除此之外,无论我如何尝试,似乎都无法让 Couch 验证 SSL 证书,因此我将该配置保留为关闭状态。这有问题吗?我听说 Couch 要求证书有密码才能使此设置起作用。是真的吗?(http://thinkinginsoftware.blogspot.ca/2012/12/couchdb-unknown-ssl-protocol-error-in.html)我是否确实需要启用此配置?
最后,需要单独说明的是,couch.uri 文件中既有 http URL,也有 https URL。因此,它启动了 2 个实例。既然我现在正在使用 SSL,我可以安全地从启动中删除 http URL 吗?还是两者都需要?
保罗
答案1
因此,如果有人在旅途中遇到这种情况,可以参考以下答案:
当您在节点中设置 SSL 时,尤其是使用 SPDY 时,它会要求:
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'),
};
似乎您可以在自签名证书的 SSL 设置中使用 csr(证书签名请求)作为 ca。但是,在生产服务器上执行此操作意味着证书链有问题(您购买的证书(如 RapidSSL)链接到较低级别的证书(如 GeoTrust)。由于 GeoTrust 是浏览器信任的证书,因此该链需要一直追溯。)如果您不执行 ca 文件(中间证书文件),在大多数情况下都没问题 - 它会说链已断开https://www.ssllabs.com/ssltest但浏览器似乎并不在意。但正确的方法是将中间证书放在 CA 位置。
至于 node 和 couch,问题肯定是权限。我将 couchdb 用户添加到部署用户组,但由于密钥文件的权限为 600,因此该组仍然无权访问。就我而言,我只是专门为 couchDB 创建了一个自签名证书。
这意味着我必须使用这个配置标志来告诉节点信任它:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
所以现在沙发和节点对话并使用 SSL。
至于其他一些问题:
基本 openssl 的使用似乎与 couchdb 配合得很好,所以我遇到的某些证书类型或类似问题都没有问题
我似乎无法在此设置中为沙发打开证书验证。我只是得到
SSL: hello: tls_handshake.erl:285:Fatal error: internal error
所以将该设置为 false 有效
看来您可以安全地从 couchdb 的 couch.uri 文件(位于/var/run/couchdb/couch.uri
)中删除 http 服务器,而只保留 https 服务器。
希望这能帮助别人,
保罗
答案2
couchdb
并且ssl
毫无希望(至少目前如此)。这似乎是底层erlang
库中的一个错误。我花了两天时间,但还是没有成功。现在我尝试使用nginx
代理...