Skip to content

Commit

Permalink
feat(core) add support for static client SSL certificates
Browse files Browse the repository at this point in the history
Implement the proxy_ssl_certificate and proxy_ssl_certificate_key
directives in the Kong template. Because OpenResty's balancer_by_lua
handler does not cover client side certs, we cannot assign client
certs on a configurable basis, and using complex values in cert
values is unsupported in Nginx, we are left with a static approach
that can only serve one cert/key pair.

From #2556
  • Loading branch information
p0pr0ck5 authored and thibaultcha committed May 25, 2017
1 parent 23585aa commit fd86e20
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 0 deletions.
17 changes: 17 additions & 0 deletions kong.conf.default
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,23 @@
# the SSL key for the `proxy_listen_ssl`
# address.

#client_ssl = on # Determines if Nginx should send client-side
# SSL certificates when proxying requests.

#client_ssl_cert = # If `client_ssl` is enabled, the absolute path
# to the client SSL certificate for the
# `proxy_ssl_certificate` directive. Note that
# this value is statically defined on the node,
# and currently cannot be configured on a
# per-API basis.

#client_ssl_cert_key = # If `client_ssl` is enabled, the absolute path
# to the client SSL key for the
# `proxy_ssl_certificate_key` address. Note
# this value is statically defined on the node,
# and currently cannot be configured on a
# per-API basis.

#admin_ssl = on # Determines if Nginx should be listening for
# HTTPS traffic on the `admin_listen_ssl`
# address. If disabled, Nginx will only bind
Expand Down
25 changes: 25 additions & 0 deletions kong/conf_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ local PREFIX_PATHS = {
ssl_cert_key_default = {"ssl", "kong-default.key"},
ssl_cert_csr_default = {"ssl", "kong-default.csr"}
;
client_ssl_cert_default = {"ssl", "kong-default.crt"},
client_ssl_cert_key_default = {"ssl", "kong-default.key"},
client_ssl_cert_csr_default = {"ssl", "kong-default.csr"}
;
admin_ssl_cert_default = {"ssl", "admin-kong-default.crt"},
admin_ssl_cert_key_default = {"ssl", "admin-kong-default.key"},
admin_ssl_cert_csr_default = {"ssl", "admin-kong-default.csr"}
Expand Down Expand Up @@ -91,6 +95,7 @@ local CONF_INFERENCES = {
dns_resolver = {typ = "array"},

ssl = {typ = "boolean"},
client_ssl = {typ = "boolean"},
admin_ssl = {typ = "boolean"},

proxy_access_log = {typ = "string"},
Expand Down Expand Up @@ -217,6 +222,21 @@ local function check_and_infer(conf)
end
end

if conf.client_ssl then
if conf.client_ssl_cert and not conf.client_ssl_cert_key then
errors[#errors+1] = "client_ssl_cert_key must be specified"
elseif conf.client_ssl_cert_key and not conf.client_ssl_cert then
errors[#errors+1] = "client_ssl_cert must be specified"
end

if conf.client_ssl_cert and not pl_path.exists(conf.client_ssl_cert) then
errors[#errors+1] = "client_ssl_cert: no such file at "..conf.client_ssl_cert
end
if conf.client_ssl_cert_key and not pl_path.exists(conf.client_ssl_cert_key) then
errors[#errors+1] = "client_ssl_cert_key: no such file at "..conf.client_ssl_cert_key
end
end

if conf.admin_ssl then
if conf.admin_ssl_cert and not conf.admin_ssl_cert_key then
errors[#errors+1] = "admin_ssl_cert_key must be specified"
Expand Down Expand Up @@ -428,6 +448,11 @@ local function load(path, custom_conf)
conf.ssl_cert_key = pl_path.abspath(conf.ssl_cert_key)
end

if conf.client_ssl_cert and conf.client_ssl_cert_key then
conf.client_ssl_cert = pl_path.abspath(conf.client_ssl_cert)
conf.client_ssl_cert_key = pl_path.abspath(conf.client_ssl_cert_key)
end

if conf.admin_ssl_cert and conf.admin_ssl_cert_key then
conf.admin_ssl_cert = pl_path.abspath(conf.admin_ssl_cert)
conf.admin_ssl_cert_key = pl_path.abspath(conf.admin_ssl_cert_key)
Expand Down
3 changes: 3 additions & 0 deletions kong/templates/kong_defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ mem_cache_size = 128m
ssl = on
ssl_cert = NONE
ssl_cert_key = NONE
client_ssl = off
client_ssl_cert = NONE
client_ssl_cert_key = NONE
admin_ssl = on
admin_ssl_cert = NONE
admin_ssl_cert_key = NONE
Expand Down
5 changes: 5 additions & 0 deletions kong/templates/nginx_kong.lua
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ server {
}
> end
> if client_ssl then
proxy_ssl_certificate ${{CLIENT_SSL_CERT}};
proxy_ssl_certificate_key ${{CLIENT_SSL_CERT_KEY}};
> end
location / {
set $upstream_host nil;
set $upstream_scheme nil;
Expand Down
56 changes: 56 additions & 0 deletions spec/01-unit/02-conf_loader_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,62 @@ describe("Configuration loader", function()
assert.True(helpers.path.isabs(conf.ssl_cert_key))
end)
end)
describe("client", function()
it("requires both proxy SSL cert and key", function()
local conf, err = conf_loader(nil, {
client_ssl = true,
client_ssl_cert = "/path/cert.pem"
})
assert.equal("client_ssl_cert_key must be specified", err)
assert.is_nil(conf)

conf, err = conf_loader(nil, {
client_ssl = true,
client_ssl_cert_key = "/path/key.pem"
})
assert.equal("client_ssl_cert must be specified", err)
assert.is_nil(conf)

conf, err = conf_loader(nil, {
client_ssl = true,
client_ssl_cert = "spec/fixtures/kong_spec.crt",
client_ssl_cert_key = "spec/fixtures/kong_spec.key"
})
assert.is_nil(err)
assert.is_table(conf)
end)
it("requires SSL cert and key to exist", function()
local conf, _, errors = conf_loader(nil, {
client_ssl = true,
client_ssl_cert = "/path/cert.pem",
client_ssl_cert_key = "/path/cert_key.pem"
})
assert.equal(2, #errors)
assert.contains("client_ssl_cert: no such file at /path/cert.pem", errors)
assert.contains("client_ssl_cert_key: no such file at /path/cert_key.pem", errors)
assert.is_nil(conf)

conf, _, errors = conf_loader(nil, {
client_ssl = true,
client_ssl_cert = "spec/fixtures/kong_spec.crt",
client_ssl_cert_key = "/path/cert_key.pem"
})
assert.equal(1, #errors)
assert.contains("client_ssl_cert_key: no such file at /path/cert_key.pem", errors)
assert.is_nil(conf)
end)
it("resolves SSL cert/key to absolute path", function()
local conf, err = conf_loader(nil, {
client_ssl = true,
client_ssl_cert = "spec/fixtures/kong_spec.crt",
client_ssl_cert_key = "spec/fixtures/kong_spec.key"
})
assert.is_nil(err)
assert.is_table(conf)
assert.True(helpers.path.isabs(conf.client_ssl_cert))
assert.True(helpers.path.isabs(conf.client_ssl_cert_key))
end)
end)
describe("admin", function()
it("requires both admin SSL cert and key", function()
local conf, err = conf_loader(nil, {
Expand Down
20 changes: 20 additions & 0 deletions spec/01-unit/03-prefix_handler_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ describe("NGINX conf compiler", function()
assert.not_matches("ssl_protocols", kong_nginx_conf)
assert.not_matches("ssl_certificate_by_lua_block", kong_nginx_conf)
end)
describe("handles client_ssl", function()
it("on", function()
local conf = assert(conf_loader(helpers.test_conf_path, {
client_ssl = true,
client_ssl_cert = "spec/fixtures/kong_spec.crt",
client_ssl_cert_key = "spec/fixtures/kong_spec.key",
}))
local kong_nginx_conf = prefix_handler.compile_kong_conf(conf)
assert.matches("proxy_ssl_certificate.*spec/fixtures/kong_spec.crt", kong_nginx_conf)
assert.matches("proxy_ssl_certificate_key.*spec/fixtures/kong_spec.key", kong_nginx_conf)
end)
it("off", function()
local conf = assert(conf_loader(helpers.test_conf_path, {
client_ssl = false,
}))
local kong_nginx_conf = prefix_handler.compile_kong_conf(conf)
assert.not_matches("proxy_ssl_certificate.*spec/fixtures/kong_spec.crt", kong_nginx_conf)
assert.not_matches("proxy_ssl_certificate_key.*spec/fixtures/kong_spec.key", kong_nginx_conf)
end)
end)
it("does not include lua_ssl_trusted_certificate/lua_ssl_verify_depth by default", function()
local conf = assert(conf_loader(helpers.test_conf_path, {
lua_ssl_verify_depth = "2"
Expand Down

0 comments on commit fd86e20

Please sign in to comment.