show useful info in BW logs after startup/reload and reduce container images size
This commit is contained in:
parent
a686562f18
commit
2e1296d9ae
7
TODO
7
TODO
|
@ -1,6 +1,9 @@
|
|||
- YT video demo web UI
|
||||
- README
|
||||
- Ansible
|
||||
- Vagrant
|
||||
- Plugins
|
||||
- prepare new antibot challenge when not resolved and "refresh page"
|
||||
- fix doc integrations : "The Docker autoconf integration is similar to the Docker autoconf one"
|
||||
- add ipv6 to doc
|
||||
- edit doc integrations boilerplates : missing autoconf container in docker autoconf, fix syntax for autoconf service example and make them ready to use (copy / paste)
|
||||
- edit doc + misc/integrations : network bw-services: network.external.name is deprecated. Please set network.name with external: true
|
||||
- fix db warnings (Got an error reading communication packets)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.11.3-alpine
|
||||
FROM python:3.11.3-alpine AS builder
|
||||
|
||||
# Copy python requirements
|
||||
COPY src/common/gen/requirements.txt /tmp/req/requirements.txt
|
||||
|
@ -28,10 +28,18 @@ COPY src/common/helpers /usr/share/bunkerweb/helpers
|
|||
COPY src/common/settings.json /usr/share/bunkerweb/settings.json
|
||||
COPY src/common/utils /usr/share/bunkerweb/utils
|
||||
|
||||
# Add nginx user, drop bwcli, setup data folders, permissions and logging
|
||||
FROM python:3.11.3-alpine
|
||||
|
||||
# Set default umask to prevent huge recursive chmod increasing the final image size
|
||||
RUN umask 027
|
||||
|
||||
# Copy dependencies
|
||||
COPY --from=builder --chown=0:101 /usr/share/bunkerweb /usr/share/bunkerweb
|
||||
|
||||
# Add autoconf user, drop bwcli, install runtime dependencies, create data folders and set permissions
|
||||
RUN apk add --no-cache bash && \
|
||||
addgroup -g 101 nginx && \
|
||||
adduser -h /var/cache/nginx -g nginx -s /bin/sh -G nginx -D -H -u 101 nginx && \
|
||||
addgroup -g 101 autoconf && \
|
||||
adduser -h /var/cache/autoconf -g autoconf -s /bin/sh -G autoconf -D -H -u 101 autoconf && \
|
||||
cp /usr/share/bunkerweb/helpers/bwcli /usr/bin/ && \
|
||||
mkdir -p /var/tmp/bunkerweb && \
|
||||
mkdir -p /var/www && \
|
||||
|
@ -41,16 +49,11 @@ RUN apk add --no-cache bash && \
|
|||
mkdir -p /data/www && ln -s /data/www /var/www/html && \
|
||||
for dir in $(echo "configs plugins") ; do mkdir -p "/data/${dir}" && ln -s "/data/${dir}" "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:nginx /data && \
|
||||
chown -R root:autoconf /data && \
|
||||
chmod -R 770 /data && \
|
||||
chown -R root:nginx /usr/share/bunkerweb /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
find /usr/share/bunkerweb -type f -exec chmod 0740 {} \; && \
|
||||
find /usr/share/bunkerweb -type d -exec chmod 0750 {} \; && \
|
||||
chown -R root:autoconf /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
chmod -R 770 /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb && \
|
||||
chmod 750 /usr/share/bunkerweb/cli/main.py /usr/share/bunkerweb/helpers/*.sh /usr/bin/bwcli /usr/share/bunkerweb/autoconf/main.py /usr/share/bunkerweb/deps/python/bin/* && \
|
||||
mkdir /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
chown root:nginx /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
chmod 770 /var/log/letsencrypt /var/lib/letsencrypt
|
||||
chmod 750 /usr/share/bunkerweb/cli/main.py /usr/share/bunkerweb/helpers/*.sh /usr/bin/bwcli /usr/share/bunkerweb/autoconf/main.py /usr/share/bunkerweb/deps/python/bin/*
|
||||
|
||||
# Fix CVEs
|
||||
RUN apk add "libcrypto3>=3.0.8-r4" "libssl3>=3.0.8-r4"
|
||||
|
@ -59,7 +62,7 @@ VOLUME /data /etc/nginx
|
|||
|
||||
WORKDIR /usr/share/bunkerweb/autoconf
|
||||
|
||||
USER nginx:nginx
|
||||
USER autoconf:autoconf
|
||||
|
||||
HEALTHCHECK --interval=10s --timeout=10s --start-period=30s --retries=6 CMD /usr/share/bunkerweb/helpers/healthcheck-autoconf.sh
|
||||
|
||||
|
|
|
@ -22,11 +22,6 @@ RUN apk add --no-cache --virtual .build-deps py3-pip && \
|
|||
pip install --no-cache-dir --require-hashes --target /usr/share/bunkerweb/deps/python -r /usr/share/bunkerweb/deps/requirements.txt && \
|
||||
apk del .build-deps
|
||||
|
||||
FROM nginx:1.24.0-alpine
|
||||
|
||||
# Copy dependencies
|
||||
COPY --from=builder /usr/share/bunkerweb /usr/share/bunkerweb
|
||||
|
||||
# Copy files
|
||||
# can't exclude deps from . so we are copying everything by hand
|
||||
COPY src/bw/entrypoint.sh /usr/share/bunkerweb/entrypoint.sh
|
||||
|
@ -44,6 +39,14 @@ COPY src/common/utils /usr/share/bunkerweb/utils
|
|||
COPY src/VERSION /usr/share/bunkerweb/VERSION
|
||||
COPY misc/*.ascii /usr/share/bunkerweb/misc/
|
||||
|
||||
FROM nginx:1.24.0-alpine
|
||||
|
||||
# Set default umask to prevent huge recursive chmod increasing the final image size
|
||||
RUN umask 027
|
||||
|
||||
# Copy dependencies
|
||||
COPY --from=builder --chown=0:101 /usr/share/bunkerweb /usr/share/bunkerweb
|
||||
|
||||
# Install runtime dependencies, pypi packages, move bwcli, create data folders and set permissions
|
||||
RUN apk add --no-cache pcre bash python3 && \
|
||||
cp /usr/share/bunkerweb/helpers/bwcli /usr/bin/ && \
|
||||
|
@ -55,21 +58,15 @@ RUN apk add --no-cache pcre bash python3 && \
|
|||
for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:nginx /data && \
|
||||
chmod -R 770 /data && \
|
||||
chown -R root:nginx /usr/share/bunkerweb /var/cache/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
for dir in $(echo "/usr/share/bunkerweb /etc/bunkerweb") ; do find ${dir} -type f -exec chmod 0740 {} \; ; done && \
|
||||
for dir in $(echo "/usr/share/bunkerweb /etc/bunkerweb") ; do find ${dir} -type d -exec chmod 0750 {} \; ; done && \
|
||||
chown -R root:nginx /var/cache/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
chmod 770 /var/cache/bunkerweb /var/tmp/bunkerweb && \
|
||||
chmod 750 /usr/share/bunkerweb/cli/main.py /usr/share/bunkerweb/gen/main.py /usr/share/bunkerweb/helpers/*.sh /usr/share/bunkerweb/entrypoint.sh /usr/bin/bwcli /usr/share/bunkerweb/deps/python/bin/* && \
|
||||
chown -R root:nginx /etc/nginx && \
|
||||
chmod -R 770 /etc/nginx && \
|
||||
rm -f /var/log/nginx/* && \
|
||||
mkdir /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
chown root:nginx /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
chmod 770 /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
ln -s /proc/1/fd/2 /var/log/nginx/error.log && \
|
||||
ln -s /proc/1/fd/2 /var/log/nginx/modsec_audit.log && \
|
||||
ln -s /proc/1/fd/1 /var/log/nginx/access.log && \
|
||||
ln -s /proc/1/fd/1 /var/log/nginx/jobs.log
|
||||
ln -s /proc/1/fd/1 /var/log/nginx/access.log
|
||||
|
||||
# Fix CVEs
|
||||
RUN apk add "libcrypto3>=3.0.8-r4" "libssl3>=3.0.8-r4"
|
||||
|
|
|
@ -106,6 +106,7 @@ helpers.fill_ctx = function()
|
|||
data.http_user_agent = ngx.var.http_user_agent
|
||||
data.http_host = ngx.var.http_host
|
||||
data.server_name = ngx.var.server_name
|
||||
data.http_content_type = ngx.var.http_content_type
|
||||
-- IP data : global
|
||||
local ip_is_global, err = utils.ip_is_global(data.remote_addr)
|
||||
if ip_is_global == nil then
|
||||
|
|
|
@ -20,8 +20,17 @@ function plugin:initialize(id)
|
|||
end
|
||||
-- Store variables
|
||||
local metadata = cjson.decode(encoded_metadata)
|
||||
local multisite = false
|
||||
local current_phase = ngx.get_phase()
|
||||
for i, check_phase in ipairs({"set", "access", "log", "preread"}) do
|
||||
if current_phase == check_phase then
|
||||
multisite = true
|
||||
break
|
||||
end
|
||||
end
|
||||
self.is_request = multisite
|
||||
for k, v in pairs(metadata.settings) do
|
||||
local value, err = utils.get_variable(k, v.context == "multisite" and ngx.get_phase() ~= "init")
|
||||
local value, err = utils.get_variable(k, v.context == "multisite" and multisite)
|
||||
if value == nil then
|
||||
self.logger:log(ngx.ERR, "can't get " .. k .. " variable : " .. err)
|
||||
end
|
||||
|
|
|
@ -87,7 +87,7 @@ server {
|
|||
if not ok then
|
||||
logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "log")
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "log_default")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, ret)
|
||||
else
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
lua_shared_dict ready_lock 16k;
|
||||
lua_shared_dict worker_lock 16k;
|
||||
|
||||
init_worker_by_lua_block {
|
||||
|
||||
-- Our timer function
|
||||
local ready_log = function(premature)
|
||||
local ready_work = function(premature)
|
||||
|
||||
-- Libs
|
||||
local helpers = require "bunkerweb.helpers"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Instantiate objects
|
||||
local logger = require "bunkerweb.logger":new("INIT")
|
||||
local logger = require "bunkerweb.logger":new("INIT-WORKER")
|
||||
local datastore = require "bunkerweb.datastore":new()
|
||||
-- Don't print the ready log if we are in loading state
|
||||
|
||||
-- Don't go further we are in loading state
|
||||
local is_loading, err = require "bunkerweb.utils".get_variable("IS_LOADING", false)
|
||||
if not is_loading then
|
||||
logger:log(ngx.ERR, "utils.get_variable() failed : " .. err)
|
||||
|
@ -15,34 +21,101 @@ local ready_log = function(premature)
|
|||
elseif is_loading == "yes" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Instantiate lock
|
||||
local lock = require "resty.lock":new("ready_lock")
|
||||
local lock = require "resty.lock":new("worker_lock")
|
||||
if not lock then
|
||||
logger:log(ngx.ERR, "lock:new() failed : " .. err)
|
||||
return
|
||||
end
|
||||
|
||||
-- Acquire lock
|
||||
local elapsed, err = lock:lock("ready")
|
||||
if elapsed == nil then
|
||||
logger:log(ngx.ERR, "lock:lock() failed : " .. err)
|
||||
else
|
||||
-- Display ready log
|
||||
local ok, err = datastore:get("misc_ready")
|
||||
if not ok and err ~= "not found" then
|
||||
logger:log(ngx.ERR, "datastore:get() failed : " .. err)
|
||||
elseif not ok and err == "not found" then
|
||||
logger:log(ngx.NOTICE, "BunkerWeb is ready to fool hackers ! 🚀")
|
||||
local ok, err = datastore:set("misc_ready", "ok")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "datastore:set() failed : " .. err)
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if work is done
|
||||
local ok, err = datastore:get("misc_ready")
|
||||
if not ok and err ~= "not found" then
|
||||
logger:log(ngx.ERR, "datastore:get() failed : " .. err)
|
||||
local ok, err = lock:unlock()
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "lock:unlock() failed : " .. err)
|
||||
end
|
||||
return
|
||||
end
|
||||
if ok then
|
||||
local ok, err = lock:unlock()
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "lock:unlock() failed : " .. err)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
logger:log(ngx.INFO, "init_worker phase started")
|
||||
|
||||
-- Get plugins
|
||||
local plugins, err = datastore:get("plugins")
|
||||
if not plugins then
|
||||
logger:log(ngx.ERR, "can't get plugins from datastore : " .. err)
|
||||
local ok, err = lock:unlock()
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "lock:unlock() failed : " .. err)
|
||||
end
|
||||
return
|
||||
end
|
||||
plugins = cjson.decode(plugins)
|
||||
|
||||
-- Call init_worker() methods
|
||||
logger:log(ngx.INFO, "calling init_worker() methods of plugins ...")
|
||||
for i, plugin in ipairs(plugins) do
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
if plugin_lua == false then
|
||||
logger:log(ngx.ERR, err)
|
||||
elseif plugin_lua == nil then
|
||||
logger:log(ngx.INFO, err)
|
||||
else
|
||||
-- Check if plugin has init_worker method
|
||||
if plugin_lua.init_worker ~= nil then
|
||||
-- New call
|
||||
local ok, plugin_obj = helpers.new_plugin(plugin_lua)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, plugin_obj)
|
||||
else
|
||||
local ok, ret = helpers.call_plugin(plugin_obj, "init_worker")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, ret)
|
||||
elseif not ret.ret then
|
||||
logger:log(ngx.ERR, plugin.id .. ":init_worker() call failed : " .. ret.msg)
|
||||
else
|
||||
logger:log(ngx.INFO, plugin.id .. ":init_worker() call successful : " .. ret.msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
logger:log(ngx.INFO, "skipped execution of " .. plugin.id .. " because method init_worker() is not defined")
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Release lock
|
||||
lock:unlock()
|
||||
logger:log(ngx.INFO, "called init_worker() methods of plugins")
|
||||
|
||||
-- End
|
||||
local ok, err = datastore:set("misc_ready", "ok")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "datastore:set() failed : " .. err)
|
||||
end
|
||||
local ok, err = lock:unlock()
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "lock:unlock() failed : " .. err)
|
||||
end
|
||||
logger:log(ngx.INFO, "init phase ended")
|
||||
logger:log(ngx.NOTICE, "BunkerWeb is ready to fool hackers ! 🚀")
|
||||
|
||||
end
|
||||
|
||||
-- Start timer
|
||||
ngx.timer.at(5, ready_log)
|
||||
ngx.timer.at(5, ready_work)
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ function blacklist:initialize()
|
|||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Decode lists
|
||||
if ngx.get_phase() ~= "init" and self.variables["USE_BLACKLIST"] == "yes" then
|
||||
if ngx.get_phase() ~= "init" and self:is_needed() then
|
||||
local lists, err = self.datastore:get("plugin_blacklist_lists")
|
||||
if not lists then
|
||||
self.logger:log(ngx.ERR, err)
|
||||
|
@ -51,13 +51,26 @@ function blacklist:initialize()
|
|||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function blacklist:init()
|
||||
-- Check if init is needed
|
||||
local init_needed, err = utils.has_variable("USE_BLACKLIST", "yes")
|
||||
if init_needed == nil then
|
||||
return self:ret(false, "can't check USE_BLACKLIST variable : " .. err)
|
||||
function blacklist:is_needed()
|
||||
-- Loading case
|
||||
if self.is_loading then
|
||||
return false
|
||||
end
|
||||
if not init_needed or self.is_loading then
|
||||
-- Request phases (no default)
|
||||
if self.is_request and (ngx.ctx.bw.server_name ~= "_") then
|
||||
return self.variables["USE_BLACKLIST"] == "yes"
|
||||
end
|
||||
-- Other cases : at least one service uses it
|
||||
local is_needed, err = utils.has_variable("USE_BLACKLIST", "yes")
|
||||
if is_needed == nil then
|
||||
self.logger:log(ngx.ERR, "can't check USE_BLACKLIST variable : " .. err)
|
||||
end
|
||||
return is_needed
|
||||
end
|
||||
|
||||
function blacklist:init()
|
||||
-- Check if init needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
|
||||
|
@ -95,8 +108,8 @@ end
|
|||
|
||||
function blacklist:access()
|
||||
-- Check if access is needed
|
||||
if self.variables["USE_BLACKLIST"] ~= "yes" then
|
||||
return self:ret(true, "blacklist not activated")
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "access not needed")
|
||||
end
|
||||
-- Check the caches
|
||||
local checks = {
|
||||
|
|
|
@ -10,8 +10,8 @@ local bunkernet = class("bunkernet", plugin)
|
|||
function bunkernet:initialize()
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "bunkernet")
|
||||
-- Get BunkerNet ID
|
||||
if ngx.get_phase() ~= "init" and self.variables["USE_BUNKERNET"] == "yes" and not self.is_loading then
|
||||
-- Get BunkerNet ID and save info
|
||||
if ngx.get_phase() ~= "init" and self:is_needed() then
|
||||
local id, err = self.datastore:get("plugin_bunkernet_id")
|
||||
if id then
|
||||
self.bunkernet_id = id
|
||||
|
@ -23,19 +23,49 @@ function bunkernet:initialize()
|
|||
end
|
||||
end
|
||||
|
||||
function bunkernet:init()
|
||||
-- Check if init is needed
|
||||
function bunkernet:is_needed()
|
||||
-- Loading case
|
||||
if self.is_loading then
|
||||
return self:ret(true, "bunkerweb is loading")
|
||||
return false
|
||||
end
|
||||
local init_needed, err = utils.has_variable("USE_BUNKERNET", "yes")
|
||||
if init_needed == nil then
|
||||
return self:ret(false, "can't check USE_BUNKERNET variable : " .. err)
|
||||
-- Request phases (no default)
|
||||
if self.is_request and (ngx.ctx.bw.server_name ~= "_") then
|
||||
return self.variables["USE_BUNKERNET"] == "yes"
|
||||
end
|
||||
if not init_needed or self.is_loading then
|
||||
return self:ret(true, "no service uses bunkernet, skipping init")
|
||||
-- Other cases : at least one service uses it
|
||||
local is_needed, err = utils.has_variable("USE_BUNKERNET", "yes")
|
||||
if is_needed == nil then
|
||||
self.logger:log(ngx.ERR, "can't check USE_BUNKERNET variable : " .. err)
|
||||
end
|
||||
return is_needed
|
||||
end
|
||||
|
||||
function bunkernet:init_worker()
|
||||
-- Check if needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "no service uses BunkerNet, skipping init_worker")
|
||||
end
|
||||
-- Check id
|
||||
if not self.bunkernet_id then
|
||||
return self:ret(false, "missing instance ID")
|
||||
end
|
||||
-- Send ping request
|
||||
local ok, err, status, data = self:ping()
|
||||
if not ok then
|
||||
return self:ret(false, "error while sending request to API : " .. err)
|
||||
end
|
||||
if status ~= 200 then
|
||||
return self:ret(false, "received status " .. tostring(status) .. " from API using instance ID " .. self.bunkernet_id)
|
||||
end
|
||||
self.logger:log(ngx.NOTICE, "connectivity with API using instance ID " .. self.id .. " is successful")
|
||||
return self:ret(true, "connectivity with API using instance ID " .. self.id .. " is successful")
|
||||
end
|
||||
|
||||
function bunkernet:init()
|
||||
-- Check if needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "no service uses BunkerNet, skipping init")
|
||||
end
|
||||
-- Check if instance ID is present
|
||||
local f, err = io.open("/var/cache/bunkerweb/bunkernet/instance.id", "r")
|
||||
if not f then
|
||||
|
@ -74,23 +104,17 @@ function bunkernet:init()
|
|||
if not ok then
|
||||
return self:ret(false, "can't store bunkernet database into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true,
|
||||
"successfully connected to the bunkernet service " ..
|
||||
self.variables["BUNKERNET_SERVER"] .. " with machine ID " .. id .. " and " .. tostring(i) .. " bad IPs in database")
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " bad IPs using instance ID " .. id)
|
||||
end
|
||||
|
||||
function bunkernet:access()
|
||||
-- Check if not loading
|
||||
if self.is_loading then
|
||||
return self:ret(true, "bunkerweb is loading")
|
||||
-- Check if needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "service doesn't use BunkerNet, skipping access")
|
||||
end
|
||||
-- Check if enabled
|
||||
if self.variables["USE_BUNKERNET"] ~= "yes" then
|
||||
return self:ret(true, "bunkernet not activated")
|
||||
end
|
||||
-- Check if BunkerNet ID is generated
|
||||
-- Check id
|
||||
if not self.bunkernet_id then
|
||||
return self:ret(false, "bunkernet ID is not generated")
|
||||
return self:ret(false, "missing instance ID")
|
||||
end
|
||||
-- Check if IP is global
|
||||
if not ngx.ctx.bw.ip_is_global then
|
||||
|
@ -120,20 +144,16 @@ function bunkernet:access()
|
|||
return self:ret(true, "not in db")
|
||||
end
|
||||
|
||||
function bunkernet:log(bypass_use_bunkernet)
|
||||
-- Check if not loading
|
||||
if self.is_loading then
|
||||
return self:ret(true, "bunkerweb is loading")
|
||||
end
|
||||
if not bypass_use_bunkernet then
|
||||
-- Check if BunkerNet is enabled
|
||||
if self.variables["USE_BUNKERNET"] ~= "yes" then
|
||||
return self:ret(true, "bunkernet not activated")
|
||||
function bunkernet:log(bypass_checks)
|
||||
if not bypass_checks then
|
||||
-- Check if needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "service doesn't use BunkerNet, skipping log")
|
||||
end
|
||||
-- Check id
|
||||
if not self.bunkernet_id then
|
||||
return self:ret(false, "missing instance ID")
|
||||
end
|
||||
end
|
||||
-- Check if BunkerNet ID is generated
|
||||
if not self.bunkernet_id then
|
||||
return self:ret(false, "bunkernet ID is not generated")
|
||||
end
|
||||
-- Check if IP has been blocked
|
||||
local reason = utils.get_reason()
|
||||
|
@ -168,25 +188,21 @@ function bunkernet:log(bypass_use_bunkernet)
|
|||
end
|
||||
|
||||
function bunkernet:log_default()
|
||||
-- Check if not loading is needed
|
||||
if self.is_loading then
|
||||
return self:ret(true, "bunkerweb is loading")
|
||||
-- Check if needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "no service uses BunkerNet, skipping log_default")
|
||||
end
|
||||
-- Check if BunkerNet is activated
|
||||
local check, err = utils.has_variable("USE_BUNKERNET", "yes")
|
||||
if check == nil then
|
||||
return false, "error while checking variable USE_BUNKERNET (" .. err .. ")"
|
||||
end
|
||||
if not check then
|
||||
return true, "bunkernet not enabled"
|
||||
-- Check id
|
||||
if not self.bunkernet_id then
|
||||
return self:ret(false, "missing instance ID")
|
||||
end
|
||||
-- Check if default server is disabled
|
||||
local check, err = utils.get_variable("DISABLE_DEFAULT_SERVER", false)
|
||||
if check == nil then
|
||||
return false, "error while getting variable DISABLE_DEFAULT_SERVER (" .. err .. ")"
|
||||
return self:ret(false, "error while getting variable DISABLE_DEFAULT_SERVER : " .. err)
|
||||
end
|
||||
if check ~= "yes" then
|
||||
return true, "default server not disabled"
|
||||
return self:ret(true, "default server is not disabled")
|
||||
end
|
||||
-- Call log method
|
||||
return self:log(true)
|
||||
|
@ -199,15 +215,17 @@ end
|
|||
function bunkernet:request(method, url, data)
|
||||
local httpc, err = http.new()
|
||||
if not httpc then
|
||||
return false, "can't instantiate http object : " .. err, nil, nil
|
||||
return false, "can't instantiate http object : " .. err
|
||||
end
|
||||
local all_data = {
|
||||
id = self.bunkernet_id,
|
||||
version = self.version,
|
||||
integration = self.integration
|
||||
}
|
||||
for k, v in pairs(data) do
|
||||
all_data[k] = v
|
||||
if data then
|
||||
for k, v in pairs(data) do
|
||||
all_data[k] = v
|
||||
end
|
||||
end
|
||||
local res, err = httpc:request_uri(self.variables["BUNKERNET_SERVER"] .. url, {
|
||||
method = method,
|
||||
|
@ -219,14 +237,14 @@ function bunkernet:request(method, url, data)
|
|||
})
|
||||
httpc:close()
|
||||
if not res then
|
||||
return false, "error while sending request : " .. err, nil, nil
|
||||
return false, "error while sending request : " .. err
|
||||
end
|
||||
if res.status ~= 200 then
|
||||
return false, "status code != 200", res.status, nil
|
||||
end
|
||||
local ok, ret = pcall(cjson.decode, res.body)
|
||||
if not ok then
|
||||
return false, "error while decoding json : " .. ret, nil, nil
|
||||
return false, "error while decoding json : " .. ret
|
||||
end
|
||||
return true, "success", res.status, ret
|
||||
end
|
||||
|
|
|
@ -19,6 +19,32 @@ function dnsbl:initialize()
|
|||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function dnsbl:init_worker()
|
||||
-- Check if loading
|
||||
if self.is_loading then
|
||||
return self:ret(false, "BW is loading")
|
||||
end
|
||||
-- Check if at least one service uses it
|
||||
local is_needed, err = utils.has_variable("USE_DNSBL", "yes")
|
||||
if is_needed == nil then
|
||||
return self:ret(false, "can't check USE_DNSBL variable : " .. err)
|
||||
elseif not is_needed then
|
||||
return self:ret(true, "no service uses DNSBL, skipping init_worker")
|
||||
end
|
||||
-- Loop on DNSBL list
|
||||
for server in self.variables["DNSBL_LIST"]:gmatch("%S+") do
|
||||
local result, err = self:is_in_dnsbl("127.0.0.2", server)
|
||||
if result == nil then
|
||||
self.logger:log(ngx.ERR, "error while sending DNS request to " .. server .. " : " .. err)
|
||||
elseif not result then
|
||||
self.logger:log(ngx.ERR, "dnsbl check for " .. server .. " failed")
|
||||
else
|
||||
self.logger:log(ngx.NOTICE, "dnsbl check for " .. server .. " is successful")
|
||||
end
|
||||
end
|
||||
return self:ret(true, "success")
|
||||
end
|
||||
|
||||
function dnsbl:access()
|
||||
-- Check if access is needed
|
||||
if self.variables["USE_DNSBL"] ~= "yes" then
|
||||
|
|
|
@ -17,7 +17,7 @@ function greylist:initialize()
|
|||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Decode lists
|
||||
if ngx.get_phase() ~= "init" and self.variables["USE_GREYLIST"] == "yes" then
|
||||
if ngx.get_phase() ~= "init" and self:is_needed() then
|
||||
local lists, err = self.datastore:get("plugin_greylist_lists")
|
||||
if not lists then
|
||||
self.logger:log(ngx.ERR, err)
|
||||
|
@ -45,13 +45,26 @@ function greylist:initialize()
|
|||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function greylist:init()
|
||||
-- Check if init is needed
|
||||
local init_needed, err = utils.has_variable("USE_GREYLIST", "yes")
|
||||
if init_needed == nil then
|
||||
return self:ret(false, "can't check USE_GREYLIST variable : " .. err)
|
||||
function greylist:is_needed()
|
||||
-- Loading case
|
||||
if self.is_loading then
|
||||
return false
|
||||
end
|
||||
if not init_needed or self.is_loading then
|
||||
-- Request phases (no default)
|
||||
if self.is_request and (ngx.ctx.bw.server_name ~= "_") then
|
||||
return self.variables["USE_GREYLIST"] == "yes"
|
||||
end
|
||||
-- Other cases : at least one service uses it
|
||||
local is_needed, err = utils.has_variable("USE_GREYLIST", "yes")
|
||||
if is_needed == nil then
|
||||
self.logger:log(ngx.ERR, "can't check USE_GREYLIST variable : " .. err)
|
||||
end
|
||||
return is_needed
|
||||
end
|
||||
|
||||
function greylist:init()
|
||||
-- Check if init needed
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
-- Read greylists
|
||||
|
@ -83,8 +96,8 @@ end
|
|||
|
||||
function greylist:access()
|
||||
-- Check if access is needed
|
||||
if self.variables["USE_GREYLIST"] ~= "yes" then
|
||||
return self:ret(true, "greylist not activated")
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "access not needed")
|
||||
end
|
||||
-- Check the caches
|
||||
local checks = {
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
"help": "List of URI, separated with spaces, to put into the greylist.",
|
||||
"id": "greylist-uri",
|
||||
"label": "Greylist URI",
|
||||
"regex": "^( *(/[\\w\\].~:/?#[@!$&'()*+,;=-]*)(?!.*\\2(?!.)) *)*$",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"GREYLIST_URI_URLS": {
|
||||
|
|
|
@ -18,7 +18,7 @@ function limit:initialize()
|
|||
self.use_redis = use_redis == "yes"
|
||||
self.clusterstore = clusterstore:new()
|
||||
-- Load rules if needed
|
||||
if ngx.get_phase() ~= "init" and self.variables["USE_LIMIT_REQ"] == "yes" then
|
||||
if ngx.get_phase() ~= "init" and self:is_needed() then
|
||||
-- Get all rules from datastore
|
||||
local limited = false
|
||||
local all_rules, err = self.datastore:get("plugin_limit_rules")
|
||||
|
@ -43,14 +43,27 @@ function limit:initialize()
|
|||
end
|
||||
end
|
||||
|
||||
function limit:is_needed()
|
||||
-- Loading case
|
||||
if self.is_loading then
|
||||
return false
|
||||
end
|
||||
-- Request phases (no default)
|
||||
if self.is_request and (ngx.ctx.bw.server_name ~= "_") then
|
||||
return self.variables["USE_LIMIT_REQ"] == "yes"
|
||||
end
|
||||
-- Other cases : at least one service uses it
|
||||
local is_needed, err = utils.has_variable("USE_LIMIT_REQ", "yes")
|
||||
if is_needed == nil then
|
||||
self.logger:log(ngx.ERR, "can't check USE_LIMIT_REQ variable : " .. err)
|
||||
end
|
||||
return is_needed
|
||||
end
|
||||
|
||||
function limit:init()
|
||||
-- Check if init is needed
|
||||
local init_needed, err = utils.has_variable("USE_LIMIT_REQ", "yes")
|
||||
if init_needed == nil then
|
||||
return self:ret(false, err)
|
||||
end
|
||||
if not init_needed or self.is_loading then
|
||||
return self:ret(true, "no service uses Limit for requests, skipping init")
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "no service uses limit for requests, skipping init")
|
||||
end
|
||||
-- Get variables
|
||||
local variables, err = utils.get_multiple_variables({"LIMIT_REQ_URL", "LIMIT_REQ_RATE"})
|
||||
|
@ -86,8 +99,8 @@ function limit:access()
|
|||
return self:ret(true, "client is whitelisted")
|
||||
end
|
||||
-- Check if access is needed
|
||||
if self.variables["USE_LIMIT_REQ"] ~= "yes" then
|
||||
return self:ret(true, "limit req is disabled")
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "limit request not enabled")
|
||||
end
|
||||
-- Check if URI is limited
|
||||
local rate = nil
|
||||
|
|
|
@ -11,25 +11,27 @@ function redis:initialize()
|
|||
plugin.initialize(self, "redis")
|
||||
end
|
||||
|
||||
function redis:init()
|
||||
-- Check if init is needed
|
||||
function redis:init_worker()
|
||||
-- Check if init_worker is needed
|
||||
if self.variables["USE_REDIS"] ~= "yes" or self.is_loading then
|
||||
return self:ret(true, "init not needed")
|
||||
return self:ret(true, "init_worker not needed")
|
||||
end
|
||||
-- Check redis connection ()
|
||||
-- Check redis connection
|
||||
local ok, err = clusterstore:connect()
|
||||
if not ok then
|
||||
return self:ret(false, "redis connect error : " .. err)
|
||||
end
|
||||
-- Send ping
|
||||
local ok, err = clusterstore:call("ping")
|
||||
clusterstore:close()
|
||||
if err then
|
||||
return self:ret(false, "error while sending ping command : " .. err)
|
||||
return self:ret(false, "error while sending ping command to redis server : " .. err)
|
||||
end
|
||||
if not ok then
|
||||
return self:ret(false, "ping command failed")
|
||||
return self:ret(false, "redis ping command failed")
|
||||
end
|
||||
return self:ret(true, "redis ping successful")
|
||||
self.logger:log(ngx.NOTICE, "connectivity with redis server " .. self.variables["REDIS_HOST"] .. " is successful")
|
||||
return self:ret(true, "success")
|
||||
end
|
||||
|
||||
return redis
|
|
@ -19,7 +19,7 @@ function whitelist:initialize()
|
|||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Decode lists
|
||||
if ngx.get_phase() ~= "init" and self.variables["USE_WHITELIST"] == "yes" then
|
||||
if ngx.get_phase() ~= "init" and self:is_needed() then
|
||||
local lists, err = self.datastore:get("plugin_whitelist_lists")
|
||||
if not lists then
|
||||
self.logger:log(ngx.ERR, err)
|
||||
|
@ -44,16 +44,29 @@ function whitelist:initialize()
|
|||
end
|
||||
end
|
||||
-- Instantiate cachestore
|
||||
self.cachestore = cachestore:new(self.use_redis and ngx.get_phase() == "access")
|
||||
self.cachestore = cachestore:new(self.use_redis)
|
||||
end
|
||||
|
||||
function whitelist:is_needed()
|
||||
-- Loading case
|
||||
if self.is_loading then
|
||||
return false
|
||||
end
|
||||
-- Request phases (no default)
|
||||
if self.is_request and (ngx.ctx.bw.server_name ~= "_") then
|
||||
return self.variables["USE_WHITELIST"] == "yes"
|
||||
end
|
||||
-- Other cases : at least one service uses it
|
||||
local is_needed, err = utils.has_variable("USE_WHITELIST", "yes")
|
||||
if is_needed == nil then
|
||||
self.logger:log(ngx.ERR, "can't check USE_WHITELIST variable : " .. err)
|
||||
end
|
||||
return is_needed
|
||||
end
|
||||
|
||||
function whitelist:init()
|
||||
-- Check if init is needed
|
||||
local init_needed, err = utils.has_variable("USE_WHITELIST", "yes")
|
||||
if init_needed == nil then
|
||||
return self:ret(false, "can't check USE_WHITELIST variable : " .. err)
|
||||
end
|
||||
if not init_needed or self.is_loading then
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
-- Read whitelists
|
||||
|
@ -89,7 +102,7 @@ function whitelist:set()
|
|||
ngx.ctx.bw.is_whitelisted = "no"
|
||||
env.set("is_whitelisted", "no")
|
||||
-- Check if set is needed
|
||||
if self.variables["USE_WHITELIST"] ~= "yes" then
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "whitelist not activated")
|
||||
end
|
||||
-- Check cache
|
||||
|
@ -107,7 +120,7 @@ end
|
|||
|
||||
function whitelist:access()
|
||||
-- Check if access is needed
|
||||
if self.variables["USE_WHITELIST"] ~= "yes" then
|
||||
if not self:is_needed() then
|
||||
return self:ret(true, "whitelist not activated")
|
||||
end
|
||||
-- Check cache
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.11.3-alpine
|
||||
FROM python:3.11.3-alpine AS builder
|
||||
|
||||
# Copy python requirements
|
||||
COPY src/scheduler/requirements.txt /tmp/req/requirements.txt
|
||||
|
@ -33,6 +33,14 @@ COPY src/common/utils /usr/share/bunkerweb/utils
|
|||
COPY src/scheduler /usr/share/bunkerweb/scheduler
|
||||
COPY src/VERSION /usr/share/bunkerweb/VERSION
|
||||
|
||||
FROM python:3.11.3-alpine
|
||||
|
||||
# Set default umask to prevent huge recursive chmod increasing the final image size
|
||||
RUN umask 027
|
||||
|
||||
# Copy dependencies
|
||||
COPY --from=builder --chown=0:101 /usr/share/bunkerweb /usr/share/bunkerweb
|
||||
|
||||
# Add scheduler user, drop bwcli, install runtime dependencies, create data folders and set permissions
|
||||
RUN apk add --no-cache bash libgcc libstdc++ openssl && \
|
||||
ln -s /usr/local/bin/python3 /usr/bin/python3 && \
|
||||
|
@ -50,20 +58,15 @@ RUN apk add --no-cache bash libgcc libstdc++ openssl && \
|
|||
for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:scheduler /data && \
|
||||
chmod -R 770 /data && \
|
||||
chown -R root:scheduler /usr/share/bunkerweb /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
find /usr/share/bunkerweb -type f -exec chmod 0740 {} \; && \
|
||||
find /usr/share/bunkerweb -type d -exec chmod 0750 {} \; && \
|
||||
chown -R root:scheduler /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
chmod -R 770 /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb && \
|
||||
find /usr/share/bunkerweb/core/*/jobs/* -type f -exec chmod 750 {} \; && \
|
||||
chmod 750 /usr/share/bunkerweb/cli/main.py /usr/share/bunkerweb/gen/*.py /usr/share/bunkerweb/scheduler/main.py /usr/share/bunkerweb/scheduler/entrypoint.sh /usr/share/bunkerweb/helpers/*.sh /usr/share/bunkerweb/deps/python/bin/* /usr/bin/bwcli && \
|
||||
mkdir -p /etc/nginx && \
|
||||
chown -R scheduler:scheduler /etc/nginx && \
|
||||
chmod -R 770 /etc/nginx && \
|
||||
mkdir -p /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
chown root:scheduler /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
chmod 770 /var/log/letsencrypt /var/lib/letsencrypt && \
|
||||
ln -s /proc/1/fd/1 /var/log/letsencrypt/letsencrypt.log && \
|
||||
chmod 660 /usr/share/bunkerweb/INTEGRATION
|
||||
chmod 660 /usr/share/bunkerweb/INTEGRATION && \
|
||||
chown root:scheduler /usr/share/bunkerweb/INTEGRATION
|
||||
|
||||
# Fix CVEs
|
||||
RUN apk add "libcrypto3>=3.0.8-r4" "libssl3>=3.0.8-r4"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.11.3-alpine
|
||||
FROM python:3.11.3-alpine AS builder
|
||||
|
||||
# Copy python requirements
|
||||
COPY src/ui/requirements.txt /tmp/req/requirements.txt
|
||||
|
@ -30,7 +30,15 @@ COPY src/common/helpers /usr/share/bunkerweb/helpers
|
|||
COPY src/ui /usr/share/bunkerweb/ui
|
||||
COPY src/VERSION /usr/share/bunkerweb/VERSION
|
||||
|
||||
# Add ui user
|
||||
FROM python:3.11.3-alpine
|
||||
|
||||
# Set default umask to prevent huge recursive chmod increasing the final image size
|
||||
RUN umask 027
|
||||
|
||||
# Copy dependencies
|
||||
COPY --from=builder --chown=0:101 /usr/share/bunkerweb /usr/share/bunkerweb
|
||||
|
||||
# Add ui user, drop bwcli, install runtime dependencies, create data folders and set permissions
|
||||
RUN apk add --no-cache bash && \
|
||||
addgroup -g 101 ui && \
|
||||
adduser -h /var/cache/nginx -g ui -s /bin/sh -G ui -D -H -u 101 ui && \
|
||||
|
@ -44,12 +52,11 @@ RUN apk add --no-cache bash && \
|
|||
for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:ui /data && \
|
||||
chmod -R 770 /data && \
|
||||
chown -R root:ui /usr/share/bunkerweb /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/log/nginx && \
|
||||
for dir in $(echo "/usr/share/bunkerweb /etc/bunkerweb") ; do find ${dir} -type f -exec chmod 0740 {} \; ; done && \
|
||||
for dir in $(echo "/usr/share/bunkerweb /etc/bunkerweb") ; do find ${dir} -type d -exec chmod 0750 {} \; ; done && \
|
||||
chown -R root:ui /usr/share/bunkerweb/INTEGRATION /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/log/nginx && \
|
||||
chmod 770 /var/cache/bunkerweb /var/lib/bunkerweb /var/tmp/bunkerweb /var/log/nginx/ui.log && \
|
||||
chmod 750 /usr/share/bunkerweb/gen/*.py /usr/share/bunkerweb/ui/*.py /usr/share/bunkerweb/ui/src/*.py /usr/share/bunkerweb/deps/python/bin/* /usr/share/bunkerweb/helpers/*.sh && \
|
||||
chmod 660 /usr/share/bunkerweb/INTEGRATION
|
||||
chmod 660 /usr/share/bunkerweb/INTEGRATION && \
|
||||
chown root:ui /usr/share/bunkerweb/INTEGRATION
|
||||
|
||||
# Fix CVEs
|
||||
RUN apk add "libcrypto3>=3.0.8-r4" "libssl3>=3.0.8-r4"
|
||||
|
|
Loading…
Reference in New Issue