Compare commits

...

4 commits

Author SHA1 Message Date
2c1f155328 update README 2024-02-16 17:56:06 -03:00
84ff7bd1b6 update docs 2024-02-16 02:13:37 -03:00
7f8e86fbd8 lint pass 2023-10-26 22:19:08 -03:00
84cb21b26a Merge pull request 'add config file validation' (#2) from config-validation into mistress
Reviewed-on: #2
2022-12-07 18:50:30 +00:00
8 changed files with 92 additions and 53 deletions

View file

@ -19,8 +19,37 @@ It is an effective replacement to your NGINX installation, but you can have
them coexisting (say, NGINX on port 80, OpenResty being reverse proxied by
NGINX on port 8069, though I wouldn't recommend it in production environments).
### how does it work
aproxy has two "hooks" into openresty:
- initialization of the lua vm
- callback for every incoming request
initialization will run validation of your configuration file and check
if it is valid. if it is not you will see logs emitted about what failed
when a request comes in, the scripts declared in the aproxy config file will
be executed sequentially (TODO: ensure order on conf file is chain order).
each script has two types of callbacks: init and request
init callbacks are called when initializing the request, so that the script
may do some conversion or transform the config data into a more performant
in-memory structure.
request callbacks are called on each request, as directed by the main script.
scripts define which paths they want to attach to (via PCRE regex), and so
they can do their own filtering.
look at `scripts/webfinger_allowlist.lua` for an example of how this looks
in a simple form.
### actually installing aproxy
- get openresty installed
- keep in mind that the specifics of configuring openresty for a double reverse proxy setup aren't included here.
- instructions here are for aproxy's setup in an existing openresty installation
```sh
mkdir /opt
git clone https://gitdab.com/luna/aproxy
@ -28,6 +57,9 @@ git clone https://gitdab.com/luna/aproxy
cd aproxy
mkdir /etc/aproxy
cp ./conf.lua /etc/aproxy/conf.lua
# keep in mind the default configuration will lead to your users not being discovered at all,
# it is provided as an example for you to modify.
$EDITOR /etc/aproxy/conf.lua
```
@ -51,23 +83,26 @@ http {
You need to do the following:
- Configure OpenResty package path so that it can call aproxy.
- Insert aproxy as a callback on `location / {` block
- insert aproxy hooks for initialization and for callbacks on every request
It'll look something like this:
It'll look something like this if you use a single `location /` block:
```nginx
# set this to 'on' after you have tested that it actually works.
# once you do that, performance will be increased
# while the friction to quickly debug aproxy will also be increased
lua_code_cache off;
lua_package_path '/opt/?.lua;/opt/aproxy/?.lua;;';
init_by_lua_block {
require("aproxy.main").init()
}
http {
lua_package_path '/opt/?.lua;/opt/aproxy/?.lua;;';
server {
server_name example.com;
location / {
# set this to 'on' after you have tested that it actually works.
# once you do that, performance will be increased
# while the friction to quickly debug aproxy will also be increased
lua_code_cache off;
access_by_lua_block {
require("aproxy.main")()
require("aproxy.main").access()
}
proxy_http_version 1.1;

View file

@ -2,19 +2,8 @@ local env_config_path = os.getenv('APROXY_CONFIG_PATH')
local DEFAULT_CONFIG_PATH = ".;/etc/aproxy"
local config_path = env_config_path or DEFAULT_CONFIG_PATH
function mysplit (inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
local function findConfigFile()
for _, config_directory in ipairs(mysplit(config_path, ";")) do
for _, config_directory in ipairs(string.split(config_path, ";")) do
local possible_config_path = config_directory .. "/" .. "conf.lua"
local fd, res = io.open(possible_config_path, "rb")
if fd then
@ -37,7 +26,7 @@ end
local function fakeTableSchema(value_schema)
return setmetatable({ __list = true }, {
__index = function (self, key)
__index = function ()
return value_schema
end
})
@ -45,8 +34,8 @@ end
local SPECIAL_KEYS = {__list = true}
local function validateSchema(schema, input, errors)
local errors = errors or {}
local function validateSchema(schema, input, errors_in)
local errors = errors_in or {}
if schema.__list then
-- generate full schema for lists that are same size as input
for k, _ in pairs(input) do schema[k] = schema.__schema_value end
@ -105,12 +94,8 @@ local function validateConfigFile(config_object)
return all_schema_errors
end
local function writeSchemaErrors(errors, out)
out('sex')
end
local function loadConfigFile(options)
local options = options or {}
local function loadConfigFile(options_in)
local options = options_in or {}
local config_file_data = assert(findConfigFile(), 'no config file found, config path: ' .. config_path)
local config_file_function = assert(loadstring(config_file_data))

12
ctx.lua
View file

@ -1,3 +1,5 @@
local util = require("util")
function log(msg)
ngx.log(ngx.STDERR, tostring(msg))
end
@ -13,13 +15,14 @@ function ctx:loadFromConfig(conf)
ctx:loadChain()
end
function ctx:loadChain()
self.compiled_chain = {}
for module_name, module_config in pairs(self._wanted_scripts) do
local module = require('scripts.' .. module_name)
local module_state = module.init(module_config)
-- TODO is it possible to make module_config readonly?
table.insert(self.compiled_chain, {module, module_config, module_state})
local module_config_readonly = table.readonly(module_config)
local module_state = module.init(module_config_readonly)
table.insert(self.compiled_chain, {module, module_config_readonly, module_state})
end
end
@ -32,7 +35,7 @@ function ctx:onRequest()
local module, module_config, state = unpack(filter)
for callback_regex, callback_function in pairs(module.callbacks) do
local match, error = ngx.re.match(request_uri, callback_regex)
local match = ngx.re.match(request_uri, callback_regex)
if match then
table.insert(callbacks_to_call, {module, callback_function, module_config, state})
end
@ -47,6 +50,7 @@ function ctx:onRequest()
ngx.status = status_code
ngx.say(body or "request denied")
ngx.exit(status_code)
return
end
end
end

View file

@ -1,11 +1,3 @@
-- function loadConfig()
-- -- TODO load config_path
-- return require("./config.lua")
-- end
--
-- local config = loadConfig()
local ctx = require('ctx')
local config = require('config')
require('util')

View file

@ -1,10 +1,10 @@
lua_code_cache off;
init_by_lua_block {
require("aproxy.main").init()
}
server {
listen 80;
lua_code_cache off;
location / {
default_type text/html;

View file

@ -1,4 +1,4 @@
function webfingerInit(cfg)
local function webfingerInit(cfg)
local accounts_set = {}
for _, account in ipairs(cfg.accounts) do
accounts_set["acct:" .. account] = true
@ -6,7 +6,7 @@ function webfingerInit(cfg)
return accounts_set
end
function webfingerCallback(cfg, accounts_set)
local function webfingerCallback(cfg, accounts_set)
local args, err = ngx.req.get_uri_args()
if err == "truncated" then
return 400, 'uri args too long'

View file

@ -64,7 +64,7 @@ function setupTest(module_require_path, input_config)
local count = table.pprint(schema_errors)
lu.assertIs(count, 0)
state = module.init(input_config)
local state = module.init(input_config)
ctx.compiled_chain = {
{module, input_config, state}
}
@ -74,9 +74,9 @@ end
function onRequest()
ctx:setWantedScripts()
local ctx = require('ctx')
local context = require('ctx')
do
ctx:onRequest()
context:onRequest()
end
end

View file

@ -4,11 +4,11 @@ function table.len(t)
return count
end
function table.pprint(t, options, ident, total_count)
local ident = ident or 0
local total_count = total_count or 0
function table.pprint(t, options_in, ident_in, total_count_in)
local ident = ident_in or 0
local total_count = total_count_in or 0
local options = options or {}
local options = options_in or {}
local print_function = options.call or print
if type(t) == 'table' then
local count = 0
@ -18,7 +18,7 @@ function table.pprint(t, options, ident, total_count)
total_count = table.pprint(v, options, ident + 1, total_count)
end
if count == 0 then
--print('<empty table>')
print_function('{}')
end
else
print_function(string.rep('\t', ident) .. tostring(t))
@ -26,3 +26,26 @@ function table.pprint(t, options, ident, total_count)
end
return total_count
end
function table.readonly(t)
return setmetatable({}, {
__index = t,
__newindex = function ()
error("Attempt to modify read-only table")
end,
__metatable = false
});
end
function string.split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end