mirror of
https://github.com/Mailu/Mailu.git
synced 2024-12-12 10:45:38 +02:00
Merge #3350
3350: Feature: dkim for alternative domains r=mergify[bot] a=Jumper78 ## What type of PR? feature ## What does this PR do? ### General Idea #### use same DKIM key of main domain for signing Instead of dealing with key creation for each alternative domain, this implementation of the solution uses one key for all domains, the main domain and all alternative domains. Upon Rspamd requesting the DKIM key of a domain, it is not only checked if the domain is in the list of main domains, it also checked if it part of the alternative domains. If it is in this list, it sends the DKIM key of the connected main domain together with the name of the alternative domain. #### show needed entries in the domain detailed view of the main domain To make it easier for the admin to create the DKIM and DMARC entries (and the MX and SPF entries) for the alternative domains, we go through all alternative domains and print the entries. ### missing (and currently not planned to be added) The zonefile at the top of the detail page will still only cover the main domain. ### Related issue(s) - DKIM signing of the alternative domains is a requested feature; it closes #1519 - it keeps the original file based handling of DKIM keys; it does not implement #2952 ## Prerequisites Before we can consider review and merge, please make sure the following list is done and checked. If an entry in not applicable, you can check it or remove it from the list. - [ ] In case of feature or enhancement: documentation updated accordingly - [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file. Co-authored-by: Jumper78 <52802286+Jumper78@users.noreply.github.com>
This commit is contained in:
commit
2fca41235b
core/admin/mailu
towncrier/newsfragments
@ -24,6 +24,15 @@ def rspamd_dkim_key(domain_name):
|
||||
'selector': flask.current_app.config.get('DKIM_SELECTOR', 'dkim'),
|
||||
}
|
||||
)
|
||||
elif domain := models.Alternative.query.get(domain_name):
|
||||
if key := domain.domain.dkim_key:
|
||||
selectors.append(
|
||||
{
|
||||
'domain' : domain.name,
|
||||
'key' : key.decode('utf8'),
|
||||
'selector': flask.current_app.config.get('DKIM_SELECTOR', 'dkim'),
|
||||
}
|
||||
)
|
||||
return flask.jsonify({'data': {'selectors': selectors}})
|
||||
|
||||
@internal.route("/rspamd/local_domains", methods=['GET'])
|
||||
|
@ -355,6 +355,54 @@ class Alternative(Base):
|
||||
domain = db.relationship(Domain,
|
||||
backref=db.backref('alternatives', cascade='all, delete-orphan'))
|
||||
|
||||
@property
|
||||
def dns_dkim(self):
|
||||
""" return DKIM record for domain """
|
||||
if self.domain.dkim_key:
|
||||
selector = app.config['DKIM_SELECTOR']
|
||||
return f'{selector}._domainkey.{self.name}. 600 IN TXT "v=DKIM1; k=rsa; p={self.domain.dkim_publickey}"'
|
||||
|
||||
@cached_property
|
||||
def dns_dmarc(self):
|
||||
""" return DMARC record for domain """
|
||||
if self.domain.dkim_key:
|
||||
domain = app.config['DOMAIN']
|
||||
rua = app.config['DMARC_RUA']
|
||||
rua = f' rua=mailto:{rua}@{domain};' if rua else ''
|
||||
ruf = app.config['DMARC_RUF']
|
||||
ruf = f' ruf=mailto:{ruf}@{domain};' if ruf else ''
|
||||
return f'_dmarc.{self.name}. 600 IN TXT "v=DMARC1; p=reject;{rua}{ruf} adkim=s; aspf=s"'
|
||||
|
||||
@cached_property
|
||||
def dns_dmarc_report(self):
|
||||
""" return DMARC report record for mailu server """
|
||||
if self.domain.dkim_key:
|
||||
domain = app.config['DOMAIN']
|
||||
return f'{self.name}._report._dmarc.{domain}. 600 IN TXT "v=DMARC1;"'
|
||||
|
||||
@cached_property
|
||||
def dns_mx(self):
|
||||
""" return MX record for domain """
|
||||
hostname = app.config['HOSTNAME']
|
||||
return f'{self.name}. 600 IN MX 10 {hostname}.'
|
||||
|
||||
@cached_property
|
||||
def dns_spf(self):
|
||||
""" return SPF record for domain """
|
||||
hostname = app.config['HOSTNAME']
|
||||
return f'{self.name}. 600 IN TXT "v=spf1 mx a:{hostname} ~all"'
|
||||
|
||||
def check_mx(self):
|
||||
""" checks if MX record for domain points to mailu host """
|
||||
try:
|
||||
hostnames = set(app.config['HOSTNAMES'].split(','))
|
||||
return any(
|
||||
rset.exchange.to_text().rstrip('.') in hostnames
|
||||
for rset in dns.resolver.resolve(self.name, 'MX')
|
||||
)
|
||||
except dns.exception.DNSException:
|
||||
return False
|
||||
|
||||
|
||||
class Relay(Base):
|
||||
""" Relayed mail domain.
|
||||
|
@ -545,6 +545,10 @@ msgstr "DNS TLSA Eintrag"
|
||||
msgid "DNS client auto-configuration entries"
|
||||
msgstr "DNS Einträge für die automatische Client-Konfiguration"
|
||||
|
||||
#: mailu/ui/templates/domain/details.html:71
|
||||
msgid "Alternative Domain name"
|
||||
msgstr "Alternativer Domain Name"
|
||||
|
||||
#: mailu/ui/templates/domain/edit.html:4
|
||||
msgid "Edit domain"
|
||||
msgstr "Domain bearbeiten"
|
||||
|
@ -63,4 +63,36 @@
|
||||
</pre></td>
|
||||
</tr>
|
||||
{%- endcall %}
|
||||
|
||||
{%- for alternative in domain.alternatives %}
|
||||
|
||||
{%- call macros.table(datatable=False) %}
|
||||
<tr>
|
||||
<th>{% trans %}Alternative Domain name{% endtrans %}</th>
|
||||
<td>{{ alternative.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans %}DNS MX entry{% endtrans %} <i class="fa {{ 'fa-check-circle text-success' if alternative.check_mx() else 'fa-exclamation-circle text-danger' }}"></i></th>
|
||||
<td>{{ macros.clip("dns_mx") }}<pre id="dns_mx" class="pre-config border bg-light">{{ alternative.dns_mx }}</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans %}DNS SPF entries{% endtrans %}</th>
|
||||
<td>{{ macros.clip("dns_spf") }}<pre id="dns_spf" class="pre-config border bg-light">{{ alternative.dns_spf }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
{%- if alternative.domain.dkim_publickey %}
|
||||
<tr>
|
||||
<th>{% trans %}DNS DKIM entry{% endtrans %}</th>
|
||||
<td>{{ macros.clip("dns_dkim") }}<pre id="dns_dkim" class="pre-config border bg-light">{{ alternative.dns_dkim }}</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{% trans %}DNS DMARC entry{% endtrans %}</th>
|
||||
<td>
|
||||
{{ macros.clip("dns_dmarc") }}<pre id="dns_dmarc" class="pre-config border bg-light">{{ alternative.dns_dmarc }}</pre>
|
||||
{{ macros.clip("dns_dmarc_report") }}<pre id="dns_dmarc_report" class="pre-config border bg-light">{{ alternative.dns_dmarc_report }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
{%- endif %}
|
||||
{%- endcall %}
|
||||
{%- endfor %}
|
||||
{%- endblock %}
|
||||
|
1
towncrier/newsfragments/3350.feature
Normal file
1
towncrier/newsfragments/3350.feature
Normal file
@ -0,0 +1 @@
|
||||
Add DKIM support for alternative domains: alternative domains use the same DKIM key as the main domain.
|
Loading…
Reference in New Issue
Block a user