Skip to content

Commit

Permalink
feat(ssl) configurable ssl cipher suites
Browse files Browse the repository at this point in the history
Provide a shorthand config option to define cipher suites based on
Mozilla's recommended cipher list, and an optional config to define
custom ciphers.
  • Loading branch information
p0pr0ck5 committed May 25, 2017
1 parent fd86e20 commit 92f9895
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 0 deletions.
1 change: 1 addition & 0 deletions kong-0.10.2-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ build = {
["kong.api.routes.certificates"] = "kong/api/routes/certificates.lua",
["kong.api.routes.snis"] = "kong/api/routes/snis.lua",

["kong.tools.ciphers"] = "kong/tools/ciphers.lua",
["kong.tools.dns"] = "kong/tools/dns.lua",
["kong.tools.utils"] = "kong/tools/utils.lua",
["kong.tools.public"] = "kong/tools/public.lua",
Expand Down
12 changes: 12 additions & 0 deletions kong.conf.default
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@
# itself on `proxy_listen`, and all SSL
# settings will be ignored.

#ssl_cipher_suite = modern # Defines the TLS ciphers served by Nginx.
# Accepted values are 'modern', 'intermediate',
# 'old', or 'custom'.
# Note: See https://wiki.mozilla.org/Security/Server_Side_TLS for detailed
# descriptions of each cipher suite.

#ssl_ciphers = # Defines a custom list of TLS ciphers to be
# served by Nginx. This list must conform to
# the pattern defined by `openssl ciphers`.
# This value is ignored if `ssl_ciphers_suite`
# is not 'custom'.

#ssl_cert = # If `ssl` is enabled, the absolute path to
# the SSL certificate for the
# `proxy_listen_ssl` address.
Expand Down
10 changes: 10 additions & 0 deletions kong/conf_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ local pl_path = require "pl.path"
local tablex = require "pl.tablex"
local utils = require "kong.tools.utils"
local log = require "kong.cmd.utils.log"
local ciphers = require "kong.tools.ciphers"

local DEFAULT_PATHS = {
"/etc/kong/kong.conf",
Expand Down Expand Up @@ -252,6 +253,15 @@ local function check_and_infer(conf)
end
end

if conf.ssl_cipher_suite ~= "custom" then
local ok, err = pcall(function()
conf.ssl_ciphers = ciphers(conf.ssl_cipher_suite)
end)
if not ok then
errors[#errors + 1] = err
end
end

if conf.dns_resolver then
for _, server in ipairs(conf.dns_resolver) do
local dns = utils.normalize_ip(server)
Expand Down
2 changes: 2 additions & 0 deletions kong/templates/kong_defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ ssl_cert_key = NONE
client_ssl = off
client_ssl_cert = NONE
client_ssl_cert_key = NONE
ssl_cipher_suite = modern
ssl_ciphers = ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
admin_ssl = on
admin_ssl_cert = NONE
admin_ssl_cert_key = NONE
Expand Down
10 changes: 10 additions & 0 deletions kong/templates/nginx_kong.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ server {
ssl_certificate_by_lua_block {
kong.ssl_certificate()
}
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_prefer_server_ciphers on;
ssl_ciphers ${{SSL_CIPHERS}};
> end
> if client_ssl then
Expand Down Expand Up @@ -159,6 +164,11 @@ server {
ssl_certificate ${{ADMIN_SSL_CERT}};
ssl_certificate_key ${{ADMIN_SSL_CERT_KEY}};
ssl_protocols TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_prefer_server_ciphers on;
ssl_ciphers ${{SSL_CIPHERS}};
> end
location / {
Expand Down
115 changes: 115 additions & 0 deletions kong/tools/ciphers.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
local _ciphers = {
modern = {
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES256-SHA384",
"ECDHE-RSA-AES256-SHA384",
"ECDHE-ECDSA-AES128-SHA256",
"ECDHE-RSA-AES128-SHA256",
},
intermediate = {
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"DHE-RSA-AES128-GCM-SHA256",
"DHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES128-SHA256",
"ECDHE-RSA-AES128-SHA256",
"ECDHE-ECDSA-AES128-SHA",
"ECDHE-RSA-AES256-SHA384",
"ECDHE-RSA-AES128-SHA",
"ECDHE-ECDSA-AES256-SHA384",
"ECDHE-ECDSA-AES256-SHA",
"ECDHE-RSA-AES256-SHA",
"DHE-RSA-AES128-SHA256",
"DHE-RSA-AES128-SHA",
"DHE-RSA-AES256-SHA256",
"DHE-RSA-AES256-SHA",
"ECDHE-ECDSA-DES-CBC3-SHA",
"ECDHE-RSA-DES-CBC3-SHA",
"EDH-RSA-DES-CBC3-SHA",
"AES128-GCM-SHA256",
"AES256-GCM-SHA384",
"AES128-SHA256",
"AES256-SHA256",
"AES128-SHA",
"AES256-SHA",
"DES-CBC3-SHA",
"!DSS",
},
old = {
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"DHE-RSA-AES128-GCM-SHA256",
"DHE-DSS-AES128-GCM-SHA256",
"kEDH+AESGCM",
"ECDHE-RSA-AES128-SHA256",
"ECDHE-ECDSA-AES128-SHA256",
"ECDHE-RSA-AES128-SHA",
"ECDHE-ECDSA-AES128-SHA",
"ECDHE-RSA-AES256-SHA384",
"ECDHE-ECDSA-AES256-SHA384",
"ECDHE-RSA-AES256-SHA",
"ECDHE-ECDSA-AES256-SHA",
"DHE-RSA-AES128-SHA256",
"DHE-RSA-AES128-SHA",
"DHE-DSS-AES128-SHA256",
"DHE-RSA-AES256-SHA256",
"DHE-DSS-AES256-SHA",
"DHE-RSA-AES256-SHA",
"ECDHE-RSA-DES-CBC3-SHA",
"ECDHE-ECDSA-DES-CBC3-SHA",
"EDH-RSA-DES-CBC3-SHA",
"AES128-GCM-SHA256",
"AES256-GCM-SHA384",
"AES128-SHA256",
"AES256-SHA256",
"AES128-SHA",
"AES256-SHA",
"AES",
"DES-CBC3-SHA",
"HIGH",
"SEED",
"!aNULL",
"!eNULL",
"!EXPORT",
"!DES",
"!RC4",
"!MD5",
"!PSK",
"!RSAPSK",
"!aDH",
"!aECDH",
"!EDH-DSS-DES-CBC3-SHA",
"!KRB5-DES-CBC3-SHA",
"!SRP",
},
}


local ciphers = setmetatable(_ciphers, {
__index = function(t, k) error("Undefined cipher suite " .. tostring(k)) end,
})


local function build_cipher_string(suite)
return table.concat(ciphers[suite], ":")
end


return setmetatable({}, {
__call = function(_, suite)
return build_cipher_string(suite)
end,
})
38 changes: 38 additions & 0 deletions spec/01-unit/02-conf_loader_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,44 @@ describe("Configuration loader", function()
assert.True(helpers.path.isabs(conf.ssl_cert))
assert.True(helpers.path.isabs(conf.ssl_cert_key))
end)
it("defines ssl_ciphers by default", function()
local conf, err = conf_loader(nil, {})
assert.is_nil(err)
-- looks kinda like a cipher suite
assert.matches(":", conf.ssl_ciphers, nil, true)
end)
it("explicitly defines ssl_ciphers", function()
local conf, err = conf_loader(nil, {
ssl_cipher_suite = "old"
})
assert.is_nil(err)
-- looks kinda like a cipher suite
assert.matches(":", conf.ssl_ciphers, nil, true)
end)
it("errors on invalid ssl_cipher_suite", function()
local conf, _, errors = conf_loader(nil, {
ssl_cipher_suite = "foo"
})
assert.is_nil(conf)
assert.equal(1, #errors)
assert.matches("Undefined cipher suite foo", errors[1], nil, true)
end)
it("overrides ssl_ciphers when ssl_cipher_suite is custom", function()
local conf, err = conf_loader(nil, {
ssl_cipher_suite = "custom",
ssl_ciphers = "foo:bar",
})
assert.is_nil(err)
assert.equals("foo:bar", conf.ssl_ciphers)
end)
it("doesn't override ssl_ciphers when undefined", function()
local ciphers = require "kong.tools.ciphers"
local conf, err = conf_loader(nil, {
ssl_cipher_suite = "custom",
})
assert.is_nil(err)
assert.same(ciphers("modern"), conf.ssl_ciphers)
end)
end)
describe("client", function()
it("requires both proxy SSL cert and key", function()
Expand Down

0 comments on commit 92f9895

Please sign in to comment.