Reputation: 6370
I'm struggling to proxy with nginx to an SSL upstream. I realize that proxying to HTTPS is wasteful, but here's my setup, sometimes the API is accessed directly, other times I'm using nginx to serve a JS app which is also a client of the API, CORS and browser security mandates that the JS app communicates with the same domain as the app is served from:
+--------------------+ +---------------------+
| |+-------------------->| |
| Pure HTTP API Host | | CLI Tool API Client |
| |<--------------------+| |
+--------------------+ +---------------------+
| ^ (:3152)
| |
| | | +---------------------+
| +--------------------------------| |
| | | Javascript App |
+---------------------------------->| |
| +---------------------+
|
nginx proxy for CORS
With that out of the way, here's the stack. The API Host is written in GoLang, served using a signed certificate from StartSSL:
$ openssl s_client -ssl3 -connect local.api.theproject.io:3251
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : SSLv3
Cipher : AES256-SHA
Session-ID:
Session-ID-ctx:
Master-Key: E021B27717F5A4
Key-Arg : None
Start Time: 1377589306
Timeout : 7200 (sec)
Verify return code: 21 (unable to verify the first certificate)
I've truncated that output, but sufficed to say that Go's ListenAndServeTLS only appears to work with SSLv3, as the following fails:
$ openssl s_client -connect local.api.theproject.io:3251
CONNECTED(00000003)
35899:error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/ssl/s23_clnt.c:602:
Thus the problem coming out of nginx is clear:
2013/08/27 09:30:21 [error] 35674#0: *3 kevent() reported that connect() failed (61:
Connection refused) while connecting to upstream, client: 127.0.0.1, server:
local.www.theproject.io, request: "GET / HTTP/1.1", upstream: "https://[::1]:3251//",
host: "local.www.theproject.io:4443"
2013/08/27 09:30:21 [error] 35674#0: *3 SSL_do_handshake() failed (SSL: error:1407742
E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version) while SSL handshaking
to upstream, client: 127.0.0.1, server: local.www.theproject.io, request: "GET /
HTTP/1.1", upstream: "https://127.0.0.1:3251//", host: "local.www.theproject.io:4443"
(Note: I'm using [::1]
here, but that's not significant, it also fails, of course on 127.0.0.1
)
Thus the question is, what is missing from:
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_pass https://local.api.theproject.io:3251/;
in order to get this to proxy correctly using SSLv3 internally?
Upvotes: 4
Views: 3682
Reputation: 11
Have you tried "ssl_ciphers ALL;"?
Although that's not recommended (because that allows weak ciphers), that shall narrow down the scope of the problem. If that doesn't work, most likely the cause of your problem is that the openssl you use doesn't have the suitable ciphers to complete the SSL handshake with your Go server.
Note that Go's tls package is only "partially" implemented and the supported ciphers is very limited.
There are two solutions:
openssl ciphers
provides by adding the appropriate suite ids to cipherSuites in tls/cipher_suites.go (I think)Upvotes: 1