Created
January 28, 2016 16:41
-
-
Save jumanjiman/da6935986c1d1d2a7451 to your computer and use it in GitHub Desktop.
exim in a docker container
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Default aliases file, installed by Exim. This file contains no real aliases. | |
# You should edit it to taste. | |
# The following alias is required by the mail RFCs 2821 and 2822. | |
# Set it to the address of a HUMAN who deals with this system's mail problems. | |
# postmaster: [email protected] | |
# It is also common to set the following alias so that if anybody replies to a | |
# bounce message from this host, the reply goes to the postmaster. | |
# mailer-daemon: postmaster | |
# You should also set up an alias for messages to root, because it is not | |
# usually a good idea to deliver mail as root. | |
# root: postmaster | |
# It is a good idea to redirect any messages sent to system accounts so that | |
# they don't just get ignored. Here are some common examples: | |
# bin: root | |
# daemon: root | |
# ftp: root | |
# nobody: root | |
# operator: root | |
# uucp: root | |
# You should check your /etc/passwd for any others. | |
# Other commonly enountered aliases are: | |
# | |
# abuse: the person dealing with network and mail abuse | |
# hostmaster: the person dealing with DNS problems | |
# webmaster: the person dealing with your web site | |
#### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM alpine:3.3 | |
RUN echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories | |
RUN apk add --no-cache exim | |
COPY . / | |
RUN /usr/sbin/harden.sh | |
# Volumes must be created AFTER we harden. | |
VOLUME ["/var/log/exim", "/var/spool/exim"] | |
USER exim | |
# http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html | |
ENTRYPOINT ["exim"] | |
CMD ["-bd", "-v", "-oP", "/dev/null", "-C", "/etc/mail/local.conf"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ tree | |
. | |
├── Dockerfile | |
├── etc | |
│ ├── aliases | |
│ └── local.conf | |
└── usr | |
└── sbin | |
└── harden.sh | |
4 directories, 4 files |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
set -x | |
set -e | |
# | |
# Docker build calls this script to harden the image during build. | |
# | |
# NOTE: To build on CircleCI, you must take care to keep the `find` | |
# command out of the /proc filesystem to avoid errors like: | |
# | |
# find: /proc/tty/driver: Permission denied | |
# lxc-start: The container failed to start. | |
# lxc-start: Additional information can be obtained by \ | |
# setting the --logfile and --logpriority options. | |
# Remove existing crontabs, if any. | |
rm -fr /var/spool/cron | |
rm -fr /etc/crontabs | |
rm -fr /etc/periodic | |
# Remove all but a handful of admin commands. | |
find /sbin /usr/sbin ! -type d \ | |
-a ! -name exim \ | |
-a ! -name nologin \ | |
-delete | |
# Remove world-writable permissions. | |
# This breaks apps that need to write to /tmp, | |
# such as ssh-agent. | |
find / -xdev -type d -perm +0002 -exec chmod o-w {} + | |
find / -xdev -type f -perm +0002 -exec chmod o-w {} + | |
# Remove unnecessary user accounts, including root. | |
sed -i -r '/^(exim)/!d' /etc/group | |
sed -i -r '/^(exim)/!d' /etc/passwd | |
# Disable interactive login for everybody. | |
sed -i -r 's#^(.*):[^:]*$#\1:/sbin/nologin#' /etc/passwd | |
sysdirs=" | |
/bin | |
/etc | |
/lib | |
/sbin | |
/usr | |
" | |
# Remove apk configs. | |
find $sysdirs -xdev -regex '.*apk.*' -exec rm -fr {} + | |
# Remove crufty... | |
# /etc/shadow- | |
# /etc/passwd- | |
# /etc/group- | |
find $sysdirs -xdev -type f -regex '.*-$' -exec rm -f {} + | |
# Ensure system dirs are owned by root and not writable by anybody else. | |
find $sysdirs -xdev -type d \ | |
-exec chown 0:0 {} \; \ | |
-exec chmod 0755 {} \; | |
# Create spool dir so that exim user doesn't have to. | |
# Dockerfile treats this as a volume. | |
mkdir -p /var/spool/exim | |
chown -R exim:exim /var/spool/exim | |
chmod 0755 /var/spool/exim | |
# Remove suid bit from exim. | |
chmod u-s /usr/sbin/exim | |
# Remove all suid files. | |
find $sysdirs -xdev -type f -a -perm +4000 -delete | |
# Remove other programs that could be dangerous. | |
find $sysdirs -xdev \( \ | |
-name hexdump -o \ | |
-name chgrp -o \ | |
-name chmod -o \ | |
-name chown -o \ | |
-name ln -o \ | |
-name od -o \ | |
-name strings -o \ | |
-name su \ | |
\) -delete | |
# Remove init scripts since we do not use them. | |
rm -fr /etc/init.d | |
rm -fr /lib/rc | |
rm -fr /etc/conf.d | |
rm -fr /etc/inittab | |
rm -fr /etc/runlevels | |
rm -fr /etc/rc.conf | |
# Remove kernel tunables since we do not need them. | |
rm -fr /etc/sysctl* | |
rm -fr /etc/modprobe.d | |
rm -fr /etc/modules | |
rm -fr /etc/mdev.conf | |
rm -fr /etc/acpi | |
# Remove root homedir since we do not need it. | |
rm -fr /root | |
# Remove fstab since we do not need it. | |
rm -f /etc/fstab | |
# Remove broken symlinks (because we removed the targets above). | |
find $sysdirs -xdev -type l -exec test ! -e {} \; -delete |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
###################################################################### | |
# Runtime configuration file for Exim # | |
###################################################################### | |
# This is a default configuration file which will operate correctly in | |
# uncomplicated installations. Please see the manual for a complete list | |
# of all the runtime configuration options that can be included in a | |
# configuration file. There are many more than are mentioned here. The | |
# manual is in the file doc/spec.txt in the Exim distribution as a plain | |
# ASCII file. Other formats (PostScript, Texinfo, HTML, PDF) are available | |
# from the Exim ftp sites. The manual is also online at the Exim web sites. | |
# This file is divided into several parts, all but the first of which are | |
# headed by a line starting with the word "begin". Only those parts that | |
# are required need to be present. Blank lines, and lines starting with # | |
# are ignored. | |
########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ########### | |
# # | |
# Whenever you change Exim's configuration file, you *must* remember to # | |
# HUP the Exim daemon, because it will not pick up the new configuration # | |
# until you do. However, any other Exim processes that are started, for # | |
# example, a process started by an MUA in order to send a message, will # | |
# see the new configuration as soon as it is in place. # | |
# # | |
# You do not need to HUP the daemon for changes in auxiliary files that # | |
# are referenced from this file. They are read every time they are used. # | |
# # | |
# It is usually a good idea to test a new configuration for syntactic # | |
# correctness before installing it (for example, by running the command # | |
# "exim -C /config/file.new -bV"). # | |
# # | |
########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ########### | |
# Avoid any local log files because we start in Dockerfile to stdout. | |
log_file_path = syslog | |
# The next three settings create two lists of domains and one list of hosts. | |
# These lists are referred to later in this configuration using the syntax | |
# +local_domains, +relay_to_domains, and +relay_from_hosts, respectively. They | |
# are all colon-separated lists: | |
# We do not accept local delivery. We only relay. | |
domainlist local_domains = | |
# We relay TO these domains. | |
domainlist relay_to_domains = *.example.com | |
# We relay FROM these IP ranges. | |
# The "<;" means to use semicolon as separator. | |
hostlist relay_from_hosts = <; 127.0.0.1 ; ::1 ; 10.8.0.0/16 ; 10.188.0.0/16 | |
# The lists above are used in the ACLs for checking incoming messages. | |
# The names of these ACLs are defined here: | |
acl_smtp_rcpt = acl_check_rcpt | |
acl_smtp_data = acl_check_data | |
# Start daemon on high port so we can start unprivileged. | |
# Docker maps the port to 25 on the host to enable clients | |
# to use plain old port 25. | |
daemon_smtp_ports = 2525 | |
# If somebody sends email to "pmorgan", | |
# change the address to "[email protected]". | |
qualify_domain = example.com | |
# Disable RFC1413 (ident) callbacks for incoming smtp calls. | |
rfc1413_query_timeout = 0s | |
# Unfreeze bounce messages after one day, then try again to deliver. | |
# Remove frozen messages that are older than two days. | |
# See also the retry configuration elsewhere in this file. | |
ignore_bounce_errors_after = 1d | |
timeout_frozen_after = 2d | |
# By default, messages that are waiting on Exim's queue are all held in a | |
# single directory called "input" which it itself within Exim's spool | |
# directory. (The default spool directory is specified when Exim is built, and | |
# is often /var/spool/exim/.) Exim works best when its queue is kept short, but | |
# there are circumstances where this is not always possible. If you uncomment | |
# the setting below, messages on the queue are held in 62 subdirectories of | |
# "input" instead of all in the same directory. The subdirectories are called | |
# 0, 1, ... A, B, ... a, b, ... z. This has two benefits: (1) If your file | |
# system degrades with many files in one directory, this is less likely to | |
# happen; (2) Exim can process the queue one subdirectory at a time instead of | |
# all at once, which can give better performance with large queues. | |
# split_spool_directory = true | |
# If you're in a part of the world where ASCII is not sufficient for most | |
# text, then you're probably familiar with RFC2047 message header extensions. | |
# By default, Exim adheres to the specification, including a limit of 76 | |
# characters to a line, with encoded words fitting within a line. | |
# If you wish to use decoded headers in message filters in such a way | |
# that successful decoding of malformed messages matters, you may wish to | |
# configure Exim to be more lenient. | |
# | |
# check_rfc2047_length = false | |
# | |
# In particular, the Exim maintainers have had multiple reports of problems | |
# from Russian administrators of issues until they disable this check, | |
# because of some popular, yet buggy, mail composition software. | |
# If you wish to be strictly RFC compliant, or if you know you'll be | |
# exchanging email with systems that are not 8-bit clean, then you may | |
# wish to disable advertising 8BITMIME. Uncomment this option to do so. | |
# accept_8bitmime = false | |
###################################################################### | |
# ACL CONFIGURATION # | |
# Specifies access control lists for incoming SMTP mail # | |
###################################################################### | |
begin acl | |
# This access control list is used for every RCPT command in an incoming | |
# SMTP message. The tests are run in order until the address is either | |
# accepted or denied. | |
acl_check_rcpt: | |
# Accept if the source is local SMTP (i.e. not over TCP/IP). We do this by | |
# testing for an empty sending host field. | |
accept hosts = : | |
control = dkim_disable_verify | |
############################################################################# | |
# The following section of the ACL is concerned with local parts that contain | |
# @ or % or ! or / or | or dots in unusual places. | |
# | |
# The characters other than dots are rarely found in genuine local parts, but | |
# are often tried by people looking to circumvent relaying restrictions. | |
# Therefore, although they are valid in local parts, these rules lock them | |
# out, as a precaution. | |
# | |
# Empty components (two dots in a row) are not valid in RFC 2822, but Exim | |
# allows them because they have been encountered. (Consider local parts | |
# constructed as "firstinitial.secondinitial.familyname" when applied to | |
# someone like me, who has no second initial.) However, a local part starting | |
# with a dot or containing /../ can cause trouble if it is used as part of a | |
# file name (e.g. for a mailing list). This is also true for local parts that | |
# contain slashes. A pipe symbol can also be troublesome if the local part is | |
# incorporated unthinkingly into a shell command line. | |
# | |
# Two different rules are used. The first one is stricter, and is applied to | |
# messages that are addressed to one of the local domains handled by this | |
# host. The line "domains = +local_domains" restricts it to domains that are | |
# defined by the "domainlist local_domains" setting above. The rule blocks | |
# local parts that begin with a dot or contain @ % ! / or |. If you have | |
# local accounts that include these characters, you will have to modify this | |
# rule. | |
deny message = Restricted characters in address | |
domains = +local_domains | |
local_parts = ^[.] : ^.*[@%!/|] | |
# The second rule applies to all other domains, and is less strict. The line | |
# "domains = !+local_domains" restricts it to domains that are NOT defined by | |
# the "domainlist local_domains" setting above. The exclamation mark is a | |
# negating operator. This rule allows your own users to send outgoing | |
# messages to sites that use slashes and vertical bars in their local parts. | |
# It blocks local parts that begin with a dot, slash, or vertical bar, but | |
# allows these characters within the local part. However, the sequence /../ | |
# is barred. The use of @ % and ! is blocked, as before. The motivation here | |
# is to prevent your users (or your users' viruses) from mounting certain | |
# kinds of attack on remote sites. | |
deny message = Restricted characters in address | |
domains = !+local_domains | |
local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./ | |
############################################################################# | |
# Accept mail to postmaster in any local domain, regardless of the source, | |
# and without verifying the sender. | |
accept local_parts = postmaster | |
domains = +local_domains | |
# Deny unless the sender address can be verified. | |
require verify = sender | |
# Accept if the message comes from one of the hosts for which we are an | |
# outgoing relay. It is assumed that such hosts are most likely to be MUAs, | |
# so we set control=submission to make Exim treat the message as a | |
# submission. It will fix up various errors in the message, for example, the | |
# lack of a Date: header line. If you are actually relaying out out from | |
# MTAs, you may want to disable this. If you are handling both relaying from | |
# MTAs and submissions from MUAs you should probably split them into two | |
# lists, and handle them differently. | |
# Recipient verification is omitted here, because in many cases the clients | |
# are dumb MUAs that don't cope well with SMTP error responses. If you are | |
# actually relaying out from MTAs, you should probably add recipient | |
# verification here. | |
# Note that, by putting this test before any DNS black list checks, you will | |
# always accept from these hosts, even if they end up on a black list. The | |
# assumption is that they are your friends, and if they get onto a black | |
# list, it is a mistake. | |
accept hosts = +relay_from_hosts | |
control = submission | |
control = dkim_disable_verify | |
# Accept if the message arrived over an authenticated connection, from | |
# any host. Again, these messages are usually from MUAs, so recipient | |
# verification is omitted, and submission mode is set. And again, we do this | |
# check before any black list tests. | |
accept authenticated = * | |
control = submission | |
control = dkim_disable_verify | |
# Insist that any other recipient address that we accept is either in one of | |
# our local domains, or is in a domain for which we explicitly allow | |
# relaying. Any other domain is rejected as being unacceptable for relaying. | |
require message = relay not permitted | |
domains = +local_domains : +relay_to_domains | |
# We also require all accepted addresses to be verifiable. This check will | |
# do local part verification for local domains, but only check the domain | |
# for remote domains. The only way to check local parts for the remote | |
# relay domains is to use a callout (add /callout), but please read the | |
# documentation about callouts before doing this. | |
require verify = recipient | |
############################################################################# | |
# There are no default checks on DNS black lists because the domains that | |
# contain these lists are changing all the time. However, here are two | |
# examples of how you can get Exim to perform a DNS black list lookup at this | |
# point. The first one denies, whereas the second just warns. | |
# | |
# deny message = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text | |
# dnslists = black.list.example | |
# | |
# warn dnslists = black.list.example | |
# add_header = X-Warning: $sender_host_address is in a black list at $dnslist_domain | |
# log_message = found in $dnslist_domain | |
############################################################################# | |
############################################################################# | |
# This check is commented out because it is recognized that not every | |
# sysadmin will want to do it. If you enable it, the check performs | |
# Client SMTP Authorization (csa) checks on the sending host. These checks | |
# do DNS lookups for SRV records. The CSA proposal is currently (May 2005) | |
# an Internet draft. You can, of course, add additional conditions to this | |
# ACL statement to restrict the CSA checks to certain hosts only. | |
# | |
# require verify = csa | |
############################################################################# | |
# At this point, the address has passed all the checks that have been | |
# configured, so we accept it unconditionally. | |
accept | |
# This ACL is used after the contents of a message have been received. This | |
# is the ACL in which you can test a message's headers or body, and in | |
# particular, this is where you can invoke external virus or spam scanners. | |
# Some suggested ways of configuring these tests are shown below, commented | |
# out. Without any tests, this ACL accepts all messages. If you want to use | |
# such tests, you must ensure that Exim is compiled with the content-scanning | |
# extension (WITH_CONTENT_SCAN=yes in Local/Makefile). | |
acl_check_data: | |
# Deny if the message contains a virus. Before enabling this check, you | |
# must install a virus scanner and set the av_scanner option above. | |
# | |
# deny malware = * | |
# message = This message contains a virus ($malware_name). | |
# Add headers to a message if it is judged to be spam. Before enabling this, | |
# you must install SpamAssassin. You may also need to set the spamd_address | |
# option above. | |
# | |
# warn spam = nobody | |
# add_header = X-Spam_score: $spam_score\n\ | |
# X-Spam_score_int: $spam_score_int\n\ | |
# X-Spam_bar: $spam_bar\n\ | |
# X-Spam_report: $spam_report | |
# Accept the message. | |
accept | |
###################################################################### | |
# ROUTERS CONFIGURATION # | |
# Specifies how addresses are handled # | |
###################################################################### | |
# THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT! # | |
# An address is passed to each router in turn until it is accepted. # | |
###################################################################### | |
begin routers | |
# This alternative router can be used when you want to send all mail to a | |
# server which handles DNS lookups for you; an ISP will typically run such | |
# a server for their customers. If you uncomment "smarthost" then you | |
# should comment out "dnslookup" above. Setting a real hostname in route_data | |
# wouldn't hurt either. | |
smarthost: | |
driver = manualroute | |
domains = ! +local_domains | |
transport = remote_smtp | |
# This is the public IP of our Threat Mgmt Gateway (TMG). | |
route_data = 74.120.84.40 | |
ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1 | |
no_more | |
###################################################################### | |
# TRANSPORTS CONFIGURATION # | |
###################################################################### | |
# ORDER DOES NOT MATTER # | |
# Only one appropriate transport is called for each delivery. # | |
###################################################################### | |
# A transport is used only when referenced from a router that successfully | |
# handles an address. | |
begin transports | |
# This transport is used for delivering messages over SMTP connections. | |
remote_smtp: | |
driver = smtp | |
###################################################################### | |
# RETRY CONFIGURATION # | |
###################################################################### | |
begin retry | |
# This single retry rule applies to all domains and all errors. It specifies | |
# retries every 15 minutes for 2 hours, then increasing retry intervals, | |
# starting at 1 hour and increasing each time by a factor of 1.5, up to 16 | |
# hours, then retries every 6 hours until 4 days have passed since the first | |
# failed delivery. | |
# WARNING: If you do not have any retry rules at all (this section of the | |
# configuration is non-existent or empty), Exim will not do any retries of | |
# messages that fail to get delivered at the first attempt. The effect will | |
# be to treat temporary errors as permanent. Therefore, DO NOT remove this | |
# retry rule unless you really don't want any retries. | |
# Address or Domain Error Retries | |
# ----------------- ----- ------- | |
* * F,2h,15m; G,16h,1h,1.5; F,4d,6h | |
###################################################################### | |
# REWRITE CONFIGURATION # | |
###################################################################### | |
# There are no rewriting specifications in this default configuration file. | |
begin rewrite | |
###################################################################### | |
# AUTHENTICATION CONFIGURATION # | |
###################################################################### | |
# The following authenticators support plaintext username/password | |
# authentication using the standard PLAIN mechanism and the traditional | |
# but non-standard LOGIN mechanism, with Exim acting as the server. | |
# PLAIN and LOGIN are enough to support most MUA software. | |
# | |
# These authenticators are not complete: you need to change the | |
# server_condition settings to specify how passwords are verified. | |
# They are set up to offer authentication to the client only if the | |
# connection is encrypted with TLS, so you also need to add support | |
# for TLS. See the global configuration options section at the start | |
# of this file for more about TLS. | |
# | |
# The default RCPT ACL checks for successful authentication, and will accept | |
# messages from authenticated users from anywhere on the Internet. | |
begin authenticators | |
# PLAIN authentication has no server prompts. The client sends its | |
# credentials in one lump, containing an authorization ID (which we do not | |
# use), an authentication ID, and a password. The latter two appear as | |
# $auth2 and $auth3 in the configuration and should be checked against a | |
# valid username and password. In a real configuration you would typically | |
# use $auth2 as a lookup key, and compare $auth3 against the result of the | |
# lookup, perhaps using the crypteq{}{} condition. | |
#PLAIN: | |
# driver = plaintext | |
# server_set_id = $auth2 | |
# server_prompts = : | |
# server_condition = Authentication is not yet configured | |
# server_advertise_condition = ${if def:tls_in_cipher } | |
# LOGIN authentication has traditional prompts and responses. There is no | |
# authorization ID in this mechanism, so unlike PLAIN the username and | |
# password are $auth1 and $auth2. Apart from that you can use the same | |
# server_condition setting for both authenticators. | |
#LOGIN: | |
# driver = plaintext | |
# server_set_id = $auth1 | |
# server_prompts = <| Username: | Password: | |
# server_condition = Authentication is not yet configured | |
# server_advertise_condition = ${if def:tls_in_cipher } | |
###################################################################### | |
# CONFIGURATION FOR local_scan() # | |
###################################################################### | |
# If you have built Exim to include a local_scan() function that contains | |
# tables for private options, you can define those options here. Remember to | |
# uncomment the "begin" line. It is commented by default because it provokes | |
# an error with Exim binaries that are not built with LOCAL_SCAN_HAS_OPTIONS | |
# set in the Local/Makefile. | |
# begin local_scan | |
# End of Exim configuration file |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Unit] | |
Description=Site-local Mail Relay | |
After=docker.service | |
Requires=dns.service | |
[Service] | |
ExecStartPre=-/usr/bin/docker rm -f %n | |
ExecStart=/usr/bin/docker run \ | |
--name %n \ | |
-c 1023 \ | |
-m 20m \ | |
-p 25:2525 \ | |
-h ix-smtp01.inf.example.com \ | |
--dns 10.188.2.254 \ | |
--dns-search prod.example.com \ | |
--dns-search inf.example.com \ | |
--read-only \ | |
--cap-drop all \ | |
--cap-add setgid \ | |
--cap-add setuid \ | |
quay.io/example/mail_relay:latest | |
ExecStop=/usr/bin/docker stop %n | |
RestartSec=5s | |
Restart=always | |
[Install] | |
WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment