[PATCH v2] uwsgi over ssl

Maxim Dounin mdounin at mdounin.ru
Wed Dec 4 15:51:19 UTC 2013


Hello!

On Tue, Nov 19, 2013 at 11:24:50AM +0100, Roberto De Ioris wrote:

> Hi, this is a new patch for uwsgi over ssl support aimed at nginx 1.5.x
> 
> It now exposes 4 options:
> 
> uwsgi_ssl
> 
> uwsgi_ssl_session_reuse
> 
> uwsgi_ssl_protocols
> 
> uwsgi_ssl_ciphers

Sorry for long delay.  I've looked into this, and I tend to think 
that "uwsgi_ssl" is a wrong aproach.  E.g., consider the following 
configuration:

    location / {
        uwsgi_pass upstream1;
        uwsgi_ssl on;

        location /nested/ {
            uwsgi_pass upstream2;
            uwsgi_ssl_protocols TLSv2;
        }
    }

Requests to upstream2 will use SSL, but uwsgi_ssl_protocols won't 
have any effect.  While this is easy to fix, this is certainly 
counter-intuitive.

Instead, I think it would be better to use something like this:

    uwsgi_pass uwsgis://upstream;

Where "uwsgis" scheme means "uwsgi over ssl", much like in https 
with proxy_pass.  This way, SSL is configured with the uwsgi_pass 
and don't have unexpected side effects like the above.

Below is a patch which implements this aproach.  What do you 
think?

# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1386171311 -14400
#      Wed Dec 04 19:35:11 2013 +0400
# Node ID 289c2c5ccc381cea89b69cac0cb130b0b9b4494c
# Parent  692afcea9d0d05c10b1dd7f2bd095dd014665f4c
SSL support in the uwsgi module.

Based on patch by Roberto De Ioris.

diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -34,6 +34,12 @@ typedef struct {
 
     ngx_uint_t                 modifier1;
     ngx_uint_t                 modifier2;
+
+#if (NGX_HTTP_SSL)
+    ngx_uint_t                 ssl;
+    ngx_uint_t                 ssl_protocols;
+    ngx_str_t                  ssl_ciphers;
+#endif
 } ngx_http_uwsgi_loc_conf_t;
 
 
@@ -66,6 +72,11 @@ static char *ngx_http_uwsgi_cache_key(ng
     void *conf);
 #endif
 
+#if (NGX_HTTP_SSL)
+static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf,
+    ngx_http_uwsgi_loc_conf_t *uwcf);
+#endif
+
 
 static ngx_conf_num_bounds_t  ngx_http_uwsgi_modifier_bounds = {
     ngx_conf_check_num_bounds, 0, 255
@@ -86,6 +97,20 @@ static ngx_conf_bitmask_t ngx_http_uwsgi
 };
 
 
+#if (NGX_HTTP_SSL)
+
+static ngx_conf_bitmask_t  ngx_http_uwsgi_ssl_protocols[] = {
+    { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
+    { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
+    { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
+    { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
+    { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_null_string, 0 }
+};
+
+#endif
+
+
 ngx_module_t  ngx_http_uwsgi_module;
 
 
@@ -361,6 +386,31 @@ static ngx_command_t ngx_http_uwsgi_comm
       offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_headers),
       &ngx_http_upstream_ignore_headers_masks },
 
+#if (NGX_HTTP_SSL)
+
+    { ngx_string("uwsgi_ssl_session_reuse"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_session_reuse),
+      NULL },
+
+    { ngx_string("uwsgi_ssl_protocols"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_protocols),
+      &ngx_http_uwsgi_ssl_protocols },
+
+    { ngx_string("uwsgi_ssl_ciphers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphers),
+      NULL },
+
+#endif
+
       ngx_null_command
 };
 
@@ -448,15 +498,29 @@ ngx_http_uwsgi_handler(ngx_http_request_
 
     uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
 
-    if (uwcf->uwsgi_lengths) {
+    u = r->upstream;
+
+    if (uwcf->uwsgi_lengths == NULL) {
+
+#if (NGX_HTTP_SSL)
+        u->ssl = (uwcf->upstream.ssl != NULL);
+
+        if (u->ssl) {
+            ngx_str_set(&u->schema, "uwsgis://");
+
+        } else {
+            ngx_str_set(&u->schema, "uwsgi://");
+        }   
+#else
+        ngx_str_set(&u->schema, "uwsgi://");
+#endif
+
+    } else {
         if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
     }
 
-    u = r->upstream;
-
-    ngx_str_set(&u->schema, "uwsgi://");
     u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module;
 
     u->conf = &uwcf->upstream;
@@ -494,6 +558,7 @@ ngx_http_uwsgi_handler(ngx_http_request_
 static ngx_int_t
 ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
 {
+    size_t                add;
     ngx_url_t             url;
     ngx_http_upstream_t  *u;
 
@@ -506,6 +571,41 @@ ngx_http_uwsgi_eval(ngx_http_request_t *
         return NGX_ERROR;
     }
 
+    if (url.url.len > 8
+        && ngx_strncasecmp(url.url.data, (u_char *) "uwsgi://", 8) == 0)
+    {
+        add = 8;
+
+    } else if (url.url.len > 9
+               && ngx_strncasecmp(url.url.data, (u_char *) "uwsgis://", 9) == 0)
+    {
+
+#if (NGX_HTTP_SSL)
+        add = 9;
+        r->upstream->ssl = 1;
+#else
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "uwsgis protocol requires SSL support");
+        return NGX_CONF_ERROR;
+#endif
+
+    } else {
+        add = 0;
+    }
+
+    u = r->upstream;
+
+    if (add) {
+        u->schema.len = add;
+        u->schema.data = url.url.data;
+
+        url.url.data += add;
+        url.url.len -= add;
+
+    } else {
+        ngx_str_set(&u->schema, (u_char *) "uwsgi://");
+    }
+
     url.no_resolve = 1;
 
     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
@@ -517,8 +617,6 @@ ngx_http_uwsgi_eval(ngx_http_request_t *
         return NGX_ERROR;
     }
 
-    u = r->upstream;
-
     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
     if (u->resolved == NULL) {
         return NGX_ERROR;
@@ -1145,6 +1243,9 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_
     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
 
     conf->upstream.intercept_errors = NGX_CONF_UNSET;
+#if (NGX_HTTP_SSL)
+    conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
+#endif
 
     /* "uwsgi_cyclic_temp_file" is disabled */
     conf->upstream.cyclic_temp_file = 0;
@@ -1392,6 +1493,27 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
     ngx_conf_merge_value(conf->upstream.intercept_errors,
                          prev->upstream.intercept_errors, 0);
 
+#if (NGX_HTTP_SSL)
+    ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
+                              prev->upstream.ssl_session_reuse, 1);
+
+    ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
+                                 (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3
+                                  |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                                  |NGX_SSL_TLSv1_2));
+
+    ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
+                             "DEFAULT");
+
+    if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->upstream.ssl == NULL) {
+        conf->upstream.ssl = prev->upstream.ssl;
+    }
+#endif
+
     ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, "");
 
     hash.max_size = 512;
@@ -1670,6 +1792,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_
 {
     ngx_http_uwsgi_loc_conf_t *uwcf = conf;
 
+    size_t                      add;
     ngx_url_t                   u;
     ngx_str_t                  *value, *url;
     ngx_uint_t                  n;
@@ -1705,12 +1828,35 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_
             return NGX_CONF_ERROR;
         }
 
+#if (NGX_HTTP_SSL)
+        uwcf->ssl = 1;
+#endif
+
         return NGX_CONF_OK;
     }
 
+    if (ngx_strncasecmp(url->data, (u_char *) "uwsgi://", 8) == 0) {
+        add = 8;
+
+    } else if (ngx_strncasecmp(url->data, (u_char *) "uwsgis://", 9) == 0) {
+
+#if (NGX_HTTP_SSL)
+        add = 9;
+        uwcf->ssl = 1;
+#else
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "uwsgis protocol requires SSL support");
+        return NGX_CONF_ERROR;
+#endif
+
+    } else {
+        add = 0;
+    }
+
     ngx_memzero(&u, sizeof(ngx_url_t));
 
-    u.url = value[1];
+    u.url.len = url->len - add;
+    u.url.data = url->data + add;
     u.no_resolve = 1;
 
     uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
@@ -1844,3 +1990,47 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf,
 }
 
 #endif
+
+
+#if (NGX_HTTP_SSL)
+
+static ngx_int_t
+ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
+{
+    ngx_pool_cleanup_t  *cln;
+
+    uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
+    if (uwcf->upstream.ssl == NULL) {
+        return NGX_ERROR;
+    }
+
+    uwcf->upstream.ssl->log = cf->log;
+
+    if (ngx_ssl_create(uwcf->upstream.ssl, uwcf->ssl_protocols, NULL)
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (SSL_CTX_set_cipher_list(uwcf->upstream.ssl->ctx,
+                                (const char *) uwcf->ssl_ciphers.data)
+        == 0)
+    {
+        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
+                      "SSL_CTX_set_cipher_list(\"%V\") failed",
+                      &uwcf->ssl_ciphers);
+        return NGX_ERROR;
+    }
+
+    cln = ngx_pool_cleanup_add(cf->pool, 0);
+    if (cln == NULL) {
+        return NGX_ERROR;
+    }
+
+    cln->handler = ngx_ssl_cleanup_ctx;
+    cln->data = uwcf->upstream.ssl;
+
+    return NGX_OK;
+}
+
+#endif

-- 
Maxim Dounin
http://nginx.org/en/donation.html



More information about the nginx-devel mailing list