Skip to content

NGINX C module that extends ngx_http_lua_module for enhanced SSL/TLS capabilities

Notifications You must be signed in to change notification settings

openresty/lua-ssl-nginx-module

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NAME

lua-ssl-nginx-module - NGINX C module that extends ngx_http_lua_module for enhanced SSL/TLS capabilities

Table of Contents

Synopsis

http {
    lua_package_path "/path/to/lua-ssl-nginx-module/lualib/?.lua;;";

    lua_shared_dict my_cache 10m;
    lua_shared_dict locks 1m;

    init_by_lua_block {
        require("ngx.ssl.session.ticket.key_rotation").init{
            locks_shdict_name = "locks",

            disable_shm_cache = false,  -- default false
            cache_shdict_name = "my_cache",
            shm_cache_positive_ttl = 24 * 3600 * 1000,   -- in ms
            shm_cache_negative_ttl = 0,   -- in ms

            ticket_ttl = 24 * 3600,   -- in sec
            key_rotation_period = 3600,   -- in sec

            memc_key_prefix = "ticket-key/",

            memc_host = "127.0.0.1",
            memc_port = 11211,
            memc_timeout = 500,  -- in ms
            memc_conn_pool_size = 1,
            memc_fetch_retries = 1,  -- optional, default 1
            memc_fetch_retry_delay = 100, -- in ms, optional, default to 100 (ms)

            memc_conn_max_idle_time = 1 * 1000,  -- in ms, for in-pool connections,
                                                  -- optional, default to nil
            key_length = 48   -- in bytes, optional, default 48, possible 80 if using with
                              -- nginx > 1.12.0, any other values it will
                              -- fallback to default length
        }
    }

    init_worker_by_lua_block {
        require("ngx.ssl.session.ticket.key_rotation").start_update_timer()
    }

    server {
        listen 443 ssl;
        server_name "foo.com";

        # SSL session ticket key sharing
        # Put a dummy key to trigger external ticket key usage in nginx/OpenSSL
        # init_by_lua* will replace this dummy key with existing cached keys
        # or a random key if cached keys are not available.
        # If key_length was set to 80 bytes in init_by_lua*, the dummy key needs to be 80 bytes too.
        ssl_session_ticket_key  dummy.key;

        ...
    }

    ...
}

Description

This NGINX module adds new Lua API and modules to OpenResty that enables more SSL/TLS features like automatic TLS session ticket key manipulation and rotation (on the global network level).

For global TLS session ticket key rotation, we require an external mechanism (could be in a dedicated NGINX or OpenResty server itself, however) to feed the TLS session ticket keys for each hour in Memcached servers or Memcached-compatible servers (like Kyoto Tycoon). Each NGINX or OpenResty server node automatically queries the Memcached server(s) with a key containing the timestamp every hour. It has the following advantages:

  1. We keep a list of keys inside the nginx server and only evict the oldest key every hour, which allows gradual phase-out of old keys. The size of the list depends on the ticket_ttl and key_rotation_period settings.
  2. The keys are updated automatically for all the virtual (SSL) servers defined in the nginx.conf file.
  3. No NGINX server reload or restart is needed. New keys are pulled from Memcached or Memcached-compatible servers automatically every hour.
  4. All network I/O is 100% nonblocking, that is, it never blocks any OS threads nor the nginx event loop, even on shm cache misses.
  5. All the core logic is in pure Lua, which is every easy to hack and adjust for special requirements.
  6. Uses shm cache for the keys so that only one worker needs to query the Memcached or Memcached-compatible servers. The shm cache can be disabled though.

NOTE: ticket key should be protected by some key encryption key. The ticket key should be decrypted before being used. However we leave this to the user to handle.

Methods

This section documents the methods for the ngx.ssl.session.ticket.key_rotation Lua module.

init

syntax: module.init(opts)

Initialize the settings of this module.

start_update_timer

syntax: module.start_update_timer()

Starts a recurring timer that periodically populates and rotates the ticket key list. When invoked, it does three things:

  1. Look up a ticket key for current time slot and insert it to the beginning of the ticket key list.
  2. Look up a ticket key for next time slot and replace the the last element of the key list with it.
  3. Start a new timer for next check.

Note we use rounded down timestamp based indexing in the shared memcached to store/fetch ticket key.

For example, using a time slot of 1000 second, we would round the timestamp down to the nearest 1000: 1001 -> 1000, 1987 -> 1000, and 2001 -> 2000. In practice we usually use 1 hour as slot size. You can check out the Lua function ticket_key_index for implementation details.

Timers across hosts are only loosely synchronized, there are cases that host A is waken up by its timer and host B is not. host A would start to use new key while session B is yet to load it. The problem is solved by preloading the key for the next slot, as described by item 2 above.

Installation

This module depends on lua-nginx-module.

If you are using the official nginx distribution, then build like this:

./configure --with-http_ssl_module \
            --add-module=/path/to/lua-nginx-module \
            --add-module=/path/to/lua-ssl-nginx-module
make
sudo make install

You can also compile this module as a dynamic module, by using the --add-dynamic-module=/path/to/lua-ssl-nginx-module instead of --add-module on the ./configure command line above. Then load the module in nginx.conf via the load_module directive.

Otherwise, if you are using the OpenResty distribution, build it as follows:

./configure --add-module=/path/to/lua-ssl-nginx-module
make
sudo make install

This module also ships with Lua modules under the lualib/ directory. You can configure the lua_package_path directive like below:

lua_package_path "/path/to/lua-ssl-nginx-module/lualib/?.lua;;";

Some of our Lua modules depend on the following Lua libraries:

Back to TOC

Author

  • Zi Lin, Cloudflare Inc.
  • Yichun "agentzh" Zhang (章亦春) agentzh@gmail.com, Cloudflare Inc.

Back to TOC

Copyright and License

This module is licensed under the BSD license.

Copyright (C) 2016, by Cloudflare Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Back to TOC