diff options
Diffstat (limited to 'roles')
25 files changed, 766 insertions, 119 deletions
diff --git a/roles/MX/templates/etc/postfix/virtual/transport.j2 b/roles/MX/templates/etc/postfix/virtual/transport.j2 index 57a0349..69a8c83 100644 --- a/roles/MX/templates/etc/postfix/virtual/transport.j2 +++ b/roles/MX/templates/etc/postfix/virtual/transport.j2 @@ -6,24 +6,24 @@ # transport_maps. Hence high latency maps such as LDAP or SQL would # congestion the queue manager. On the other hand, virtual aliasing is # performed by cleanup(8), multiples instances of which can run in # parallel. See http://www.postfix.org/ADDRESS_REWRITING_README.html . # # /!\ WARNING: xxx.fripost.org should NOT be in the list of valid # domains ($virtual_alias_domains)! Otherwise at the next iteration of # the alias resolution loop the domain will be validated but not the # address, and the MTA will reply with "Recipient address rejected: User # unknown in virtual alias table". reserved.fripost.org reserved-alias: {% if 'LDA' in group_names %} mda.fripost.org smtpl:[127.0.0.1]:{{ postfix_instance.IMAP.port }} {% else %} mda.fripost.org smtp:[mda.fripost.org]:{{ postfix_instance.IMAP.port }} {% endif %} {% if 'lists' in group_names %} -mailman.fripost.org smtpl:[127.0.0.1]:{{ postfix_instance.lists.port }} +sympa.fripost.org smtpl:[127.0.0.1]:{{ postfix_instance.lists.port }} {% else %} -mailman.fripost.org smtp:[lists.fripost.org]:{{ postfix_instance.lists.port }} +sympa.fripost.org smtp:[lists.fripost.org]:{{ postfix_instance.lists.port }} {% endif %} diff --git a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 index 48758be..a7e4fa2 100644 --- a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 +++ b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 @@ -38,41 +38,41 @@ olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap.fripost.org.key # TLS-protected simple binds, though. olcTLSVerifyClient: try olcTLSCACertificateFile: /etc/ldap/ssl/clients.pem olcAuthzRegexp: "^(cn=[^,]+,ou=syncRepl),ou=LDAP,ou=SSLcerts,o=Fripost$" "$1,dc=fripost,dc=org" olcSaslSecProps: minssf=128,noanonymous,noplain,nodict olcTLSCipherSuite: PFS:%LATEST_RECORD_VERSION:!VERS-SSL3.0:!VERS-TLS1.0:!VERS-TLS1.1:!CIPHER-ALL:+AES-128-GCM:+AES-256-GCM {% endif %} olcLocalSSF: 128 # /!\ This is not portable! But we only use glibc's crypt(3), which # supports (salted, streched) SHA512 olcPasswordHash: {CRYPT} olcPasswordCryptSaltFormat: $6$%s dn: olcDatabase=mdb,cn=config objectClass: olcDatabaseConfig objectClass: olcMdbConfig olcDbDirectory: /var/lib/ldap olcSuffix: dc=fripost,dc=org -{% if 'LDAP-provider' not in group_names and ('MX' in group_names or 'lists' in group_names) %} +{% if 'LDAP-provider' not in group_names and 'MX' in group_names %} olcReadOnly: TRUE {% endif %} {% if 'LDAP-provider' in group_names %} olcLastMod: TRUE olcDbCheckpoint: 512 15 {% else %} olcLastMod: FALSE {% endif %} # The root user has all rights on the whole database (when SASL-binding # on a UNIX socket). olcRootDN: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth # Ensure that all DIT access is made according to the LDAPv3 protocol, # and must use 1/ authentication, and 2/ SASL or TLS. (Local clients # should use ldapi:// and SASL/EXERNAL, while remote clients should use # TLS.) # XXX: olcRequires: none LDAPv3 authc strong olcRequires: none LDAPv3 authc olcSecurity: simple_bind=128 ssf=128 update_ssf=128 # # @@ -83,45 +83,42 @@ olcSecurity: simple_bind=128 ssf=128 update_ssf=128 # * Stop slapd sudo service slapd stop # * Reindex sudo -u openldap slapindex -b 'dc=fripost,dc=org' # * Restart slapd sudo service slapd start # olcDbIndex: objectClass eq # Let us make Postfix's life easier. {% if 'LDAP-provider' in group_names %} olcDbIndex: fvd,fvl eq,sub olcDbIndex: fripostIsStatusActive eq {% elif 'MX' in group_names or 'MDA' in group_names %} olcDbIndex: fripostIsStatusActive,fvd,fvl eq {% endif %} {% if 'LDAP-provider' in group_names %} olcDbIndex: fripostOptionalMaildrop,fripostMaildrop eq,sub olcDbIndex: fripostCanAddDomain,fripostCanAddAlias,fripostCanAddList,fripostOwner,fripostPostmaster,fripostListManager eq {% elif 'MX' in group_names %} olcDbIndex: fripostOptionalMaildrop pres {% endif %} {% if 'LDAP-provider' in group_names %} {% endif %} -{% if ('LDAP-provider' not in group_names and - ('MX' in group_names or 'lists' in group_names)) or - 'LDAP-provider' in group_names and - (groups.MX | difference([inventory_hostname]) or - groups.lists | difference([inventory_hostname])) %} +{% if ('LDAP-provider' not in group_names and 'MX' in group_names) or + ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) %} # SyncProv/SyncRepl specific indexing. olcDbIndex: entryCSN,entryUUID eq {% endif%} # # # References # - https://wiki.zimbra.com/wiki/OpenLDAP_Performance_Tuning_5.0 # - http://www.openldap.org/doc/admin24/tuning.html # - http://www.openldap.org/faq/data/cache/42.html # - http://www.openldap.org/faq/data/cache/136.html # - http://www.zytrax.com/books/ldap/apa/indeces.html # # ######################################################################## # Sync Replication # # References: # - http://www.openldap.org/doc/admin24/replication.html#Syncrepl # - http://www.zytrax.com/books/ldap/ch7/#ol-syncrepl-rap # @@ -135,57 +132,40 @@ olcLimits: dn.onelevel="ou=syncRepl,dc=fripost,dc=org" {% if 'MX' in group_names and 'LDAP-provider' not in group_names %} # Test it: # LDAPSASL_MECH=external LDAPTLS_CACERT=/etc/ldap/ssl/ldap.fripost.org.pem LDAPTLS_CERT=/etc/ldap/ssl/mx.pem LDAPTLS_KEY=/etc/ldap/ssl/mx.key sudo -u openldap ldapwhoami -H ldaps://ldap.fripost.org/ # LDAPSASL_MECH=external LDAPTLS_CACERT=/etc/ldap/ssl/ldap.fripost.org.pem LDAPTLS_CERT=/etc/ldap/ssl/mx.pem LDAPTLS_KEY=/etc/ldap/ssl/mx.key sudo -u openldap ldapsearch -H ldaps://ldap.fripost.org/ -b ou=virtual,dc=fripost,dc=org olcSyncrepl: rid=000 provider=ldaps://ldap.fripost.org type=refreshAndPersist retry="10 30 300 +" searchbase="ou=virtual,dc=fripost,dc=org" attrs=objectClass,fvd,fvl,fripostIsStatusActive,fripostMaildrop,fripostOptionalMaildrop,fripostPostmaster,fripostOwner,fripostUseContentFilter,fripostListManager scope=sub sizelimit=unlimited schemachecking=off bindmethod=sasl saslmech=external tls_cert=/etc/ldap/ssl/mx.pem tls_key=/etc/ldap/ssl/mx.key tls_cacert=/etc/ldap/ssl/ldap.fripost.org.pem tls_reqcert=hard {% endif %} -{% if 'lists' in group_names and 'LDAP-provider' not in group_names %} -olcSyncrepl: rid=001 - provider=ldaps://ldap.fripost.org - type=refreshAndPersist - retry="10 30 300 +" - searchbase="ou=virtual,dc=fripost,dc=org" - attrs=objectClass,fvd,fvl,fripostListManager,fripostOwner - scope=sub - sizelimit=unlimited - schemachecking=off - bindmethod=sasl - saslmech=external - tls_cert=/etc/ldap/ssl/lists.pem - tls_key=/etc/ldap/ssl/lists.key - tls_cacert=/etc/ldap/ssl/ldap.fripost.org.pem - tls_reqcert=hard -{% endif %} # # ######################################################################## # Access control # /!\ WARN: All modification to the ACL should be reflected to the test # /!\ suite as well! olcAddContentAcl: TRUE # # Overview: # - Authentication (XXX: strong authentication) is required prior to any DIT # operation (see 'olcRequires'). # - We force a Security Strength Factor of 128 or above for all operations (see # 'olcSecurity'), meaning one must use either a local connection (eg, # ldapi://, possible since we set the 'olcLocalSSF' to 128), or TLS with at # least 128 bits of security. # - XXX: Services may not simple bind other than locally on a ldapi:// socket. # If no remote access is needed, they should use SASL/EXTERNAL on a ldapi:// # socket whenever possible (if the service itself supports SASL binds). # If remote access is needed, they should use SASL/EXTERNAL on a ldaps:// # socket, and their identity should be derived from the Subject of the @@ -292,43 +272,40 @@ olcAccess: to dn.exact="ou=virtual,dc=fripost,dc=org" # * The SyncRepl replicates have read access to the entry itself, when # using a TLS-protected connection. # * So has Postfix, when connecting a local ldapi:// socket from the # 'private' directory in one of the non-default instance's chroot. # * So has Dovecot on the MDA (for the iterate filter), when # SASL-binding using the EXTERNAL mechanism and connecting to a local # ldapi:// socket. # * Amavis may use the entry as searchBase (required to look for the # per-user preferences) but doesn't have read access to the entry. # * The 'nobody' UNIX user has read access on the MX:es, when using # SASL-binding using the EXTERNAL mechanism and connecting to a local # ldapi:// socket. This is required for the 'reserved-alias.pl' # script. olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$" attrs=entry,objectClass,fvd filter=(&(objectClass=FripostVirtualDomain)(!(objectClass=FripostPendingEntry))) {% if 'LDAP-provider' in group_names -%} {% if groups.MX | difference([inventory_hostname]) -%} by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd {% endif -%} - {% if groups.lists | difference([inventory_hostname]) -%} - by dn.exact="cn=lists,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd - {% endif -%} {% endif -%} by dn.exact="cn=postfix,ou=services,dc=fripost,dc=org" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd {% if 'MDA' in group_names -%} by dn.exact="username=dovecot,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd by dn.exact="username=amavis,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =sd {% endif -%} {% if 'MX' in group_names -%} by dn.exact="username=nobody,cn=peercred,cn=external,cn=auth" sockurl.regex="^ldapi://" =rsd {% endif -%} by users =0 break # # * The SyncRepl MX replicates can check whether a virtual domain is # active, and read the destination address for catch-alls, when using # a TLS-protected connection. # * So can Postfix on the MX:es, when connecting a local ldapi:// socket # from the 'private' directory in one of the non-default instance's # chroot. {% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %} olcAccess: to dn.regex="^fvd=[^,]+,ou=virtual,dc=fripost,dc=org$" attrs=fripostIsStatusActive,fripostOptionalMaildrop @@ -453,58 +430,50 @@ olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$" # from the 'private' directory in one of the non-default instance's # chroot. {% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %} olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$" attrs=entry,objectClass,fvl,fripostMaildrop,fripostIsStatusActive filter=(objectClass=FripostVirtualAlias) {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%} by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd {% endif -%} {% if 'MX' in group_names -%} by dn.exact="cn=postfix,ou=services,dc=fripost,dc=org" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd {% endif -%} by users =0 break {% endif %} # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # List entries # # * The SyncRepl replicates can read the entry itelf and the list manager, when # using a TLS-protected connection. -# * So can Postfix on the MX:es and lists managers, when connecting a local -# ldapi:// socket from the 'private' directory in one of the non-default -# instance's chroot. -# XXX: where does sympa enter the picture? we really don't want to reintroduce listcomands... -{% if 'MX' in group_names or 'lists' in group_names or ('LDAP-provider' in group_names and - (groups.lists | difference([inventory_hostname]) or groups.MX | difference([inventory_hostname]))) %} +# * So can Postfix on the MX:es, when connecting a local ldapi:// socket +# from the 'private' directory in one of the non-default instance's chroot. +{% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %} olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$" attrs=entry,objectClass,fvl,fripostListManager filter=(&(objectClass=FripostVirtualList)(!(objectClass=FripostPendingEntry))) - {% if 'LDAP-provider' in group_names -%} - {% if groups.MX | difference([inventory_hostname]) -%} + {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%} by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd {% endif -%} - {% if groups.lists | difference([inventory_hostname]) -%} - by dn.exact="cn=lists,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd - {% endif -%} - {% endif -%} - {% if 'MX' in group_names or 'lists' in group_names -%} + {% if 'MX' in group_names -%} by dn.exact="cn=postfix,ou=services,dc=fripost,dc=org" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd {% endif -%} by users =0 break {% endif %} # # * The SyncRepl MX replicates can check whether a virtual list is # active when using a TLS-protected connection. # * So can Postfix on the MX:es, when connecting a local ldapi:// socket # from the 'private' directory in one of the non-default instance's # chroot. {% if 'MX' in group_names or ('LDAP-provider' in group_names and groups.MX | difference([inventory_hostname])) %} olcAccess: to dn.regex="^fvl=[^,]+,fvd=[^,]+,ou=virtual,dc=fripost,dc=org$" attrs=fripostIsStatusActive filter=(&(objectClass=FripostVirtualList)(!(objectClass=FripostPendingEntry))) {% if 'LDAP-provider' in group_names and groups.MX | difference([inventory_hostname]) -%} by dn.exact="cn=mX,ou=syncRepl,dc=fripost,dc=org" tls_ssf=128 =rsd {% endif -%} {% if 'MX' in group_names -%} by dn.exact="cn=postfix,ou=services,dc=fripost,dc=org" sockurl.regex="^ldapi://%2Fvar%2Fspool%2Fpostfix-[-[:alnum:]]+%2Fprivate%2F" =rsd {% endif -%} diff --git a/roles/common/files/etc/logcheck/ignore.d.server/common-local b/roles/common/files/etc/logcheck/ignore.d.server/common-local index d15e350..c8553c8 100644 --- a/roles/common/files/etc/logcheck/ignore.d.server/common-local +++ b/roles/common/files/etc/logcheck/ignore.d.server/common-local @@ -2,20 +2,21 @@ # Do NOT edit this file directly! # ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: subsystem request for sftp by user [-_.[:alnum:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: User [-_.[:alnum:]]+ not allowed because account is locked$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: Read from socket failed: (Connection reset by peer|Connection timed out) \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Received disconnect from [:.[:xdigit:]]+: (3|11|14): .* \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Protocol major versions differ for [:.[:xdigit:]]+: SSH-2\.0-OpenSSH_ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnecting: Change of username or service not allowed: \(\S+\) -> \(\S+\) \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: userauth_pubkey: unsupported public key algorithm: [[:alnum:]-]+ \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: Write failed: (Connection (timed out|reset by peer)|Broken pipe) \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: fatal: no hostkey alg \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: invalid public DH value: .* \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Corrupted MAC on input\. \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Disconnecting: bad client public DH value \[preauth\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sshd\[[[:digit:]]+\]: Bad protocol version identification '.*' from [:.[:xdigit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (slapd\[[[:digit:]]+\]|slap(acl|add|auth|cat|dn|index)|ldap(add|compare|delete|exop|modify|modrdn|passwd|search|url|whoami)): DIGEST-MD5 common mech free$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ sudo:[[:space:]]+[_[:alnum:].-]+ : TTY=(unknown|(pts/|tty|vc/)[[:digit:]]+) ; PWD=[^;]+ ; USER=[._[:alnum:]-]+ (; ENV=([_a-zA-Z]+=\S* )+)?; COMMAND=(/(usr|etc|bin|sbin)/|sudoedit ) ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ rsyslogd: \[origin software="rsyslogd" swVersion="[.[:digit:]]+" x-pid="[[:digit:]]+" x-info="http://www.rsyslog.com"\] rsyslogd was HUPed$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ansible-([_a-z]+|<stdin>): Invoked with ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ slapd\[[[:digit:]]+\]: connection_input: conn=[[:digit:]]+ deferring operation: binding$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (sympa\((command|distribute)\)|wwsympa|archived|bounced|bulk|task_manager)\[[[:digit:]]+\]: (info|notice)\s diff --git a/roles/common/files/etc/logcheck/ignore.d.server/postfix-local b/roles/common/files/etc/logcheck/ignore.d.server/postfix-local index a5a1bbe..7632e0f 100644 --- a/roles/common/files/etc/logcheck/ignore.d.server/postfix-local +++ b/roles/common/files/etc/logcheck/ignore.d.server/postfix-local @@ -28,58 +28,58 @@ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: Connection concurrency limit exceeded: [0-9]+ from [._[:alnum:]-]+\[[[:digit:].]{7,15}\] for service smtpd$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: timeout after [-[:upper:]]+( \([[:digit:]]+ bytes\))? from [^[:space:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-((msa|mx)/smtpd|out/smtp)\[[[:digit:]]+\]: warning: (tls_text_name: [-._[:alnum:]]+\[[[:xdigit:].:]{3,39}\]: )?peer certificate has no (subject CN|issuer Organization)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|webmail)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.2)? <[^>]*>: Recipient address rejected: Domain not found;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|webmail)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 450( 4\.1\.8)? <[^>]*>: Sender address rejected: Domain not found;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|webmail)/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 504( 5\.5\.2)? <[^>]*>: (Recipient|Sender) address rejected: need fully-qualified address;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: 554 5\.7\.1 <[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]>: Client host rejected: Access denied;( from=<[^>]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mda/lmtp\[[[:digit:]]+\]: [[:xdigit:]]{10}: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,)? relay=[._[:alnum:]-]+\[private/dovecot-lmtpd\],( conn_use=[[:digit:]]+,)? delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=2(\.[[:digit:]]+){2})?, status=sent \(2[[:digit:]][[:digit:]] .+\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/(error|n?qmgr|smtp)\[[[:digit:]]+\]: [[:alnum:]]+: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,)? relay=(none|[^[:space:]]+\[[[:digit:].]{7,15}\]:(25|587)),( conn_use=[[:digit:]]+,)? delay=[[:digit:].]+,( delays=[[:digit:]./]+,)?( dsn=[45]\.[[:digit:]]\.[[:digit:]],)? status=(deferred|undeliverable) \((delivery temporarily suspended: )?((lost connection with [^[:space:]]+|conversation with [^[:space:]]+ timed out) while (sending [[:alnum:]]+( [[:alnum:]]+)?|performing the (HELO|EHLO) handshake|receiving the initial server greeting|sending [[:alnum:]]+( [/[:alnum:]]+)?|sending end of data -- message may be sent more than once)|connect to [^[:space:]]+: (Connection timed out|read timeout|Connection refused)|Host or domain name not found. Name service errorfor name=[^[:space:]]+ type=MX: Host not found, try again|User unknown in virtual alias table)\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:alnum:]]+: lost connection with [._[:alnum:]-]+\[[[:digit:].]{7,15}\] while receiving the initial server greeting$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:alnum:]]+: conversation with [^[:space:]]+ timed out while sending message body$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: to=<[^[:space:]]+>(, orig_to=<[^[:space:]]+>)?, relay=[._[:alnum:]-]+\[[[:digit:].]{7,15}\](:[[:digit:]]{1,5})?,( conn_use=[[:digit:]]+,)? delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=[45](\.[[:digit:]]+){2})?, status=(deferred|bounced|undeliverable|SOFTBOUNCE) \(host [._[:alnum:]-]+\[[[:digit:].]{7,15}\] said: [45][[:digit:]][[:digit:]][- ]+.* \(in reply to (HELO|EHLO|MAIL FROM|RCPT TO|DATA|end of DATA) command\)\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: connect to [^[:space:]]+: (read timeout|Connection (refused|timed out)|Network is unreachable|No route to host)( \(port [[:digit:]]+\))?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/[ls]mtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: to=<[^[:space:]]+>, relay=[._[:alnum:]-]+\[[[:digit:].]{7,15}\](:[[:digit:]]{1,5})?, (conn_use=[[:digit:]]+, )?delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=[45](\.[[:digit:]]+){2})?, status=(deferred|bounced|undeliverable) \(host [._[:alnum:]-]+\[[[:digit:].]{7,15}\] said: [45][[:digit:]][[:digit:]] .+ \(in reply to (HELO|EHLO|MAIL FROM|RCPT TO|end of DATA) command\)\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: host [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] said: [45][[:digit:]][[:digit:]][- ]+.* \(in reply to (HELO|EHLO|MAIL FROM|RCPT TO|(end of )?DATA) command\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mda|out)/smtpd\[[[:digit:]]+\]: [[:xdigit:]]{10}: client=[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\], orig_queue_id=[[:xdigit:]]{10}, orig_client=[._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [A-Z[:digit:]]+: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,) relay=[^[:space:]]+, delay=[[:digit:]]+, status=deferred \(host [^[:space:]]+ said: [45][[:digit:]]{2} <[^[:space:]]*>: Recipient address rejected: Greylisted for [[:digit:]]+ (seconds|minutes)(\(see http://isg.ee.ethz.ch/tools/postgrey/help/[.[:alnum:]-]+.html\))? \(in reply to (HELO|EHLO|MAIL FROM|RCPT TO|DATA|end of DATA) command\)\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:alnum:]]+: to=<.*>,( orig_to=<[^[:space:]]+>,)? relay=[^[:space:]]+\](:[[:digit:]]+)?,( conn_use=[[:digit:]]+,)? delay=[[:digit:].]+,( delays=[[:digit:]./]+,)?( dsn=4\.[[:digit:]]\.[[:digit:]],)? status=deferred \(host [^[:space:]]+\] said: .*$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mda|out)/smtpd?\[[[:digit:]]+\]: warning: numeric domain name in resource data of MX record for [._[:alnum:]-]+: [[:xdigit:].:]{3,39}$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(msa|mx)/smtpd\[[[:digit:]]+\]: SSL_accept error from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\]: (lost connection|Connection reset by peer|-?[[:digit:]]+|Connection timed out)$ -^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: warning: TLS library problem: [[:digit:]]+:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1258:SSL alert number 48:$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-msa/smtpd\[[[:digit:]]+\]: warning: TLS library problem: [[:digit:]]+:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:[0-9]+:SSL alert number 48:$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(out|mx)/bounce\[[[:digit:]]+\]: [[:xdigit:]]+: sender (delay|non-delivery|delivery status) notification: [[:xdigit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: host [^[:space:]]+ refused to talk to me: [45][[:digit:]][[:digit:]].*$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: enabling PIX <CRLF>\.<CRLF> workaround for [._[:alnum:]-]+\[[[:digit:].]{7,15}\](:[[:digit:]]{1,5})?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: enabling PIX workarounds:( (disable_esmtp|delay_dotcrlf))+ for [._[:alnum:]-]+\[[[:digit:].]{7,15}\](:[[:digit:]]{1,5})?$ -^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: to=<[^>]+>, relay=[-_.[:alnum:]]+, delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=4(\.[[:digit:]]+){2})?, status=deferred \(connect to [._[:alnum:]-]+\[(unknown|[[:xdigit:].:]{3,39})\]:[[:digit:]]+: Network is unreachable\)$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-out/smtp\[[[:digit:]]+\]: [[:upper:][:digit:]]+: to=<[^>]+>, relay=[-_.[:alnum:]]+, delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=4(\.[[:digit:]]+){2})?, status=deferred \(connect to [._[:alnum:]-]+\[(unknown|[[:xdigit:].:]{3,39})\]:[[:digit:]]+: (Network is unreachable|No route to host)\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:upper:][:digit:]]+: reject: RCPT from [^[:space:]]+: 4[[:digit:]][[:digit:]]( 4(\.[[:digit:]]){2}) <[^[:space:]]*>: Recipient address rejected: Greylisted( for [[:digit:]]+ (second|minute)s)?, see https?://[-_.:/[:alnum:]]+\.html?; from=<[^[:space:]]*> to=<[^[:space:]]+> proto=E?SMTP helo=<[^[:space:]]+>$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|msa)/smtpd\[[[:digit:]]+\]: lost connection after [[:upper:]]+( \([[:digit:]]+ bytes\))? from [._[:alnum:]-]+\[(unknown|[[:xdigit:].:]{3,39})\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:upper:][:digit:]]+: reject: (CONNECT|RCPT) from [^[:space:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]){2})? Service unavailable; Client host \[([[:digit:].]{7,15}|[-._[:alnum:]]+)\] blocked using [._[:alnum:]-]+;( .+;)? (from=<[^[:space:]]*> to=<[^[:space:]]+> )?proto=E?SMTP( helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:upper:][:digit:]]+: reject: RCPT from [^[:space:]]+: [[:digit:]]{3}( [45](\.[[:digit:]]){2})? <[^[:space:]]*>: Relay access denied; from=<[^[:space:]]*> to=<[^[:space:]]+> proto=E?SMTP helo=<[^[:space:]]+>$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: ([-._[:alnum:]]+): RBL lookup error: Host or domain name not found\. Name service error for name=\1 type=A: Host not found, try again$ -^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: TLS library problem: [[:digit:]]+:error:[[:xdigit:]]+:SSL routines:SSL2?3_(GET_RECORD:decryption failed or bad record mac:s3_pkt\.c:484:|READ_BYTES:(reason\([[:digit:]]+\)|sslv3 alert (unexpected message|bad certificate)):s3_pkt\.c:[[:digit:]]+:SSL alert number (0|10|42):|GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1361:|GET_CLIENT_HELLO:unsupported protocol:s23_srvr.c:557:)$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: TLS library problem: [[:digit:]]+:error:[[:xdigit:]]+:SSL routines:SSL2?3_(GET_RECORD:decryption failed or bad record mac:s3_pkt\.c:[0-9]+:|READ_BYTES:(reason\([[:digit:]]+\)|sslv3 alert (unexpected message|bad certificate)):s3_pkt\.c:[[:digit:]]+:SSL alert number (0|10|42):|GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:[0-9]+:|GET_CLIENT_HELLO:unsupported protocol:s23_srvr.c:[0-9]+:)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: (NOQUEUE|[[:xdigit:]]+): reject: [[:upper:]]+ from [^[:space:]]+: 554( 5\.1\.[01])? <[^[:space:]]*>: Recipient address rejected: User unknown in virtual alias table;( from=<[^[:space:]]*> to=<[^[:space:]]+>)? proto=E?SMTP( helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: [[:upper:][:digit:]]+: reject: RCPT from [^[:space:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]){2})? <[^[:space:]]*>: Helo command rejected: .+; from=<[^[:space:]]*> to=<[^[:space:]]+> proto=E?SMTP helo=<[^[:space:]]+>$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: too many errors after ([[:upper:]]{4}|END-OF-MESSAGE|UNKNOWN|DATA \(0 bytes\)) from [._[:alnum:]-]+\[[.[:digit:]]+\]$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: hostname [^[:space:]]+ does not resolve to address [[:xdigit:].:]{3,39}: (No address associated with hostname|Temporary failure in name resolution)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: (numeric hostname: [[:xdigit:].:]{3,39}|valid_hostname: misplaced delimiter: \S)$ -^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/pipe\[[[:digit:]]+\]: [[:upper:][:digit:]]+: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,)* relay=([-_.[:alnum:]]+), delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=2(\.[[:digit:]]+){2})?, status=sent \(delivered via \2 service\)$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-(mx|lists)/pipe\[[[:digit:]]+\]: [[:upper:][:digit:]]+: to=<[^[:space:]]+>,( orig_to=<[^[:space:]]+>,)* relay=([-_.[:alnum:]]+), delay=[.[:digit:]]+(, delays=([.[:digit:]]+/){3}[.[:digit:]]+)?(, dsn=2(\.[[:digit:]]+){2})?, status=sent \(delivered via \3 service\)$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/smtpd\[[[:digit:]]+\]: warning: Illegal address syntax from [._[:alnum:]-]+\[[[:xdigit:].:]{3,39}\] in MAIL command: .*$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: (PASS (OLD|NEW)|WHITELISTED) \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: CONNECT from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+ to \[[[:xdigit:].:]{3,39}\]:25$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: DISCONNECT \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: PREGREET [[:digit:]]+ after [.[:digit:]]+ from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+:\s ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: HANGUP after [.[:digit:]]+ from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+ in tests (before|after) SMTP handshake$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: BARE NEWLINE from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NON-SMTP COMMAND from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+\s ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: COMMAND PIPELINING from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+ after\s ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: DNSBL rank [[:digit:]]+ for \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NOQUEUE: reject: RCPT from (\[[[:xdigit:].:]{3,39}\]):[[:digit:]]+: [45][[:digit:]][[:digit:]]( [45](\.[[:digit:]]){2})? (Service unavailable; client \1 blocked using [._[:alnum:]-]+|Protocol error);( .+;)? (from=<[^>]*>, to=<[^>]+>, )?proto=E?SMTP(, helo=<[^[:space:]]+>)?$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: NOQUEUE: reject: CONNECT from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+: too many connections$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: COMMAND (COUNT|TIME) LIMIT from \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: cache [a-z]+:\S+ full cleanup: retained=[[:digit:]]+ dropped=[[:digit:]]+ entries$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: warning: getpeername: Transport endpoint is not connected -- dropping this connection$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/postscreen\[[[:digit:]]+\]: warning: psc_cache_update: btree:/var/lib/postfix-mx/postscreen_cache update average delay is [[:digit:]]+ ms$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/dnsblog\[[[:digit:]]+\]: addr [[:xdigit:].:]{3,39} listed by domain [._[:alnum:]-]+ as [[:xdigit:].:]{3,39}$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/dnsblog\[[[:digit:]]+\]: warning: dnsblog_query: lookup error for DNS query ([._[:alnum:]-]+): Host or domain name not found. Name service error for name=\1 type=A: Host not found, try again$ ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ postfix-mx/tlsproxy\[[[:digit:]]+\]: (CONNECT from|DISCONNECT) \[[[:xdigit:].:]{3,39}\]:[[:digit:]]+$ # diff --git a/roles/common/files/etc/postfix/master.cf b/roles/common/files/etc/postfix/master.cf index b60be94..5fb91a5 100644 --- a/roles/common/files/etc/postfix/master.cf +++ b/roles/common/files/etc/postfix/master.cf @@ -31,42 +31,42 @@ smtp unix - - - - - smtp smtpl unix - - - - - smtp -o smtp_bind_address=127.0.0.1 relay unix - - - - - smtp # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - - - - showq error unix - - - - - error retry unix - - - - - error discard unix - - - - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - - - - lmtp anvil unix - - - - 1 anvil scache unix - - - - 1 scache 127.0.0.1:16132 inet n - - - - smtpd 2525 inet n - - - - smtpd 2526 inet n - - - - smtpd 2527 inet n - - - - smtpd 127.0.0.1:2580 inet n - - - - smtpd reserved-alias unix - n n - - pipe flags=Rhu user=nobody argv=/usr/local/sbin/reserved-alias.pl ${sender} ${original_recipient} @fripost.org -mlmmj unix - n n - - pipe - flags=Rhu user=mlmmj argv=/usr/bin/mlmmj-receive -L /var/spool/mlmmj/${domain}/${user} +sympa unix - n n - - pipe + flags=Rhu user=sympa argv=/usr/local/bin/sympa-queue ${user} # Client part (lmtp) - amavis amavisfeed unix - - n - 5 lmtp -o lmtp_destination_recipient_limit=1000 -o lmtp_send_xforward_command=yes -o lmtp_data_done_timeout=1200s -o disable_dns_lookups=yes # Server part (smtpd) - amavis (if the MDA and outgoing proxy are on the # same machine, we need to create another entry, on another port.) 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o smtpd_restriction_classes= diff --git a/roles/common/templates/etc/iptables/services.j2 b/roles/common/templates/etc/iptables/services.j2 index 7709066..c628d50 100644 --- a/roles/common/templates/etc/iptables/services.j2 +++ b/roles/common/templates/etc/iptables/services.j2 @@ -28,30 +28,33 @@ out tcp {{ postfix_instance.IMAP.port }} {% endif %} {% if 'lists' not in group_names %} out tcp {{ postfix_instance.lists.port }} {% endif %} {% endif %} {% if 'out' in group_names %} {% if groups.all | difference([inventory_hostname]) %} in tcp {{ postfix_instance.out.port }} {% endif %} out tcp 25 # SMTP {% else %} out tcp {{ postfix_instance.out.port }} {% endif %} {% if 'IMAP' in group_names %} in tcp 993 # IMAPS in tcp 4190 # ManageSieve {% endif %} {% if 'MDA' in group_names and 'MX' not in group_names %} in tcp {{ postfix_instance.IMAP.port }} {% endif %} +{% if 'lists' in group_names and 'MX' not in group_names %} +in tcp {{ postfix_instance.lists.port }} +{% endif %} {% if 'MSA' in group_names %} in tcp 587 # SMTP-AUTH {% endif %} -{% if 'webmail' in group_names %} +{% if 'webmail' in group_names or 'lists' in group_names %} in tcp 80,443 # HTTP/HTTPS {% if 'IMAP' not in group_names %} out tcp 993 # IMAP out tcp 4190 {% endif %} {% endif %} diff --git a/roles/common/templates/etc/postfix/tls_policy.j2 b/roles/common/templates/etc/postfix/tls_policy.j2 index d53b0a0..5ff7d26 100644 --- a/roles/common/templates/etc/postfix/tls_policy.j2 +++ b/roles/common/templates/etc/postfix/tls_policy.j2 @@ -1,25 +1,25 @@ # {{ ansible_managed }} # /!\ WARNING: smtp_tls_fingerprint_digest MUST be sha256! {% if 'out' not in group_names %} [outgoing.fripost.org]:{{ postfix_instance.out.port }} fingerprint ciphers=high protocols=TLSv1.2 {% for h in groups.out | sort %} match={{ lookup('pipe', 'openssl x509 -in certs/postfix/'+h+'.pem -noout -fingerprint -sha256 | cut -d= -f2') }} {% endfor %} {% endif %} {% if 'MX' in group_names %} {% if 'IMAP' not in group_names %} [mda.fripost.org]:{{ postfix_instance.IMAP.port }} fingerprint ciphers=high protocols=TLSv1.2 {% for h in groups.IMAP | sort %} match={{ lookup('pipe', 'openssl x509 -in certs/postfix/'+h+'.pem -noout -fingerprint -sha256 | cut -d= -f2') }} {% endfor %} {% endif %} {% if 'lists' not in group_names %} -[antilop.fripost.org]:{{ postfix_instance.lists.port }} fingerprint ciphers=high +[lists.fripost.org]:{{ postfix_instance.lists.port }} fingerprint ciphers=high protocols=TLSv1.2 {% for h in groups.lists | sort %} match={{ lookup('pipe', 'openssl x509 -in certs/postfix/'+h+'.pem -noout -fingerprint -sha256 | cut -d= -f2') }} {% endfor %} {% endif %} {% endif %} diff --git a/roles/lists/files/etc/nginx/sites-available/sympa b/roles/lists/files/etc/nginx/sites-available/sympa new file mode 100644 index 0000000..5887dd0 --- /dev/null +++ b/roles/lists/files/etc/nginx/sites-available/sympa @@ -0,0 +1,62 @@ +server { + listen 80; + listen [::]:80 ipv6only=on; + + server_name lists.fripost.org; + + access_log /var/log/nginx/lists.access.log; + error_log /var/log/nginx/lists.error.log info; + + return 301 https://$host$request_uri; +} + + +server { + listen 443; + listen [::]:443 ipv6only=on; + + server_name lists.fripost.org; + + include ssl/config; + ssl_certificate /etc/nginx/ssl/lists.fripost.org.pem; + ssl_certificate_key /etc/nginx/ssl/lists.fripost.org.key; + + location = / { + return 301 /sympa$args; + } + + location ^~ /static-sympa/ { + alias /var/lib/sympa/static_content/; + } + + location ^~ /sympa { + fastcgi_split_path_info ^(/sympa)(.*)$; + include fastcgi/params; + + fastcgi_pass unix:/run/wwsympa.socket; + gzip off; + } + + location ~* ^/([^/]+)/?$ { + return 301 /$1/sympa$args; + } + location ~* ^/([^/]+)/sympa(/.*)?$ { + set $vhost $1; + + if (!-f /etc/sympa/$vhost/robot.conf) { + return 404; + } + + fastcgi_split_path_info ^(/[^/]+/sympa)(.*)$; + include fastcgi/params; + + fastcgi_pass unix:/run/wwsympa.socket; + gzip off; + + fastcgi_param SERVER_NAME $vhost; + } + + location / { + return 404; + } +} diff --git a/roles/lists/files/etc/postfix/transport b/roles/lists/files/etc/postfix/transport new file mode 100644 index 0000000..d3ddde3 --- /dev/null +++ b/roles/lists/files/etc/postfix/transport @@ -0,0 +1,11 @@ +# Each valid address user@example.org is aliased (on the MX) into some +# example.org/user@xxx.fripost.org, and non-defaults next-hop:port are +# chosen here in that table, depending on 'xxx'. The reason for such +# indirection is that there is only one qmgr(8) daemon, which delegate +# the routing strategy to the trivial-rewrite(8), which in turns queries +# transport_maps. Hence high latency maps such as LDAP or SQL would +# congestion the queue manager. On the other hand, virtual aliasing is +# performed by cleanup(8), multiples instances of which can run in +# parallel. See http://www.postfix.org/ADDRESS_REWRITING_README.html . + +sympa.fripost.org sympa: diff --git a/roles/lists/files/etc/postfix/virtual/domains.cf b/roles/lists/files/etc/postfix/virtual/domains.cf deleted file mode 120000 index 320a970..0000000 --- a/roles/lists/files/etc/postfix/virtual/domains.cf +++ /dev/null @@ -1 +0,0 @@ -../../../../../MX/templates/etc/postfix/virtual/domains.cf.j2
\ No newline at end of file diff --git a/roles/lists/files/etc/postfix/virtual/transport_list.cf b/roles/lists/files/etc/postfix/virtual/transport_list.cf deleted file mode 100644 index 384b832..0000000 --- a/roles/lists/files/etc/postfix/virtual/transport_list.cf +++ /dev/null @@ -1,8 +0,0 @@ -server_host = ldapi://%2Fprivate%2Fldapi/ -version = 3 -search_base = fvl=%u,fvd=%d,ou=virtual,dc=fripost,dc=org -domain = static:all -scope = base -bind = none -query_filter = (&(objectClass=FripostVirtualList)(fvl=%u)) -result_attribute = fripostListManager diff --git a/roles/lists/files/etc/sympa/sympa.conf b/roles/lists/files/etc/sympa/sympa.conf new file mode 100644 index 0000000..f761383 --- /dev/null +++ b/roles/lists/files/etc/sympa/sympa.conf @@ -0,0 +1,319 @@ +###\\\\ Site customization ////### + +## Main robot hostname +domain lists.fripost.org + +## Local part of sympa email address +## Effective address will be [EMAIL]@[HOST] +email sympa + +## Listmasters email list comma separated +## Sympa will associate listmaster privileges to these email addresses (mail and web interfaces). Some error reports may also be sent to these addresses. +listmaster listmaster@fripost.org + +## URL of main Web page +#wwsympa_url http://lists.fripost.org/sympa + +max_wrong_password 19 + +## Directory for storing static contents (CSS, members pictures, documentation) directly delivered by Apache +static_content_path /var/lib/sympa/static_content + +## URL mapped with the static_content_path directory defined above +static_content_url /static-sympa + +css_url /static-sympa/css + +## Secret used by Sympa to make MD5 fingerprint in web cookies secure +## Should not be changed ! May invalid all user password +cookie `cat /etc/sympa/cookie` + +## Who is able to create lists +## This parameter is a scenario, check sympa documentation about scenarios if you want to define one +create_list intranet + +###\\\\ Directories ////### + +## Directory containing mailing lists subdirectories +home /var/lib/sympa/list_data + +## Directory for configuration files; it also contains scenari/ and templates/ directories +etc /etc/sympa + +###\\\\ System related ////### + +## Syslog facility for sympa +## Do not forget to edit syslog.conf +syslog `cat /etc/sympa/facility` + +## Log verbosity +## 0: normal, 2,3,4: for debug +log_level 0 + +## Communication mode with syslogd (unix | inet) +log_socket_type unix + +## Umask used for file creation by Sympa +umask 027 + +###\\\\ Sending related ////### + +## Path to the MTA (sendmail, postfix, exim or qmail) +## should point to a sendmail-compatible binary (eg: a binary named "sendmail" is distributed with Postfix) +sendmail /usr/sbin/sendmail +sendmail_aliases none + +distribution_mode fork + +## Max. number of Sendmail processes (launched by Sympa) running simultaneously +## Proposed value is quite low, you can rise it up to 100, 200 or even 300 with powerfull systems. +maxsmtp 128 + +log_smtp off + +## comma separated list of operations for which blacklist filter is applied +## Setting this parameter to "none" will hide the blacklist feature +use_blacklist send,create_list + +## Default maximum size (in bytes) for messages (can be re-defined for each list) +max_size 5242880 + +## Maximum number of recipients per call to Sendmail. The nrcpt_by_domain.conf file allows a different tuning per destination domain. +nrcpt 25 + +## Max. number of different domains per call to Sendmail +avg 10 + +## Specify which rfc2369 mailing list headers to add +rfc2369_header_fields help,subscribe,unsubscribe,post,owner,archive + +## Specify header fields to be removed before message distribution +remove_headers X-Sympa-To,X-Family-To,Return-Receipt-To,Precedence,X-Sequence,Disposition-Notification-To + +## Reject mail from automates (crontab, etc) sent to a list? +reject_mail_from_automates_feature on + +alias_manager /bin/true + +###\\\\ Bulk mailer ////### + +## Default priority for a packet to be sent by bulk. +sympa_packet_priority 5 + +## Minimum number of packets in database before the bulk forks to increase sending rate +## +bulk_fork_threshold 1 + +## Max number of bulks that will run on the same server +## +bulk_max_count 3 + +## The number of seconds a slave bulk will remain running without processing a message before it spontaneously dies. +## +bulk_lazytime 600 + +## The number of seconds a bulk sleeps between starting a new loop if it didn't find a message to send. +## Keep it small if you want your server to be reactive. +bulk_sleep 1 + +## Number of seconds a master bulk waits between two packets number checks. +## Keep it small if you expect brutal increases in the message sending load. +bulk_wait_to_fork 10 + +###\\\\ Quotas ////### + +###\\\\ Spool related ////### + +## Directory containing various specialized spools +## All spool are created at runtime by sympa.pl +spool /var/spool/sympa + +## Directory for incoming spool +queue /var/spool/sympa/msg + +queuedistribute /var/spool/sympa/distribute + +## Directory for moderation spool +queuemod /var/spool/sympa/moderation + +## Directory for digest spool +queuedigest /var/spool/sympa/digest + +## Directory for authentication spool +queueauth /var/spool/sympa/auth + +## Directory for outgoing spool +queueoutgoing /var/spool/sympa/outgoing + +## Directory for subscription spool +queuesubscribe /var/spool/sympa/subscribe + +## Directory for topic spool +queuetopic /var/spool/sympa/topic + +## Directory for bounce incoming spool +queuebounce /var/spool/sympa/bounce + +## Directory for task spool +queuetask /var/spool/sympa/task + +## Directory for automatic list creation spool +queueautomatic /var/spool/sympa/automatic + +###\\\\ Internationalization related ////### + +## Supported languages +## This is the set of language that will be proposed to your users for the Sympa GUI. Don't select a language if you don't have the proper locale packages installed. +supported_lang sv,en_US + +## Default language (one of supported languages) +## This is the default language used by Sympa +lang sv + +## If set to "on", enables support of legacy character set +## In some language environments, legacy encoding (character set) is preferred for e-mail messages: for example iso-2022-jp in Japanese language. +legacy_character_support_feature off + +###\\\\ Bounce related ////### + +## Welcome message return-path ( unique | owner ) +## If set to unique, new subcriber is removed if welcome message bounce +welcome_return_path owner + +## Remind message return-path ( unique | owner ) +## If set to unique, subcriber is removed if remind message bounce, use with care +remind_return_path owner + +## Task name for expiration of old bounces +expire_bounce_task daily + +## Bouncing email rate for warn list owner +bounce_warn_rate 30 + +## Bouncing email rate for halt the list (not implemented) +## Not yet used in current version, Default is 50 +bounce_halt_rate 50 + +###\\\\ Tuning ////### + +## Use of binary version of the list config structure on disk (none | binary_file) +## Set this parameter to "binary_file" if you manage a big amount of lists (1000+); it should make the web interface startup faster +cache_list_config none + +## Sympa commands priority +sympa_priority 1 + +request_priority 0 + +owner_priority 9 + +## Default priority for list messages +default_list_priority 5 + +## comma-separated list of files that will be parsed by Sympa when instantiating a family (no space allowed in file names) +parsed_family_files message.footer,message.header,message.footer.mime,message.header.mime,info + +###\\\\ Database related ////### + +## Type of the database (mysql|ODBC|Oracle|Pg|SQLite|Sybase) +## Be careful to the case +db_type mysql + +## Name of the database +## With SQLite, the name of the DB corresponds to the DB file +db_name sympa + +## Hostname of the database server +db_host localhost + +## User for the database connection +db_user sympa + +## Password for the database connection +## What ever you use a password or not, you must protect the SQL server (is it not a public internet service ?) +#db_passwd your_passwd + +## Database private extention to subscriber table +## You need to extend the database format with these fields +#db_additional_subscriber_fields billing_delay,subscription_expiration + +## Database private extention to user table +## You need to extend the database format with these fields +#db_additional_user_fields age,address + +## Number of months that elapse before a log is expired +logs_expiration_period 3 + +## Default timeout between two scheduled synchronizations of list members with data sources. +default_ttl 3600 + +## Default timeout between two action-triggered synchronizations of list members with data sources. +default_distribution_ttl 300 + +## Default timeout while performing a fetch for an include_sql_query sync +default_sql_fetch_timeout 300 + +###\\\\ Loop prevention ////### + +###\\\\ S/MIME configuration ////### + +## Path to OpenSSL +## Sympa recognizes S/MIME if OpenSSL is installed +#openssl /usr/bin/ssl + +## Directory containing trusted CA certificates +#capath /etc/sympa/ssl.crt + +## File containing bundled trusted CA certificates +#cafile /usr/local/apache/conf/ssl.crt/ca-bundle.crt + +crl_dir /var/lib/sympa/list_data/crl + +## Directory containing user certificates +ssl_cert_dir /var/lib/sympa/list_data/X509-user-certs + +## Password used to crypt lists private keys +#key_passwd your_password + +###\\\\ DKIM ////### + +dkim_feature off + +## Insert a DKIM signature to message from the robot, from the list or both +dkim_add_signature_to robot,list + +## Type of message that is added a DKIM signature before distribution to subscribers. Possible values are "none", "any" or a list of the following keywords: "md5_authenticated_messages", "smime_authenticated_messages", "dkim_authenticated_messages", "editor_validated_messages". +dkim_signature_apply_on md5_authenticated_messages,smime_authenticated_messages,dkim_authenticated_messages,editor_validated_messages + +###\\\\ Antivirus plug-in ////### + +## Path to the antivirus scanner engine +## Supported antivirus: McAfee/uvscan, Fsecure/fsav, Sophos, AVP and Trend Micro/VirusWall +#antivirus_path /usr/local/uvscan/uvscan + +## Antivirus plugin command argument +#antivirus_args --secure --summary --dat /usr/local/uvscan + +###\\\\ Tag based spam filtering ////### + +## If a spam filter (like spamassassin or j-chkmail) add a smtp headers to tag spams, name of this header (example X-Spam-Status) +antispam_tag_header_name X-Spam-Status + +## Regexp applied on this header to verify message is a spam (example \s*Yes) +antispam_tag_header_spam_regexp ^\s*Yes + +## Regexp applied on this header to verify message is NOT a spam (example \s*No) +antispam_tag_header_ham_regexp ^\s*No + +## Messages are supposed to be filtered by an antispam that add one more headers to messages. This parameter is used to select a special scenario in order to decide the message spam status: ham, spam or unsure. This parameter replace antispam_tag_header_name, antispam_tag_header_spam_regexp and antispam_tag_header_ham_regexp. +spam_status x-spam-status + +###\\\\ Web interface parameters ////### + +edit_list owner + +## URL of a virtual host +#http_host http://fripost.org + +## The password validation techniques to be used against user passwords that are added to mailing lists. Options come from Data::Password (http://search.cpan.org/~razinf/Data-Password-1.07/Password.pm#VARIABLES) +#password_validation MINLEN=8,GROUPS=3,DICTIONARY=4,DICTIONARIES=/pentest/dictionaries diff --git a/roles/lists/files/etc/sympa/topics.conf b/roles/lists/files/etc/sympa/topics.conf new file mode 100644 index 0000000..e45c9c2 --- /dev/null +++ b/roles/lists/files/etc/sympa/topics.conf @@ -0,0 +1 @@ +other diff --git a/roles/lists/files/etc/sympa/wwsympa.conf b/roles/lists/files/etc/sympa/wwsympa.conf new file mode 100644 index 0000000..4d420a3 --- /dev/null +++ b/roles/lists/files/etc/sympa/wwsympa.conf @@ -0,0 +1,85 @@ +###\\\\ Site customization ////### + +###\\\\ Directories ////### + +###\\\\ System related ////### + +###\\\\ Sending related ////### + +###\\\\ Bulk mailer ////### + +###\\\\ Quotas ////### + +###\\\\ Spool related ////### + +###\\\\ Internationalization related ////### + +###\\\\ Bounce related ////### + +## Directory for storing bounces +## Better if not in a critical partition +bounce_path /var/spool/sympa/wwsbounce + +###\\\\ Tuning ////### + +###\\\\ Database related ////### + +###\\\\ Loop prevention ////### + +###\\\\ S/MIME configuration ////### + +###\\\\ DKIM ////### + +###\\\\ Antivirus plug-in ////### + +###\\\\ Tag based spam filtering ////### + +###\\\\ Web interface parameters ////### + +## Directory for storing HTML archives +## Better if not in a critical partition +arc_path /var/lib/sympa/wwsarchive + +## Default index organization when entering the web archive: either threaded (thrd) or in chronological (mail) order +archive_default_index thrd + +## HTTP cookies lifetime +cookie_expire 0 + +## HTTP cookies validity domain +cookie_domain localhost + +## Average interval to refresh HTTP session ID. +cookie_refresh 60 + +## Type of main Web page ( lists | home ) +default_home home + +## When using LDAP authentication, if the identifier provided by the user was a valid email, if this parameter is set to false, then the provided email will be used to authenticate the user. Otherwise, use of the first email returned by the LDAP server will be used. +ldap_force_canonical_email 1 + +## Syslog facility for wwsympa, archived and bounced +## Default is to use previously defined sympa log facility. +log_facility `cat /etc/sympa/facility` + +## Path to MHonArc mail2html plugin +## This is required for HTML mail archiving +mhonarc /usr/bin/mhonarc + +## Password case (insensitive | sensitive) +## Should not be changed ! May invalid all user password +password_case insensitive + +## Default number of lines of the array displaying users in the review page +review_page_size 25 + +## Title of main Web page +title Mailing lists service + +## Is fast_cgi module for Apache (or Roxen) installed (0 | 1) +## This module provide much faster web interface +use_fast_cgi 1 + +## Default number of lines of the array displaying the log entries in the logs page +viewlogs_page_size 25 + diff --git a/roles/lists/files/lib/systemd/system/wwsympa.service b/roles/lists/files/lib/systemd/system/wwsympa.service new file mode 100644 index 0000000..ea2a78f --- /dev/null +++ b/roles/lists/files/lib/systemd/system/wwsympa.service @@ -0,0 +1,14 @@ +[Unit] +Description=WWSympa Service +After=network.target +PartOf=sympa.service +Requires=wwsympa.socket + +[Service] +StandardInput=socket +User=sympa +Group=sympa +ExecStart=/usr/lib/cgi-bin/sympa/wwsympa.fcgi + +[Install] +WantedBy=multi-user.target diff --git a/roles/lists/files/lib/systemd/system/wwsympa.socket b/roles/lists/files/lib/systemd/system/wwsympa.socket new file mode 100644 index 0000000..10fe721 --- /dev/null +++ b/roles/lists/files/lib/systemd/system/wwsympa.socket @@ -0,0 +1,11 @@ +[Unit] +Description=WWSympa Listen Socket + +[Socket] +SocketUser=www-data +SocketGroup=www-data +SocketMode=0600 +ListenStream=/run/wwsympa.socket + +[Install] +WantedBy=sockets.target diff --git a/roles/lists/files/usr/local/bin/sympa-queue b/roles/lists/files/usr/local/bin/sympa-queue new file mode 100755 index 0000000..85001bb --- /dev/null +++ b/roles/lists/files/usr/local/bin/sympa-queue @@ -0,0 +1,17 @@ +#!/bin/sh + +PATH=/bin:/usr/bin +set -ue + +[ $# -eq 1 ] || exit 1 + +username="${1#*/}" +domainname="${1%%/*}" + +if [ "$username" = 'abuse-feedback-report' ] || [ "$username" = bounce ]; then + exec /usr/lib/sympa/lib/sympa/bouncequeue "sympa@$domainname" +elif [ "${username%-owner}" != "$username" ]; then + exec /usr/lib/sympa/lib/sympa/bouncequeue "${username%-owner}@$domainname" +else + exec /usr/lib/sympa/lib/sympa/queue "$username@$domainname" +fi diff --git a/roles/lists/handlers/main.yml b/roles/lists/handlers/main.yml index 76084e4..811b86d 100644 --- a/roles/lists/handlers/main.yml +++ b/roles/lists/handlers/main.yml @@ -1,6 +1,12 @@ --- - name: Reload Postfix service: name=postfix state=reloaded - name: Restart Nginx service: name=nginx state=restarted + +- name: Restart Sympa + service: name=sympa state=restarted + +- name: systemctl daemon-reload + command: /bin/systemctl daemon-reload diff --git a/roles/lists/tasks/mail.yml b/roles/lists/tasks/mail.yml index 15d381d..6d1a4f5 100644 --- a/roles/lists/tasks/mail.yml +++ b/roles/lists/tasks/mail.yml @@ -1,33 +1,54 @@ - name: Install Postfix apt: pkg={{ item }} with_items: - postfix - postfix-ldap - name: Configure Postfix template: src=etc/postfix/main.cf.j2 dest=/etc/postfix-{{ postfix_instance[inst].name }}/main.cf owner=root group=root mode=0644 notify: - Reload Postfix -- name: Create directory /etc/postfix-.../virtual - file: path=/etc/postfix-{{ postfix_instance[inst].name }}/virtual - state=directory - owner=root group=root - mode=0755 - -- name: Copy lookup tables - copy: src=etc/postfix/virtual/{{ item }} - dest=/etc/postfix-{{ postfix_instance[inst].name }}/virtual/{{ item }} +- name: Copy the transport maps + copy: src=etc/postfix/transport + dest=/etc/postfix-{{ postfix_instance[inst].name }}/transport owner=root group=root mode=0644 - with_items: - - domains.cf - - transport_list.cf + # no need to reload upon change, as cleanup(8) is short-running + +- name: Copy the Postfix relay clientcerts map + template: src=etc/postfix/relay_clientcerts.j2 + dest=/etc/postfix-{{ postfix_instance[inst].name }}/relay_clientcerts + owner=root group=root + mode=0644 + tags: + - tls_policy + +- name: Compile the Postfix relay clientcerts map + postmap: cmd=postmap src=/etc/postfix-{{ postfix_instance[inst].name }}/relay_clientcerts db=cdb + owner=root group=root + mode=0644 + tags: + - tls_policy + +- name: Compile the Postfix transport maps + # trivial-rewrite(8) is a long-running process, so it's safer to reload + postmap: cmd=postmap src=/etc/postfix-{{ postfix_instance[inst].name }}/transport db=cdb + owner=root group=root + mode=0644 + notify: + - Reload Postfix - meta: flush_handlers - name: Start Postfix service: name=postfix state=started + +- name: Copy the 'sympa-queue' wrapper + copy: src=usr/local/bin/sympa-queue + dest=/usr/local/bin/sympa-queue + owner=root group=root + mode=0755 diff --git a/roles/lists/tasks/main.yml b/roles/lists/tasks/main.yml index 13d3451..f0e8e26 100644 --- a/roles/lists/tasks/main.yml +++ b/roles/lists/tasks/main.yml @@ -1,2 +1,3 @@ - include: mail.yml tags=postfix,mail -- include: mlmmj.yml tags=mlmmj,lists +- include: nginx.yml tags=nginx,www,web +- include: sympa.yml tags=sympa,lists diff --git a/roles/lists/tasks/nginx.yml b/roles/lists/tasks/nginx.yml new file mode 100644 index 0000000..a0aab68 --- /dev/null +++ b/roles/lists/tasks/nginx.yml @@ -0,0 +1,40 @@ +- name: Install Nginx + apt: pkg=nginx + +- name: Generate a private key and a X.509 certificate for Nginx + command: genkeypair.sh x509 + --pubkey=/etc/nginx/ssl/lists.fripost.org.pem + --privkey=/etc/nginx/ssl/lists.fripost.org.key + --ou=WWW --cn=lists.fripost.org --dns=lists.fripost.org + -t rsa -b 4096 -h sha512 + register: r1 + changed_when: r1.rc == 0 + failed_when: r1.rc > 1 + notify: + - Restart Nginx + tags: + - genkey + +- name: Copy /etc/nginx/sites-available/sympa + copy: src=etc/nginx/sites-available/sympa + dest=/etc/nginx/sites-available/sympa + owner=root group=root + mode=0644 + register: r2 + notify: + - Restart Nginx + +- name: Create /etc/nginx/sites-enabled/sympa + file: src=../sites-available/sympa + dest=/etc/nginx/sites-enabled/sympa + owner=root group=root + state=link + register: r3 + notify: + - Restart Nginx + +- name: Start nginx + service: name=nginx state=started + when: not (r1.changed or r2.changed or r3.changed) + +- meta: flush_handlers diff --git a/roles/lists/tasks/sympa.yml b/roles/lists/tasks/sympa.yml new file mode 100644 index 0000000..d1ae505 --- /dev/null +++ b/roles/lists/tasks/sympa.yml @@ -0,0 +1,79 @@ +- apt: pkg={{ item }} install_recommends=no + with_items: + - mysql-server + - sympa + +- name: Make the 'sympa' MySQL user use auth_socket + mysql_user: name=sympa auth_plugin=auth_socket + state=present + +- name: Configure Sympa + copy: src=etc/sympa/{{ item }} + dest=/etc/sympa/{{ item }} + owner=root group=sympa + mode=0644 + with_items: + - sympa.conf + - wwsympa.conf + - topics.conf + register: r1 + notify: + - Restart Sympa + +- name: Create Virtual hosts for Sympa (1) + file: path=/etc/sympa/{{ item }} + state=directory + owner=root group=root + mode=0755 + with_items: + - lists.fripost.org + register: r2 + notify: + - Restart Sympa + +- name: Create Virtual hosts for Sympa (2) + file: path=/var/lib/sympa/list_data/{{ item }} + state=directory + owner=sympa group=sympa + mode=0770 + with_items: + - lists.fripost.org + register: r3 + notify: + - Restart Sympa + +- name: Install robot.conf + template: src=etc/sympa/robot.conf.j2 + dest=/etc/sympa/{{ item }}/robot.conf + owner=root group=root + mode=0644 + with_items: + - lists.fripost.org + register: r4 + notify: + - Restart Sympa + +- name: Start Sympa + service: name=sympa state=started + when: not (r1.changed or r2.changed or r3.changed or r4.changed) + +- meta: flush_handlers + +- name: Copy wwsympa.{service,socket} + copy: src=lib/systemd/system/{{ item }} + dest=/lib/systemd/system/{{ item }} + owner=root group=root + mode=0644 + notify: + - systemctl daemon-reload + with_items: + - wwsympa.service + - wwsympa.socket + +- meta: flush_handlers + +- name: Enable WWSympa + service: name=wwsympa enabled=yes + +- name: Start WWSympa + service: name=wwsympa state=started diff --git a/roles/lists/templates/etc/postfix/main.cf.j2 b/roles/lists/templates/etc/postfix/main.cf.j2 index da68a42..e55eb9e 100644 --- a/roles/lists/templates/etc/postfix/main.cf.j2 +++ b/roles/lists/templates/etc/postfix/main.cf.j2 @@ -1,90 +1,97 @@ ######################################################################## -# Lists configuration +# Sympa configuration # # {{ ansible_managed }} # Do NOT edit this file directly! smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) biff = no readme_directory = no mail_owner = postfix delay_warning_time = 4h maximal_queue_lifetime = 5d myorigin = /etc/mailname -myhostname = lists{{ listsno | default('') }}.$mydomain +myhostname = lists.$mydomain mydomain = fripost.org append_dot_mydomain = no -# Turn off all TCP/IP listener ports except that necessary for the list server. -# XXX: mlmmj is not compatible with the MX, see -# http://mlmmj.org/bugs/bug.php?id=51 -master_service_disable = !127.0.0.1:smtp.inet !2527.inet inet +# Turn off all TCP/IP listener ports except that necessary for Sympa +master_service_disable = !2527.inet inet queue_directory = /var/spool/postfix-{{ postfix_instance[inst].name }} data_directory = /var/lib/postfix-{{ postfix_instance[inst].name }} multi_instance_group = {{ postfix_instance[inst].group | default('') }} multi_instance_name = postfix-{{ postfix_instance[inst].name }} multi_instance_enable = yes # This server is a Mail Delivery Agent mynetworks_style = host -inet_interfaces = 172.16.0.1 -{% if 'MX' in group_names %} - 127.0.0.1 -{% endif %} -inet_protocols = ipv4 +inet_interfaces = all + # No local delivery mydestination = local_transport = error:5.1.1 Mailbox unavailable alias_maps = alias_database = local_recipient_maps = message_size_limit = 67108864 recipient_delimiter = + -# Forward everything to our internal mailhub -{% if 'out' in group_names %} -relayhost = [127.0.0.1]:{{ postfix_instance.out.port }} -{% else %} -relayhost = [outgoing.fripost.org]:{{ postfix_instance.out.port }} -{% endif %} -relay_domains = +# No relay: this server is inbound-only +relay_transport = error:5.1.1 Relay unavailable +default_transport = error:5.1.1 Transport unavailable + -# Virtual transport (the alias resolution is already done by the MX:es) -transport_maps = ldap:$config_directory/virtual/transport_list.cf -mlmmj_destination_recipient_limit = 1 +relay_domains = sympa.$mydomain +transport_maps = cdb:$config_directory/transport +sympa_destination_recipient_limit = 1 # Don't rewrite remote headers -local_header_rewrite_clients = -# Avoid splitting the envelope and scanning messages multiple times -smtp_destination_recipient_limit = 1000 -# Tolerate occasional high latency -smtp_data_done_timeout = 1200s - - -# Forward everything to our internal outgoing proxy -{% if 'out' in group_names %} -relayhost = [127.0.0.1]:{{ postfix_instance.out.port }} -{% else %} -relayhost = [outgoing.fripost.org]:{{ postfix_instance.out.port }} -{% endif %} -relay_domains = - -{% if 'out' in group_names %} -smtp_tls_security_level = none -smtp_bind_address = 127.0.0.1 -{% else %} -smtp_tls_security_level = encrypt -smtp_tls_cert_file = $config_directory/ssl/{{ ansible_fqdn }}.pem -smtp_tls_key_file = $config_directory/ssl/{{ ansible_fqdn }}.key -smtp_tls_session_cache_database = btree:$data_directory/smtp_tls_session_cache -smtp_tls_policy_maps = cdb:$config_directory/tls_policy -smtp_tls_fingerprint_digest = sha256 -{% endif %} -smtpd_tls_security_level = none +local_header_rewrite_clients = + + +relay_clientcerts = cdb:$config_directory/relay_clientcerts +smtpd_tls_security_level = may +smtpd_tls_cert_file = /etc/postfix/ssl/{{ ansible_fqdn }}.pem +smtpd_tls_key_file = /etc/postfix/ssl/{{ ansible_fqdn }}.key +smtpd_tls_session_cache_database= btree:$data_directory/smtpd_tls_session_cache +smtpd_tls_received_header = yes +smtpd_tls_ask_ccert = yes +smtpd_tls_session_cache_timeout = 3600s +smtpd_tls_fingerprint_digest = sha256 + + +strict_rfc821_envelopes = yes +smtpd_delay_reject = yes +disable_vrfy_command = yes + +smtpd_client_restrictions = + permit_mynetworks + permit_tls_clientcerts + # We are the only ones using this proxy, but if things go wrong we + # want to know why + defer + +smtpd_helo_required = yes +smtpd_helo_restrictions = + reject_invalid_helo_hostname + +smtpd_sender_restrictions = + reject_non_fqdn_sender + +smtpd_relay_restrictions = + permit_mynetworks + permit_tls_clientcerts + reject + +smtpd_recipient_restrictions = + reject_non_fqdn_recipient + +smtpd_data_restrictions = + reject_unauth_pipelining # vim: set filetype=pfmain : diff --git a/roles/lists/templates/etc/postfix/relay_clientcerts.j2 b/roles/lists/templates/etc/postfix/relay_clientcerts.j2 new file mode 100644 index 0000000..42a83b5 --- /dev/null +++ b/roles/lists/templates/etc/postfix/relay_clientcerts.j2 @@ -0,0 +1,6 @@ +# {{ ansible_managed }} +# /!\ WARNING: smtp_tls_fingerprint_digest MUST be sha256! + +{% for h in groups.MX | difference([inventory_hostname]) | sort %} +{{ lookup('pipe', 'openssl x509 -in certs/postfix/'+h+'.pem -noout -fingerprint -sha256 | cut -d= -f2') }} {{ h }} +{% endfor %} diff --git a/roles/lists/templates/etc/sympa/robot.conf.j2 b/roles/lists/templates/etc/sympa/robot.conf.j2 new file mode 100644 index 0000000..75687d8 --- /dev/null +++ b/roles/lists/templates/etc/sympa/robot.conf.j2 @@ -0,0 +1,3 @@ +http_host {{ item }} +wwsympa_url https://{{ item }}/sympa +# wwsympa_url https://lists.fripost.org/{{ item }}/sympa |