mirror of
https://github.com/bokysan/docker-postfix.git
synced 2025-09-11 00:44:37 +08:00
Add the option to log to rsyslog as plain or JSON and restructure tests
- It's now possible to choose the logging type - either 'plain' or 'json' - The code is ready to support multiple integration tests (with different configurations) - `OPENDKIM_` and `POSTFIX_` variables are handled properly and recorded in the corresponding files. (This had a downfall that `bash` now needs to be installed, so we can probably simplify some of the shell scripts.)
This commit is contained in:
parent
9b1902c047
commit
ff2d080279
17 changed files with 211 additions and 17 deletions
|
@ -29,6 +29,8 @@ ENV MESSAGE_SIZE_LIMIT=
|
|||
ENV INBOUND_DEBUGGING=
|
||||
# DKIM domain selector. If not set, the default (mail) will be used
|
||||
ENV DKIM_SELECTOR=
|
||||
# Logformat. Defaults to "plain". Can be either "plain" or "json".
|
||||
ENV LOG_FORMAT=
|
||||
|
||||
# Install supervisor, postfix
|
||||
# Install postfix first to get the first account (101)
|
||||
|
@ -37,13 +39,12 @@ RUN true && \
|
|||
apk add --no-cache --upgrade cyrus-sasl cyrus-sasl-plain cyrus-sasl-login && \
|
||||
apk add --no-cache postfix && \
|
||||
apk add --no-cache opendkim && \
|
||||
apk add --no-cache ca-certificates tzdata supervisor rsyslog && \
|
||||
apk add --no-cache --upgrade musl musl-utils && \
|
||||
apk add --no-cache --upgrade ca-certificates tzdata supervisor rsyslog musl musl-utils bash && \
|
||||
(rm "/tmp/"* 2>/dev/null || true) && (rm -rf /var/cache/apk/* 2>/dev/null || true)
|
||||
|
||||
# Set up configuration
|
||||
COPY /configs/supervisord.conf /etc/supervisord.conf
|
||||
COPY /configs/rsyslog.conf /etc/rsyslog.conf
|
||||
COPY /configs/rsyslog*.conf /etc/
|
||||
COPY /configs/opendkim.conf /etc/opendkim/opendkim.conf
|
||||
COPY /configs/smtp_header_checks /etc/postfix/smtp_header_checks
|
||||
COPY /scripts/*.sh /
|
||||
|
|
32
README.md
32
README.md
|
@ -219,6 +219,8 @@ This means:
|
|||
|
||||
## Extending the image
|
||||
|
||||
### Using custom init scripts
|
||||
|
||||
If you need to add custom configuration to postfix or have it do something outside of the scope of this configuration, simply
|
||||
add your scripts to `/docker-init.db/`: All files with the `.sh` extension will be executed automatically at the end of the
|
||||
startup script.
|
||||
|
@ -243,7 +245,37 @@ For example, your script could contain something like this:
|
|||
postconf -e "address_verify_negative_cache=yes"
|
||||
```
|
||||
|
||||
### Overriding specific postfix settings
|
||||
|
||||
Any Postfix [configuration option](http://www.postfix.org/postconf.5.html) can be overriden using `POSTFIX_<name>` environment variables, e.g.
|
||||
`POSTFIX_allow_mail_to_commands=alias,forward,include`. Specifying no content (empty variable) will remove that variable from postfix config.
|
||||
|
||||
Any OpenDKIM [configuration option](http://opendkim.org/opendkim.conf.5.html) can be overriden using `OPENDKIM_<name>` environment variables, e.g.
|
||||
`OPENDKIM_RequireSafeKeys=yes`. Specifying no content (empty variable) will remove that variable from OpenDKIM config.
|
||||
|
||||
## Log format
|
||||
|
||||
The image will by default output logs in human-readable (`plain`) format. If you are deploying the image to Kubernetes, it might be worth chaging
|
||||
the output format to `json` as it's more easily parsable by tools such as [Prometheus](https://prometheus.io/).
|
||||
|
||||
To change the log format, set the (unsuprisingly named) variable `LOG_FORMAT=json`.
|
||||
|
||||
## Security
|
||||
|
||||
Postfix will run the master proces as `root`, because that's how it's designed. Subprocesses will run under the `postfix` account
|
||||
which will use `UID:GID` of `100:101`. `opendkim` will run under account `102:103`.
|
||||
|
||||
## Similar projects
|
||||
|
||||
There are may other project offering similar functionality. The aim of this project, however, is:
|
||||
|
||||
- to make it as simple as possible to run the relay, without going too much into postfix configuration details
|
||||
- to make as small image as possible (hence basing on Alpine linux)
|
||||
- to make the image and the corresponding code testable
|
||||
|
||||
The other projects are, in completely random order:
|
||||
|
||||
- [wader/postfix-relay](https://github.com/wader/postfix-relay)
|
||||
- [catatnight/postfix](https://github.com/catatnight/docker-postfix)
|
||||
- [juanluisbaptiste/docker-postfix](https://github.com/juanluisbaptiste/docker-postfix)
|
||||
- [docker-mail-relay](https://github.com/alterrebe/docker-mail-relay)
|
||||
|
|
|
@ -10,8 +10,7 @@ $Umask 0022
|
|||
|
||||
template (name="devicelog" type="string" string="/dev/stdout")
|
||||
|
||||
template(name="json_syslog"
|
||||
type="list") {
|
||||
template(name="json" type="list") {
|
||||
constant(value="{")
|
||||
constant(value="\"@timestamp\":\"") property(name="timereported" dateFormat="rfc3339")
|
||||
constant(value="\",\"type\":\"syslog_json")
|
||||
|
@ -26,17 +25,29 @@ template(name="json_syslog"
|
|||
constant(value="\",\"facility\":\"") property(name="syslogfacility")
|
||||
constant(value="\",\"severity_label\":\"") property(name="syslogseverity-text")
|
||||
constant(value="\",\"facility_label\":\"") property(name="syslogfacility-text")
|
||||
constant(value="\",\"message\":\"") property(name="rawmsg" format="json")
|
||||
constant(value="\",\"message\":\"") property(name="msg" format="json")
|
||||
constant(value="\",\"end_msg\":\"")
|
||||
constant(value="\"}\n")
|
||||
}
|
||||
|
||||
template(name="plain" type="list") {
|
||||
property(name="timereported" dateFormat="rfc3339")
|
||||
constant(value=" ")
|
||||
property(name="syslogseverity-text" caseconversion="upper" fixedwidth="on" position.to="7")
|
||||
constant(value=" ")
|
||||
property(name="syslogtag")
|
||||
property(name="msg" spifno1stsp="on")
|
||||
property(name="msg" droplastlf="on")
|
||||
constant(value="\n")
|
||||
}
|
||||
|
||||
if $syslogseverity <= '6' then {
|
||||
# matching logs will be saved
|
||||
action(type="omfile" DynaFile="devicelog" template="json_syslog" DirCreateMode="0755" FileCreateMode="0644")
|
||||
action(type="omfile" DynaFile="devicelog" template="<log-format>" DirCreateMode="0755" FileCreateMode="0644")
|
||||
# enable below to stop processing further this log
|
||||
stop
|
||||
}
|
||||
|
||||
include(file="/etc/rsyslog.d/*.conf" mode="optional")
|
||||
|
||||
stop
|
|
@ -1,3 +1,14 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
cd integration-tests
|
||||
docker-compose up --build --abort-on-container-exit --exit-code-from tests
|
||||
for i in `find -maxdepth 1 -type d`; do
|
||||
i="$(basename "$i")"
|
||||
if [ "$i" == "tester" ] || [ "$i" == "." ] || [ "$i" == ".." ]; then
|
||||
continue
|
||||
fi
|
||||
(
|
||||
echo "$i"
|
||||
cd "$i"
|
||||
docker-compose up --build --abort-on-container-exit --exit-code-from tests
|
||||
)
|
||||
done
|
|
@ -4,7 +4,7 @@ services:
|
|||
hostname: "postfix"
|
||||
image: "boky/postfix"
|
||||
build:
|
||||
context: ..
|
||||
context: ../..
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: [ "CMD", "sh", "-c", "netstat -an | fgrep 587 | fgrep -q LISTEN" ]
|
||||
|
@ -21,7 +21,7 @@ services:
|
|||
image: "boky/postfix-integration-test"
|
||||
restart: "no"
|
||||
volumes:
|
||||
- "..:/code"
|
||||
- "../tester:/code"
|
||||
build:
|
||||
context: .
|
||||
command: "/code/integration-tests/"
|
||||
context: ../tester
|
||||
command: "/"
|
|
@ -12,7 +12,6 @@ if [ -z "$TO" ]; then
|
|||
fi
|
||||
|
||||
# Wait for postfix to startup
|
||||
echo "Waiting for startup..."
|
||||
wait-for-service -q tcp://postfix_test_587:587
|
||||
|
||||
SMTP_DATA="-smtp postfix_test_587 -port 587"
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
announce_startup() {
|
||||
echo -e "******************************"
|
||||
|
@ -21,6 +21,15 @@ setup_timezone() {
|
|||
fi
|
||||
}
|
||||
|
||||
rsyslog_log_format() {
|
||||
local log_format="${LOG_FORMAT}"
|
||||
if [[ -z "${log_format}" ]]; then
|
||||
log_format="plain"
|
||||
fi
|
||||
echo -e "‣ $info Using ${emphasis}${log_format}${reset} log format for rsyslog."
|
||||
sed -i -E "s/<log-format>/${log_format}/" /etc/rsyslog.conf
|
||||
}
|
||||
|
||||
reown_folders() {
|
||||
mkdir -p /var/spool/postfix/ && mkdir -p /var/spool/postfix/pid
|
||||
chown root: /var/spool/postfix/
|
||||
|
@ -250,6 +259,52 @@ postfix_setup_dkim() {
|
|||
fi
|
||||
}
|
||||
|
||||
opendkim_custom_commands() {
|
||||
local setting
|
||||
local key
|
||||
local padded_key
|
||||
local value
|
||||
for setting in ${!OPENDKIM_*}; do
|
||||
key="${setting:9}"
|
||||
value="${!setting}"
|
||||
if [ -n "${value}" ]; then
|
||||
if [ "${#key}" -gt 23 ]; then
|
||||
padded_key="${key} "
|
||||
else
|
||||
padded_key="$(printf %-24s "${key}")"
|
||||
fi
|
||||
if cat /etc/opendkim/opendkim.conf | egrep -q "^[[:space:]]*#?[[:space:]]*${key}"; then
|
||||
echo -e "‣ $info Updating custom OpenDKIM setting: ${emphasis}${key}=${value}${reset}"
|
||||
sed -i -E "s/^[ \t]*#?[ \t]*${key}[ \t]*.+$/${padded_key}${value}/" /etc/opendkim/opendkim.conf
|
||||
else
|
||||
echo -e "‣ $info Adding custom OpenDKIM setting: ${emphasis}${key}=${value}${reset}"
|
||||
echo "Adding ${padded_key}${value}"
|
||||
echo "${padded_key}${value}" >> /etc/opendkim/opendkim.conf
|
||||
fi
|
||||
else
|
||||
echo -e "‣ $info Deleting custom OpenDKIM setting: ${emphasis}${key}${reset}"
|
||||
sed -i -E "/^[ \t]*#?[ \t]*${key}[ \t]*.+$/d" /etc/opendkim/opendkim.conf
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
postfix_custom_commands() {
|
||||
local setting
|
||||
local key
|
||||
local value
|
||||
for setting in ${!POSTFIX_*}; do
|
||||
key="${setting:8}"
|
||||
value="${!setting}"
|
||||
if [ -n "${value}" ]; then
|
||||
echo -e "‣ $info Applying custom postfix setting: ${emphasis}${key}=${value}${reset}"
|
||||
postconf -e "${key}=${value}"
|
||||
else
|
||||
echo -e "‣ $info Deleting custom postfix setting: ${emphasis}${key}${reset}"
|
||||
postconf -# "${key}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
postfix_open_submission_port() {
|
||||
# Use 587 (submission)
|
||||
sed -i -r -e 's/^#submission/submission/' /etc/postfix/master.cf
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
reset=""
|
||||
yellow=""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
. /common.sh
|
||||
|
@ -6,6 +6,7 @@ set -e
|
|||
|
||||
announce_startup # Print startup banner
|
||||
setup_timezone # Check if we need to configure the container timezone
|
||||
rsyslog_log_format # Setup rsyslog output format
|
||||
reown_folders # Make and reown postfix folders
|
||||
postfix_disable_utf8 # Disable SMTPUTF8, because libraries (ICU) are missing in alpine
|
||||
postfix_create_aliases # Update aliases database. It's not used, but postfix complains if the .db file is missing
|
||||
|
@ -23,6 +24,8 @@ postfix_setup_sender_domains # Configure allowed sender domains
|
|||
postfix_setup_masquarading # Setup masquaraded domains
|
||||
postfix_setup_header_checks # Enable SMTP header checks, if defined
|
||||
postfix_setup_dkim # Configure DKIM, if enabled
|
||||
postfix_custom_commands # Apply custom postfix settings
|
||||
opendkim_custom_commands # Apply custom OpenDKIM settings
|
||||
postfix_open_submission_port # Enable the submission port
|
||||
execute_post_init_scripts # Execute any scripts found in /docker-init.db/
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache bash bats
|
||||
RUN true && \
|
||||
apk add --no-cache bash bats && \
|
||||
apk add --no-cache --upgrade cyrus-sasl cyrus-sasl-plain cyrus-sasl-login && \
|
||||
apk add --no-cache postfix && \
|
||||
apk add --no-cache opendkim && \
|
||||
(rm "/tmp/"* 2>/dev/null || true) && (rm -rf /var/cache/apk/* 2>/dev/null || true)
|
||||
|
||||
WORKDIR /code
|
||||
ENTRYPOINT ["/usr/bin/bats"]
|
||||
|
|
60
unit-tests/opendkim_custom_commands.bats
Normal file
60
unit-tests/opendkim_custom_commands.bats
Normal file
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
load /code/scripts/common.sh
|
||||
load /code/scripts/common-run.sh
|
||||
|
||||
setup() {
|
||||
mkdir -p /etc/opendkim/
|
||||
cat > /etc/opendkim/opendkim.conf <<-EOF
|
||||
AutoRestart Yes
|
||||
AutoRestartRate 10/1h
|
||||
UMask 002
|
||||
Syslog Yes
|
||||
SyslogSuccess Yes
|
||||
LogWhy No
|
||||
|
||||
Canonicalization relaxed/simple
|
||||
RequireSafeKeys no
|
||||
|
||||
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
|
||||
InternalHosts refile:/etc/opendkim/TrustedHosts
|
||||
KeyTable refile:/etc/opendkim/KeyTable
|
||||
SigningTable refile:/etc/opendkim/SigningTable
|
||||
|
||||
Mode sv
|
||||
PidFile /var/run/opendkim/opendkim.pid
|
||||
SignatureAlgorithm rsa-sha256
|
||||
|
||||
UserID opendkim:opendkim
|
||||
Socket inet:8891@localhost
|
||||
|
||||
SignHeaders From,Sender,To,CC,Subject,Message-Id,Date,MIME-Version,Content-Type,Reply-To
|
||||
OversignHeaders From,Sender,To,CC,Subject,Message-Id,Date,MIME-Version,Content-Type,Reply-To
|
||||
EOF
|
||||
}
|
||||
|
||||
teardown() {
|
||||
rm -f /etc/opendkim/opendkim.conf
|
||||
}
|
||||
|
||||
@test "Make sure that opendkim_custom_commands changes lines" {
|
||||
local OPENDKIM_RequireSafeKeys=yes
|
||||
opendkim_custom_commands
|
||||
cat /etc/opendkim/opendkim.conf | fgrep -qx "RequireSafeKeys yes"
|
||||
}
|
||||
|
||||
@test "Make sure that opendkim_custom_commands adds lines" {
|
||||
local OPENDKIM_CaptureUnknownErrors=yes
|
||||
opendkim_custom_commands
|
||||
cat /etc/opendkim/opendkim.conf | fgrep -qx "CaptureUnknownErrors yes"
|
||||
}
|
||||
|
||||
@test "Make sure that opendkim_custom_commands removes lines" {
|
||||
local OPENDKIM_SignHeaders=
|
||||
opendkim_custom_commands
|
||||
if cat /etc/opendkim/opendkim.conf | egrep -q "^SignHeaders"; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
17
unit-tests/postfix_custom_commands.bats
Normal file
17
unit-tests/postfix_custom_commands.bats
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
load /code/scripts/common.sh
|
||||
load /code/scripts/common-run.sh
|
||||
|
||||
|
||||
@test "Make sure that postfix_custom_commands adds lines" {
|
||||
local POSTFIX_alias_database=hash:/etc/mail/aliases
|
||||
postfix_custom_commands
|
||||
cat /etc/postfix/main.cf | fgrep -qx "alias_database = hash:/etc/mail/aliases"
|
||||
}
|
||||
|
||||
@test "Make sure that postfix_custom_commands removes lines" {
|
||||
local POSTFIX_readme_directory=
|
||||
postfix_custom_commands
|
||||
cat /etc/postfix/main.cf | egrep -q "^#readme_directory"
|
||||
}
|
Loading…
Add table
Reference in a new issue