From d176d906f6ceaf22fbcbba64c0fb94d7a415b07a Mon Sep 17 00:00:00 2001 From: themilchenko Date: Tue, 12 Nov 2024 18:41:35 +0300 Subject: [PATCH] roles: add tls support Since we support TLS in this module, we need to add it into roles too. After the patch TLS params was added. It can be configurated like the following: ```yaml server_name: listen: "localhost:3013" params: ssl_key_file: "path/to/key/file" ssl_cert_file: "path/to/key/file" ssl_ca_file: "path/to/key/file" ssl_ciphers: "cipher1:cipher2" ssl_password: "password" ssl_password_file: "path/to/ssl/password" ``` Closes #199 --- CHANGELOG.md | 1 + README.md | 17 +++++++++ roles/httpd.lua | 20 +++++++++- test/integration/httpd_role_test.lua | 56 ++++++++++++++++++++++------ test/mocks/mock_role.lua | 6 +++ 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e2e48..a59c94f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - SSL support (#35). +- SSL support into roles (#199). ### Changed diff --git a/README.md b/README.md index 8b7d3dd..e816423 100644 --- a/README.md +++ b/README.md @@ -581,6 +581,23 @@ end return M ``` +To enable TLS, provide the following params into roles config (for proper work +it's enough to provide only `ssl_key_file` and `ssl_cert_file`): + +```yaml +roles_cfg: + roles.httpd: + default: + listen: 8081 + params: + ssl_key_file: "path/to/key/file" + ssl_cert_file: "path/to/key/file" + ssl_ca_file: "path/to/key/file" + ssl_ciphers: "cipher1:cipher2" + ssl_password: "password" + ssl_password_file: "path/to/ssl/password" +``` + This role accepts a server by name from a config and creates a route to return `Hello, world!` to every request by this route. diff --git a/roles/httpd.lua b/roles/httpd.lua index 5e7f2f8..141075d 100644 --- a/roles/httpd.lua +++ b/roles/httpd.lua @@ -72,14 +72,32 @@ local function parse_listen(listen) return host, port, nil end +-- get_params returns table with set params from config to +-- pass it into new() func. +local function get_params(params) + if params ~= nil then + return { + ssl_cert_file = params.ssl_cert_file, + ssl_key_file = params.ssl_key_file, + ssl_password = params.ssl_password, + ssl_password_file = params.ssl_password_file, + ssl_ca_file = params.ssl_ca_file, + ssl_ciphers = params.ssl_ciphers, + } + end +end + local function apply_http(name, node) local host, port, err = parse_listen(node.listen) if err ~= nil then error("failed to parse URI: " .. err) end + local params = get_params(node.params) + if servers[name] == nil then - local httpd = http_server.new(host, port) + local httpd = http_server.new(host, port, params) + httpd:start() servers[name] = { httpd = httpd, diff --git a/test/integration/httpd_role_test.lua b/test/integration/httpd_role_test.lua index 7b99ff7..a2676df 100644 --- a/test/integration/httpd_role_test.lua +++ b/test/integration/httpd_role_test.lua @@ -3,10 +3,18 @@ local treegen = require('luatest.treegen') local server = require('luatest.server') local fun = require('fun') local yaml = require('yaml') +local fio = require('fio') +local http_client = require('http.client').new() + local helpers = require('test.helpers') -local g = t.group() +local g = t.group(nil, { + { use_tls = false }, + { use_tls = true }, +}) + +local ssl_data_dir = fio.abspath(fio.pathjoin(helpers.get_testdir_path(), "ssl_data")) local config = { credentials = { @@ -55,29 +63,55 @@ local config = { }, } -g.before_each(function() +local tls_config = table.deepcopy(config) +tls_config.groups['group-001'].replicasets['replicaset-001'].roles_cfg['roles.httpd'].default.params = { + ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'), + ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.enc.key'), + ssl_password_file = fio.pathjoin(ssl_data_dir, 'passwords'), +} + +g.before_each(function(cg) helpers.skip_if_not_tarantool3() local dir = treegen.prepare_directory({}, {}) + local cfg = config + if cg.params.use_tls then + cfg = tls_config + end + local config_file = treegen.write_file(dir, 'config.yaml', - yaml.encode(config)) + yaml.encode(cfg)) local opts = {config_file = config_file, chdir = dir} - g.server = server:new(fun.chain(opts, {alias = 'instance-001'}):tomap()) - helpers.update_lua_env_variables(g.server) + cg.server = server:new(fun.chain(opts, {alias = 'instance-001'}):tomap()) + helpers.update_lua_env_variables(cg.server) - g.server:start() + cg.server:start() end) -g.after_each(function() - g.server:stop() +g.after_each(function(cg) + helpers.teardown(cg.server) end) -g.test_httpd_role_usage = function() - t.assert_equals(g.server:eval( +g.test_httpd_role_usage = function(cg) + if cg.params.use_tls then + local resp = http_client:get('https://localhost:13000/ping', { + ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt') + }) + t.assert_equals(resp.status, 200, 'response not 200') + t.assert_equals(resp.body, 'pong') + end + + -- We can use https only for one endpoind due to we haven't publish separate + -- certificates for it. + local resp = http_client:get('http://localhost:13001/ping') + t.assert_equals(resp.status, 200, 'response not 200') + t.assert_equals(resp.body, 'pong') + + t.assert_equals(cg.server:eval( 'return require("test.mocks.mock_role").get_server_port(1)' ), 13000) - t.assert_equals(g.server:eval( + t.assert_equals(cg.server:eval( 'return require("test.mocks.mock_role").get_server_port(2)' ), 13001) end diff --git a/test/mocks/mock_role.lua b/test/mocks/mock_role.lua index 01118c8..8753c21 100644 --- a/test/mocks/mock_role.lua +++ b/test/mocks/mock_role.lua @@ -7,6 +7,12 @@ M.validate = function() end M.apply = function(conf) for _, server in pairs(conf) do servers[server.id] = require('roles.httpd').get_server(server.name) + + servers[server.id]:route({ + path = '/ping', + }, function(tx) + return tx:render({text = 'pong'}) + end) end end