docker-mailserver/test/mail_fail2ban.bats

201 lines
7.2 KiB
Plaintext
Raw Normal View History

load 'test_helper/common'
function setup_file() {
tests(fix): Adjust for local testing conditions (#2606) * tests(fix): Increase some timeouts Running tests locally via a VM these tests would fail sometimes due to the time from being queued and Amavis actually processing being roughly around 30 seconds. There should be no harm in raising this to 60 seconds, other than delaying a failure case which will ripple through other time sensitive tests. It's better to pass when functionality is actually correct but just needs a bit longer to complete. * tests(fix): Don't setup an invalid hostname During container startup `helpers/dns.sh` would panic with `hostname -f` failing. Dropping `--domainname` for this container is fine and does not affect the point of it's test. --- It's unclear why this does not occur in CI. Possibly changes within the docker daemon since as CI runs docker on Ubuntu 20.04? (2020). For clarity, this may be equivalent to setting a hostname of `domain.com.domain.com`, or `--hostname` value truncated the NIS domain (`--domainname`) of the same value. IIRC, it would still fail with both options using different values if `--hostname` was multi-label. I believe I've documented how non-deterministic these options can be across different environments. `--hostname` should be preferred. There doesn't seem to be any reason to actually need `--domainname` (which is NIS domain name, unrelated to the DNS domain name). We still need to properly investigate reworking our ENV support that `dns.sh` manages. --- Containers were also not removing themselves after failures either (missing teardown). Which would cause problems when running tests again. * chore: Normalize white-space Sets a consistent indent size of 2 spaces. Previously this varied a fair bit, sometimes with tabs or mixed tabs and spaces. Some formatting with blank lines. Easier to review with white-space in diff ignored. Some minor edits besides blank lines, but no change in functionality. * fix: `setup.sh` target container under test Some of the `setup.sh` commands did not specify the container which was problematic if another `docker-mailserver` container was running, causing test failures. This probably doesn't help with `test/no_container.bats`, but at least prevents `test/tests.bats` failing at this point.
2022-05-30 00:53:30 +00:00
local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run --rm -d --name mail_fail2ban \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_FAIL2BAN=1 \
-e POSTSCREEN_ACTION=ignore \
--cap-add=NET_ADMIN \
tests: Ensure excessive FD limits are avoided (#2730) * tests: Ensure excessive FD limits are avoided Processes that run as daemons (`postsrsd` and `fail2ban-server`) initialize by closing all FDs (File Descriptors). This behaviour queries that maximum limit and iterates through the entire range even if only a few FDs are open. In some environments (Docker, limit configured by distro) this can be a range exceeding 1 billion (from kernel default of 1024 soft, 4096 hard), causing an 8 minute delay with heavy CPU activity. `postsrsd` has since been updated to use `close_range()` syscall, and `fail2ban` will now iterate through `/proc/self/fd` (open FDs) which should resolve the performance hit. Until those updates reach our Docker image, we need to workaround it with `--ulimit` option. NOTE: If `docker.service` on a distro sets `LimitNOFILE=` to approx 1 million or lower, it should not be an issue. On distros such as Fedora 36, it is `LimitNOFILE=infinity` (approx 1 billion) that causes excessive delays. * chore: Use Docker host limits instead Typically on modern distros with systemd, this should equate to 1024 (soft) and 512K (hard) limits. A distro may override the built-in global defaults systemd sets via setting `DefaultLimitNOFILE=` in `/etc/systemd/user.conf` and `/etc/systemd/system.conf`. * tests(fix): Better prevent non-deterministic failures - `no_containers.bats` tests the external script `setup.sh` (without `-c`). It's expected that no existing DMS container is running - otherwise it may attempt to use that container and fail. Detect this and fail early via `setup_file()` step. - `mail_hostname.bats` had a odd timing failure with teardown due to the last tests bringing the containers down earlier (`docker stop` paired with the `docker run --rm`). Adding a moment of delay via `sleep` helps avoid that false positive scenario.
2022-08-22 23:24:23 +00:00
--hostname mail.my-domain.com \
--tty \
--ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \
"${NAME}"
tests(fix): Adjust for local testing conditions (#2606) * tests(fix): Increase some timeouts Running tests locally via a VM these tests would fail sometimes due to the time from being queued and Amavis actually processing being roughly around 30 seconds. There should be no harm in raising this to 60 seconds, other than delaying a failure case which will ripple through other time sensitive tests. It's better to pass when functionality is actually correct but just needs a bit longer to complete. * tests(fix): Don't setup an invalid hostname During container startup `helpers/dns.sh` would panic with `hostname -f` failing. Dropping `--domainname` for this container is fine and does not affect the point of it's test. --- It's unclear why this does not occur in CI. Possibly changes within the docker daemon since as CI runs docker on Ubuntu 20.04? (2020). For clarity, this may be equivalent to setting a hostname of `domain.com.domain.com`, or `--hostname` value truncated the NIS domain (`--domainname`) of the same value. IIRC, it would still fail with both options using different values if `--hostname` was multi-label. I believe I've documented how non-deterministic these options can be across different environments. `--hostname` should be preferred. There doesn't seem to be any reason to actually need `--domainname` (which is NIS domain name, unrelated to the DNS domain name). We still need to properly investigate reworking our ENV support that `dns.sh` manages. --- Containers were also not removing themselves after failures either (missing teardown). Which would cause problems when running tests again. * chore: Normalize white-space Sets a consistent indent size of 2 spaces. Previously this varied a fair bit, sometimes with tabs or mixed tabs and spaces. Some formatting with blank lines. Easier to review with white-space in diff ignored. Some minor edits besides blank lines, but no change in functionality. * fix: `setup.sh` target container under test Some of the `setup.sh` commands did not specify the container which was problematic if another `docker-mailserver` container was running, causing test failures. This probably doesn't help with `test/no_container.bats`, but at least prevents `test/tests.bats` failing at this point.
2022-05-30 00:53:30 +00:00
# Create a container which will send wrong authentications and should get banned
docker run --name fail-auth-mailer \
-e MAIL_FAIL2BAN_IP="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_fail2ban)" \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test \
-d "${NAME}" \
tail -f /var/log/faillog
wait_for_finished_setup_in_container mail_fail2ban
}
function teardown_file() {
tests(fix): Adjust for local testing conditions (#2606) * tests(fix): Increase some timeouts Running tests locally via a VM these tests would fail sometimes due to the time from being queued and Amavis actually processing being roughly around 30 seconds. There should be no harm in raising this to 60 seconds, other than delaying a failure case which will ripple through other time sensitive tests. It's better to pass when functionality is actually correct but just needs a bit longer to complete. * tests(fix): Don't setup an invalid hostname During container startup `helpers/dns.sh` would panic with `hostname -f` failing. Dropping `--domainname` for this container is fine and does not affect the point of it's test. --- It's unclear why this does not occur in CI. Possibly changes within the docker daemon since as CI runs docker on Ubuntu 20.04? (2020). For clarity, this may be equivalent to setting a hostname of `domain.com.domain.com`, or `--hostname` value truncated the NIS domain (`--domainname`) of the same value. IIRC, it would still fail with both options using different values if `--hostname` was multi-label. I believe I've documented how non-deterministic these options can be across different environments. `--hostname` should be preferred. There doesn't seem to be any reason to actually need `--domainname` (which is NIS domain name, unrelated to the DNS domain name). We still need to properly investigate reworking our ENV support that `dns.sh` manages. --- Containers were also not removing themselves after failures either (missing teardown). Which would cause problems when running tests again. * chore: Normalize white-space Sets a consistent indent size of 2 spaces. Previously this varied a fair bit, sometimes with tabs or mixed tabs and spaces. Some formatting with blank lines. Easier to review with white-space in diff ignored. Some minor edits besides blank lines, but no change in functionality. * fix: `setup.sh` target container under test Some of the `setup.sh` commands did not specify the container which was problematic if another `docker-mailserver` container was running, causing test failures. This probably doesn't help with `test/no_container.bats`, but at least prevents `test/tests.bats` failing at this point.
2022-05-30 00:53:30 +00:00
docker rm -f mail_fail2ban fail-auth-mailer
}
#
# processes
#
@test "checking process: fail2ban (fail2ban server enabled)" {
run docker exec mail_fail2ban /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/python3 /usr/bin/fail2ban-server'"
assert_success
}
#
# fail2ban
#
@test "checking fail2ban: localhost is not banned because ignored" {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep 'IP list:.*127.0.0.1'"
assert_failure
run docker exec mail_fail2ban /bin/sh -c "grep 'ignoreip = 127.0.0.1/8' /etc/fail2ban/jail.conf"
assert_success
}
@test "checking fail2ban: fail2ban-fail2ban.cf overrides" {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get loglevel | grep DEBUG"
assert_success
}
@test "checking fail2ban: fail2ban-jail.cf overrides" {
2021-04-11 15:33:39 +00:00
FILTERS=(dovecot postfix postfix-sasl)
for FILTER in "${FILTERS[@]}"; do
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} bantime"
assert_output 1234
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} findtime"
assert_output 321
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} maxretry"
assert_output 2
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'dovecot', 'addaction', 'nftables-multiport']\""
assert_output "['set', 'dovecot', 'addaction', 'nftables-multiport']"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix', 'addaction', 'nftables-multiport']\""
assert_output "['set', 'postfix', 'addaction', 'nftables-multiport']"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix-sasl', 'addaction', 'nftables-multiport']\""
assert_output "['set', 'postfix-sasl', 'addaction', 'nftables-multiport']"
done
}
@test "checking fail2ban: ban ip on multiple failed login" {
# can't pipe the file as usual due to postscreen. (respecting postscreen_greet_wait time and talking in turn):
# shellcheck disable=SC1004
for _ in {1,2}
do
docker exec fail-auth-mailer /bin/bash -c \
'exec 3<>/dev/tcp/${MAIL_FAIL2BAN_IP}/25 && \
while IFS= read -r cmd; do \
head -1 <&3; \
[[ ${cmd} == "EHLO"* ]] && sleep 6; \
echo ${cmd} >&3; \
done < "/tmp/docker-mailserver-test/auth/smtp-auth-login-wrong.txt"'
done
sleep 5
FAIL_AUTH_MAILER_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' fail-auth-mailer)
# Checking that FAIL_AUTH_MAILER_IP is banned in mail_fail2ban
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep '${FAIL_AUTH_MAILER_IP}'"
assert_success
2022-10-05 10:19:49 +00:00
# Checking that FAIL_AUTH_MAILER_IP is banned by nftables
run docker exec mail_fail2ban /bin/sh -c "nft list set inet f2b-table addr-set-postfix-sasl"
assert_output --partial "elements = { ${FAIL_AUTH_MAILER_IP} }"
}
@test "checking fail2ban: unban ip works" {
FAIL_AUTH_MAILER_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' fail-auth-mailer)
docker exec mail_fail2ban fail2ban-client set postfix-sasl unbanip "${FAIL_AUTH_MAILER_IP}"
sleep 5
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep 'IP list:.*${FAIL_AUTH_MAILER_IP}'"
assert_failure
# Checking that FAIL_AUTH_MAILER_IP is unbanned by nftables
2022-10-05 10:19:49 +00:00
run docker exec mail_fail2ban /bin/sh -c "nft list set inet f2b-table addr-set-postfix-sasl"
refute_output --partial "${FAIL_AUTH_MAILER_IP}"
}
@test "checking fail2ban ban" {
2022-10-15 10:01:59 +00:00
# Ban single IP address
run docker exec mail_fail2ban fail2ban ban 192.0.66.7
assert_success
assert_output "Banned custom IP: 1"
run docker exec mail_fail2ban fail2ban
assert_success
assert_output --regexp "Banned in custom:.*192\.0\.66\.7"
2022-10-05 10:19:49 +00:00
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
assert_success
assert_output --partial "elements = { 192.0.66.7 }"
run docker exec mail_fail2ban fail2ban unban 192.0.66.7
assert_success
assert_output --partial "Unbanned IP from custom: 1"
2022-10-05 10:19:49 +00:00
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
refute_output --partial "192.0.66.7"
2022-10-15 10:01:59 +00:00
# Ban IP network
run docker exec mail_fail2ban fail2ban ban 192.0.66.0/24
assert_success
assert_output "Banned custom IP: 1"
run docker exec mail_fail2ban fail2ban
assert_success
assert_output --regexp "Banned in custom:.*192\.0\.66\.0/24"
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
assert_success
assert_output --partial "elements = { 192.0.66.0/24 }"
run docker exec mail_fail2ban fail2ban unban 192.0.66.0/24
assert_success
assert_output --partial "Unbanned IP from custom: 1"
run docker exec mail_fail2ban nft list set inet f2b-table addr-set-custom
refute_output --partial "192.0.66.0/24"
2022-10-05 10:19:49 +00:00
}
@test "checking FAIL2BAN_BLOCKTYPE is really set to drop" {
run docker exec mail_fail2ban bash -c 'nft list table inet f2b-table'
assert_success
assert_output --partial 'tcp dport { 110, 143, 465, 587, 993, 995, 4190 } ip saddr @addr-set-dovecot drop'
assert_output --partial 'tcp dport { 25, 110, 143, 465, 587, 993, 995 } ip saddr @addr-set-postfix-sasl drop'
assert_output --partial 'tcp dport { 25, 110, 143, 465, 587, 993, 995, 4190 } ip saddr @addr-set-custom drop'
}
@test "checking setup.sh: setup.sh fail2ban" {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.4"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.5"
2021-05-15 09:11:10 +00:00
sleep 10
2021-05-15 09:11:10 +00:00
run ./setup.sh -c mail_fail2ban fail2ban
assert_output --regexp '^Banned in dovecot:.*192\.0\.66\.4'
assert_output --regexp '^Banned in dovecot:.*192\.0\.66\.5'
2021-05-15 09:11:10 +00:00
run ./setup.sh -c mail_fail2ban fail2ban unban 192.0.66.4
2021-05-15 09:11:10 +00:00
assert_output --partial "Unbanned IP from dovecot: 1"
run ./setup.sh -c mail_fail2ban fail2ban
assert_output --regexp "^Banned in dovecot:.*192\.0\.66\.5"
2021-05-15 09:11:10 +00:00
run ./setup.sh -c mail_fail2ban fail2ban unban 192.0.66.5
2021-05-15 09:11:10 +00:00
assert_output --partial "Unbanned IP from dovecot: 1"
run ./setup.sh -c mail_fail2ban fail2ban unban
scripts: refactored scripts located under `target/bin/` (#2500) * refactored scripts located under `target/bin/` The scripts under `target/bin/` now use the new log and I replaced some `""` with `''` on the way. The functionality stays the same, this mostly style and log. * corrected fail2ban (script and tests) * corrected OpenDKIM log output in tests * reverted (some) changes to `sedfile` Moreover, a few messages for BATS were streamlined and a regression in the linting script reverted. * apple PR feedback * improve log output from `fail2ban` script The new output has a single, clear message with the '[ ERROR ] ' prefix, and then output that explains the error afterwards. This is coherent with the logging style which should be used while providing more information than just a single line about IPTables not functioning. * simplified `setquota` script * consistently named the `__usage` function Before, scripts located under `target/bin/` were using `usage` or `__usage`. Now, they're using `__usage` as they should. * improved `sedfile` With `sedfile`, we cannot use the helper functions in a nice way because it is used early in the Dockerfile at a stage where the helper scripts are not yet copied. The script has been adjusted to be canonical with all the other scripts under `target/bin/`. * fixed tests * removed `__usage` from places where it does not belong `__usage` is to be used on wrong user input, not on other failures as well. This was fixed in `delquota` and `setquota`. * apply PR review feedback
2022-03-26 08:30:09 +00:00
assert_output --partial "You need to specify an IP address: Run"
}
#
# supervisor
#
@test "checking restart of process: fail2ban (fail2ban server enabled)" {
run docker exec mail_fail2ban /bin/bash -c "pkill fail2ban && sleep 10 && ps aux --forest | grep -v grep | grep '/usr/bin/python3 /usr/bin/fail2ban-server'"
assert_success
}