https://github.com/wikimedia/operations-puppet
Raw File
Tip revision: f8b741c6b549bbe4dee172a29bd06426ecae6ad4 authored by Eric Evans on 25 May 2016, 21:23:02 UTC
stub out missing 'c' instances
Tip revision: f8b741c
exim4.conf.mx.erb
# This file is managed by puppet

##########
# Macros #
##########

CONFDIR=/etc/exim4

<% if @site == "eqiad" -%>
# wiki-mail-eqiad
WIKI_INTERFACE=<; 208.80.154.91 ; 2620:0:861:3:208:80:154:91
<% elsif @site == "codfw" -%>
# wiki-mail-codfw
WIKI_INTERFACE=<; 208.80.153.46 ; 2620:0:860:2:208:80:153:46
<% end %>

OTRSQUERY=SELECT value0 FROM system_address WHERE value0='${quote_mysql:$local_part@$domain}' AND valid_id=1;

VERP_BOUNCE_LOCALPART_REGEXP = \N^wiki-\w+-\w+-\w+-[+/\w]+$\N

###############################
# Main configuration settings #
###############################

# MySQL lookups (OTRS)
hide mysql_servers =  m2-master.eqiad.wmnet/otrs/exim/<%= @otrs_mysql_password %> : m2-slave.eqiad.wmnet/otrs/exim/<%= @otrs_mysql_password %>

# LDAP lookups (Office)
ldap_default_servers = ldap-corp.<%= @site %>.wikimedia.org : ldap-corp.<%= @other_site %>.wikimedia.org
LDAPPASSWORD=<%= @smtp_ldap_password %>

domainlist system_domains = @
domainlist local_domains = +system_domains : +wikimedia_domains : +legacy_mailman_domains : +verp_domains
domainlist wikimedia_domains = lsearch;CONFDIR/wikimedia_domains
domainlist verp_domains = <%= @verp_domains.join(" : ") %>
domainlist relay_domains = +wikimedia_domains

# a list of domains to always respond defer; used for emergencies or planned downtimes
domainlist defer_domains = lsearch;CONFDIR/defer_domains

# Standard lists
domainlist legacy_mailman_domains = wikimedia.org : wikipedia.org
domainlist rt_domains = rt.wikimedia.org
domainlist phab_domains = phabricator.wikimedia.org
domainlist donate_domains = donate.wikimedia.org

hostlist wikimedia_nets = <; <%= scope.lookupvar('network::constants::all_networks').join(" ; ") %>
hostlist relay_from_hosts = <; @[] ; 127.0.0.1 ; ::1 ; <%= scope.lookupvar('network::constants::external_networks').join(" ; ") %>; 10.0.0.0/8

# Administration
log_selector = +address_rewrite +all_parents +delivery_size +deliver_time +incoming_interface +incoming_port +smtp_confirmation +smtp_protocol_error +smtp_syntax_error +tls_cipher +tls_peerdn
message_logs = false

# Policy control
acl_smtp_connect = acl_check_connect
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data

helo_try_verify_hosts = *

system_filter = CONFDIR/system_filter

# Resource control
check_spool_space = 50M
smtp_reserve_hosts = <; 127.0.0.1 ; ::1 ; +wikimedia_nets
smtp_accept_queue_per_connection = 500

deliver_queue_load_max = 800.0
queue_only_load = 100.0
remote_max_parallel = 500

smtp_connect_backlog = 128
smtp_receive_timeout = 1m
smtp_accept_max = 4000
smtp_accept_max_per_host = ${if match_ip{$sender_host_address}{+wikimedia_nets}{50}{5}}
smtp_accept_reserve = 100

# Lookups
host_lookup = *
rfc1413_hosts =

# Content filtering
spamd_address = 127.0.0.1 783

# Other
never_users = root : daemon : bin
ignore_bounce_errors_after = 0h

add_environment = <; PATH=/bin:/usr/bin
keep_environment =

# TLS
tls_certificate = /etc/ssl/localcerts/mail.wikimedia.org.chained.crt
tls_privatekey = /etc/ssl/private/mail.wikimedia.org.key
tls_advertise_hosts = *

# force Gmail over IPv4 due to reports of bad spam reputation over IPv6
dns_ipv4_lookup = gmail-smtp-in.l.google.com : aspmx.l.google.com

###############################
# Access Control Lists (ACLs) #
###############################

begin acl

acl_check_rcpt:

	# If there have been ~4 times as many previous RCPT rejects than
	# accepts, drop the connection
	drop message = Too many ($rcpt_fail_count) rejected recipients, good bye
		hosts = ! +wikimedia_nets
		condition = ${if >={$rcpt_fail_count}{${eval:4*($recipients_count+1)}}}

	# Accept if the source is local SMTP (a pipe)
	accept hosts = :

	# Deny if the local part contains @, %, /, | or !, or starts with a dot
	deny local_parts = ^.*[@%!/|] : ^\\.

	# Accept relaying from networks we control. Note: no address verification
	# is done at this point, which is good for mail submission, but may render
	# recipient callout verification by affected hosts useless.
	accept domains = ! +local_domains
		hosts = +relay_from_hosts
		control = submission/sender_retain

	# Require recipient domain to be local, or a domain we relay for
	require message = Relay not permitted
		domains = +local_domains : +relay_domains
		set acl_m_relayed = yes

	# use this only for emergencies or planned downtimes
	defer	message = Administratively set to defer
		domains = +defer_domains

	# Accept mail for postmaster without further policy checking,
	# for compliance with the RFCs
	accept local_parts = postmaster : abuse
		set acl_m2 = skip_spamd

	# Verify the recipient address for local domains, or require the
	# recipient domain to exist for remote domains
	require verify = recipient

	# If the destination domain is a domain we relay for,
	# check if the local part exists at the destination,
	# reject if it doesn't.
	# Accept if the destination cannot be reached within 30s.
	deny domains = +relay_domains
		! verify = recipient/callout=10s,maxwait=30s,defer_ok

	# Check whether the sender address domain exists
	require verify = sender

	accept

acl_check_connect:
	# Deny external connections to the internal bulk mail submission interface
	deny condition = ${if match_ip{$interface_address}{WIKI_INTERFACE}{true}{false}}
		! hosts = +wikimedia_nets

	accept

acl_check_data:
	# Let's trust local senders to not send out spam
	accept hosts = +wikimedia_nets
		set acl_m0 = trusted relay

	# Only run through SpamAssassin if requested for this domain and
	# the message is not too large
	accept condition = ${if >{$message_size}{400K}}

	# Skip if so requested
	accept condition = ${if eq{$acl_m2}{skip_spamd}}

	# Add spam headers if score >= 1
	warn spam = nonexistent:true
		condition = ${if >{$spam_score_int}{10}{1}{0}}
		set acl_m0 = $spam_score ($spam_bar)
		set acl_m1 = $spam_report

	# Reject spam at high scores (> 12)
	deny message = This message scored $spam_score spam points.
		spam = nonexistent/defer_ok
		condition = ${if >{$spam_score_int}{120}{1}{0}}

	accept

###########
# Routers #
###########

begin routers

# Route mail generated by MediaWiki differently
wiki_mail:
	driver = dnslookup
	domains = ! +local_domains
	condition = ${if and{{match_ip{$interface_address}{WIKI_INTERFACE}}{eqi{$header_X-Mailer:}{MediaWiki mailer}}}}
	transport = bulk_smtp
	ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; 10/8 ; 172.16/12 ; 192.168/16
	no_verify

# Send donate.wikimedia.org mail to Fundraising CiviCRM server
donate:
	driver = manualroute
	domains = +donate_domains
	route_list = * barium.frack.eqiad.wmnet byname
	transport = remote_smtp

# Route non-local domains (including +relay_domains) via DNS MX and A records
dnslookup:
	driver = dnslookup
	domains = ! +local_domains
	transport = ${if eq {$acl_m_relayed}{yes}{remote_smtp}{remote_smtp_signed}}
	ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; 10/8 ; 172.16/12 ; 192.168/16
	cannot_route_message = Cannot route to remote domain $domain
	no_more

# Route bounce emails
mw_verp_api:
	driver = accept
	domains = +verp_domains
	condition = ${if match{$local_part}{VERP_BOUNCE_LOCALPART_REGEXP}{true}{false}}
	transport = mwverpbounceprocessor

eat:
	driver = redirect
	domains = +local_domains
	local_parts = no-reply-notifications
	data = :blackhole:

# Use the system aliasfile /etc/aliases for system domains
system_aliases:
	driver = redirect
	domains = +system_domains
	data = ${lookup{$local_part}lsearch{/etc/aliases}}
	pipe_transport = address_pipe
	allow_fail
	allow_defer
	forbid_file

# Use alias files /etc/exim4/aliases/$domain for domains like
# wikimedia.org, wikipedia.org, wiktionary.org etc.
aliases:
	driver = redirect
	domains = +local_domains
	require_files = CONFDIR/aliases/$domain
	data = ${lookup{$local_part}lsearch*{CONFDIR/aliases/$domain}}
	qualify_preserve_domain
	allow_fail
	allow_defer
	forbid_file
	include_directory = CONFDIR
	pipe_transport = address_pipe

# Alias old mailing list addresses to @lists.wikimedia.org
legacy_mailing_lists:
	driver = redirect
	domains = +legacy_mailman_domains
	data = $local_part$local_part_suffix@lists.wikimedia.org
	local_parts = lsearch;CONFDIR/legacy_mailing_lists
	local_part_suffix = -bounces : -bounces+* : \
				-confirm+* : -join : -leave : \
				-owner : -request : -admin : \
				-subscribe : -unsubscribe
	local_part_suffix_optional

# LDAP accounts
ldap_account:
	driver = manualroute
	domains = wikimedia.org
	condition = ${lookup ldap \
			{user="cn=eximagent,ou=other,dc=corp,dc=wikimedia,dc=org" pass=LDAPPASSWORD \
			ldap:///ou=people,dc=corp,dc=wikimedia,dc=org?mail?sub?(&(objectClass=inetOrgPerson)(mail=${quote_ldap:$local_part}@$domain)(x121Address=1))} \
			{true}fail}
	local_part_suffix = +*
	local_part_suffix_optional
	transport = remote_smtp
	route_list = *  aspmx.l.google.com

ldap_group:
	driver = manualroute
	domains = wikimedia.org
	condition = ${lookup ldap \
			{user="cn=eximagent,ou=other,dc=corp,dc=wikimedia,dc=org" pass=LDAPPASSWORD \
			ldap:///ou=groups,dc=corp,dc=wikimedia,dc=org?businessCategory?sub?(businessCategory=${quote_ldap:$local_part}@$domain)} \
			{true}fail}
	local_part_suffix = +*
	local_part_suffix_optional
	transport = remote_smtp
	route_list = *  aspmx.l.google.com

ldap_alias:
	driver = redirect
	domains = wikimedia.org
	data = ${lookup ldap \
			{user="cn=eximagent,ou=other,dc=corp,dc=wikimedia,dc=org" pass=LDAPPASSWORD \
			ldap:///ou=people,dc=corp,dc=wikimedia,dc=org?mail?sub?(&(objectClass=inetOrgPerson)(initials=${quote_ldap:$local_part}@$domain)(x121Address=1))} \
			{$value}fail}

# send phabricator.wm.org emails to Phabricator
phabricator:
       driver = manualroute
       domains = +phab_domains
       route_list = * iridium.eqiad.wmnet byname
       transport = remote_smtp

# Send RT mails to the RT server
rt:
	driver = manualroute
	domains = +rt_domains
	route_list = * magnesium.wikimedia.org byname
	transport = remote_smtp

# Query the OTRS MySQL server(s) for the existence of the queue address
# $local_part@$domain, and manually route to the OTRS server if
# successful.
otrs:
	driver = manualroute
	domains = +local_domains
	condition = ${lookup mysql{OTRSQUERY}{true}fail}
	route_list = *  mendelevium.eqiad.wmnet  byname
	transport = remote_smtp

# Redirect postmaster@$domain if it hasn't been accepted before
postmaster:
	driver = redirect
	domains = +local_domains
	local_parts = postmaster
	data = postmaster@$primary_hostname
	cannot_route_message = Address $local_part@$domain does not exist

##############
# Transports #
##############

begin transports

# Generic remote SMTP transport

remote_smtp:
	driver = smtp

remote_smtp_signed:
	driver = smtp
	dkim_domain = wikimedia.org
	dkim_selector = wikimedia
	dkim_private_key = ${if exists{/etc/exim4/dkim/${dkim_domain}-${dkim_selector}.key}{/etc/exim4/dkim/${dkim_domain}-${dkim_selector}.key}{0}}
	dkim_canon = relaxed

# Transport for sending out automated bulk (wiki) mail
# DKIM signed with wikimedia.org irrespective of actual sender domain
# but using a separate selector that only allows "wiki" as the local part
bulk_smtp:
	driver = smtp
	interface = WIKI_INTERFACE
	helo_data = ${lookup dnsdb{ptr=$sending_ip_address}{$value}{wiki-mail.wikimedia.org}}
	dkim_domain = wikimedia.org
	dkim_selector = wiki-mail
	dkim_private_key = ${if exists{/etc/exim4/dkim/${dkim_domain}-${dkim_selector}.key}{/etc/exim4/dkim/${dkim_domain}-${dkim_selector}.key}{0}}
	dkim_canon = relaxed

# Generic pipe local delivery transport (for use by alias/forward files)

address_pipe:
	driver = pipe
	return_output

# POST VERP bounce emails to a MediaWiki 'bouncehandler' API
mwverpbounceprocessor:
	driver = pipe
	command = /usr/bin/curl -H 'Host: <%= @verp_post_connect_server %>' <%= @verp_bounce_post_url %> -d "action=bouncehandler" --data-urlencode "email@-" -o /dev/null
	user = nobody
	group = nogroup

###############
# Retry rules #
###############

begin retry

*	*	senders=wiki@wikimedia.org	F,1h,15m; G,8h,1h,1.5
*	*	F,2h,15m; G,16h,1h,1.5; F,4d,6h

#################
# Rewrite rules #
#################

begin rewrite

# Rewrite the envelope From for mails from internal servers in *.site.wmnet,
# as they are usually rejected by sender domain address verification.
*@*.eqiad.wmnet		root@wikimedia.org	F
*@*.codfw.wmnet		root@wikimedia.org	F
*@*.esams.wmnet		root@wikimedia.org	F
*@*.ulsfo.wmnet		root@wikimedia.org	F
back to top