* first adjustments to use Fail2Ban with nftables
* replace `iptables` -> `nftables` and adjust tests
nftables lists IPs a bit differently , so the order was adjusted for the
tests to be more flexible.
* line correction in mailserver.env
* change from `.conf` -> `.local` and remove redundant config
* revert HEREDOC to `echo`
Co-authored-by: Casper <casperklein@users.noreply.github.com>
* chore: Normalize container setup
Easier to grok what is different between configurations.
- Container name usage replaced with variable
- Volumes defined earlier and redeclared when relevant (only real difference is `VOLUME_LETSENCRYPT`)
- Contextual comment about the `acme.json` copy.
- Quoting `SSL_TYPE`, `SSL_DOMAIN` and `-h` values for syntax highlighting.
- Moved `-t` and `${NAME}` to separate line.
- Consistent indentation.
* chore: DRY test logic
Extracts out repeated test logic into methods
* chore: Scope configs to individual test cases (1/3)
- Preparation step for shifting out the container configs to their own scoped test cases. Split into multiple commits to ease reviewing by diffs for this change.
- Re-arrange the hostname and domain configs to match the expected order of the new test cases.
- Shuffle the hostname and domainname grouped tests into tests per container config scope.
- Collapse the `acme.json` test cases into single test case.
* chore: Scope configs to individual test cases (2/3)
- Shifts the hostname and domainname container configs into their respective scoped test cases.
- Moving the `acme.json` container config produces a less favorable diff, so is deferred to a follow-up commit.
- Test cases updated to refer to their `${CONTAINER_NAME}` var instead of the hard-coded string name.
* chore: Scope configs to individual test cases (3/3)
Final commit to shift out the container configs.
- Common vars are exported in `setup_file()` for the test cases to use without needing to repeat the declaration in each test case.
- `teardown_file()` shifts container removal at end of scoped test case.
* chore: Adapt to `common_container_setup` template
- `CONTAINER_NAME` becomes `TEST_NAME` (`common.bash` helper via `init_with_defaults`).
- `docker run ...` and related configuration is now outsourced to the `common.bash` helper, only extra args that the default template does not cover are defined in the test case.
- `TARGET_DOMAIN`establishes the domain folder name for `/etc/letsencrypt/live`.
- `_should*` methods no longer manage a `CONTAINER_NAME` arg, instead using the `TEST_NAME` global that should be valid as test is run as a sequence of test cases.
- `PRIVATE_CONFIG` and the `private_config_path ...` are now using the global `TEST_TMP_CONFIG` initialized at the start of each test case, slightly different as not locally defined/scoped like `PRIVATE_CONFIG` would be within the test case, hence the explicit choice of a different name for context.
* chore: Minor tweaks
- Test case comment descriptions.
- DRY: `docker rm -f` lines moved to `teardown()`
- Use `wait_for_service` helper instead of checking the `changedetector` script itself is running.
- There is a startup delay before the `changedetector` begins monitoring, wait until it ready event is logged.
- Added a helper to query logs for a service (useful later).
- `/bin/sh` commands reduced to `sh`.
- Change the config check to match and compare output, not number of lines returned. Provides better failure output by bats to debug against.
* chore: Add more test functions for `acme.json`
This just extracts out existing logic from the test case to functions to make the test case itself more readable/terse.
* chore: Housekeeping
No changes, just moving logic around and grouping into inline functions, with some added comments.
* chore: Switch to `example.test` certs
This also required copying the source files to match the expected letsencrypt file structure expected in the test/container usage.
* chore: Delete `test/config/letsencrypt/`
No longer necessary, using the `example.test/` certs instead.
These letsencrypt certs weren't for the domains they were used for, and of course long expired.
* chore: Housekeeping
Add more maintainer comments, rename some functions.
* tests: Expand `acme.json` extraction coverage
Finally able to add more test coverage! :)
- Two new methods to validate expected success/failure of extraction for a given FQDN.
- Added an RSA test prior to the wildcard to test a renewal simulation (just with different cert type).
- Added extra method to make sure we're detecting multiple successful change events, not just a previous logged success (false positive).
* tests: Refactor the negotiate_tls functionality
Covers all ports (except POP) and correctly tests against expected verification status with new `example.test` certs.
The `FQDN` var will be put to use in a follow-up commit.
* tests: Verify the certs contain the expected FQDNs
* chore: Extract TLS test methods into a separate helper script
Can be useful for other TLS tests to utilize.
* chore: Housekeeping
* chore: Fix test typo
There was a mismatch between the output and expected output between these two files "find key for" and "find key & cert for". Changed to "find key and/or cert for" to make the warning more clear that it's issued for either or both failure conditions.
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Dovecot quota support would log auth failures when Postfix validated incoming mail to accept/reject and the `check_policy_service` for `quota-status` was queried with a recipient that was an account alias.
When Dovecot is not aware of the user account, it will not be able to check a quota and inform Postfix that everything is fine, Postfix will accept the mail and send it to Dovecot, where if the quota is exceeded will result in a bounce back to the sender. This is considered "backscatter" and can be abused by spammers forging the sender address which can get your server blacklisted.
The solution is to either disable quota support `ENABLE_QUOTAS=0`, or as a workaround, add dummy accounts to Dovecot userdb for aliases in `postfix-virtual.cf` (not `postfix-aliases.cf`), these dummy accounts will map to the real user account mailbox (real users are defined in `postfix-accounts.cf`).
The workaround is naive, in that we only check for basic 1-to-1 alias mapping to real accounts. This will still be an issue for aliases that map to another alias or multiple addresses (real or alias). Unfortunately Postfix will not expand aliases until accepting mail where this would be too late.
A better solution is to proxy the `check_policy_service` from Dovecot `quota-status` that Postfix queries in `main.cf:smtpd_recipient_restrictions`, however this requires a fair amount more of additional work and still requires an implementation to recursively query aliases for nested or multiple address mappings, which can then be forwarded to the `quota-status` service configured by Dovecot in `/etc/dovecot/conf.d/90-quota.conf`.
LDAP users are unaffected as quota support is not supported/implemented with `docker-mailserver` at this time, it is always considered disabled when using LDAP.
---
Additionally Dovecot configuration for `passdb` has been fixed to use the correct password hash scheme of `SHA512-CRYPT`.
Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
* chore(refactor): DRY up the `_setup_ssl` method
- `/etc/postfix/ssl` was a bit misleading in usage here. As a maintainer (of my own contribution!) I was confused why only `/etc/postfix/ssl` was referenced and not `/etc/dovecot/ssl`.
- The postfix specific path is unnecessary, dovecot was referencing it via it's config, the same can be done from postfix to a generic DMS specific config location instead.
- This location is defined and created early as `/etc/dms/tls` (with var `DMS_TLS_PATH`). All usage of `/etc/postfix/ssl` has been replaced, making it easier to grok. Several `mkdir` commands related to this have been dropped as a result.
- Likewise, a related `TMP_DMS_TLS_PATH` var provides a reference to the config volume path `/tmp/docker-mailserver` which is used for conditions on presently hard-coded paths.
- Other values that benefit from being DRY have been lifted up into vars. Definitely easier to follow now and makes some further opportunities clearer to tackle in a future refactor.
- `chmod` has been updated where appropriate. Public key/cert is acceptable to have as readable by non-root users (644). The custom type with single fullchain file was not root accessible only, but should as it contains a private key.
- That said, the security benefit can be a bit moot due to source files that were copied remain present, the user would be responsible to ensure similar permissions on their source files.
- I've not touched LetsEncrypt section as I don't have time to investigate into that yet (not familiar with that portion).
---
* chore: Remove mkcert logic and dovecot cert
- No longer serving a purpose.
- Our own TLS startup script handles a variety of cert scenarios, while the dropped code was always generating a self-signed cert and persisting an unused cert regardless with `ONE_DIR=1`.
- To avoid similar issues that DH params had with doveadm validating filepath values in the SSL config, the default dummy values match postfix pointing to "snakeoil" cert. That serves the same purpose as mkcert was covering in the image.
- Bonus, no more hassle with differing mkcert target paths for users replacing our supplied Dovecot with the latest community edition.
---
* Error handling for SSL_TYPE
- Added a panic utility to exit early when SSL_TYPE conditions are misconfigured.
- Some info text had order of key/cert occurrence swapped to be consistent with key then cert.
- Some existing comments moved and rephrased.
- Additional comments added.
- `-f` test for cert files instead of `-e` (true also for directories/devices/symlinks).
- _notify messages lifted out of conditionals so that they always output when the case is hit.
- ~~Empty SSL_TYPE collapsed into catch all panic, while it's contents is now mapped to a new 'disabled' value.~~
---
* Use sedfile + improve sed expressions + update case style
- Uses sedfile when appropriate (file change intentional, not optional match/check).
- sed expressions modified to be DRY and reduce escaping via `-r` flag (acceptable if actual text content contains no `?`,`+`,`()` or `{}` characters, [otherwise they must be escaped](https://www.gnu.org/software/sed/manual/html_node/Extended-regexps.html)).
- sed captures anything matched between the parenthesis`()` and inserts it via `\1` as part of the replacement.
- case statements adopt the `(` prefix, adopting recent shell style for consistency.
---
* Refactor SSL_TYPE=disabled
- Postfix is also disabled now.
- Included heavy inline documentation reference for maintainers.
- Dropped an obsolete postfix config option 'use_tls' on the relayhost function, it was replaced by 'security_level'.
---
* I'm a friggin' sed wizard now
- The `modern` TLS_LEVEL is the default values for the configs they modify. As such, `sedfile` outputs an "Error" which isn't an actual concern, back to regular `sed`.
- I realized that multiple edits for the same file can all be done at once via `-e` (assuming other sed options are the same for each operation), and that `g` suffix is global scope for single line match, not whole file (default as sed iterates through individual lines).
- Some postfix replacements have `smtp` and `smtpd` lines, collapsed into a single `smtpd?` instead now that I know sed better.
---
* tests(fix): Tests that require SSL/TLS to pass
- SSL_TYPE=snakeoil added as temporary workaround.
- nmap tests are being dropped. These were added about 4-5 years ago, I have since made these redundant with the `testssl.sh` tests.
- Additionally the `--link` option is deprecated and IIRC these grades were a bit misleading when I initially used nmap in my own TLS cipher suite update PRs in the past.
- The removed SSL test is already handled in mail_ssl_manual.bats
ldap test:
- Replace `--link` alias option with `--network` and alias assignment.
- Parameterized some values and added the `SSL_TYPE` to resolve the starttls test failure.
privacy test:
- Also needed `SSL_TYPE` to pass the starttls test.
`tests.bats` had another starttls test for imap:
- Workaround for now is to give the main test container `SSL_TYPE=snakeoil`.
---
* Remove the expired lets-encrypt cert
This expired in March 2021. It was originally required when first added back in 2016 as LetsEncrypt was fairly new and not as broadly accepted into OS trust stores.
No longer the case today.
---
* chore: Housekeeping
Not required for this PR branch, little bit of tidying up while working on these two test files.
- privacy test copied over content when extracted from `tests.bats` that isn't relevant.
- ldap test was not as easy to identify the source of DOVECOT_TLS. Added comment to make the prefix connection to `configomat.sh` and `.ext` files more easier to find.
- Additionally converted the two localhost FQDN to vars.
---
* Default SSL_TYPE becomes `''` (aka equivalent to desired `disabled` case)
- This is to prevent other tests from failing by hitting the panic catchall case.
- More ideal would be adjusting tests to default to `disabled`, rather than treating `disabled` as an empty / unset SSL_TYPE value.
---
* Add inline documentation for `dms_panic`
- This could later be better formatted and placed into contributor docs.
Panic with kill (shutdown) not exit (errex):
- `kill 1` from `_shutdown` will send SIGTERM signal to PID 1 (init process).
- `exit 1` within the `start-mailserver.sh` init scripts context, will just exit the initialization script leaving the container running when it shouldn't.
The two previous `_shutdown` methods can benefit from using `dms_panic` wrapper instead to standardize on panic messages.
* feat: Change Postfix smtpd_tls key and cert files to chain_files
Since Postfix 3.4, `smtpd_tls_cert_file` and `smtpd_tls_key_file` have been deprecated in favor of `smtpd_tls_chain_files` which supports a list of values where a single or sequence of file paths provide a private key followed by it's certificate chain.
* feat: Dual certificate support
`smtpd_tls_chain_files` allows for multiple key+cert bundles so that you can provide different key types, such as ECDSA and RSA.
To maintain compatibility with the current CERT/KEY ENV vars only a 2nd certificate is supported.
Since Dovecot 2.2.31 a related feature is also available, but it is limited to only providing one alternative certificate via separate cert and key settings.
---
This feature enables support for multiple certificates, eg for serving modern ECDSA certs with RSA as fallback.
* chore: Refactor variable names to meet style guide
Improved some comments too.
* chore: Have function definitions respect style guide
* chore: Minor edits to comments
* chore: Expand on comments for maintenance, alert of insecure config
When `SSL_TYPE` isn't properly setup, we're still offering SSL connections but not warning in logs about the insecurity of such, or why a misconfiguration may have occurred.
This commit more clearly communicates to the user that they should look into the issue before considering deploying to production.
The `TODO` comments communicate to any future maintainer to consider treating these improper configs as disabling TLS instead.
* fix: Use `snakeoil` cert
I mistakenly thought this was placeholder text, which broke some tests. This adds the two files in the correct order (private key followed by cert/chain), to fix that issue.
* fix: Disable alt cert for Dovecot if necessary
Certain scenarios may persist state of previously configured alt cert via ENV vars that are removed from a future run. If the config is not reset to original immutable state, this will correctly disable the config from using alt cert unintentionally.
* fix: Satisfy ShellCheck lint
By switching from string var to array / list expansion, this better stores the extracted result and applies it in a manner that ShellCheck linting approves, removing the need to disable the rule.
* feat: Support dual cert test
Few tweaks to the test script allows re-purposing it for covering dual cert support as well.
* chore: Rearranged cert and key lines
A little reorganization, mostly placing private key ahead of related cert lines.
* chore: Refactor `_set_certificate`
This should make the parameters a little less confusing.
Previously was 3 parameters, but the Postfix parameter (1st) may look like two variables if you don't pay attention to the surrounding quotes; while the Dovecot parameters (2nd + 3rd) would have an opposing order. There was also a variant where the `FULLKEYCHAIN` var was passed in three times.
Now it's two params, with the 2nd param as an optional one. If the 2nd param is provided, then the two params are in the order of private key then certificate, otherwise if only a single parameter it's a single PEM file with the full cert chain and private key bundled.
This avoids implying that Postfix and Dovecot might use different files.
* chore: Document current state of `SSL_TYPE` logic better
Inlined for the benefit of anyone else maintaining this section if I'm unable to address the concerns within my own time.
* docs: ENV vars
`TLS_LEVEL=old` isn't in the codebase anymore, not likely to be relevant to retain.
No point in documenting what is considered invalid / unsupported config value in the first place for `SSL_TYPE`.
`SSL_TYPE=manual` was missing documentation for both related file path ENV vars, they've been added along with their alt fallback variants.
* chore: Update Dovecot LMTP SSL test config
Not sure how relevant this is, the file isn't complete sync with the main dovecot `10-ssl.conf` config, adding the support just in case.
* chore: Rename `FULLKEYCHAIN` to avoid confusion
There doesn't appear to be a standardized name for this type of file bundle, and `keychain` may be misleading (fullkeychain often provides macOS keychain results on search engines).
Opting for a more explicit `KEY_WITH_FULLCHAIN` name instead.
* fix: Invalid var name
`_set_certificate` refactor commit accidentally changed a var name and committed that breaking the dual cert support (thanks tests!).
* test: Refactor `mail_ssl_manual.bats`
Proper test return values instead of `wc -l` based checking.
Tests with dual cert support active, tests that feature (to better detect failure case.
Third test case was unable to verify new self-signed certificate, added new certs signed with self-signed root CA.
Adjusted openssl `CApath` parameter to use `CAfile` instead as `letsencrypt` cert was replaced thus CA cert is missing from the system trust store.
* test: Properly check for files in `mail_ssl_manual.bats`
Fixes lint error.
Also realized I was accidentally asserting a file exists in the test environment, not within the container.
Resolved that and also added an additional test case to ensure the ENV var files are valid when passed in, in the event a change misconfigures them and that the issue is identified earlier.
* chore: Apply PR review feedback
Better format some strings that had mixed quotes when they weren't necessary.
Additionally DRYed up the config path for Postfix and Dovecot within the `_setup_ssl` method.
Co-authored-by: Georg Lauterbach <infrastructure@itbsd.com>
* Migrate PR#1730 from tomav/docker-mailserver repo to new
docker-mailserver/docker-mailserver repo
* Resolved review comments
* Moved counter increment to have consistency between fetchmail process
and fetchmail config files
* Added tests for new fetchmail option
Co-authored-by: Georg Lauterbach <44545919+aendeavor@users.noreply.github.com>
this is needed to make test
"checking accounts: user3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf even when that file does not exist"
pass
Previously, only postfix-relaymap.cf and postfix-accounts.cf would be
used to populate the relayhost_map file.
Now, also use postfix-virtual.cf when present. To me, there is nothing
absurd about sending mail "From:" a virtual account (or more
specifically its domain) so it makes sense that when a $RELAY_HOST is
defined it should be used for virtual accounts as well.
Will extract certificates from acme.json as written by traefik for usage in dovecot and postfix.
Also watches acme.json for changes. For this to work the file has to be mounted/present at `/etc/letsencrypt/acme.json`
on hosts that belong to wildcard domains pop3.example.com might
actually resolve to pop3.example.com.[mydomain.com] and give a valid ip
the return code of fetchmail then no longer is 11 (dns failure) but
something else (2 for socket error in our case)
to make sure we always get return code 11 we use the domain name
pop3.example.com. that is not allowed to be resolved to a subdomain.
* Add new configuration for multi-domain relay hosts (#922)
* Creates new environment variables (replacing existing AWS_SES variables)
* Optionally allows more advanced setups using config files
* Update relay hosts during change detection (#922)
* Add helper scripts for adding relay hosts and per-domain auth
* Allow the possibility to deliver some mail directly
* adding a domain with no destination will exclude it from the
relayhost_map and so Postfix will attempt to deliver the mail directly
* tests for setup.sh script
* tests for relay host configuration
* these tests cover the code in `start-mailserver.sh` dealing with both
the env vars and the configuration files
* backup and restore of test/config folder as done for the regular config folder as well.
* permissions fix
* preserving permissions and ownership
* new backup rule
* remove two ciphers according to https://www.htbridge.com/ssl/ (NIST, HIPAA)
* added a switch via an environment variable to choose between modern and intermediate ciphers
* new setup.sh function, new tests, new script and some minor updates to main.cf
* fix for missing files
* removed obsolete test-files
* restart postfix if neccessary.
* see pr #845
* fixed typo
* fixed branchmixup
* changed postfix reload command & changed to operate on container instead of image
* reload postfix only on adding new restriction
* main.cf is only changed when user is added.
- Postfix reload changed
- working on container instead of image now in setup.sh
- added cleanup after tests
* moved cleanup to makefile
* install dovecot from backports
* dovecot 2.2.33 has a slightly different TLS-configuration than 2.2.27
* want to have both images a the same time
* make use of the /etc/dovecot/ssl as mkcert.sh (2.2.33) is using that folder for certs.
* Allow setup of LDAP STARTTLS for Dovecot and Postfix
* Added tests for TLS config override
* Add missing Postfix TLS options
* Added missing new line at the end of the file
* Added STARTTLS tests for Postfix config
* Switch to stretch-slim as base image.
- first step correct the testdata, as newer packages are more strict
about the mail-structure.
* Switch to stretch-slim: correcting the test-environment and the build
- add missing build-step to make
- clean the userdb aswell
- use timeout of netcat, as postgrey would not close the connection
- there is 2 extra mail-logs -> assert_output 5
- cosmetic: use "" instead of ''
* Switch to stretch-slim:
new image:
- smaller size
- 0 CVEs compared to 11 CVEs in ubuntu 16.04 Image
better backport situation
- postfix 3.1.6 vs 3.1.0
- fail2ban 0.9.6 vs 0.9.3
...
changes needed because of stretch-slim:
- add missing gnupg and iproute2 package
- remove non-free rar, unrar-free should do
- rsyslog does not add syslog user and has different conf-structure
- pyzor command discover was deprecated and is missing in the new
stretch package
- dovecot does not know SSLv2 anymore. removed because of warnings in
log
- iptables does not know imap3, IMAP working group chose imap2 in favor
of imap3
* Switch to debian stretch slim:
SSLv2 seems to be a not known protocol anymore - good!
* switch to debian stretch slim:
make this test more stable. there might be more than only one mail.log
(mail.info, mail.warn, ...)
* switch to debian stretc slim:
new openssl 1.1.0 needs stronger ciphers, removed some weekers ones.
Please, look through the new list of cipher! this needs to be done in
another commit for all other SSL/TLS-Endpoints aswell.
* Switch to debian stretch slim:
let our server pre-empt the cipher list.
Did a read through, wwwDOTpostfixDOTorg/FORWARD_SECRECY_READMEDOThtml
and
wwwDOTpostfixDOTorg/TLS_READMEDOThtml
* Switch to debian stretch slim: lets give this openssl-based test a new and independent but identical container. many other test on the main 'mail' container might interfere here.
* Switch to debian stretch slim: remove unused lines
* First pass at adding support for pipe and filter in Sieve, excluding unit tests.
* Reduce insight into copied scripts
* Added test
* Adjustments related to switch to 16.04
* Add method overwrite_config()
This method takes 2 arguments:
1.) Environment Variable Prefix
2.) String of files separated by whitespace
e.g.
export LDAP_SEARCH_BASE=dc=domain,dc=loc
export LDAP_BIND_PW=test
overwrite_config "LDAP_" "/etc/postfix/ldap-users.cf
/etc/postfix/ldap-groups.cf"
Logic:
+ all env vars will be search for vars with the prefix LDAP_
+ afterwards they will be dissembled in key value pairs
LDAP_BIND_PW=test --> bind_pw test
+ the key and value will be substituted within the provided files
via sed
* Fix#503 added logic for custom configs provided at container
provisioning within /tmp/docker-mailserver
* Add additional unit tests for postfix ldap integration
* check custom configs copied
* check environment variables substituted
* Fix quoting problems in tests.bats
* Fix missing brackets in function _fix_var_amavis_permissions()
* Fix typo in _setup_ldap
* Fix notify in overwrite_config
* Fix typo
* Fix added dovecot ldap config provisioning again and Add notify for tasks