Solved pyspf-milter service silently not starting

I am configuring a new migration install of mail/py-spf-engine on FreeBSD 14 and the service won't run for me, that is,
sh:
# service pyspf-milter restart
pyspf_milter not running? (check /var/run/pyspf-milter/pyspf-milter.pid).
Starting pyspf_milter.

Then silently fails to be running. I'm not collecting any errors in the log files.

Versions (that seem relevant)
py311-pyspf-2.0.14_2
py311-spf-engine-3.0.4
openssl32-3.2.3
py311-openssl-24.1.0,1

The interpreter, python3.11 exists and the command is correct, the pid folder, /var/run/pyspf-milter exists:

drwxr-xr-x 2 pyspf-milter pyspf-milter 0B Sep 1 22:26 pyspf-milter/

The conf file at /usr/local/etc/pyspf-milter/pyspf-milter.conf exists:

Code:
#  For a fully commented sample config file see policyd-spf.conf.commented

debugLevel = 1
TestOnly = 1

HELO_reject = Fail
Mail_From_reject = Fail

PermError_reject = False
TempError_Defer = False

skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1

# Milter specific options
Socket = local:/var/run/pyspf-milter/pyspf-milter.sock
#Socket = inet:8893@localhost
PidFile = /var/run/pyspf-milter/pyspf-milter.pid
UserID = pyspf-milter
InternalHosts = 127.0.0.1
#MacroListVerify =

Executing the daemon command without the -f option, as:
# /usr/sbin/daemon -c /usr/local/bin/pyspf-milter /usr/local/etc/pyspf-milter/pyspf-milter.conf

yields some scary looking errors (below), well one and one I can't figure out.

* Does spf require the legacy option built into OpenSSL?
* py311-dnspython-2.6.1,1 is installed as a FreeBSD package. I think that's what is being asked for.
* are the below errors why it is failing to start or irrelevant to another problem?

Code:
# Traceback (most recent call last):

  File "/usr/local/bin/spf.py", line 155, in <module>

    import dns.resolver  # http://www.dnspython.org

    ^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/site-packages/dns/resolver.py", line 30, in <module>

    import dns._ddr

  File "/usr/local/lib/python3.11/site-packages/dns/_ddr.py", line 12, in <module>

    import dns.nameserver

  File "/usr/local/lib/python3.11/site-packages/dns/nameserver.py", line 5, in <module>

    import dns.asyncquery

  File "/usr/local/lib/python3.11/site-packages/dns/asyncquery.py", line 32, in <module>

    import dns.quic

  File "/usr/local/lib/python3.11/site-packages/dns/quic/__init__.py", line 7, in <module>

    import aioquic.quic.configuration  # type: ignore

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/site-packages/aioquic/quic/configuration.py", line 6, in <module>

    from ..tls import (

  File "/usr/local/lib/python3.11/site-packages/aioquic/tls.py", line 26, in <module>

    import service_identity

  File "/usr/local/lib/python3.11/site-packages/service_identity/__init__.py", line 6, in <module>

    from . import cryptography, hazmat, pyopenssl

  File "/usr/local/lib/python3.11/site-packages/service_identity/cryptography.py", line 11, in <module>

    from cryptography.x509 import (

  File "/usr/local/lib/python3.11/site-packages/cryptography/x509/__init__.py", line 7, in <module>

    from cryptography.x509 import certificate_transparency, verification

  File "/usr/local/lib/python3.11/site-packages/cryptography/x509/certificate_transparency.py", line 11, in <module>

    from cryptography.hazmat.bindings._rust import x509 as rust_x509

RuntimeError: OpenSSL 3.0's legacy provider failed to load. This is a fatal error by default, but cryptography supports running without legacy algorithms by setting the environment variable CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error, you have likely made a mistake with your OpenSSL configuration.



During handling of the above exception, another exception occurred:



Traceback (most recent call last):

  File "/usr/local/bin/pyspf-milter", line 5, in <module>

    from spf_engine.milter_spf import main

  File "/usr/local/lib/python3.11/site-packages/spf_engine/__init__.py", line 53, in <module>

    import spf

  File "/usr/local/bin/spf.py", line 165, in <module>

    import DNS    # https://launchpad.net/pydns

    ^^^^^^^^^^

ModuleNotFoundError: No module named 'DNS'
 
I found a resolution based on sixpiece comment for mail/py311-spf-engine-3.0.4 so it works with security/openssl32-3.2.3 (and likely all 3.x OpenSSL variants): as the error advises, export the CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1 variable.

Details:
If the pyspf service refuses, silently, to start, for example:

sh:
# service pyspf-milter start
Starting pyspf_milter.
# service pyspf-milter status
pyspf_milter is not running.

Verify the location of the pyspf_milter executable and pyspf-milter.conf config file. Assuming they're in the usual places try unspressing standard IO and otherwise execute the service startup script manually.
/usr/sbin/daemon -c /usr/local/bin/pyspf-milter /usr/local/etc/pyspf-milter/pyspf-milter.conf
If you get an error stream that includes:
Code:
  File "/usr/local/lib/python3.11/site-packages/cryptography/x509/certificate_transparency.py", line 11, in <module>
    from cryptography.hazmat.bindings._rust import x509 as rust_x509
RuntimeError: OpenSSL 3.0's legacy provider failed to load. This is a fatal error by default, but cryptography supports running without legacy algorithms by setting the environment variable CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error, you have likely made a mistake with your OpenSSL configuration.
Follow the instructions given by executing export CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1 and rerunning the startup command. If that works and the service stays up, then the following patch to /usr/local/bin/pyspf-milter should enable startup without user intervention.
Diff:
*** /usr/local/bin/pyspf-milter     Thu Oct  3 23:10:03 2024
--- /usr/local/bin/pyspf-milter.mod Fri Oct  4 05:34:09 2024
***************
*** 1,8 ****
--- 1,10 ----
  #!/usr/local/bin/python3.11
  # -*- coding: utf-8 -*-
  import re
  import sys
+ import os
+ os.environ['CRYPTOGRAPHY_OPENSSL_NO_LEGACY'] = '1'
  from spf_engine.milter_spf import main
  if __name__ == "__main__":
      sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0])
      sys.exit(main())
 
Back
Top