mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-03-18 09:10:49 +00:00
email: postfix: dovecot: Set strong security parameters
Other changes: - Fix linter error - Postfix port 25: do not trust localhost IP addresses
This commit is contained in:
parent
b172b0b1cd
commit
9a98ddadd4
@ -1,6 +1,8 @@
|
||||
"""FreedomBox email server app"""
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import logging
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
@ -10,7 +12,9 @@ import plinth.frontpage
|
||||
import plinth.menu
|
||||
from plinth import actions
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.config import get_domainname
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
|
||||
from . import audit
|
||||
from . import manifest
|
||||
@ -36,6 +40,7 @@ managed_services = ['postfix', 'dovecot', 'rspamd']
|
||||
|
||||
managed_packages = packages + packages_bloat
|
||||
app = None
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EmailServerApp(plinth.app.App):
|
||||
@ -56,6 +61,18 @@ class EmailServerApp(plinth.app.App):
|
||||
urls=['https://{host}/rspamd'])
|
||||
self.add(webserver)
|
||||
|
||||
# Let's Encrypt event hook
|
||||
default_domain = get_domainname()
|
||||
domains = [default_domain] if default_domain else []
|
||||
letsencrypt = LetsEncrypt(
|
||||
'letsencrypt-email-server', domains=domains,
|
||||
daemons=['postfix', 'dovecot'], should_copy_certificates=False,
|
||||
managing_app='email_server')
|
||||
self.add(letsencrypt)
|
||||
|
||||
if not domains:
|
||||
logger.warning('Could not fetch the FreedomBox domain name!')
|
||||
|
||||
def _add_ui_components(self):
|
||||
info = plinth.app.Info(
|
||||
app_id=self.app_id,
|
||||
@ -119,6 +136,7 @@ class EmailServerApp(plinth.app.App):
|
||||
results.extend([r.summarize() for r in audit.domain.get()])
|
||||
results.extend([r.summarize() for r in audit.ldap.get()])
|
||||
results.extend([r.summarize() for r in audit.spam.get()])
|
||||
results.extend([r.summarize() for r in audit.tls.get()])
|
||||
return results
|
||||
|
||||
|
||||
@ -128,6 +146,7 @@ def setup(helper, old_version=None):
|
||||
helper.install(packages_bloat, skip_recommends=True)
|
||||
helper.call('post', audit.ldap.repair)
|
||||
helper.call('post', audit.spam.repair)
|
||||
helper.call('post', audit.tls.repair)
|
||||
for srvname in managed_services:
|
||||
actions.superuser_run('service', ['reload', srvname])
|
||||
# Final step: expose service daemons to public internet
|
||||
|
||||
@ -126,7 +126,7 @@ def schedule_hash_update():
|
||||
key = alias.email_name.encode('ascii') + b'\0'
|
||||
if alias.enabled:
|
||||
value = str(alias.uid_number).encode('ascii')
|
||||
value += b'@localhost\0'
|
||||
value += b'@localhost\0'
|
||||
else:
|
||||
value = b'/dev/null\0'
|
||||
db[key] = value
|
||||
|
||||
@ -7,5 +7,6 @@ from . import domain
|
||||
from . import home
|
||||
from . import ldap
|
||||
from . import spam
|
||||
from . import tls
|
||||
|
||||
__all__ = ['domain', 'home', 'ldap', 'spam']
|
||||
__all__ = ['domain', 'home', 'ldap', 'spam', 'tls']
|
||||
|
||||
@ -15,7 +15,11 @@ default_config = {
|
||||
'smtpd_sasl_type': 'dovecot',
|
||||
'smtpd_sasl_path': 'private/auth',
|
||||
'mailbox_transport': 'lmtp:unix:private/dovecot-lmtp',
|
||||
'virtual_transport': 'lmtp:unix:private/dovecot-lmtp'
|
||||
'virtual_transport': 'lmtp:unix:private/dovecot-lmtp',
|
||||
|
||||
'smtpd_relay_restrictions': ','.join([
|
||||
'permit_sasl_authenticated', 'defer_unauth_destination',
|
||||
])
|
||||
}
|
||||
|
||||
submission_flags = postconf.ServiceFlags(
|
||||
|
||||
84
plinth/modules/email_server/audit/tls.py
Normal file
84
plinth/modules/email_server/audit/tls.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""TLS configuration"""
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import logging
|
||||
|
||||
from plinth import actions
|
||||
|
||||
from . import models
|
||||
from plinth.modules.email_server import postconf
|
||||
|
||||
# Mozilla Guideline v5.6, Postfix 1.17.7, OpenSSL 1.1.1d, intermediate
|
||||
# Generated 2021-08
|
||||
# https://ssl-config.mozilla.org/
|
||||
tls_medium_cipherlist = [
|
||||
'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256',
|
||||
'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384',
|
||||
'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305',
|
||||
'DHE-RSA-AES128-GCM-SHA256', 'DHE-RSA-AES256-GCM-SHA384'
|
||||
]
|
||||
|
||||
postfix_config = {
|
||||
# Enable TLS
|
||||
'smtpd_tls_security_level': 'may',
|
||||
'smtpd_tls_auth_only': 'yes',
|
||||
|
||||
# Debugging information
|
||||
'smtpd_tls_received_header': 'yes',
|
||||
|
||||
# Use a strong hashing algorithm
|
||||
'smtp_tls_fingerprint_digest': 'sha256',
|
||||
'smtpd_tls_fingerprint_digest': 'sha256',
|
||||
|
||||
# Mozilla Intermediate Configuration
|
||||
'smtpd_tls_mandatory_protocols': '!SSLv2, !SSLv3, !TLSv1, !TLSv1.1',
|
||||
'smtpd_tls_protocols': '!SSLv2, !SSLv3, !TLSv1, !TLSv1.1',
|
||||
'smtpd_tls_mandatory_ciphers': 'medium',
|
||||
'tls_medium_cipherlist': ':'.join(tls_medium_cipherlist),
|
||||
'tls_preempt_cipherlist': 'no',
|
||||
|
||||
# Postfix SMTP client
|
||||
'smtp_tls_mandatory_protocols': '!SSLv2, !SSLv3, !TLSv1, !TLSv1.1',
|
||||
'smtp_tls_protocols': '!SSLv2, !SSLv3, !TLSv1, !TLSv1.1',
|
||||
'smtp_tls_mandatory_ciphers': 'medium',
|
||||
|
||||
# Use DNSSEC to validate TLS certificates
|
||||
'smtp_host_lookup': 'dns',
|
||||
'smtp_dns_support_level': 'dnssec',
|
||||
'smtp_tls_security_level': 'dane', # Opportunistic DANE TLS
|
||||
|
||||
# Maintain 1 cipherlist and keep it the most secure
|
||||
'tls_low_cipherlist': '$tls_medium_cipherlist',
|
||||
'tls_high_cipherlist': '$tls_medium_cipherlist',
|
||||
}
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get():
|
||||
results = []
|
||||
with postconf.mutex.lock_all():
|
||||
results.append(check_tls())
|
||||
return results
|
||||
|
||||
|
||||
def repair():
|
||||
actions.superuser_run('email_server', ['-i', 'tls', 'set_up'])
|
||||
|
||||
|
||||
def check_tls():
|
||||
diagnosis = models.MainCfDiagnosis('Postfix TLS')
|
||||
current = postconf.get_many_unsafe(list(postfix_config.keys()))
|
||||
diagnosis.compare_and_advise(current=current, default=postfix_config)
|
||||
return diagnosis
|
||||
|
||||
|
||||
def repair_tls(diagnosis):
|
||||
diagnosis.assert_resolved()
|
||||
logger.info('Setting postconf: %r', diagnosis.advice)
|
||||
postconf.set_many_unsafe(diagnosis.advice)
|
||||
|
||||
|
||||
def action_set_up():
|
||||
with postconf.mutex.lock_all():
|
||||
repair_tls(check_tls())
|
||||
@ -0,0 +1,12 @@
|
||||
# Direct edits to this file will be lost!
|
||||
# Manage your settings on Plinth <https://localhost/plinth/apps/email_server>
|
||||
|
||||
# Mozilla Guideline v5.6, Dovecot 2.3.9, OpenSSL 1.1.1d, intermediate
|
||||
# Generated 2021-08
|
||||
# https://ssl-config.mozilla.org/
|
||||
ssl = required
|
||||
|
||||
ssl_min_protocol = TLSv1.2
|
||||
ssl_prefer_server_ciphers = no
|
||||
|
||||
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
|
||||
Loading…
x
Reference in New Issue
Block a user