Commit 86295f82 authored by Vincent Pelletier's avatar Vincent Pelletier

erp5: Rework postfix integration.

Add support for "hosts" aliasing in Zope instances.
Add support for SASL relayhost with mandatory TLS encryption.
Add mandatory TSL + SASL authentication, to not be an open relay.
Wrap postfix commands with proper environment instead of symlink +
source-able script.
Add ipv6 listening support (untested).
Drop non-required main.cf configuration options.
Make postifx instance optional (requires postmaster address to be
provided).
Document and rework smtp-related parameters.
Expose an userhosts hostname for smtp server.
Add diversion support (solution to "prod clone sent mails to real customer").
Use etc/run rather than etc/service, for consistency (if it needs to be
changed, it must be changed for all software types).
Hook into syslog and setup local syslog daemon, with logrotate integration.
Update TODO entries.
parent 48672684
{
"$schema": "http://json-schema.org/draft-04/schema#",
"extends": "./schema-definitions.json#",
"required": ["tcpv4-port"],
"properties": {
"tcpv4-port": {
"allOf": [{
"$ref": "#/definitions/tcpv4port"
}, {
"description": "Start allocating ports at this value, going upward"
}]
},
"postmaster": {
"description": "Mail address to send technical mails to. Non-empty value required for smptd relay service to be deployed. Values will be put in alias-dict as 'postmaster' key (alias-dict takes precedence)",
"default": "",
"type": "string"
},
"alias-dict": {
"description": "Mail alias support",
"default": {},
"patternProperties": {
".*": {
"description": "List of addresses alias expands to",
"type": "array"
}
},
"type": "object"
},
"relay": {
"description": "Forward outgoing mails to a specific relay. If enabled, relay must support TLS-encrypted SASL authentication.",
"dependencies": {
"host": ["sasl-credential"]
},
"properties": {
"host": {
"description": "Host name or address of relay, with optional port (ex: '[example.com]:submissionu'). Enclosing hostname with [] prevents MX lookup.",
"type": "string"
},
"sasl-credential": {
"description": "SASL credential, in the login:password form",
"type": "string"
}
},
"default": {},
"type": "object"
},
"divert": {
"description": "Intercept all mails and send them to given addresses instead of original recipient",
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
}
}
}
......@@ -6,7 +6,8 @@ General:
- resilience
- make mariadb user accounts accept connections only from relevant IPs
or make x509 mandatory (needs ZMySQLD*A support)
- postfix
- make postfix log inside partition
- document postfix parameters (only once it actually works)
Monitoring:
- daily slow-query digest
......
......@@ -202,24 +202,29 @@ md5sum = 79f789360e71146486c82a7a10834bae
[template-postfix]
< = download-base
filename = instance-postfix.cfg.in
md5sum = a1b131b5bf6a749b0c853e9577f43cca
md5sum = 90a017581116f14014a039d38ef36ffd
[template-postfix-master-cf]
< = download-base
filename = postfix_master.cf.in
md5sum = 67f06ed63c5d3fa47908a83071b76bd3
md5sum = 9ac81647368068a1a98a785d08074b43
[template-postfix-main-cf]
< = download-base
filename = postfix_main.cf.in
md5sum = b6f44d8507aa15d71fdff75bf3eeddb9
md5sum = d51897728755e14d8005344608098009
[template-postfix-aliases]
< = download-base
filename = postfix_aliases.in
md5sum = 0969fbb25b05c02ef3c2d437b2f4e1a0
[template]
recipe = slapos.recipe.template:jinja2
# XXX: "template.cfg" is hardcoded in instanciation recipe
rendered = ${buildout:directory}/template.cfg
template = ${:_profile_base_location_}/instance.cfg.in
md5sum = 4b7ef360e34de488daab0d44973fd598
md5sum = 4d043c96d70b35d1fbbd8120d8edee7c
mode = 640
context =
key mariadb_link_binary template-mariadb:link-binary
......@@ -232,6 +237,7 @@ context =
key coreutils_location coreutils:location
key cups_location cups:location
key curl_location curl:location
key cyrus_sasl_location cyrus-sasl:location
key dash_location dash:location
key dbus_glib_location dbus-glib:location
key dbus_location dbus:location
......@@ -286,6 +292,7 @@ context =
key template_mariadb_initial_setup template-mariadb-initial-setup:target
key template_my_cnf template-my-cnf:target
key template_postfix template-postfix:target
key template_postfix_aliases template-postfix-aliases:target
key template_postfix_main_cf template-postfix-main-cf:target
key template_postfix_master_cf template-postfix-master-cf:target
key template_runzope_userhosts_preloaded template-runzope-userhosts-preloaded:target
......@@ -301,7 +308,7 @@ context =
[template-erp5]
<= download-base
filename = instance-erp5.cfg.in
md5sum = bb951a205def0235f3c041045abd7801
md5sum = 60cdf98d996f220d66daa11452c3f4bf
[template-zeo]
<= download-base
......@@ -311,7 +318,7 @@ md5sum = 9670cf63099e2c520017a23defff51a4
[template-zope]
<= download-base
filename = instance-zope.cfg.in
md5sum = 74f2fbd7d653b0e6cfe29efcd1042ace
md5sum = 995257c4d08365db7ac0d1b40936ef8b
link-binary =
${aspell:location}/bin/aspell
${dmtx-utils:location}/bin/dmtxwrite
......
......@@ -4,11 +4,12 @@
{% set site_id = slapparameter_dict.get('site-id', 'erp5') -%}
{% set inituser_login = slapparameter_dict.get('inituser-login', 'zope') -%}
{% set publish_dict = {'site-id': site_id, 'inituser-login': inituser_login} -%}
{% set has_posftix = slapparameter_dict.get('smtp', {}).get('postmaster') -%}
[request-common]
<= request-common-base
config-use-ipv6 = {{ dumps(slapparameter_dict.get('use-ipv6', False)) }}
{% macro request(name, software_type, config_key, config, ret={'url': True}) -%}
{% macro request(name, software_type, config_key, config, ret={'url': True}, key_config={}) -%}
{% do config.update(slapparameter_dict.get(config_key, {})) -%}
{% set section = 'request-' ~ name -%}
[{{ section }}]
......@@ -25,13 +26,22 @@ return = {{ ' '.join(ret) }}
{% for k, v in config.iteritems() -%}
config-{{ k }} = {{ dumps(v) }}
{% endfor -%}
{% for k, v in key_config.iteritems() -%}
config-{{ k }} = {{ '${' ~ v ~ '}' }}
{% endfor -%}
{% endmacro -%}
{{ request('memcached-persistent', 'kumofs', 'kumofs', {'tcpv4-port': 2000}) }}
{{ request('memcached-volatile', 'kumofs', 'memcached', {'tcpv4-port': 2010, 'ram-storage-size': 64}) }}
{{ request('cloudooo', 'cloudooo', 'cloudooo', {'tcpv4-port': 2020}) }}
{{ request('mariadb', 'mariadb', 'mariadb', {'tcpv4-port': 2099}, {'database-list': True, 'test-database-list': True}) }}
{{ request('postfix', 'postfix', 'postfix', {'tcpv4-port': 2025}) }}
{% if has_posftix -%}
{{ request('smtp', 'postfix', 'smtp', {'tcpv4-port': 2025, 'smtpd-sasl-user': 'erp5@nowhere'}, key_config={'smtpd-sasl-password': 'publish-early:smtpd-sasl-password'}) }}
{%- else %}
[request-smtp]
# Placeholder smtp service URL
connection-url = smtp://127.0.0.2:0/
{%- endif %}
{# ZODB -#}
{% set zodb_dict = {} -%}
......@@ -66,6 +76,9 @@ recipe = slapos.cookbook:publish-early
-init =
inituser-password gen-password:passwd
deadlock-debugger-password gen-deadlock-debugger-password:passwd
{%- if has_posftix %}
smtpd-sasl-password gen-smtpd-sasl-password:passwd
{%- endif %}
{%- if neo %}
neo-cluster gen-neo-cluster:name
{%- if neo[0] %}
......@@ -94,6 +107,9 @@ storage-path =
[gen-neo-cluster]
name = neo-${gen-neo-cluster-base:passwd}
[gen-smtpd-sasl-password]
< = gen-password
[request-zope-base]
<= request-common
return =
......@@ -113,7 +129,7 @@ config-memcached-url = ${request-memcached-volatile:connection-url}
config-mysql-test-url-list = ${request-mariadb:connection-test-database-list}
config-mysql-url-list = ${request-mariadb:connection-database-list}
config-site-id = {{ dumps(site_id) }}
config-smtp-url = {{ dumps(slapparameter_dict.get('smtp-url', 'smtp://localhost:25/')) }}
config-smtp-url = ${request-smtp:connection-url}
config-timezone = {{ dumps(slapparameter_dict.get('timezone', 'UTC')) }}
config-zodb-dict = {{ dumps(zodb_dict) }}
{% for server_type, server_dict in storage_dict.iteritems() -%}
......
This diff is collapsed.
......@@ -114,6 +114,7 @@ ipv6 = {{ ipv6 }}
('erp5-memcached-volatile', slapparameter_dict['memcached-url']),
('erp5-memcached-persistent', slapparameter_dict['kumofs-url']),
('erp5-cloudooo', slapparameter_dict['cloudooo-url']),
('erp5-smtp', slapparameter_dict['smtp-url']),
) -%}
{% do hosts_dict.__setitem__(
alias,
......
......@@ -45,7 +45,11 @@ extra-context =
section parameter_dict dynamic-template-cloudooo-parameters
[dynamic-template-postfix-parameters]
bin-directory = {{ bin_directory }}
cyrus-sasl-location = {{ cyrus_sasl_location }}
openssl = {{ openssl_location }}
postfix-location = {{ postfix_location }}
template-postfix-aliases = {{ template_postfix_aliases }}
template-postfix-main-cf = {{ template_postfix_main_cf }}
template-postfix-master-cf = {{ template_postfix_master_cf }}
......@@ -56,6 +60,7 @@ filename = instance-postfix.cfg
extensions = jinja2.ext.do
extra-context =
section parameter_dict dynamic-template-postfix-parameters
import urllib urllib
[dynamic-template-erp5-parameters]
local-bt5-repository = {{ local_bt5_repository }}
......
# See http://www.postfix.org/aliases.5.html for format
{% for name, alias_list in alias_dict.items() -%}
{{ name }}: {{ alias_list | join(', ') }}
{% endfor %}
# http://www.postfix.org/STANDARD_CONFIGURATION_README.html
# http://www.postfix.org/postconf.5.html
queue_directory = {{ queue_directory }}
command_directory = {{ command_directory }}
daemon_directory = {{ daemon_directory }}
command_directory = {{ bin_directory }}
daemon_directory = {{ usr_directory }}/libexec/postfix
data_directory = {{ data_directory }}
mail_owner = {{ mail_owner }}
myhostname = {{ myhostname }}
mydomain = {{ mydomain }}
unknown_local_recipient_reject_code = 550
alias_maps = {{ alias_maps }}
alias_database = {{ alias_database }}
mail_spool_directory = {{ mail_spool_directory }}
debug_peer_level = 2
alias_maps = {{ aliases }}
alias_database = {{ aliases }}
mail_spool_directory = {{ spool_directory }}
sendmail_path =
newaliases_path =
mailq_path =
......@@ -20,5 +16,45 @@ html_directory =
manpage_directory =
sample_directory =
readme_directory =
inet_protocols = ipv4
inet_interfaces = {{ inet_interfaces }}
virtual_alias_maps = {{ divert }}
# Compared to default:
# - remove X-related variables, irrelevant for slapos, to be concise
# - add SASL_CONF_PATH to have per-partition cyrus-sasl configuration
import_environment =
MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ LANG=C
SASL_CONF_PATH
# Mandatory sasl auth over TLS
# XXX: no man-in-the-middle protection
smtpd_tls_cert_file = {{ cert }}
smtpd_tls_key_file = {{ key }}
smtpd_tls_dh512_param_file = {{ dh_512 }}
{#
Note: 1024 vs. 2048 is not a typo, but what is actually recommended in
postfix documentation
-#}
smtpd_tls_dh1024_param_file = {{ dh_2048 }}
smtpd_tls_security_level = encrypt
smtpd_sasl_auth_enable = yes
# Reject as many bogus cases as soon as possible, so errors are visible to ERP5
# developper rather than relying on bounces.
smtpd_recipient_restrictions =
reject_non_fqdn_recipient
reject_unknown_recipient_domain
permit_sasl_authenticated
reject
# Disable local delivery
local_transport = error
{% if relayhost -%}
relayhost = {{ relayhost }}
smtp_tls_security_level = encrypt
smtp_tls_session_cache_database = btree:{{ data_directory }}/smtp_scache
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = {{ sasl_passwd }}
smtp_sasl_tls_security_options = noanonymous
{%- endif %}
{% set smtp = parameter_dict['smtp_port'] -%}
# http://www.postfix.org/master.5.html
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
{{smtp}} inet n - n - - smtpd
#submission inet n - n - - smtpd
{{ smtp }} inet n - n - - smtpd
pickup unix n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr unix n - n 300 1 qmgr
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment