option(WITH_RADOSGW_BEAST_OPENSSL "Rados Gateway's Beast frontend uses OpenSSL" ON)
option(WITH_RADOSGW_AMQP_ENDPOINT "Rados Gateway's pubsub support for AMQP push endpoint" ON)
option(WITH_RADOSGW_KAFKA_ENDPOINT "Rados Gateway's pubsub support for Kafka push endpoint" ON)
+option(WITH_RADOSGW_LUA_PACKAGES "Rados Gateway's support for dynamically adding lua packagess" ON)
if(WITH_RADOSGW)
find_package(EXPAT REQUIRED)
list(APPEND BOOST_COMPONENTS filesystem timer)
endif()
+if(WITH_RADOSGW AND WITH_RADOSGW_LUA_PACKAGES)
+ list(APPEND BOOST_COMPONENTS filesystem)
+endif()
+
set(Boost_USE_MULTITHREADED ON)
# require minimally the bundled version
if(WITH_SYSTEM_BOOST)
%endif
%endif
+%if 0%{?suse_version}
+%if !0%{?is_opensuse}
+# SLE does not support luarocks
+%bcond_with lua_packages
+%else
+%global luarocks_package_name lua53-luarocks
+%bcond_without lua_packages
+%endif
+%else
+%global luarocks_package_name luarocks
+%bcond_without lua_packages
+%endif
+
%{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d}
%{!?tmpfiles_create: %global tmpfiles_create systemd-tmpfiles --create}
%{!?python3_pkgversion: %global python3_pkgversion 3}
%if 0%{with kafka_endpoint}
BuildRequires: librdkafka-devel
%endif
+%if 0%{with lua_packages}
+BuildRequires: %{luarocks_package_name}
+%endif
%if 0%{with make_check}
BuildRequires: jq
BuildRequires: libuuid-devel
%else
-DWITH_RADOSGW_KAFKA_ENDPOINT=OFF \
%endif
+%if 0%{without lua_packages}
+ -DWITH_RADOSGW_LUA_PACKAGES=OFF
+%endif
%if 0%{with zbd}
-DWITH_ZBD=ON \
%endif
# Crimson libyaml-cpp-dev,
librabbitmq-dev,
librdkafka-dev,
+ luarocks,
# Make-Check libxmlsec1,
# Make-Check libxmlsec1-nss,
# Make-Check libxmlsec1-openssl,
operation was taken, and "postRequest" that will execute after each operation is taken. Script may be uploaded to address requests for users of a specific tenant.
The script can access fields in the request and modify some fields. All Lua language features can be used in the script.
+By default, all lua standard libraries are available in the script, however, in order to allow for other lua modules to be used in the script, we support adding packages to an allowlist:
+
+ - All packages in the allowlist are being re-installed using the luarocks package manager on radosgw restart. Therefore a restart is needed for adding or removing of packages to take effect
+ - To add a package that contains C source code that needs to be compiled, use the `--allow-compilation` flag. In this case a C compiler needs to be available on the host
+ - Lua packages are installed in, and used from, a directory local to the radosgw. Meaning that lua packages in the allowlist are separated from any lua packages available on the host.
+ By default, this directory would be `/tmp/luarocks/`, and could be set to a different location via the `rgw_luarocks_location` configuration parameter.
+ Note that this parameter should not be set to one of the default locations where luarocks install packages (e.g. `$HOME/.luarocks`, `/usr/lib64/lua`, `/usr/share/lua`)
+
+
.. toctree::
:maxdepth: 1
# radosgw-admin script rm --context={preRequest|postRequest} [--tenant={tenant-name}]
+Package Management via CLI
+--------------------------
+
+To add a package to the allowlist:
+
+::
+
+ # radosgw-admin script-package add --package={package name} [--allow-compilation]
+
+
+To remove a package from the allowlist:
+
+::
+
+ # radosgw-admin script-package rm --package={package name}
+
+
+To print the list of packages in the allowlist:
+
+::
+
+ # radosgw-admin script-package list
+
+
Context Free Functions
----------------------
Debug Log
RGWDebugLog("key=" .. k .. ", " .. "value=" .. v)
end
+- Use modules to create Unix socket based, JSON encoded, "access log":
+
+First we should add the following packages to the allowlist:
+
+::
+
+ # radosgw-admin script-package add --package=luajson
+ # radosgw-admin script-package add --package=luasocket --allow-compilation
+
+
+Then, do a restart for the radosgw and upload the following script to the `postRequest` context:
+
+.. code-block:: lua
+
+ if Request.RGWOp == "get_obj" then
+ local json = require("json")
+ local socket = require("socket")
+ local unix = require("socket.unix")
+ local s = assert(unix())
+ E = {}
+
+ msg = {bucket = (Request.Bucket or (Request.CopyFrom or E).Bucket).Name,
+ time = Request.Time,
+ operation = Request.RGWOp,
+ http_status = Request.Response.HTTPStatusCode,
+ error_code = Request.Response.HTTPStatus,
+ object_size = Request.Object.Size,
+ trans_id = Request.TransactionId}
+
+ assert(s:connect("/tmp/socket"))
+ assert(s:send(json.encode(msg).."\n"))
+ assert(s:close())
+ end
+
"but will default to FIFO if there isn't an existing log. Either of "
"the explicit options will cause startup to fail if the other log is "
"still around."),
+
+ Option("rgw_luarocks_location", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+ .set_flag(Option::FLAG_STARTUP)
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+ .set_default("/tmp/luarocks")
+#else
+ // if set to empty string, system default luarocks package location (if exist) will be used
+ .set_default("")
+#endif
+ .set_description("Directory where luarocks install packages from allowlist"),
});
}
/* Defined if libedkafka is available for rgw kafka push endpoint */
#cmakedefine WITH_RADOSGW_KAFKA_ENDPOINT
+/* Defined if lua packages can be installed by radosgw */
+#cmakedefine WITH_RADOSGW_LUA_PACKAGES
+
/* Defined if std::map::merge() is supported */
#cmakedefine HAVE_STDLIB_MAP_SPLICING
list(APPEND rgw_libs ${LUA_LIBRARIES})
+if(WITH_RADOSGW_LUA_PACKAGES)
+ list(APPEND rgw_libs Boost::filesystem)
+endif()
+
set(rgw_schedulers_srcs
rgw_dmclock_scheduler_ctx.cc
rgw_dmclock_sync_scheduler.cc)
cout << " script put upload a lua script to a context\n";
cout << " script get get the lua script of a context\n";
cout << " script rm remove the lua scripts of a context\n";
+ cout << " script-package add add a lua package to the scripts allowlist\n";
+ cout << " script-package rm remove a lua package from the scripts allowlist\n";
+ cout << " script-package list get the lua packages allowlist\n";
cout << "options:\n";
cout << " --tenant=<tenant> tenant name\n";
cout << " --user_ns=<namespace> namespace of user (oidc in case of users authenticated with oidc provider)\n";
cout << " --event-id event id in a pubsub subscription\n";
cout << "\nScript options:\n";
cout << " --context context in which the script runs. one of: preRequest, postRequest\n";
+ cout << " --package name of the lua package that should be added/removed to/from the allowlist\n";
+ cout << " --allow-compilation package is allowed to compile C code as part of its installation\n";
cout << "\n";
generic_client_usage();
}
SCRIPT_PUT,
SCRIPT_GET,
SCRIPT_RM,
+ SCRIPT_PACKAGE_ADD,
+ SCRIPT_PACKAGE_RM,
+ SCRIPT_PACKAGE_LIST
};
}
{ "script put", OPT::SCRIPT_PUT },
{ "script get", OPT::SCRIPT_GET },
{ "script rm", OPT::SCRIPT_RM },
+ { "script-package add", OPT::SCRIPT_PACKAGE_ADD },
+ { "script-package rm", OPT::SCRIPT_PACKAGE_RM },
+ { "script-package list", OPT::SCRIPT_PACKAGE_LIST },
};
static SimpleCmd::Aliases cmd_aliases = {
string event_id;
std::optional<std::string> str_script_ctx;
+ std::optional<std::string> script_package;
+ int allow_compilation = false;
std::optional<string> opt_group_id;
std::optional<string> opt_status;
// do nothing
} else if (ceph_argparse_witharg(args, i, &val, "--context", (char*)NULL)) {
str_script_ctx = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--package", (char*)NULL)) {
+ script_package = val;
+ } else if (ceph_argparse_binary_flag(args, i, &allow_compilation, NULL, "--allow-compilation", (char*)NULL)) {
+ // do nothing
} else if (strncmp(*i, "-", 1) == 0) {
cerr << "ERROR: invalid flag " << *i << std::endl;
return EINVAL;
auto rc = read_input(infile, bl);
if (rc < 0) {
cerr << "ERROR: failed to read script: '" << infile << "'. error: " << rc << std::endl;
- return rc;
+ return -rc;
}
const std::string script = bl.to_str();
std::string err_msg;
rc = rgw::lua::write_script(store, tenant, null_yield, script_ctx, script);
if (rc < 0) {
cerr << "ERROR: failed to put script. error: " << rc << std::endl;
- return rc;
+ return -rc;
}
}
(tenant.empty() ? "" : (" in tenant: " + tenant)) << std::endl;
} else if (rc < 0) {
cerr << "ERROR: failed to read script. error: " << rc << std::endl;
- return rc;
+ return -rc;
} else {
std::cout << script << std::endl;
}
const auto rc = rgw::lua::delete_script(store, tenant, null_yield, script_ctx);
if (rc < 0) {
cerr << "ERROR: failed to remove script. error: " << rc << std::endl;
+ return -rc;
+ }
+ }
+
+ if (opt_cmd == OPT::SCRIPT_PACKAGE_ADD) {
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+ if (!script_package) {
+ cerr << "ERROR: lua package name was not provided (via --package)" << std::endl;
+ return EINVAL;
+ }
+ const auto rc = rgw::lua::add_package(store, null_yield, *script_package, bool(allow_compilation));
+ if (rc < 0) {
+ cerr << "ERROR: failed to add lua package: " << script_package << " .error: " << rc << std::endl;
+ return -rc;
+ }
+#else
+ cerr << "ERROR: adding lua packages in not permitted" << std::endl;
+ return EPERM;
+#endif
+ }
+
+ if (opt_cmd == OPT::SCRIPT_PACKAGE_RM) {
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+ if (!script_package) {
+ cerr << "ERROR: lua package name was not provided (via --package)" << std::endl;
+ return EINVAL;
+ }
+ const auto rc = rgw::lua::remove_package(store, null_yield, *script_package);
+ if (rc == -ENOENT) {
+ cerr << "WARNING: package " << script_package << " did not exists or already removed" << std::endl;
+ return 0;
+ }
+ if (rc < 0) {
+ cerr << "ERROR: failed to remove lua package: " << script_package << " .error: " << rc << std::endl;
+ return -rc;
+ }
+#else
+ cerr << "ERROR: removing lua packages in not permitted" << std::endl;
+ return EPERM;
+#endif
+ }
+
+ if (opt_cmd == OPT::SCRIPT_PACKAGE_LIST) {
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+ rgw::lua::packages_t packages;
+ const auto rc = rgw::lua::list_packages(store, null_yield, packages);
+ if (rc == -ENOENT) {
+ std::cout << "no lua packages in allowlist" << std::endl;
+ } else if (rc < 0) {
+ cerr << "ERROR: failed to read lua packages allowlist. error: " << rc << std::endl;
return rc;
+ } else {
+ for (const auto& package : packages) {
+ std::cout << package << std::endl;
+ }
}
+#else
+ cerr << "ERROR: listing lua packages in not permitted" << std::endl;
+ return EPERM;
+#endif
}
return 0;
#include "rgw_lua_utils.h"
#include "rgw_sal_rados.h"
#include "rgw_lua.h"
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+#include <boost/process.hpp>
+#include <boost/filesystem.hpp>
+#include "rgw_lua_version.h"
+#endif
#define dout_subsys ceph_subsys_rgw
{
lua_State *L = luaL_newstate();
lua_state_guard guard(L);
- luaL_openlibs(L);
+ open_standard_libs(L);
try {
if (luaL_loadstring(L, script.c_str()) != LUA_OK) {
err_msg.assign(lua_tostring(L, -1));
return true;
}
-static const std::string SCRIPT_OID_PREFIX("script.");
+std::string script_oid(context ctx, const std::string& tenant) {
+ static const std::string SCRIPT_OID_PREFIX("script.");
+ return SCRIPT_OID_PREFIX + to_string(ctx) + "." + tenant;
+}
+
int read_script(rgw::sal::RGWRadosStore* store, const std::string& tenant, optional_yield y, context ctx, std::string& script)
{
RGWSysObjectCtx obj_ctx(store->svc()->sysobj->init_obj_ctx());
RGWObjVersionTracker objv_tracker;
- const auto script_oid = SCRIPT_OID_PREFIX + to_string(ctx) + tenant;
- rgw_raw_obj obj(store->svc()->zone->get_zone_params().log_pool, script_oid);
+ rgw_raw_obj obj(store->svc()->zone->get_zone_params().log_pool, script_oid(ctx, tenant));
bufferlist bl;
RGWSysObjectCtx obj_ctx(store->svc()->sysobj->init_obj_ctx());
RGWObjVersionTracker objv_tracker;
- const auto script_oid = SCRIPT_OID_PREFIX + to_string(ctx) + tenant;
- rgw_raw_obj obj(store->svc()->zone->get_zone_params().log_pool, script_oid);
+ rgw_raw_obj obj(store->svc()->zone->get_zone_params().log_pool, script_oid(ctx, tenant));
bufferlist bl;
ceph::encode(script, bl);
{
RGWObjVersionTracker objv_tracker;
- const auto script_oid = SCRIPT_OID_PREFIX + to_string(ctx) + tenant;
- rgw_raw_obj obj(store->svc()->zone->get_zone_params().log_pool, script_oid);
+ rgw_raw_obj obj(store->svc()->zone->get_zone_params().log_pool, script_oid(ctx, tenant));
const auto rc = rgw_delete_system_obj(
store->svc()->sysobj,
return 0;
}
+
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+
+const std::string PACKAGE_LIST_OBJECT_NAME = "lua_package_allowlist";
+
+namespace bp = boost::process;
+
+int add_package(rgw::sal::RGWRadosStore* store, optional_yield y, const std::string& package_name, bool allow_compilation) {
+ // verify that luarocks can load this oackage
+ const auto p = bp::search_path("luarocks");
+ if (p.empty()) {
+ return -ECHILD;
+ }
+ bp::ipstream is;
+ const auto cmd = p.string() + " search --porcelain" + (allow_compilation ? " " : " --binary ") + package_name;
+ bp::child c(cmd,
+ bp::std_in.close(),
+ bp::std_err > bp::null,
+ bp::std_out > is);
+
+ std::string line;
+ bool package_found = false;
+ // TODO: yield on reading the output
+ while (c.running() && std::getline(is, line) && !line.empty()) {
+ package_found = true;
+ }
+ c.wait();
+ auto ret = c.exit_code();
+ if (ret) {
+ return -ret;
+ }
+
+ if (!package_found) {
+ return -EINVAL;
+ }
+
+ // add package to list
+ const bufferlist empty_bl;
+ std::map<std::string, bufferlist> new_package{{package_name, empty_bl}};
+ librados::ObjectWriteOperation op;
+ op.omap_set(new_package);
+ ret = rgw_rados_operate(*(store->getRados()->get_lc_pool_ctx()),
+ PACKAGE_LIST_OBJECT_NAME, &op, y);
+
+ if (ret < 0) {
+ return ret;
+ }
+ return 0;
+}
+
+int remove_package(rgw::sal::RGWRadosStore* store, optional_yield y, const std::string& package_name) {
+ librados::ObjectWriteOperation op;
+ op.omap_rm_keys(std::set<std::string>({package_name}));
+ const auto ret = rgw_rados_operate(*(store->getRados()->get_lc_pool_ctx()),
+ PACKAGE_LIST_OBJECT_NAME, &op, y);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+int list_packages(rgw::sal::RGWRadosStore* store, optional_yield y, packages_t& packages) {
+ constexpr auto max_chunk = 1024U;
+ std::string start_after;
+ bool more = true;
+ int rval;
+ while (more) {
+ librados::ObjectReadOperation op;
+ packages_t packages_chunk;
+ op.omap_get_keys2(start_after, max_chunk, &packages_chunk, &more, &rval);
+ const auto ret = rgw_rados_operate(*(store->getRados()->get_lc_pool_ctx()),
+ PACKAGE_LIST_OBJECT_NAME, &op, nullptr, y);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ packages.merge(packages_chunk);
+ }
+
+ return 0;
+}
+
+int install_packages(rgw::sal::RGWRadosStore* store, optional_yield y, packages_t& failed_packages, std::string& output) {
+ // luarocks directory cleanup
+ const auto& luarocks_location = g_conf().get_val<std::string>("rgw_luarocks_location");
+ boost::system::error_code ec;
+ boost::filesystem::remove_all(luarocks_location, ec);
+ if (ec.value() != 0 && ec.value() != ENOENT) {
+ output.append("failed to clear luarock directory: ");
+ output.append(ec.message());
+ output.append("\n");
+ return ec.value();
+ }
+
+ packages_t packages;
+ auto ret = list_packages(store, y, packages);
+ if (ret == -ENOENT) {
+ // allowlist is empty
+ return 0;
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ // verify that luarocks exists
+ const auto p = bp::search_path("luarocks");
+ if (p.empty()) {
+ return -ECHILD;
+ }
+
+ // the lua rocks install dir will be created by luarocks the first time it is called
+ for (const auto& package : packages) {
+ bp::ipstream is;
+ bp::child c(p, "install", "--lua-version", CEPH_LUA_VERSION, "--tree", luarocks_location, "--deps-mode", "one", package,
+ bp::std_in.close(),
+ (bp::std_err & bp::std_out) > is);
+
+ // TODO: yield until wait returns
+ std::string line = "CMD: luarocks install --lua-version " + std::string(CEPH_LUA_VERSION) + std::string(" --tree ") +
+ luarocks_location + " --deps-mode one " + package;
+
+ do {
+ if (!line.empty()) {
+ output.append(line);
+ output.append("\n");
+ }
+ } while (c.running() && std::getline(is, line));
+
+ c.wait();
+ if (c.exit_code()) {
+ failed_packages.insert(package);
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
}
// delete the stored lua script from a context
int delete_script(rgw::sal::RGWRadosStore* store, const std::string& tenant, optional_yield y, context ctx);
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+#include <set>
+
+using packages_t = std::set<std::string>;
+
+// add a lua package to the allowlist
+int add_package(rgw::sal::RGWRadosStore* store, optional_yield y, const std::string& package_name, bool allow_compilation);
+
+// remove a lua package from the allowlist
+int remove_package(rgw::sal::RGWRadosStore* store, optional_yield y, const std::string& package_name);
+
+// list lua packages in the allowlist
+int list_packages(rgw::sal::RGWRadosStore* store, optional_yield y, packages_t& packages);
+
+// install all packages from the allowlist
+// return the list of packages that failed to install and the output of the install command
+int install_packages(rgw::sal::RGWRadosStore* store, optional_yield y, packages_t& failed_packages, std::string& output);
+#endif
}
#include "common/dout.h"
#include "services/svc_zone.h"
#include "rgw_lua_utils.h"
+#include "rgw_lua.h"
#include "rgw_common.h"
#include "rgw_log.h"
#include "rgw_process.h"
OpsLogSocket* olog,
req_state* s,
const char* op_name,
- const std::string& script)
+ const std::string& script,
+ const std::string& package_path)
+
{
auto L = luaL_newstate();
lua_state_guard lguard(L);
- luaL_openlibs(L);
+ open_standard_libs(L);
+ set_package_path(L, package_path);
create_debug_action(L, s->cct);
OpsLogSocket* olog,
req_state *s,
const char* op_name,
- const std::string& script);
+ const std::string& script,
+ const std::string& package_path);
}
#include "common/ceph_context.h"
#include "common/dout.h"
#include "rgw_lua_utils.h"
+#include "rgw_lua_version.h"
#define dout_subsys ceph_subsys_rgw
std::cout << "--------------- Stack Dump Finished ---------------" << std::endl;
}
+void set_package_path(lua_State* L, const std::string& install_dir) {
+ if (install_dir.empty()) {
+ return;
+ }
+ lua_getglobal(L, "package");
+ if (!lua_istable(L, -1)) {
+ return;
+ }
+ const auto path = install_dir+"/share/lua/"+CEPH_LUA_VERSION+"/?.lua";
+ pushstring(L, path);
+ lua_setfield(L, -2, "path");
+
+ const auto cpath = install_dir+"/lib/lua/"+CEPH_LUA_VERSION+"/?.so";
+ pushstring(L, cpath);
+ lua_setfield(L, -2, "cpath");
+}
+
+void open_standard_libs(lua_State* L) {
+ luaL_openlibs(L);
+ unsetglobal(L, "load");
+ unsetglobal(L, "loadfile");
+ unsetglobal(L, "loadstring");
+ unsetglobal(L, "dofile");
+ unsetglobal(L, "debug");
+ // remove os.exit()
+ lua_getglobal(L, "os");
+ lua_pushstring(L, "exit");
+ lua_pushnil(L);
+ lua_settable(L, -3);
+}
+
}
lua_pushlstring(L, str.data(), str.size());
}
+static inline void unsetglobal(lua_State* L, const char* name)
+{
+ lua_pushnil(L);
+ lua_setglobal(L, name);
+}
+
// dump the lua stack to stdout
void stack_dump(lua_State* L);
//
void create_debug_action(lua_State* L, CephContext* cct);
+// set the packages search path according to:
+// package.path = "<install_dir>/share/lua/5.3/?.lua" │ LuaRocks.
+// package.cpath= "<install_dir>/lib/lua/5.3/?.so"
+void set_package_path(lua_State* L, const std::string& install_dir);
+
+// open standard lua libs and remove the following functions:
+// os.exit()
+// load()
+// loadfile()
+// loadstring()
+// dofile()
+// and the "debug" library
+void open_standard_libs(lua_State* L);
+
}
--- /dev/null
+#pragma once
+
+#include <lua.hpp>
+#include <string>
+
+namespace rgw::lua {
+
+const std::string CEPH_LUA_VERSION(LUA_VERSION_MAJOR "." LUA_VERSION_MINOR);
+
+}
+
#include "rgw_asio_frontend.h"
#endif /* WITH_RADOSGW_BEAST_FRONTEND */
#include "rgw_dmclock_scheduler_ctx.h"
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+#include "rgw_lua.h"
+#endif
#include "services/svc_zone.h"
#endif
}
+#ifdef WITH_RADOSGW_LUA_PACKAGES
+ rgw::lua::packages_t failed_packages;
+ std::string output;
+ r = rgw::lua::install_packages(store, null_yield, failed_packages, output);
+ if (r < 0) {
+ dout(1) << "ERROR: failed to install lua packages from allowlist" << dendl;
+ }
+ if (!output.empty()) {
+ dout(10) << "INFO: lua packages installation output: \n" << output << dendl;
+ }
+ for (const auto& p : failed_packages) {
+ dout(5) << "WARNING: failed to install lua package: " << p << " from allowlist" << dendl;
+ }
+#endif
+
if (apis_map.count("swift") > 0) {
RGWRESTMgr_SWIFT* const swift_resource = new RGWRESTMgr_SWIFT;
frontend_prefix,
client_io, &mgr, &init_error);
rgw::dmclock::SchedulerCompleter c;
+ const auto& lua_package_path = g_conf().get_val<std::string>("rgw_luarocks_location");
+
if (init_error != 0) {
abort_early(s, nullptr, init_error, nullptr, yield);
goto done;
} else if (rc < 0) {
ldpp_dout(op, 5) << "WARNING: failed to read pre request script. error: " << rc << dendl;
} else {
- rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script);
+ rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script, lua_package_path);
if (rc < 0) {
ldpp_dout(op, 5) << "WARNING: failed to execute pre request script. error: " << rc << dendl;
}
} else if (rc < 0) {
ldpp_dout(op, 5) << "WARNING: failed to read post request script. error: " << rc << dendl;
} else {
- rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script);
+ rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script, lua_package_path);
if (rc < 0) {
ldpp_dout(op, 5) << "WARNING: failed to execute post request script. error: " << rc << dendl;
}
script put upload a lua script to a context
script get get the lua script of a context
script rm remove the lua scripts of a context
+ script-package add add a lua package to the scripts allowlist
+ script-package rm remove a lua package from the scripts allowlist
+ script-package list get the lua packages allowlist
options:
--tenant=<tenant> tenant name
--user_ns=<namespace> namespace of user (oidc in case of users authenticated with oidc provider)
Script options:
--context context in which the script runs. one of: preRequest, postRequest
+ --package name of the lua package that should be added/removed to/from the allowlist
+ --allow-compilation package is allowed to compile C code as part of its installation
--conf/-c FILE read configuration from the given configuration file
--id ID set ID portion of my name
add_library(kafka_stub STATIC ${kafka_stub_src})
endif()
+if(WITH_RADOSGW_LUA_PACKAGES)
+ list(APPEND rgw_libs Boost::filesystem)
+endif()
+
#unittest_rgw_bencode
add_executable(unittest_rgw_bencode test_rgw_bencode.cc)
add_ceph_unittest(unittest_rgw_bencode)
uint64_t id = 0;
req_state s(cct, &e, id);
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script, "");
ASSERT_EQ(rc, 0);
}
DEFINE_REQ_STATE;
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script, "");
ASSERT_EQ(rc, -1);
}
DEFINE_REQ_STATE;
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script, "");
ASSERT_EQ(rc, 0);
}
DEFINE_REQ_STATE;
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script, "");
ASSERT_EQ(rc, 0);
}
DEFINE_REQ_STATE;
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script, "");
ASSERT_EQ(rc, -1);
}
DEFINE_REQ_STATE;
s.decoded_uri = "http://hello.world/";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", script, "");
ASSERT_EQ(rc, 0);
}
s.err.err_code = "Bad Request";
s.err.message = "This is a bad request";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
DEFINE_REQ_STATE;
s.err.message = "this is a bad request";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
DEFINE_REQ_STATE;
s.host_id = "foo";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_NE(rc, 0);
}
DEFINE_REQ_STATE;
s.host_id = "foo";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "kaboom", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "kaboom", script, "");
ASSERT_EQ(rc, -1);
}
DEFINE_REQ_STATE;
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "kaboom", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "kaboom", script, "");
ASSERT_EQ(rc, -1);
}
b.bucket_id = "myid";
s.bucket.reset(new sal::RGWRadosBucket(nullptr, b));
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
s.generic_attrs["goodbye"] = "cruel world";
s.generic_attrs["ka"] = "boom";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
s.env["goodbye"] = "cruel world";
s.env["ka"] = "boom";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
s.tagset.add_tag("goodbye", "cruel world");
s.tagset.add_tag("ka", "boom");
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
DEFINE_REQ_STATE;
s.tagset.add_tag("hello", "world");
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_NE(rc, 0);
}
s.info.x_meta_map["foo"] = "bar";
s.info.x_meta_map["ka"] = "boom";
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
s.user_acl->get_acl().add_grant(&grant3);
s.user_acl->get_acl().add_grant(&grant4);
s.user_acl->get_acl().add_grant(&grant5);
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
s.object_acl->get_owner().set_name("user five");
s.object_acl->get_owner().set_id(rgw_user("tenant5", "user5"));
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
b.name = "my-bucket-name-is-fish";
s.bucket.reset(new sal::RGWRadosBucket(nullptr, b));
- const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
ASSERT_EQ(rc, 0);
}
+TEST(TestRGWLua, NotAllowedInLib)
+{
+ const std::string script = R"(
+ os.clock() -- this should be ok
+ os.exit() -- this should fail (os.exit() is removed)
+ )";
+
+ DEFINE_REQ_STATE;
+
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script, "");
+ ASSERT_NE(rc, 0);
+}
#include <sys/socket.h>
#include <stdlib.h>
s.cio = ∾
s.cct->_conf->rgw_ops_log_rados = false;
- auto rc = lua::request::execute(store.get(), nullptr, olog.get(), &s, "put_obj", script);
+ auto rc = lua::request::execute(store.get(), nullptr, olog.get(), &s, "put_obj", script, "");
EXPECT_EQ(rc, 0);
s.err.http_ret = 400;
- rc = lua::request::execute(store.get(), nullptr, olog.get(), &s, "put_obj", script);
+ rc = lua::request::execute(store.get(), nullptr, olog.get(), &s, "put_obj", script, "");
EXPECT_EQ(rc, 0);
// give the socket client time to read
--log-file=${CEPH_OUT_DIR}/radosgw.${current_port}.log \
--admin-socket=${CEPH_OUT_DIR}/radosgw.${current_port}.asok \
--pid-file=${CEPH_OUT_DIR}/radosgw.${current_port}.pid \
+ --rgw_luarocks_location=${CEPH_OUT_DIR}/luarocks \
${RGWDEBUG} \
-n ${rgw_name} \
"--rgw_frontends=${rgw_frontend} port=${current_port}${CEPH_RGW_HTTPS}"