Rename the program to sww and its deciding daemon to discriminator (closes #218) (#221)
check / check (push) Failing after 1m34s
check / check (push) Failing after 1m34s
This commit was merged in pull request #221.
This commit is contained in:
1 parent
2e2f6f7175
commit
beb503b233
106 files changed
+3302
-3275
No files matched your search
+2
-2
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# script/build: build bin/smallwebwaf on the host, with Go installed, for
|
||||
# script/build: build bin/sww on the host, with Go installed, for
|
||||
# working on the code by hand. The version it reports comes from git, as
|
||||
# in script/docker, and the no_fs_access tag is the Dockerfile's.
|
||||
set -eu
|
||||
@@ -12,7 +12,7 @@ main() {
|
||||
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
|
||||
[ -n "$version" ] || version="unknown"
|
||||
go build -tags no_fs_access -trimpath -ldflags "-X main.Version=$version" \
|
||||
-o bin/smallwebwaf ./cmd/smallwebwaf
|
||||
-o bin/sww ./cmd/sww
|
||||
}
|
||||
|
||||
main "$@"
|
||||
+79
-79
@@ -1,25 +1,25 @@
|
||||
#!/bin/sh
|
||||
# script/example-app: build the image, and on it the example app in
|
||||
# deploy/example-app, then run the app's container, with rproxy in it, and
|
||||
# servewaf in a container of its own with a volume for the state files. It
|
||||
# discriminator in a container of its own with a volume for the state files. It
|
||||
# checks:
|
||||
# - that the health checks pass;
|
||||
# - that a request is served through rproxy, and a second one in a minute
|
||||
# bans the client;
|
||||
# - that a probe for /.env bans another client, which its next request bans
|
||||
# for good;
|
||||
# - that only servewaf's container changes the state directory's owner;
|
||||
# - that the app still answers through rproxy with servewaf stopped, and
|
||||
# that once servewaf has started again, bans apply again;
|
||||
# - that only discriminator's container changes the state directory's owner;
|
||||
# - that the app still answers through rproxy with discriminator stopped, and
|
||||
# that once discriminator has started again, bans apply again;
|
||||
# - that `sv stop` stops rproxy in order, and `docker stop` stops each
|
||||
# container without having to kill it;
|
||||
# - that a new servewaf container on the same volume still refuses the banned
|
||||
# - that a new discriminator container on the same volume still refuses the banned
|
||||
# client;
|
||||
# - that a servewaf container with its state files on a new volume mounted at
|
||||
# the directory SWWAF_STATE_DIR_FILE names becomes healthy;
|
||||
# - that one whose SWWAF_STATE_DIR does not exist logs servewaf's message
|
||||
# - that a discriminator container with its state files on a new volume mounted at
|
||||
# the directory SWW_STATE_DIR_FILE names becomes healthy;
|
||||
# - that one whose SWW_STATE_DIR does not exist logs discriminator's message
|
||||
# about it.
|
||||
# servewaf runs with SWWAF_LOOKUP_SOURCE=off, so that no address is sent to
|
||||
# discriminator runs with SWW_LOOKUP_SOURCE=off, so that no address is sent to
|
||||
# GeoJS. The containers, the network, the volumes and both images are removed
|
||||
# however the script ends. Building the app needs network access, for nixpkgs'
|
||||
# binary cache. script/check does not run this.
|
||||
@@ -35,15 +35,15 @@ IMAGE="$NAME-base"
|
||||
APP_IMAGE="$NAME-app"
|
||||
NETWORK="$NAME"
|
||||
APP="$NAME-app-container"
|
||||
SERVEWAF="$NAME-servewaf"
|
||||
DISCRIMINATOR="$NAME-discriminator"
|
||||
VOLUME="$NAME-state"
|
||||
# The volumes of the container whose state directory SWWAF_STATE_DIR_FILE
|
||||
# The volumes of the container whose state directory SWW_STATE_DIR_FILE
|
||||
# names: its state files, and the file that names their directory.
|
||||
MOVED_VOLUME="$NAME-moved-state"
|
||||
SETTINGS_VOLUME="$NAME-settings"
|
||||
|
||||
cleanup() {
|
||||
docker rm --force "$APP" "$SERVEWAF" >/dev/null 2>&1 || true
|
||||
docker rm --force "$APP" "$DISCRIMINATOR" >/dev/null 2>&1 || true
|
||||
docker network rm "$NETWORK" >/dev/null 2>&1 || true
|
||||
docker volume rm --force "$VOLUME" "$MOVED_VOLUME" "$SETTINGS_VOLUME" \
|
||||
>/dev/null 2>&1 || true
|
||||
@@ -53,8 +53,8 @@ cleanup() {
|
||||
fail() {
|
||||
echo "example-app: $*; the app container's output:" >&2
|
||||
docker logs "$APP" >&2 || true
|
||||
echo "example-app: servewaf's output:" >&2
|
||||
docker logs "$SERVEWAF" >&2 || true
|
||||
echo "example-app: discriminator's output:" >&2
|
||||
docker logs "$DISCRIMINATOR" >&2 || true
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -87,49 +87,49 @@ logged() {
|
||||
done
|
||||
}
|
||||
|
||||
# start_servewaf: run servewaf from the image, with the state files on the
|
||||
# start_discriminator: run discriminator from the image, with the state files on the
|
||||
# volume, a rate limit of one request a minute and no client looked up, and wait
|
||||
# until it is healthy.
|
||||
start_servewaf() {
|
||||
docker run --detach --name "$SERVEWAF" --network "$NETWORK" \
|
||||
--volume "$VOLUME:/var/lib/smallwebwaf" \
|
||||
--env SMALLWEBWAF_COMMAND=servewaf \
|
||||
--env SWWAF_RATE_LIMIT_PER_MINUTE=1 \
|
||||
--env SWWAF_LOOKUP_SOURCE=off \
|
||||
start_discriminator() {
|
||||
docker run --detach --name "$DISCRIMINATOR" --network "$NETWORK" \
|
||||
--volume "$VOLUME:/var/lib/sww" \
|
||||
--env SWW_COMMAND=discriminator \
|
||||
--env SWW_RATE_LIMIT_PER_MINUTE=1 \
|
||||
--env SWW_LOOKUP_SOURCE=off \
|
||||
"$IMAGE" >/dev/null
|
||||
wait_for "servewaf's health check did not pass" healthy "$SERVEWAF"
|
||||
wait_for "discriminator's health check did not pass" healthy "$DISCRIMINATOR"
|
||||
}
|
||||
|
||||
# start_app: run the app's container, with rproxy in it, and wait until it is
|
||||
# healthy.
|
||||
start_app() {
|
||||
docker run --detach --name "$APP" --network "$NETWORK" --publish 127.0.0.1::8080 \
|
||||
--env SWRP_WAF_BACKEND="http://$SERVEWAF:8080" \
|
||||
--env SWRP_WAF_BACKEND="http://$DISCRIMINATOR:8080" \
|
||||
"$APP_IMAGE" >/dev/null
|
||||
wait_for "the app's health check did not pass" healthy "$APP"
|
||||
address="$(docker port "$APP" 8080/tcp)"
|
||||
}
|
||||
|
||||
# start_moved_servewaf: run servewaf with the state files on a new volume at
|
||||
# /srv/state, which SWWAF_STATE_DIR_FILE names in a file only the smallwebwaf
|
||||
# start_moved_discriminator: run discriminator with the state files on a new volume at
|
||||
# /srv/state, which SWW_STATE_DIR_FILE names in a file only the sww
|
||||
# user can read, as under "Settings given as files" in docs/settings.md, and
|
||||
# wait until it is healthy. servewaf can write the new volume only once the run
|
||||
# wait until it is healthy. discriminator can write the new volume only once the run
|
||||
# script has given it to that user.
|
||||
start_moved_servewaf() {
|
||||
start_moved_discriminator() {
|
||||
docker volume create "$MOVED_VOLUME" >/dev/null
|
||||
docker volume create "$SETTINGS_VOLUME" >/dev/null
|
||||
docker run --rm --volume "$SETTINGS_VOLUME:/settings" \
|
||||
--entrypoint bash "$IMAGE" -c 'echo /srv/state > /settings/state-dir &&
|
||||
chown smallwebwaf:smallwebwaf /settings/state-dir &&
|
||||
chown sww:sww /settings/state-dir &&
|
||||
chmod 0400 /settings/state-dir'
|
||||
docker run --detach --name "$SERVEWAF" --network "$NETWORK" \
|
||||
docker run --detach --name "$DISCRIMINATOR" --network "$NETWORK" \
|
||||
--volume "$MOVED_VOLUME:/srv/state" \
|
||||
--volume "$SETTINGS_VOLUME:/etc/smallwebwaf/settings:ro" \
|
||||
--env SMALLWEBWAF_COMMAND=servewaf \
|
||||
--env SWWAF_STATE_DIR_FILE=/etc/smallwebwaf/settings/state-dir \
|
||||
--env SWWAF_LOOKUP_SOURCE=off \
|
||||
--volume "$SETTINGS_VOLUME:/etc/sww/settings:ro" \
|
||||
--env SWW_COMMAND=discriminator \
|
||||
--env SWW_STATE_DIR_FILE=/etc/sww/settings/state-dir \
|
||||
--env SWW_LOOKUP_SOURCE=off \
|
||||
"$IMAGE" >/dev/null
|
||||
wait_for "servewaf's health check did not pass" healthy "$SERVEWAF"
|
||||
wait_for "discriminator's health check did not pass" healthy "$DISCRIMINATOR"
|
||||
}
|
||||
|
||||
# status_from <client> <path>: print the status a request for path from client,
|
||||
@@ -140,7 +140,7 @@ status_from() {
|
||||
--max-time 10 --header "X-Forwarded-For: $1" "http://$address$2" || true
|
||||
}
|
||||
|
||||
# refused: a request to the container gets 403, SWWAF_BAN_RESPONSE's
|
||||
# refused: a request to the container gets 403, SWW_BAN_RESPONSE's
|
||||
# default.
|
||||
refused() {
|
||||
code="$(curl --silent --output /dev/null --write-out '%{http_code}' \
|
||||
@@ -153,9 +153,9 @@ refused_from() {
|
||||
[ "$(status_from "$1" "$2")" = 403 ]
|
||||
}
|
||||
|
||||
# owner_of_state_dir <container>: print who owns /var/lib/smallwebwaf there.
|
||||
# owner_of_state_dir <container>: print who owns /var/lib/sww there.
|
||||
owner_of_state_dir() {
|
||||
docker exec "$1" stat --format '%U' /var/lib/smallwebwaf
|
||||
docker exec "$1" stat --format '%U' /var/lib/sww
|
||||
}
|
||||
|
||||
main() {
|
||||
@@ -164,91 +164,91 @@ main() {
|
||||
trap 'exit 1' HUP INT TERM
|
||||
|
||||
docker build --no-cache -t "$IMAGE" .
|
||||
docker build --no-cache --build-arg SMALLWEBWAF_IMAGE="$IMAGE" \
|
||||
docker build --no-cache --build-arg SWW_IMAGE="$IMAGE" \
|
||||
-t "$APP_IMAGE" deploy/example-app
|
||||
|
||||
docker network create "$NETWORK" >/dev/null
|
||||
docker volume create "$VOLUME" >/dev/null
|
||||
start_servewaf
|
||||
start_discriminator
|
||||
start_app
|
||||
echo "example-app: the health checks pass"
|
||||
|
||||
[ "$(owner_of_state_dir "$SERVEWAF")" = smallwebwaf ] ||
|
||||
fail "servewaf's container did not give the state directory to smallwebwaf"
|
||||
[ "$(owner_of_state_dir "$DISCRIMINATOR")" = sww ] ||
|
||||
fail "discriminator's container did not give the state directory to sww"
|
||||
[ "$(owner_of_state_dir "$APP")" = root ] ||
|
||||
fail "the app's container changed the state directory's owner"
|
||||
echo "example-app: only servewaf's container changes the state directory's owner"
|
||||
echo "example-app: only discriminator's container changes the state directory's owner"
|
||||
|
||||
page="$(curl --fail --silent --show-error --max-time 10 "http://$address/")" ||
|
||||
fail "no answer on port 8080"
|
||||
[ "$page" = "hello from the example app" ] || fail "port 8080 answered $page"
|
||||
wait_for "servewaf logged no request it allowed" \
|
||||
logged "$SERVEWAF" '"action":"forward"' '"servewaf_line":"report"'
|
||||
wait_for "discriminator logged no request it allowed" \
|
||||
logged "$DISCRIMINATOR" '"action":"forward"' '"discriminator_line":"report"'
|
||||
echo "example-app: rproxy passes a request to the app and its answer back"
|
||||
|
||||
refused || fail "a second request in a minute was not refused"
|
||||
wait_for "servewaf logged no ban" logged "$SERVEWAF" '"action":"rate_limited"'
|
||||
wait_for "discriminator logged no ban" logged "$DISCRIMINATOR" '"action":"rate_limited"'
|
||||
echo "example-app: a second request in a minute bans the client"
|
||||
|
||||
refused_from 203.0.113.9 /.env || fail "a probe for /.env was not refused"
|
||||
wait_for "servewaf logged no ban for the probe" \
|
||||
logged "$SERVEWAF" '"action":"banned"' '"rule_ids":["env-file"]'
|
||||
wait_for "discriminator logged no ban for the probe" \
|
||||
logged "$DISCRIMINATOR" '"action":"banned"' '"rule_ids":["env-file"]'
|
||||
refused_from 203.0.113.9 / || fail "the client of the probe was let through"
|
||||
wait_for "the client's next request did not make its ban permanent" \
|
||||
logged "$SERVEWAF" '"ban_expires":"permanent"'
|
||||
logged "$DISCRIMINATOR" '"ban_expires":"permanent"'
|
||||
echo "example-app: a probe for /.env bans the client, its next request for good"
|
||||
|
||||
docker exec "$SERVEWAF" sv stop smallwebwaf >/dev/null ||
|
||||
fail "sv stop smallwebwaf failed in servewaf's container"
|
||||
wait_for "servewaf did not stop in order" logged "$SERVEWAF" '"msg":"stopped"'
|
||||
docker exec "$DISCRIMINATOR" sv stop sww >/dev/null ||
|
||||
fail "sv stop sww failed in discriminator's container"
|
||||
wait_for "discriminator did not stop in order" logged "$DISCRIMINATOR" '"msg":"stopped"'
|
||||
[ "$(status_from 203.0.113.9 /)" = 200 ] ||
|
||||
fail "with servewaf stopped, the app did not answer through rproxy"
|
||||
fail "with discriminator stopped, the app did not answer through rproxy"
|
||||
wait_for "rproxy logged no request SWRP_DEFAULT_DISPOSITION decided" \
|
||||
logged "$APP" '"default_disposition":true'
|
||||
docker exec "$APP" /usr/local/bin/smallwebwaf healthcheck ||
|
||||
fail "with servewaf stopped, the app's health check failed"
|
||||
echo "example-app: with servewaf stopped, the app answers through rproxy"
|
||||
docker exec "$APP" /usr/local/bin/sww healthcheck ||
|
||||
fail "with discriminator stopped, the app's health check failed"
|
||||
echo "example-app: with discriminator stopped, the app answers through rproxy"
|
||||
|
||||
docker exec "$SERVEWAF" sv start smallwebwaf >/dev/null ||
|
||||
fail "sv start smallwebwaf failed in servewaf's container"
|
||||
wait_for "once servewaf had started again, the ban did not apply" \
|
||||
docker exec "$DISCRIMINATOR" sv start sww >/dev/null ||
|
||||
fail "sv start sww failed in discriminator's container"
|
||||
wait_for "once discriminator had started again, the ban did not apply" \
|
||||
refused_from 203.0.113.9 /
|
||||
echo "example-app: once servewaf has started again, bans apply again"
|
||||
echo "example-app: once discriminator has started again, bans apply again"
|
||||
|
||||
docker exec "$APP" sv stop smallwebwaf >/dev/null ||
|
||||
fail "sv stop smallwebwaf failed in the app's container"
|
||||
docker exec "$APP" sv stop sww >/dev/null ||
|
||||
fail "sv stop sww failed in the app's container"
|
||||
wait_for "rproxy did not stop in order" logged "$APP" '"msg":"stopped"'
|
||||
echo "example-app: sv stop stops rproxy in order"
|
||||
|
||||
for container in "$APP" "$SERVEWAF"; do
|
||||
for container in "$APP" "$DISCRIMINATOR"; do
|
||||
docker stop "$container" >/dev/null
|
||||
status="$(docker inspect --format '{{.State.ExitCode}}' "$container")"
|
||||
[ "$status" = 0 ] || fail "docker stop left exit status $status"
|
||||
done
|
||||
echo "example-app: docker stop stops each container in order"
|
||||
|
||||
docker rm "$APP" "$SERVEWAF" >/dev/null
|
||||
start_servewaf
|
||||
docker rm "$APP" "$DISCRIMINATOR" >/dev/null
|
||||
start_discriminator
|
||||
start_app
|
||||
refused || fail "the new servewaf container let the banned client through"
|
||||
wait_for "servewaf logged no request refused under the ban" \
|
||||
logged "$SERVEWAF" '"action":"banned"'
|
||||
echo "example-app: a new servewaf container on the same volume keeps the ban"
|
||||
refused || fail "the new discriminator container let the banned client through"
|
||||
wait_for "discriminator logged no request refused under the ban" \
|
||||
logged "$DISCRIMINATOR" '"action":"banned"'
|
||||
echo "example-app: a new discriminator container on the same volume keeps the ban"
|
||||
|
||||
docker rm --force "$SERVEWAF" >/dev/null
|
||||
start_moved_servewaf
|
||||
docker rm --force "$DISCRIMINATOR" >/dev/null
|
||||
start_moved_discriminator
|
||||
echo "example-app: the run script gives the state files' directory named" \
|
||||
"by SWWAF_STATE_DIR_FILE to the smallwebwaf user"
|
||||
"by SWW_STATE_DIR_FILE to the sww user"
|
||||
|
||||
docker rm --force "$SERVEWAF" >/dev/null
|
||||
docker run --detach --name "$SERVEWAF" --network "$NETWORK" \
|
||||
--env SMALLWEBWAF_COMMAND=servewaf \
|
||||
--env SWWAF_STATE_DIR=/srv/missing \
|
||||
--env SWWAF_LOOKUP_SOURCE=off \
|
||||
docker rm --force "$DISCRIMINATOR" >/dev/null
|
||||
docker run --detach --name "$DISCRIMINATOR" --network "$NETWORK" \
|
||||
--env SWW_COMMAND=discriminator \
|
||||
--env SWW_STATE_DIR=/srv/missing \
|
||||
--env SWW_LOOKUP_SOURCE=off \
|
||||
"$IMAGE" >/dev/null
|
||||
wait_for "servewaf did not report the missing state directory" \
|
||||
logged "$SERVEWAF" "SWWAF_STATE_DIR cannot be written"
|
||||
echo "example-app: servewaf reports a state directory that does not exist"
|
||||
wait_for "discriminator did not report the missing state directory" \
|
||||
logged "$DISCRIMINATOR" "SWW_STATE_DIR cannot be written"
|
||||
echo "example-app: discriminator reports a state directory that does not exist"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
+20
-20
@@ -1,50 +1,50 @@
|
||||
#!/bin/sh
|
||||
# script/run: build bin/smallwebwaf with script/build and run servewaf and
|
||||
# script/run: build bin/sww with script/build and run discriminator and
|
||||
# rproxy on the host, with the settings in the environment, until rproxy
|
||||
# exits or the script is told to stop. rproxy listens on port 8080 unless
|
||||
# SWRP_LISTEN_ADDR says otherwise, in front of the app at SWRP_UPSTREAM_URL.
|
||||
# servewaf listens on port 8090 unless SWWAF_LISTEN_ADDR says otherwise, and
|
||||
# discriminator listens on port 8090 unless SWW_LISTEN_ADDR says otherwise, and
|
||||
# rproxy asks it there unless SWRP_WAF_BACKEND says otherwise. Unless
|
||||
# SWWAF_STATE_DIR is set, the state files go in bin/state, beside the binary,
|
||||
# and unless SWWAF_RULES_DIR is set, the rule files are those of share/rules.d,
|
||||
# SWW_STATE_DIR is set, the state files go in bin/state, beside the binary,
|
||||
# and unless SWW_RULES_DIR is set, the rule files are those of share/rules.d,
|
||||
# which the image ships.
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||
|
||||
SERVEWAF=""
|
||||
DISCRIMINATOR=""
|
||||
RPROXY=""
|
||||
|
||||
# stop_both: stop what runs, and wait for it, so that servewaf writes its state
|
||||
# stop_both: stop what runs, and wait for it, so that discriminator writes its state
|
||||
# files.
|
||||
stop_both() {
|
||||
trap '' HUP INT TERM
|
||||
kill $SERVEWAF $RPROXY 2>/dev/null || true
|
||||
kill $DISCRIMINATOR $RPROXY 2>/dev/null || true
|
||||
wait || true
|
||||
}
|
||||
|
||||
main() {
|
||||
"$SCRIPT_DIR/build"
|
||||
if [ -z "${SWWAF_STATE_DIR+set}" ]; then
|
||||
SWWAF_STATE_DIR="$ROOT/bin/state"
|
||||
export SWWAF_STATE_DIR
|
||||
mkdir -p "$SWWAF_STATE_DIR"
|
||||
if [ -z "${SWW_STATE_DIR+set}" ]; then
|
||||
SWW_STATE_DIR="$ROOT/bin/state"
|
||||
export SWW_STATE_DIR
|
||||
mkdir -p "$SWW_STATE_DIR"
|
||||
fi
|
||||
if [ -z "${SWWAF_RULES_DIR+set}" ]; then
|
||||
SWWAF_RULES_DIR="$ROOT/share/rules.d"
|
||||
export SWWAF_RULES_DIR
|
||||
if [ -z "${SWW_RULES_DIR+set}" ]; then
|
||||
SWW_RULES_DIR="$ROOT/share/rules.d"
|
||||
export SWW_RULES_DIR
|
||||
fi
|
||||
SWWAF_LISTEN_ADDR="${SWWAF_LISTEN_ADDR:-:8090}"
|
||||
SWRP_WAF_BACKEND="${SWRP_WAF_BACKEND:-http://127.0.0.1:${SWWAF_LISTEN_ADDR##*:}}"
|
||||
export SWWAF_LISTEN_ADDR SWRP_WAF_BACKEND
|
||||
SWW_LISTEN_ADDR="${SWW_LISTEN_ADDR:-:8090}"
|
||||
SWRP_WAF_BACKEND="${SWRP_WAF_BACKEND:-http://127.0.0.1:${SWW_LISTEN_ADDR##*:}}"
|
||||
export SWW_LISTEN_ADDR SWRP_WAF_BACKEND
|
||||
|
||||
trap stop_both EXIT
|
||||
trap 'exit 1' HUP INT TERM
|
||||
|
||||
"$ROOT/bin/smallwebwaf" servewaf &
|
||||
SERVEWAF=$!
|
||||
"$ROOT/bin/smallwebwaf" rproxy &
|
||||
"$ROOT/bin/sww" discriminator &
|
||||
DISCRIMINATOR=$!
|
||||
"$ROOT/bin/sww" rproxy &
|
||||
RPROXY=$!
|
||||
wait "$RPROXY"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user