diff --git a/software/erp5/instance-smtp-schema.json b/software/erp5/instance-smtp-schema.json new file mode 100644 index 0000000000000000000000000000000000000000..fd3b1f4599511c81036d0519b88af11845671a2e --- /dev/null +++ b/software/erp5/instance-smtp-schema.json @@ -0,0 +1,56 @@ +{ + "$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 + } + } +} diff --git a/stack/erp5/TODO b/stack/erp5/TODO index 4d9b4e427e7ce66a7c2cdf6bf83abab4da78ed31..11ab49b0b6159e75bc9870b08569ec389622e4e2 100644 --- a/stack/erp5/TODO +++ b/stack/erp5/TODO @@ -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 diff --git a/stack/erp5/buildout.cfg b/stack/erp5/buildout.cfg index fd8fe1f2469f2a7cff450204222d968376906ff0..772c80e4f1e1c7b847d766887d0799ae6f3ded7b 100644 --- a/stack/erp5/buildout.cfg +++ b/stack/erp5/buildout.cfg @@ -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 diff --git a/stack/erp5/instance-erp5.cfg.in b/stack/erp5/instance-erp5.cfg.in index ebdc5930c2a977be4ca4db6a6aa2fe256850a7d0..34b859359809415a1a70ff3539e649ec652d57d5 100644 --- a/stack/erp5/instance-erp5.cfg.in +++ b/stack/erp5/instance-erp5.cfg.in @@ -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() -%} diff --git a/stack/erp5/instance-postfix.cfg.in b/stack/erp5/instance-postfix.cfg.in index 7f8de5173b6bae9d6ff78bc4ede3e18461cfc066..23f98cbbec798b9bbb2ae36e0cdf840161d0561f 100644 --- a/stack/erp5/instance-postfix.cfg.in +++ b/stack/erp5/instance-postfix.cfg.in @@ -1,168 +1,251 @@ -{% if software_type == slap_software_type -%} {% set part_list = [] -%} {% macro section(name) %}{% do part_list.append(name) %}{{ name }}{% endmacro -%} -{% set ipv4 = (ipv4_set | list)[0] -%} +{% if slapparameter_dict['use-ipv6'] -%} +{% set ip = '[' ~ (ipv6_set | list)[0] ~ ']' -%} +{% else -%} +{% set ip = (ipv4_set | list)[0] -%} +{% endif -%} {% set tcpv4_port = slapparameter_dict['tcpv4-port'] -%} - -[buildout] -parts = - publish-postfix-connection-information - postfix-main-cf - postfix-master-cf - postfix-symlinks-bin - postfix-symlinks-sbin - postfix-symlinks-libexec - service-postfix-master - sh-postfix-environment - newaliases - {{ part_list | join('\n ') }} - -eggs-directory = {{ eggs_directory }} -develop-eggs-directory = {{ develop_eggs_directory }} - - -[publish-postfix-connection-information] +{% set relay = slapparameter_dict.get('relay', {}) -%} +{% set divert = slapparameter_dict.get('divert', []) -%} +{% set alias_dict = slapparameter_dict.get('alias-dict', {}) -%} +{% do alias_dict.setdefault('postmaster', [slapparameter_dict['postmaster']]) -%} +{% set smtpd_sasl_user = slapparameter_dict['smtpd-sasl-user'] -%} +{% set smtpd_sasl_password = slapparameter_dict['smtpd-sasl-password'] -%} + +[smtpd-password] +recipe = slapos.cookbook:generate.password +storage-path = + +[{{ section('publish') }}] recipe = slapos.cookbook:publish.serialised -url = smtp://${:ipv4}:${:port}/ -ipv4 = {{ ipv4 }} -port = ${postfix-master-cf-parameters:smtp_port} - +url = {{ dumps('smtp://' ~ urllib.quote_plus(smtpd_sasl_user) ~ ':' ~ urllib.quote_plus(smtpd_sasl_password) ~ '@' ~ ip ~ ':' ~ tcpv4_port) }} [directory] recipe = slapos.cookbook:mkdirectory etc = ${buildout:directory}/etc -etc_postfix = ${:etc}/postfix -script = ${:etc}/run -service = ${:etc}/service promise = ${:etc}/promise +etc-postfix = ${:etc}/postfix +etc-cyrus = ${:etc}/cyrus +run = ${:etc}/run +bin = ${buildout:directory}/bin usr = ${buildout:directory}/usr -usr_bin = ${:usr}/bin -usr_sbin = ${:usr}/sbin var = ${buildout:directory}/var -var_spool = ${:var}/spool -var_spool_postfix = ${:var_spool}/postfix -var_spool_postfix_active = ${:var_spool_postfix}/active -var_spool_postfix_bounce = ${:var_spool_postfix}/bounce -var_spool_postfix_corrupt = ${:var_spool_postfix}/corrupt -var_spool_postfix_defer = ${:var_spool_postfix}/defer -var_spool_postfix_deferred = ${:var_spool_postfix}/deferred -var_spool_postfix_flush = ${:var_spool_postfix}/flush -var_spool_postfix_hold = ${:var_spool_postfix}/hold -var_spool_postfix_incoming = ${:var_spool_postfix}/incoming -var_spool_postfix_maildrop = ${:var_spool_postfix}/maildrop -var_spool_postfix_pid = ${:var_spool_postfix}/pid -var_spool_postfix_private = ${:var_spool_postfix}/private -var_spool_postfix_public = ${:var_spool_postfix}/public -var_spool_postfix_saved = ${:var_spool_postfix}/saved -var_spool_postfix_trace = ${:var_spool_postfix}/trace -var_lib = ${:var}/lib -var_mail = ${:var}/mail -var_lib_postfix = ${:var_lib}/postfix - +var-lib = ${:var}/lib +var-lib-postfix = ${:var-lib}/postfix +var-spool = ${:var}/spool +var-spool-postfix = ${:var-spool}/postfix +# Not used at buildout level, presence needed by postfix. +var-spool-postfix-active = ${:var-spool-postfix}/active +var-spool-postfix-bounce = ${:var-spool-postfix}/bounce +var-spool-postfix-corrupt = ${:var-spool-postfix}/corrupt +var-spool-postfix-defer = ${:var-spool-postfix}/defer +var-spool-postfix-deferred = ${:var-spool-postfix}/deferred +var-spool-postfix-flush = ${:var-spool-postfix}/flush +var-spool-postfix-hold = ${:var-spool-postfix}/hold +var-spool-postfix-incoming = ${:var-spool-postfix}/incoming +var-spool-postfix-maildrop = ${:var-spool-postfix}/maildrop +var-spool-postfix-pid = ${:var-spool-postfix}/pid +var-spool-postfix-private = ${:var-spool-postfix}/private +var-spool-postfix-public = ${:var-spool-postfix}/public +var-spool-postfix-saved = ${:var-spool-postfix}/saved +var-spool-postfix-trace = ${:var-spool-postfix}/trace + +[configuration] +smtp = {{ dumps(tcpv4_port) }} +inet-interfaces = {{ dumps(ip) }} +alias-dict = {{ dumps(alias_dict) }} +relayhost = {{ dumps(relay.get('host')) }} +relay-sasl-credential = {{ dumps(relay.get('sasl-credential')) }} +divert = {{ dumps(divert) }} +cyrus-sasldb = ${directory:etc-cyrus}/postfix.gdbm [userinfo] recipe = slapos.cookbook:userinfo +[smtp-sasl-passwd] +recipe = slapos.recipe.template:jinja2 +rendered = ${directory:etc-postfix}/sasl_passwd +{% if relay -%} +template = inline:{{ "{{ host }} {{ sasl_credential }}" }} +{%- else -%} +template = inline: +{%- endif %} +context = + key host configuration:relayhost + key sasl_credential configuration:relay-sasl-credential +mode = 600 -[postfix-main-cf] +[{{ section('cyrus-smtpd-conf') }}] recipe = slapos.recipe.template:jinja2 -rendered = ${directory:etc_postfix}/main.cf -template = {{ parameter_dict['template-postfix-main-cf'] }} +rendered = ${directory:etc-cyrus}/smtpd.conf +template = inline: + pwcheck_method: auxprop + mech_list: PLAIN LOGIN + sasldb_path: {{ '{{ sasldb }}' }} context = - raw queue_directory ${directory:var_spool_postfix} - raw command_directory ${directory:usr_sbin} - raw daemon_directory {{ parameter_dict['postfix-location'] }}/usr/libexec/postfix - raw data_directory ${directory:var_lib_postfix} - raw mail_owner ${userinfo:pw_name} - raw alias_database hash:${aliases:rendered} - raw alias_maps hash:${aliases:rendered}, nis:mail.aliases - raw mail_spool_directory ${directory:var_mail} - raw mydomain localdomain - raw myhostname test.localdomain - raw setgid_group ${userinfo:gr_name} - raw inet_interfaces {{ ipv4 }} + key sasldb configuration:cyrus-sasldb +[{{ section('cyrus-smtpd-password') }}] +recipe = plone.recipe.command +stop-on-error = true +command = + rm -f '${configuration:cyrus-sasldb}' && + echo '{{ smtpd_sasl_password }}' | '${wrapper-postfix-saslpasswd2:wrapper-path}' -pc '{{ smtpd_sasl_user }}' +update-command = ${:command} -[postfix-master-cf-parameters] -smtp_port = {{ tcpv4_port }} +[divert] +recipe = slapos.recipe.template:jinja2 +rendered = ${directory:etc-postfix}/divert +{% if divert -%} +template = inline:{{ "/.*/ {{ ', '.join(divert) }}" }} +{%- else -%} +template = inline: +{%- endif %} +context = + key divert configuration:divert +[smtpd-ssl] +recipe = plone.recipe.command +stop-on-error = true +openssl = '{{ parameter_dict['openssl'] }}/bin/openssl' +cert = ${directory:etc-postfix}/smtpd.crt +key = ${directory:etc-postfix}/smtpd.pem +dh-512 = ${directory:etc-postfix}/dh512.pem +dh-2048 = ${directory:etc-postfix}/dh2048.pem +command = + ${:openssl} dhparam -out '${:dh-512}' 512 && + ${:openssl} dhparam -out '${:dh-2048}' 2048 && + ${:update} +update = + ${:openssl} req -newkey rsa -batch -new -x509 -days 3650 -nodes -keyout '${:key}' -out '${:cert}' -[postfix-master-cf] +[{{ section('postfix-main-cf') }}] +recipe = slapos.recipe.template:jinja2 +rendered = ${directory:etc-postfix}/main.cf +template = {{ parameter_dict['template-postfix-main-cf'] }} +context = + key bin_directory directory:bin + key usr_directory directory:usr + key queue_directory directory:var-spool-postfix + key data_directory directory:var-lib-postfix + key spool_directory directory:var-spool + key mail_owner userinfo:pw-name + key setgid_group userinfo:gr-name + key inet_interfaces configuration:inet-interfaces + key relayhost configuration:relayhost + key sasl_passwd typed-paths:smtp-sasl-passwd + key aliases typed-paths:aliases + key divert typed-paths:divert + key cyrus_directory directory:etc-cyrus + key cert smtpd-ssl:cert + key key smtpd-ssl:key + key dh_512 smtpd-ssl:dh-512 + key dh_2048 smtpd-ssl:dh-2048 + +[{{ section('postfix-master-cf') }}] recipe = slapos.recipe.template:jinja2 -rendered = ${directory:etc_postfix}/master.cf +rendered = ${directory:etc-postfix}/master.cf template = {{ parameter_dict['template-postfix-master-cf'] }} -context = section parameter_dict postfix-master-cf-parameters - +context = key smtp configuration:smtp [aliases] recipe = slapos.recipe.template:jinja2 -template = inline: - # See http://www.postfix.org/aliases.5.html for format -rendered = ${directory:etc_postfix}/aliases -mode = 644 +template = {{ parameter_dict['template-postfix-aliases'] }} +rendered = ${directory:etc-postfix}/aliases +context = + key alias_dict configuration:alias-dict +[typed-paths] +# Postfix-friendly rendering of file paths, prefixed with database type. +aliases = hash:${aliases:rendered} +smtp-sasl-passwd = hash:${smtp-sasl-passwd:rendered} +divert = pcre:${divert:rendered} -[newaliases] +[{{ section('postalias-db') }}] recipe = plone.recipe.command stop-on-error = true -command = - MAIL_CONFIG="${directory:etc_postfix}" {{ parameter_dict['postfix-location'] }}/usr/bin/newaliases +command = '${wrapper-postalias:wrapper-path}' '${typed-paths:aliases}' '${typed-paths:smtp-sasl-passwd}' update-command = ${:command} +[wrapper-postfix-saslpasswd2] +recipe = slapos.cookbook:wrapper +parameters-extra = true +command-line = '{{ parameter_dict['cyrus-sasl-location'] }}/sbin/saslpasswd2' -f '${configuration:cyrus-sasldb}' +wrapper-path = ${directory:bin}/saslpasswd2 -[postfix-symlinks-bin] -recipe = slapos.cookbook:symbolic.link -target-directory = ${directory:usr_bin} -link-binary = - {{ parameter_dict['postfix-location'] }}/usr/bin/mailq - {{ parameter_dict['postfix-location'] }}/usr/bin/newaliases - - -[postfix-symlinks-sbin] -recipe = slapos.cookbook:symbolic.link -target-directory = ${directory:usr_sbin} -link-binary = - {{ parameter_dict['postfix-location'] }}/usr/sbin/postalias - {{ parameter_dict['postfix-location'] }}/usr/sbin/postcat - {{ parameter_dict['postfix-location'] }}/usr/sbin/postconf - {{ parameter_dict['postfix-location'] }}/usr/sbin/postdrop - {{ parameter_dict['postfix-location'] }}/usr/sbin/postfix - {{ parameter_dict['postfix-location'] }}/usr/sbin/postkick - {{ parameter_dict['postfix-location'] }}/usr/sbin/postlock - {{ parameter_dict['postfix-location'] }}/usr/sbin/postlog - {{ parameter_dict['postfix-location'] }}/usr/sbin/postmap - {{ parameter_dict['postfix-location'] }}/usr/sbin/postmulti - {{ parameter_dict['postfix-location'] }}/usr/sbin/postqueue - {{ parameter_dict['postfix-location'] }}/usr/sbin/postsuper - {{ parameter_dict['postfix-location'] }}/usr/sbin/sendmail - - -[postfix-symlinks-libexec] +[base-wrapper] +recipe = slapos.cookbook:wrapper +environment = + MAIL_CONFIG=${directory:etc-postfix} + SASL_CONF_PATH=${directory:etc-cyrus} +parameters-extra = true + +[base-bin-wrapper] +< = base-wrapper +command-line = ${:path}/${:basename} +wrapper-path = ${directory:bin}/${:basename} + +[base-bin-bin-wrapper] +< = base-bin-wrapper +path = {{ parameter_dict['postfix-location'] }}/usr/bin + +[base-sbin-bin-wrapper] +< = base-bin-wrapper +path = {{ parameter_dict['postfix-location'] }}/usr/sbin + +{% for extend, basename_list in ( + ( + 'base-bin-bin-wrapper', + ( + 'mailq', + 'newaliases', + ), + ), + ( + 'base-sbin-bin-wrapper', + ( + 'postalias', + 'postcat', + 'postconf', + 'postdrop', + 'postfix', + 'postkick', + 'postlock', + 'postlog', + 'postmap', + 'postmulti', + 'postqueue', + 'postsuper', + 'sendmail', + ), + ), +) %} +{% for basename in basename_list -%} +[{{ section('wrapper-' ~ basename) }}] +< = {{ extend }} +basename = {{ basename }} +{% endfor %} +{% endfor %} + +[{{ section('postfix-symlinks-libexec') }}] recipe = slapos.cookbook:symbolic.link target-directory = ${directory:usr} link-binary = {{ parameter_dict['postfix-location'] }}/usr/libexec +[{{ section('service-postfix-master') }}] +< = base-wrapper +command-line = ${directory:usr}/libexec/postfix/master +wrapper-path = ${directory:run}/postfix-master -[service-postfix-master] -recipe = slapos.cookbook:wrapper -command-line = {{ parameter_dict['postfix-location'] }}/usr/libexec/postfix/master -wrapper-path = ${directory:service}/start-postfix-master -environment = MAIL_CONFIG=${directory:etc_postfix} - - -[postfix-environment] -MAIL_CONFIG=${directory:etc_postfix} +[{{ section('postfix-promise') }}] +recipe = slapos.cookbook:check_port_listening +path = ${directory:promise}/postfix +hostname = {{ ip }} +port = {{ tcpv4_port }} - -[sh-postfix-environment] -recipe = slapos.recipe.template:jinja2 -template = inline: - export MAIL_CONFIG="${directory:etc_postfix}" -rendered = ${buildout:directory}/postfix-environment.sh -context = - section postfix_environment postfix-environment -mode = 755 - - -{% endif %} +[buildout] +extends = {{ logrotate_cfg }} +parts = + {{ part_list | join('\n ') }} diff --git a/stack/erp5/instance-zope.cfg.in b/stack/erp5/instance-zope.cfg.in index 97df0b32564e6ddf59d0b71845749af8835c44d3..8a82b97a1a9426494224dc4e8ef1189a9a4d5ea0 100644 --- a/stack/erp5/instance-zope.cfg.in +++ b/stack/erp5/instance-zope.cfg.in @@ -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, diff --git a/stack/erp5/instance.cfg.in b/stack/erp5/instance.cfg.in index d591b05fe2b4cacafb2b8acd43b7dc5f1dac8fe3..908662864efd38be2cadf47efda8458a6bca46dd 100644 --- a/stack/erp5/instance.cfg.in +++ b/stack/erp5/instance.cfg.in @@ -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 }} diff --git a/stack/erp5/postfix_aliases.in b/stack/erp5/postfix_aliases.in new file mode 100644 index 0000000000000000000000000000000000000000..dfb8b3cdb6b44fea0c795b6efa7d6bbd7c220679 --- /dev/null +++ b/stack/erp5/postfix_aliases.in @@ -0,0 +1,4 @@ +# See http://www.postfix.org/aliases.5.html for format +{% for name, alias_list in alias_dict.items() -%} +{{ name }}: {{ alias_list | join(', ') }} +{% endfor %} diff --git a/stack/erp5/postfix_main.cf.in b/stack/erp5/postfix_main.cf.in index 8ad9e178ab67ab19e7e3f01ac5c53ab7ed752804..e438f59949e3f88957160468a01efe0088c32119 100644 --- a/stack/erp5/postfix_main.cf.in +++ b/stack/erp5/postfix_main.cf.in @@ -1,17 +1,13 @@ # 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 %} diff --git a/stack/erp5/postfix_master.cf.in b/stack/erp5/postfix_master.cf.in index 512798f2cabc074902060569bbd2db3c2a6c887c..d31f20f0b35cdd9905e7a67bc84ba18cf55953cb 100644 --- a/stack/erp5/postfix_master.cf.in +++ b/stack/erp5/postfix_master.cf.in @@ -1,10 +1,9 @@ -{% 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