1<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "https://www.w3.org/TR/html4/loose.dtd"> 3 4<html> 5 6<head> 7 8<title>Postfix TLSRPT notification Howto</title> 9 10<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 11<link rel='stylesheet' type='text/css' href='postfix-doc.css'> 12 13</head> 14 15<body> 16 17<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix TLSRPT Howto</h1> 18 19<hr> 20 21<h2> Table of Contents </h2> 22 23<ul> 24 25<li> <a href="#intro"> Introduction </a> </li> 26<li> <a href="#building"> Building Postfix with TLSRPT support </a> 27<li> <a href="#using"> Turning on TLSRPT </a> </li> 28<li> <a href="#logging"> TLSRPT Status logging </a> </li> 29<li> <a href="#delivering"> Delivering TLSRPT summaries via email</a> </li> 30<li> <a href="#mta-sts"> MTA-STS Support via smtp_tls_policy_maps </a> </li> 31<li> <a href="#limitations"> Limitations </a></li> 32<li> <a href="#credits"> Credits </a> </li> 33 34</ul> 35 36<h2> <a name="intro"> Introduction </a> </h2> 37 38<p> The TLSRPT protocol is defined in <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a>. With this, an email 39receiving domain can publish a policy in DNS, and request daily 40summary reports for successful and failed SMTP over TLS connections 41to that domain's MX hosts. Support for TLSRPT was added in Postfix 423.10. </p> 43 44<p> A policy for domain <tt>example.com</tt> could look like this: </p> 45 46<blockquote> 47<pre> 48_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-report@example.com" 49</pre> 50</blockquote> 51 52<p> Instead of <tt>mailto:</tt>, a policy may specify an <tt>https:</tt> 53destination. </p> 54 55<p> The diagram below shows how Postfix TLS handshake success and 56failure events are collected and processed into daily summary 57reports. </p> 58 59<blockquote> 60 61<table> 62 63<tr> <td align="center" bgcolor="#f0f0ff"> Postfix SMTP and TLS 64client engines </td> <td> <tt> → </tt> </td> 65 66<td align="center" bgcolor="#f0f0ff"> <a 67href="https://github.com/sys4/libtlsrpt">TLSRPT client library </a> 68(linked into Postfix) </td> <td> <tt> → </tt> </td> 69 70<td align="center" bgcolor="#f0f0ff"> <a 71href="https://github.com/sys4/tlsrpt-reporter">TLSRPT collector, 72fetcher, and summary generator</a> </td> <td> <tt> → </tt> 73</td> 74 75<td align="center" bgcolor="#f0f0ff"> Email or HTTP delivery </td> 76</tr> 77 78</table> 79 80</blockquote> 81 82<ul> 83 84<li> <p> The Postfix SMTP and TLS client engines will generate a 85"success" or "failure" event for each TLS handshake, </p> 86 87<li> <p> They will pass those events to an in-process TLSRPT client 88library that sends data over a local socket to </p> 89 90<li> <p> A local TLSRPT collector that runs on each Postfix machine. 91A TLSRPT fetcher gathers information from individual collectors, 92and a central TLSRPT report generator produces daily summary reports. 93</p> 94 95</ul> 96 97<p> The TLSRPT client library, and the infrastructure to collect, 98fetch, and report TLSRPT information, are implemented and maintained 99by sys4 at <a href="https://github.com/sys4/libtlsrpt">https://github.com/sys4/libtlsrpt</a> and 100<a href="https://github.com/sys4/tlsrpt-reporter">https://github.com/sys4/tlsrpt-reporter</a>, respectively. </p> 101 102<p> The Postfix implementation supports TLSRPT or domains with DANE 103(Postfix built-in) and MTA-STS (through an <a href="#mta-sts"> 104smtp_tls_policy_maps plug-in</a>). </p> 105 106<p> The Postfix <a href="smtp.8.html">smtp(8)</a> client process implements the SMTP client 107engine. With "<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = no", the <a href="smtp.8.html">smtp(8)</a> client 108process also implements the TLS client engine. With 109"<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = yes", the <a href="smtp.8.html">smtp(8)</a> client process 110delegates TLS processing to a Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> process. Either 111way, Postfix will generate the exact same TLSRPT events. </p> 112 113<h2> <a name="building"> Building Postfix with TLSRPT support </a> 114</h2> 115 116<p> These instructions assume that you build Postfix from source 117code as described in the <a href="INSTALL.html">INSTALL</a> document. Some modification may 118be required if you build Postfix from a vendor-specific source 119package. </p> 120 121<p> The Postfix TLSRPT client builds on a TLSRPT library which may 122be available as a built package (rpm, deb, etc.), or which you can 123build from source code from: </p> 124 125<blockquote> 126<p> <a href="https://github.com/sys4/libtlsrpt">https://github.com/sys4/libtlsrpt</a> </p> 127</blockquote> 128 129<p> The library is typically installed as a header file in 130/usr/local/include/tlsrpt.h and an object library in 131/usr/local/lib/libtlsrpt.a or /usr/local/lib/libtlsrpt.so. The 132actual pathnames will depend on OS platform conventions. </p> 133 134<p> In order to build Postfix with TLSRPT support, you will need 135to add compiler options <tt>-DUSE_TLSRPT</tt> (to build with TLSRPT 136support) and <tt>-I</tt> (with the directory containing the tlsrpt.h 137header file), and you will need to add linker options to link with 138the TLSRPT client library, for example: </p> 139 140<blockquote> 141<pre> 142make -f Makefile.init makefiles \ 143 "CCARGS=-DUSE_TLSRPT -I/usr/local/include" \ 144 "AUXLIBS=-L/usr/local/lib -Wl,-rpath,/usr/local/lib -ltlsrpt" 145</pre> 146</blockquote> 147 148<p> (On Solaris systems you may need to use "<tt>-Wl,-R</tt>" instead 149of "<tt>-Wl,-rpath</tt>".) </p> 150 151<p> Then, just run 'make'. </p> 152 153<blockquote> 154 155<p> Note: if your build command line already has CCARGS or AUXLIBS 156settings, then simply append the above settings to the existing CCARGS 157or AUXLIBS values: </p> 158 159<pre> 160make -f Makefile.init makefiles \ 161 "CCARGS=... -DUSE_TLSRPT -I/usr/local/include" \ 162 "AUXLIBS=... -L/usr/local/lib -Wl,-rpath,/usr/local/lib -ltlsrpt" 163</pre> 164</blockquote> 165 166<h2> <a name="using"> Turning on TLSRPT </a> </h2> 167 168<p> After installing Postfix TLSRPT support, you can enable TLSRPT 169support in <a href="postconf.5.html">main.cf</a> like this: </p> 170 171<blockquote> 172<pre> 173<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> = yes 174<a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> = path/to/socket 175</pre> 176</blockquote> 177 178<p> The <a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> parameter specifies either an 179absolute pathname, or a pathname that is relative to $<a href="postconf.5.html#queue_directory">queue_directory</a>. 180</p> 181 182<p> Notes: </p> 183 184<ul> 185 186<li> <p> The recommended socket location is still to be determined. 187A good socket location would be under the Postfix queue directory, 188for example: "<a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> = run/tlsrpt/tlsrpt.sock". 189The advantage of using a relative name is that it will work equally 190well whether or not Postfix chroot is turned on. </p> 191 192<li> <p> Regardless of whether Postfix chroot is enabled, the TLSRPT 193receiver (<tt>tlsrpt_collectd</tt>) will need to be configured with 194the socket's absolute pathname. </p> 195 196<li> <p> Do not specify a TLSRPT socket location under a Postfix socket 197directory such as <tt>private</tt> or <tt>public</tt>. Only Postfix 198programs should create sockets there. </p> 199 200</ul> 201 202<p> For details on how to run the TLSRPT collection and reporting 203infrastructure, see the documentation at 204<a href="https://github.com/sys4/tlsrpt-reporter">https://github.com/sys4/tlsrpt-reporter</a>. 205 206<h2> <a name="logging"> TLSRPT Status logging </a> </h2> 207 208<p> With TLSRPT support turned on, the Postfix TLSRPT client will 209not only report an event to an invisible daily success/fail summary 210queue, but it will also log a visible record to the mail logfile. 211</p> 212 213<p> Below are a few examples of logging from a Postfix SMTP client 214or tlsproxy daemon: </p> 215 216<blockquote> 217<pre> 218TLSRPT: status=success, domain=example.com, receiving_mx=mail.example.com[ipaddr] 219 220TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr], 221 failure_type=starttls_not_supported 222 223TLSRPT: status=failure, domain=example.net, receiving_mx=mail.example.net[ipaddr], 224 failure_type=validation_failure, failure_reason=self-signed_certificate 225</pre> 226</blockquote> 227 228<p> Notes: </p> 229 230<ul> 231 232<li> <p> Postfix logs and reports the TLSRPT status only for TLS 233handshakes on a new SMTP connection. There is no TLS handshake, and 234thus no TLSRPT status logging, when an SMTP connection is reused. 235Such connections have Postfix SMTP client logging like this: </p> 236 237<pre> 238Verified <b>TLS connection reused</b> to mail.example.com[ipaddr]:25: 239 TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits) 240 241Untrusted <b>TLS connection reused</b> to mail.example.com[ipaddr]:25: 242 TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits) 243</pre> 244 245<li> <p> By default, Postfix does not report the TLSRPT status for 246a TLS handshake that reuses a previously-negotiated TLS session 247(there would be no new information to report). Specify 248"<a href="postconf.5.html#smtp_tlsrpt_skip_reused_handshakes">smtp_tlsrpt_skip_reused_handshakes</a> = no" to report the TLSRPT 249status for all TLS handshakes. This may be useful for troubleshooting. 250</p> 251 252<li> <p> Postfix logging for certificate verification failures may 253differ between new or reused TLS sessions. </p> 254 255<ul> 256 257<li> <p> New TLS session: 258</p> 259 260<pre> 261TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr], 262 <b>failure_type=validation_failure</b>, <b>failure_reason=self-signed_certificate</b> 263</pre> 264 265<li> <p> Reused TLS session: </p> 266 267<pre> 268mail.example.org[ipaddr]:25: <b>re-using session</b> with untrusted peer 269 credential, look for details earlier in the log 270TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr], 271 <b>failure_type=certificate_not_trusted</b> 272</pre> 273 274</ul> 275 276<p> The logging may differ because a reused TLS session does not 277have the details for why TLS authentication failed. </p> 278 279</ul> 280 281<h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2> 282 283<p> <a href="https://datatracker.ietf.org/doc/html/rfc8460#section-3">RFC 2848460 Section 3</a> specifies that an MTA must not enforce TLS 285security when sending failure reports via email. </p> 286 287<p> Options: 288 289<ul> 290 291<li> <p> In an email report, specify the "<b>TLS-Required: no</b>" 292message header, 293defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>, to reduce the Postfix SMTP client TLS security 294level to "<b>may</b>" (that is, do not verify remote SMTP server 295certificates, and fall back to plaintext if TLS is unavailable). 296<br> <br> This feature is available in Postfix 3.10 and later. If 297your outbound MTAs run an older version, you can use one of the 298options described below. </p> 299 300<li> <p> Do nothing. When TLS security enforcement is required but 301fails, a TLSRPT summary message will be delayed 302until the problem is addressed, or until the message expires 303in the mail queue. Keep in mind that TLSRPT is not a real-time 304monitoring service; it takes on average 12 hours before a failure 305is reported through TLSRPT. </p> 306 307<li> <p> On outbound MTAs that don't support the "<b>TLS-Required: 308no</b>" header feature (such as Postfix 3.9 and earlier), disable 309TLS security enforcement for the sender of TLSRPT summaries. 310Implement the configuration below on outbound MTA instances (replace 311noreply-smtp-tls-reporting@example.com with your actual report 312generator's sender address): </p> 313 314<pre> 315/etc/postfix/<a href="postconf.5.html">main.cf</a>: 316 # Limitation: this setting is overruled with <a href="postconf.5.html#transport_maps">transport_maps</a>. 317 <a href="postconf.5.html#sender_dependent_default_transport_maps">sender_dependent_default_transport_maps</a> = <a href="DATABASE_README.html#types">inline</a>:{ 318 { noreply-smtp-tls-reporting@example.com = allow-plaintext } } 319  320/etc/postfix/<a href="master.5.html">master.cf</a>: 321 # service name type private unpriv chroot wakeup maxproc command 322 allow-plaintext unix - - - - - smtp 323 -o { <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may } 324 -o { <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">static</a>:may } 325</pre> 326 327</ul> 328 329<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps 330</a></h2> 331 332<p> Postfix supports MTA-STS though an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> policy 333plugin, which replies with a TLS security level and name=value 334attributes with certificate matching requirements. Postfix 3.10 and 335later extend the policy plugin response with additional name=value 336attributes that are needed for TLSRPT. </p> 337 338<p> Examples of <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> plugins with MTA-STS support 339are: </p> 340 341<ul> 342 343<li> <p> <a href="https://github.com/Zuplu/postfix-tlspol"> 344postfix-tlspol</a>, supports domains with DANE (using Postfix 345built-in DANE), and domains with MTA-STS. </p> 346 347<li> <p> <a href="https://github.com/Snawoot/postfix-mta-sts-resolver"> 348postfix-mta-sts-resolver</a>, supports domains with MTA-STS as of 349release 1.5.0 (February 2025). </p> 350 351</ul> 352 353<p> Both plugins can generate the additional name=value attributes 354that Postfix needs for TLSRPT support (as of February 2025). This 355is enabled by setting a <tt>tlsrpt</tt> boolean in a plugin 356configuration file. This setting is safe with Postfix 3.10 and 357later, even if Postfix TLSRPT support is disabled (at build time 358or at run time). Postfix versions 3.9 and earlier will report a 359policy error with "<tt>invalid attribute name</tt>". </p> 360 361<p> The examples in the text below apply to this MTA-STS policy example 362given in <a 363href="https://datatracker.ietf.org/doc/html/rfc8461#section-3.2"> 364RFC 8461 Section 3.2</a>: </p> 365 366<blockquote> 367<pre> 368version: STSv1 369mode: enforce 370mx: mail.example.com 371mx: *.example.net 372mx: backupmx.example.com 373max_age: 604800 374</pre> 375</blockquote> 376 377<p> The list of supported attributes is given below. Instead of 378<tt>name=value</tt>, specify <tt>{ name = value }</tt> when a value 379may contain whitespace. A policy response may contain line breaks. 380</p> 381 382<ul> 383 384<li> <p> <tt> policy_type=<i>type</i> </tt> </p> 385 386<p> Specify <tt>sts</tt> or <tt>no-policy-found</tt>. </p> 387 388<p> Example: <tt>policy_type=sts</tt> </p> </li> 389 390<li> <p> <tt> policy_domain=<i>name</i> </tt> </p> 391 392<p> The domain that the MTA-STS policy applies to. </p> 393 394<p> Example: <tt>policy_domain=example.com</tt> </p> 395 396</li> 397 398<li> <p> <tt> { policy_string = <i>value</i> } </tt> </p> 399 400<p> Specify one <tt>policy_string</tt> instance for each MTA-STS 401policy feature, enclosed inside "{" and "}" to protect whitespace 402in attribute values. <p> 403 404<p> Example: <tt> { policy_string = version: STSv1 } { policy_string 405= mode: enforce } ...</tt> </p> 406 407<p> The above form ignores whitespace after the opening "{", around 408the "=", and before the closing "}".</p> </li> 409 410<li> <p> <tt> mx_host_pattern=<i>pattern</i> </tt> </p> 411 412<p> Specify one <tt>mx_host_pattern</tt> instance for each "mx:" feature 413in the MTA-STS policy. </p> 414 415<p> Example: <tt>mx_host_pattern=mail.example.com 416mx_host_pattern=*.example.net ...</tt> </p> </li> 417 418<li> <p> <tt> policy_failure=<i>type</i> </tt> </p> 419 420<p> If specified, forces MTA-STS policy enforcement to fail with 421the indicated error, even if a server certificate would satisfy 422conventional PKI constraints. Valid errors are <tt>sts-policy-fetch-error, 423sts-policy-invalid</tt>, <tt>sts-webpki-invalid</tt>, or the less 424informative <tt>validation-failure</tt>. </p> 425 426<p> Example: <tt>policy_failure=sts-webpki-invalid</tt> </p> </li> 427 428<li> <p> <tt> policy_ttl=<i>time</i> </tt> (deprecated) </p> 429 430<p> This attribute is deprecated. The <i>time</i> value is not used, 431and support for this attribute will eventually be removed from the 432code. </p> </li> 433 434</ul> 435 436<p> Notes: </p> 437 438<ul> 439 440<li> <p> Postfix 3.10 and later will accept these additional 441attributes in an MTA-STS response even if Postfix TLSRPT support 442is disabled (at build time or at run time). With Postfix TLSRPT 443support turned off, Postfix may still use the <tt>policy_failure</tt> 444attribute, and will ignore the attributes that are used only for 445TLSRPT. </p> 446 447<li> <p> It is an error to specify these attributes for a non-STS 448policy. </p> 449 450</ul> 451 452<h2> <a name="limitations"> Limitations </a></h2> 453 454<p> The Postfix TLSRPT implementation reports only TLS handshake 455success or failure. It does not report failure to connect, or 456connections that break before or after a TLS handshake. </p> 457 458<p> The Postfix TLSRPT implementation reports at most one final TLS 459handshake status (either 'success' or 'failure') per SMTP connection. 460Postfix TLSRPT will not report a recoverable failure and then later 461report a final status of 'success' for that same connection. The 462reason is that it's too complicated to filter TLS errors and to 463report error details from the TLS engine back to the SMTP protocol 464engine. It just is not how Postfix works internally. </p> 465 466<h2> <a name="credits"> Credits </a> </h2> 467 468<ul> 469 470<li> The TLSRPT client library, and the infrastructure to collect, 471fetch, and report TLSRPT information, are implemented and maintained 472by sys4. </li> 473 474<li> Wietse Venema implemented the integration with Postfix. 475</li> 476 477</ul> 478 479</body> 480 481</html> 482