From 712b224d999405d4d995e406415661b1b87e4852 Mon Sep 17 00:00:00 2001 From: thefosk Date: Fri, 7 Aug 2015 15:26:53 -0700 Subject: [PATCH 1/2] Closes #453 and #235 --- Makefile | 3 -- kong-0.4.1-1.rockspec | 1 + kong/cli/utils/signal.lua | 7 ++- kong/cli/utils/ssl.lua | 55 ++++++++++++++++++++ kong/cli/utils/utils.lua | 26 --------- kong/tools/io.lua | 8 +-- spec/integration/cli/restart_spec.lua | 3 -- spec/integration/proxy/api_resolver_spec.lua | 2 +- spec/plugins/ssl/access_spec.lua | 22 ++++---- spec/unit/tools/io_spec.lua | 2 +- ssl/README.md | 3 ++ ssl/kong-default.crt | 15 ------ ssl/kong-default.key | 15 ------ 13 files changed, 84 insertions(+), 78 deletions(-) create mode 100644 kong/cli/utils/ssl.lua create mode 100644 ssl/README.md delete mode 100644 ssl/kong-default.crt delete mode 100644 ssl/kong-default.key diff --git a/Makefile b/Makefile index ca4e55477393..138cddc17966 100644 --- a/Makefile +++ b/Makefile @@ -59,9 +59,6 @@ test-integration: test-plugins: @busted -v spec/plugins -test-all: - @busted -v spec/ - coverage: @rm -f luacov.* @busted --coverage spec/ diff --git a/kong-0.4.1-1.rockspec b/kong-0.4.1-1.rockspec index 640109571cae..3b98553d7c4a 100644 --- a/kong-0.4.1-1.rockspec +++ b/kong-0.4.1-1.rockspec @@ -45,6 +45,7 @@ build = { ["kong.cli.utils"] = "kong/cli/utils/utils.lua", ["kong.cli.utils.dnsmasq"] = "kong/cli/utils/dnsmasq.lua", + ["kong.cli.utils.ssl"] = "kong/cli/utils/ssl.lua", ["kong.cli.utils.signal"] = "kong/cli/utils/signal.lua", ["kong.cli.utils.input"] = "kong/cli/utils/input.lua", ["kong.cli.db"] = "kong/cli/db.lua", diff --git a/kong/cli/utils/signal.lua b/kong/cli/utils/signal.lua index a2f030bad9f4..830968af9c51 100644 --- a/kong/cli/utils/signal.lua +++ b/kong/cli/utils/signal.lua @@ -4,6 +4,7 @@ local IO = require "kong.tools.io" local cutils = require "kong.cli.utils" +local ssl = require "kong.cli.utils.ssl" local constants = require "kong.constants" local syslog = require "kong.tools.syslog" local socket = require "socket" @@ -101,7 +102,7 @@ local function prepare_nginx_working_dir(args_config) cutils.logger:warn("Setting \"memory_cache_size\" to default 128MB") end - local ssl_cert_path, ssl_key_path = cutils.get_ssl_cert_and_key(kong_config) + local ssl_cert_path, ssl_key_path = ssl.get_ssl_cert_and_key(kong_config) local trusted_ssl_cert_path = kong_config.databases_available[kong_config.database].properties.ssl_certificate -- DAO ssl cert -- Extract nginx config from kong config, replace any needed value @@ -222,6 +223,7 @@ function _M.prepare_kong(args_config, signal) cutils.logger:info("Connecting to the database...") prepare_database(args_config) + ssl.prepare_ssl() prepare_nginx_working_dir(args_config, signal) end @@ -316,7 +318,8 @@ function _M.is_running(args_config) if IO.file_exists(kong_config.pid_file) then local pid = IO.read_file(kong_config.pid_file) - if os.execute("kill -0 "..pid) == 0 then + local _, code = IO.os_execute("kill -0 "..pid) + if code == 0 then return true else cutils.logger:warn("It seems like Kong crashed the last time it was started!") diff --git a/kong/cli/utils/ssl.lua b/kong/cli/utils/ssl.lua new file mode 100644 index 000000000000..b36c1234fe29 --- /dev/null +++ b/kong/cli/utils/ssl.lua @@ -0,0 +1,55 @@ +local cutils = require "kong.cli.utils" +local utils = require "kong.tools.utils" +local IO = require "kong.tools.io" + +local _M = {} + +function _M.get_ssl_cert_and_key(kong_config) + local ssl_cert_path, ssl_key_path + + if (kong_config.ssl_cert_path and not kong_config.ssl_key_path) or + (kong_config.ssl_key_path and not kong_config.ssl_cert_path) then + cutils.logger:error_exit("Both \"ssl_cert_path\" and \"ssl_key_path\" need to be specified in the configuration, or none of them") + elseif kong_config.ssl_cert_path and kong_config.ssl_key_path then + ssl_cert_path = kong_config.ssl_cert_path + ssl_key_path = kong_config.ssl_key_path + else + ssl_cert_path = IO.path:join(cutils.get_luarocks_install_dir(), "ssl", "kong-default.crt") + ssl_key_path = IO.path:join(cutils.get_luarocks_install_dir(), "ssl", "kong-default.key") + end + + -- Check that the file exists + if ssl_cert_path and not IO.file_exists(ssl_cert_path) then + cutils.logger:error_exit("Can't find default Kong SSL certificate at: "..ssl_cert_path) + end + if ssl_key_path and not IO.file_exists(ssl_key_path) then + cutils.logger:error_exit("Can't find default Kong SSL key at: "..ssl_key_path) + end + + return ssl_cert_path, ssl_key_path +end + +function _M.prepare_ssl() + local ssl_cert_path = IO.path:join(cutils.get_luarocks_install_dir(), "ssl", "kong-default.crt") + local ssl_key_path = IO.path:join(cutils.get_luarocks_install_dir(), "ssl", "kong-default.key") + + if not (IO.file_exists(ssl_cert_path) and IO.file_exists(ssl_key_path)) then + -- Autogenerating the certificates for the first time + cutils.logger:info("Auto-generating the default SSL certificate and key...") + + local file_name = os.tmpname() + local passphrase = utils.random_string() + + local res, code = IO.os_execute([[ + cd /tmp && \ + openssl genrsa -des3 -out ]]..file_name..[[.key -passout pass:]]..passphrase..[[ 1024 && \ + openssl req -new -key ]]..file_name..[[.key -out ]]..file_name..[[.csr -subj "/C=US/ST=California/L=San Francisco/O=Kong/OU=IT Department/CN=localhost" -passin pass:]]..passphrase..[[ && \ + cp ]]..file_name..[[.key ]]..file_name..[[.key.org && \ + openssl rsa -in ]]..file_name..[[.key.org -out ]]..file_name..[[.key -passin pass:]]..passphrase..[[ && \ + openssl x509 -req -in ]]..file_name..[[.csr -signkey ]]..file_name..[[.key -out ]]..file_name..[[.crt && \ + sudo mv ]]..file_name..[[.crt ]]..ssl_cert_path..[[ && \ + sudo mv ]]..file_name..[[.key ]]..ssl_key_path) + end +end + +return _M \ No newline at end of file diff --git a/kong/cli/utils/utils.lua b/kong/cli/utils/utils.lua index 901a8ab38f7e..0dd1e7abf391 100644 --- a/kong/cli/utils/utils.lua +++ b/kong/cli/utils/utils.lua @@ -119,31 +119,6 @@ local function get_kong_config_path(args_config) return config_path end -local function get_ssl_cert_and_key(kong_config) - local ssl_cert_path, ssl_key_path - - if (kong_config.ssl_cert_path and not kong_config.ssl_key_path) or - (kong_config.ssl_key_path and not kong_config.ssl_cert_path) then - logger:error_exit("Both \"ssl_cert_path\" and \"ssl_key_path\" need to be specified in the configuration, or none of them") - elseif kong_config.ssl_cert_path and kong_config.ssl_key_path then - ssl_cert_path = kong_config.ssl_cert_path - ssl_key_path = kong_config.ssl_key_path - else - ssl_cert_path = IO.path:join(get_luarocks_install_dir(), "ssl", "kong-default.crt") - ssl_key_path = IO.path:join(get_luarocks_install_dir(), "ssl", "kong-default.key") - end - - -- Check that the file exists - if ssl_cert_path and not IO.file_exists(ssl_cert_path) then - logger:error_exit("Can't find default Kong SSL certificate at: "..ssl_cert_path) - end - if ssl_key_path and not IO.file_exists(ssl_key_path) then - logger:error_exit("Can't find default Kong SSL key at: "..ssl_key_path) - end - - return ssl_cert_path, ssl_key_path -end - -- Checks if a port is open on localhost -- @param `port` The port to check -- @return `open` True if open, false otherwise @@ -157,7 +132,6 @@ return { logger = logger, get_kong_infos = get_kong_infos, get_kong_config_path = get_kong_config_path, - get_ssl_cert_and_key = get_ssl_cert_and_key, get_luarocks_install_dir = get_luarocks_install_dir, is_port_open = is_port_open } diff --git a/kong/tools/io.lua b/kong/tools/io.lua index fe834e320ab8..93ccb1b9bf94 100644 --- a/kong/tools/io.lua +++ b/kong/tools/io.lua @@ -19,11 +19,13 @@ end function _M.os_execute(command) local n = os.tmpname() -- get a temporary file name to store output - local exit_code = os.execute("/bin/bash -c '"..command.." > "..n.." 2>&1'") + local f = os.tmpname() -- get a temporary file name to store script + _M.write_to_file(f, command) + local exit_code = os.execute("/bin/bash "..f.." > "..n.." 2>&1") local result = _M.read_file(n) os.remove(n) - - return string.gsub(result, "[%\r%\n]", ""), exit_code / 256 + os.remove(f) + return string.gsub(string.gsub(result, "^"..f..":[%s%w]+:%s*", ""), "[%\r%\n]", ""), exit_code / 256 end function _M.cmd_exists(cmd) diff --git a/spec/integration/cli/restart_spec.lua b/spec/integration/cli/restart_spec.lua index ae580ce7a2f5..7af8e62ed72d 100644 --- a/spec/integration/cli/restart_spec.lua +++ b/spec/integration/cli/restart_spec.lua @@ -28,9 +28,6 @@ describe("CLI", function() it("should restart kong when it's crashed", function() local kong_pid = IO.read_file(spec_helper.get_env().configuration.pid_file) os.execute("pkill -9 nginx") - while os.execute("kill -0 "..kong_pid.." ") == 0 do - -- Wait till it's really over - end local res, code = spec_helper.restart_kong() assert.are.same(0, code) diff --git a/spec/integration/proxy/api_resolver_spec.lua b/spec/integration/proxy/api_resolver_spec.lua index 52c28b64e310..0ea2a3f9ec7c 100644 --- a/spec/integration/proxy/api_resolver_spec.lua +++ b/spec/integration/proxy/api_resolver_spec.lua @@ -94,7 +94,7 @@ describe("Resolver", function() assert.same(6, utils.table_size(cert)) assert.same("Kong", cert.organizationName) - assert.same("IT", cert.organizationalUnitName) + assert.same("IT Department", cert.organizationalUnitName) assert.same("US", cert.countryName) assert.same("California", cert.stateOrProvinceName) assert.same("San Francisco", cert.localityName) diff --git a/spec/plugins/ssl/access_spec.lua b/spec/plugins/ssl/access_spec.lua index cda24bc31b2c..498c7cc1471e 100644 --- a/spec/plugins/ssl/access_spec.lua +++ b/spec/plugins/ssl/access_spec.lua @@ -5,6 +5,7 @@ local IO = require "kong.tools.io" local http_client = require "kong.tools.http_client" local cjson = require "cjson" local ssl_fixtures = require "spec.plugins.ssl.fixtures" +local cutils = require "kong.cli.utils" local STUB_GET_SSL_URL = spec_helper.STUB_GET_SSL_URL local STUB_GET_URL = spec_helper.STUB_GET_URL @@ -21,7 +22,7 @@ describe("SSL Plugin", function() { name = "API TESTS 13 (ssl)", public_dns = "ssl3.com", target_url = "http://mockbin.com" } }, plugin_configuration = { - { name = "ssl", value = { cert = ssl_fixtures.cert, key = ssl_fixtures.key }, __api = 1 }, + { name = "ssl", value = { cert = ssl_fixtures.cert, key = ssl_fixtures.key }, __api = 1 }, { name = "ssl", value = { cert = ssl_fixtures.cert, key = ssl_fixtures.key, only_https = true }, __api = 2 } } } @@ -32,7 +33,7 @@ describe("SSL Plugin", function() teardown(function() spec_helper.stop_kong() end) - + describe("SSL Util", function() it("should not convert an invalid cert to DER", function() @@ -52,14 +53,14 @@ describe("SSL Plugin", function() end) end) - + describe("SSL Resolution", function() it("should return default CERTIFICATE when requesting other APIs", function() local parsed_url = url.parse(STUB_GET_SSL_URL) local res = IO.os_execute("(echo \"GET /\"; sleep 2) | openssl s_client -connect "..parsed_url.host..":"..tostring(parsed_url.port).." -servername test4.com") - assert.truthy(res:match("US/ST=California/L=San Francisco/O=Kong/OU=IT/CN=localhost")) + assert.truthy(res:match("US/ST=California/L=San Francisco/O=Kong/OU=IT Department/CN=localhost")) end) it("should work when requesting a specific API", function() @@ -70,7 +71,7 @@ describe("SSL Plugin", function() end) end) - + describe("only_https", function() it("should block request without https", function() @@ -91,9 +92,12 @@ describe("SSL Plugin", function() describe("should work with curl", function() local response = http_client.get(API_URL.."/apis/", {public_dns="ssl3.com"}) local api_id = cjson.decode(response).data[1].id - local current_path = IO.os_execute("pwd") - local res = IO.os_execute("curl -s -o /dev/null -w \"%{http_code}\" "..API_URL.."/apis/"..api_id.."/plugins/ --form \"name=ssl\" --form \"value.cert=@"..current_path.."/ssl/kong-default.crt\" --form \"value.key=@"..current_path.."/ssl/kong-default.key\"") - assert.are.equal("201", res) - end) + + local ssl_cert_path = IO.path:join(cutils.get_luarocks_install_dir(), "ssl", "kong-default.crt") + local ssl_key_path = IO.path:join(cutils.get_luarocks_install_dir(), "ssl", "kong-default.key") + local res = IO.os_execute("curl -s -o /dev/null -w \"%{http_code}\" "..API_URL.."/apis/"..api_id.."/plugins/ --form \"name=ssl\" --form \"value.cert=@"..ssl_cert_path.."\" --form \"value.key=@"..ssl_key_path.."\"") + assert.are.equal(201, tonumber(res)) + end) + end) diff --git a/spec/unit/tools/io_spec.lua b/spec/unit/tools/io_spec.lua index 2e302472bf0c..0f9e63829c51 100644 --- a/spec/unit/tools/io_spec.lua +++ b/spec/unit/tools/io_spec.lua @@ -31,7 +31,7 @@ describe("IO", function() local res, code = IO.os_execute("LC_ALL=\"C\";asdasda \"Hello\"") assert.are.same(127, code) - assert.are.same("/bin/bash: asdasda: command not found", res) + assert.are.same("asdasda: command not found", res) end) end) diff --git a/ssl/README.md b/ssl/README.md new file mode 100644 index 000000000000..66d561f74e5c --- /dev/null +++ b/ssl/README.md @@ -0,0 +1,3 @@ +# SSL + +This is the directory where Kong will place the auto-generated default SSL certificate and key. \ No newline at end of file diff --git a/ssl/kong-default.crt b/ssl/kong-default.crt deleted file mode 100644 index 12c01ef5903b..000000000000 --- a/ssl/kong-default.crt +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICSzCCAbQCCQCvBb0jlk/KPDANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEN -MAsGA1UECgwES29uZzELMAkGA1UECwwCSVQxEjAQBgNVBAMMCWxvY2FsaG9zdDAe -Fw0xNTA1MTkwMDE5NDNaFw0xNTA2MTgwMDE5NDNaMGoxCzAJBgNVBAYTAlVTMRMw -EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYD -VQQKDARLb25nMQswCQYDVQQLDAJJVDESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0G -CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJxSbIDDaGV/5g392+v8vG4lXE/0mKNPjO -um9XJ9WPtDvQUAYUn3x/hZuvn+d0Kg8BunWlq6KG4i4cxd+v+OyHnHf9rigpbHYt -dIcd8R110XIRUNDqKRA/JvYgpkvg2/0qsUcv69mQAs7vnxcMlr0Muq0mUFo7G8uP -tskyr9tUDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACIc3kTgS8Sdw7DjeVFw7d7S -K1i66VGRNLpzhr7VZXSkMjTj2wBt+2S97XmFWCkirsFnDAoKPIII3vLB+A82qX0O -/1d1Rlm7TvZa+kWYNS3PXNFYuyByY24e+oRL+EvMeub5MNdSNzwfrf//L3EildKj -x1n6dO9OiNsxLQUS6Ezs ------END CERTIFICATE----- diff --git a/ssl/kong-default.key b/ssl/kong-default.key deleted file mode 100644 index f1585f8805cc..000000000000 --- a/ssl/kong-default.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDJxSbIDDaGV/5g392+v8vG4lXE/0mKNPjOum9XJ9WPtDvQUAYU -n3x/hZuvn+d0Kg8BunWlq6KG4i4cxd+v+OyHnHf9rigpbHYtdIcd8R110XIRUNDq -KRA/JvYgpkvg2/0qsUcv69mQAs7vnxcMlr0Muq0mUFo7G8uPtskyr9tUDwIDAQAB -AoGABLkGpVwT0qUwoRfcWuCmZmtZ0pifIgsHX99hR8r45rozRDb7TXRGN73q3PuD -MWbinwm8Qzp3PW0B406GY9oRvzg3gohMX1Fz4YV+NzC2fnmjZpsy7MauRxyswiS6 -pN/dENILClrz5sMnC7Mv9x0aMDU/jKwOgDa4o/wOVNBpy4ECQQDp67n3SwafeRm/ -eWnnRmsmmWZ9lLaXwDcK9OCURyxJ/nCTjOx7XIcWiLOMqCRlqEg64JdWBSft5tZg -TM7sn6XvAkEA3NCP2Gxi6dOG9i6h3CqegSVkoj/ghnTH3fIYGpCeymlrKW7D8PI8 -Jbbn7HCGjaa9QBcAhlGxLmsdWhrIxSJT4QJBAIM+MM6gl4yuA1Y8psCN79xuQOTA -pVmrDLbnAYHwFNdHHJ6MeLoWBe0MscB/LjyjGDOAgyhOKEMAOtM5BPgZ8p0CQQDQ -wYQccWuZ79aaC0AOq2QqaDWZhpY3x1PlKilLhAn7Bmq/Qu6PbhMa/K6KQ1+Rr18f -ph9i3PyLC802EDha1rdBAkEA3Tsty9r2FHTaN/B4XDf5BjHcsrhR9IfTqSn5jOqB -d2GVIsnAcBtzkYKEp+PN/2ia3/NWC15M1pz8nnsPZhVwIQ== ------END RSA PRIVATE KEY----- From 2bdc7800273e6cc21af28fc7638f9248fcbbde19 Mon Sep 17 00:00:00 2001 From: thefosk Date: Fri, 7 Aug 2015 18:07:15 -0700 Subject: [PATCH 2/2] Support for chunked responses --- kong/cli/utils/ssl.lua | 2 +- kong/tools/http_client.lua | 12 ++++++++++-- spec/integration/cli/restart_spec.lua | 2 -- spec/integration/proxy/dns_resolver_spec.lua | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/kong/cli/utils/ssl.lua b/kong/cli/utils/ssl.lua index b36c1234fe29..90f69129539b 100644 --- a/kong/cli/utils/ssl.lua +++ b/kong/cli/utils/ssl.lua @@ -40,7 +40,7 @@ function _M.prepare_ssl() local file_name = os.tmpname() local passphrase = utils.random_string() - local res, code = IO.os_execute([[ + IO.os_execute([[ cd /tmp && \ openssl genrsa -des3 -out ]]..file_name..[[.key -passout pass:]]..passphrase..[[ 1024 && \ openssl req -new -key ]]..file_name..[[.key -out ]]..file_name..[[.csr -subj "/C=US/ST=California/L=San Francisco/O=Kong/OU=IT Department/CN=localhost" -passin pass:]]..passphrase..[[ && \ diff --git a/kong/tools/http_client.lua b/kong/tools/http_client.lua index 936279e0d631..14a25957ae1d 100644 --- a/kong/tools/http_client.lua +++ b/kong/tools/http_client.lua @@ -6,6 +6,14 @@ local ltn12 = require "ltn12" local _M = {} +local function get_response(resp) + if #resp == 0 then + return nil + else + return table.concat(resp, "") + end +end + local function http_call(options) -- Set Host header accordingly local parsed_url = url.parse(options.url) @@ -28,10 +36,10 @@ local function http_call(options) options.options = "all" local _, code, headers = https.request(options) - return resp[1], code, headers + return get_response(resp), code, headers else local _, code, headers = http.request(options) - return resp[1], code, headers + return get_response(resp), code, headers end end diff --git a/spec/integration/cli/restart_spec.lua b/spec/integration/cli/restart_spec.lua index 7af8e62ed72d..9e09e8463463 100644 --- a/spec/integration/cli/restart_spec.lua +++ b/spec/integration/cli/restart_spec.lua @@ -1,4 +1,3 @@ -local IO = require "kong.tools.io" local spec_helper = require "spec.spec_helpers" describe("CLI", function() @@ -26,7 +25,6 @@ describe("CLI", function() end) it("should restart kong when it's crashed", function() - local kong_pid = IO.read_file(spec_helper.get_env().configuration.pid_file) os.execute("pkill -9 nginx") local res, code = spec_helper.restart_kong() diff --git a/spec/integration/proxy/dns_resolver_spec.lua b/spec/integration/proxy/dns_resolver_spec.lua index 9656da1aac7a..12e3c7b11a76 100644 --- a/spec/integration/proxy/dns_resolver_spec.lua +++ b/spec/integration/proxy/dns_resolver_spec.lua @@ -24,7 +24,7 @@ describe("DNS", function() describe("DNS", function() it("should work when calling local IP", function() - local thread = spec_helper.start_tcp_server(TCP_PORT) -- Starting the mock TCP server + local thread = spec_helper.start_http_server(TCP_PORT) -- Starting the mock TCP server local _, status = http_client.get(spec_helper.STUB_GET_URL, nil, { host = "dns1.com" }) assert.are.equal(200, status) @@ -33,7 +33,7 @@ describe("DNS", function() end) it("should work when calling local hostname", function() - local thread = spec_helper.start_tcp_server(TCP_PORT) -- Starting the mock TCP server + local thread = spec_helper.start_http_server(TCP_PORT) -- Starting the mock TCP server local _, status = http_client.get(spec_helper.STUB_GET_URL, nil, { host = "dns2.com" }) assert.are.equal(200, status)