Changeset - 441a70c073b9
[Not reviewed]
0 9 0
Branko Majic (branko) - 2 months ago 2024-03-07 22:41:28
branko@majic.rs
MAR-232: Switch to using IP addreses in firewall rules for mail_forwarder role:

- Perform lookups on managed machine for the passed-in SMTP relay
host, and use those values when populating the firewall rules.
9 files changed with 77 insertions and 24 deletions:
0 comments (0 inline, 0 general)
docs/about.rst
Show inline comments
 
@@ -14,16 +14,15 @@ installations.
 
Roles are written for use with *Debian GNU/Linux*. For more details on
 
supported releases, see :ref:`rolereference`.
 

	
 
At the moment, the roles have been written for and tested against **Ansible
 
2.9.x**.
 

	
 
The roles also utilise the ``dig`` and ``ipv4/ipv6`` lookup plugins
 
which require ``dnspython`` and ``netaddr`` packages (respectively) to
 
be installed. Make sure you have the packages available on controller
 
machine.
 
The roles also utilise the ``ipv4/ipv6`` lookup plugins which require
 
``netaddr`` package to be installed. Make sure you have the packages
 
available on controller machine.
 

	
 

	
 
Why were these roles created?
 
-----------------------------
 

	
 
For a long time I have had a couple of Internet-facing servers where I hosted
docs/index.rst
Show inline comments
 
@@ -14,16 +14,15 @@ installations.
 
Roles are written for use with *Debian GNU/Linux*. For more details on
 
supported releases, see :ref:`rolereference`.
 

	
 
At the moment, the roles have been written for and tested against **Ansible
 
2.9.x**.
 

	
 
The roles also utilise the ``dig`` and ``ipv4/ipv6`` lookup plugins
 
which require ``dnspython`` and ``netaddr`` packages (respectively) to
 
be installed. Make sure you have the packages available on controller
 
machine.
 
The roles also utilise the ``ipv4/ipv6`` lookup plugins which require
 
``netaddr`` package to be installed. Make sure you have the packages
 
available on controller machine.
 

	
 

	
 
Contents
 
========
 

	
 
.. toctree::
docs/releasenotes.rst
Show inline comments
 
@@ -12,12 +12,14 @@ Debian 12 Bookworm. Some minor improvements and fixes.
 

	
 
* All roles
 

	
 
  * Dropped support for Debian 10 (Buster).
 
  * Added support for Debian 12 (Bookworm).
 
  * ``netaddr`` Python package is now required for using the roles.
 
  * ``dnspython`` Python package is no longer required for using the
 
    roles.
 

	
 
* ``backup_client`` role
 

	
 
  * Previously the backup would run even if pre-backup scripts would
 
    fail. This is no longer the case, and all pre-backup scripts must
 
    exit with non-zero exit code in order for backup process to
 
@@ -40,15 +42,13 @@ Debian 12 Bookworm. Some minor improvements and fixes.
 
    renamed to ``pip_check_requirements`` /
 
    ``pip_check_requirements_in``.
 

	
 
  * Parameter ``maintenance_allowed_hosts`` has been dropped and
 
    replaced with parameter ``maintenance_allowed_sources``. The new
 
    parameter expects a list of IPv4 and IPv6 addresses (or
 
    subnets). Resolvable names can no longer be specified (and this
 
    particular role no longe relies on presence of the ``dnspython``
 
    package).
 
    subnets). Resolvable names can no longer be specified.
 

	
 
  * NTP server configuration is now based on use of pools instead of
 
    servers. Parameter ``ntp_servers`` has been deprecated and
 
    replaced with parameter ``ntp_pools``.
 

	
 
* ``ldap_server`` role
 
@@ -58,12 +58,26 @@ Debian 12 Bookworm. Some minor improvements and fixes.
 
    the LDAP servers logs under ``/var/log/slapd.log``. Primary
 
    reason is that Debian 12 Bookworm no longer installs *rsyslog* by
 
    default, and it is considered to be deprecated at this point. The
 
    LDAP server logs can be read via ``journalctl -u slapd`` when
 
    necessary.
 

	
 
* ``mail_forwarder`` role
 

	
 
  * Firewall rules for incoming connections from the SMTP relay server
 
    are now based on relay's IPv4 and IPv6 addresses as resolved on
 
    managed machine during deployment time.
 

	
 
    In case the SMTP relay server's IP addresses change, the role
 
    needs to get reapplied against managed machines for those changes
 
    to take place.
 

	
 
    This change in behaviour was introduced to avoid firewall-related
 
    errors due to inability to resolve names via DNS servers during
 
    boot time.
 

	
 
* ``mail_server`` role
 

	
 
  * Parameter ``mail_server_tls_protocols`` has been dropped and
 
    replaced with parameter ``mail_server_minimum_tls_protocol``. Full
 
    list of TLS protocols can no longer be specified, only the minimum
 
    one.
docs/rolereference.rst
Show inline comments
 
@@ -1312,14 +1312,21 @@ instead.
 
The role implements the following:
 

	
 
* Installs and configures Postfix.
 
* Purges Exim4 configuration (just in case).
 
* Sets-up aliases for the local recipients.
 
* Installs SWAKS (utility for testing SMTP servers).
 
* Configures firewall to accept SMTP connections from SMTP relay (if one has
 
  been configured). This allows for delivery of bounced e-mails.
 
* Configures firewall to accept SMTP connections from SMTP relay (if
 
  one has been configured). This allows for delivery of bounced
 
  e-mails.
 

	
 
  .. note::
 
     Firewall rules are based on IPv4 and IPv6 addresses resolved via
 
     managed server at time of deployment. If the SMTP relay changes
 
     its IP addresess, this role needs to be reapplied against the
 
     managed machines.
 

	
 
Postfix is configured as follows:
 

	
 
* Local destinations are set-up.
 
* A relay host is set.
 
* TLS is enforced for relaying mails, with configurable truststore for server
docs/usage.rst
Show inline comments
 
@@ -145,18 +145,17 @@ packages, and to prepare the environment a bit on the Ansible server:
 

	
 
   ::
 

	
 
     mkdir ~/mysite/
 
     mkvirtualenv -p /usr/bin/python3 -a ~/mysite/ mysite
 
     pip install -U pip setuptools
 
     pip install 'ansible~=2.9.0' dnspython netaddr
 
     pip install 'ansible~=2.9.0' netaddr
 

	
 
.. warning::
 
   The ``dnspython`` and ``netaddr`` packages are needed since they
 
   are used internally by some of the roles for the ``dig`` and
 
   ``ipv4/ipv6`` lookup plugins.
 
   The ``netaddr`` package is needed for ``ipv4/ipv6`` lookup plugins
 
   which is used internally by some of the roles.
 

	
 

	
 
Cloning the *Majic Ansible Roles*
 
---------------------------------
 

	
 
With most of the software pieces in place, the only missing thing is the Majic
requirements.in
Show inline comments
 
ansible~=2.9.0
 
defusedxml
 
dnspython
 
gimmecert~=0.5.0
 
molecule~=2.22.0
 
netaddr
 
paramiko
 
pip
 
pip-tools
requirements.txt
Show inline comments
 
@@ -65,14 +65,12 @@ cryptography==3.2.1
 
    #   gimmecert
 
    #   paramiko
 
defusedxml==0.7.1
 
    # via -r requirements.in
 
distlib==0.3.8
 
    # via virtualenv
 
dnspython==2.6.1
 
    # via -r requirements.in
 
docutils==0.20.1
 
    # via
 
    #   sphinx
 
    #   sphinx-rtd-theme
 
exceptiongroup==1.2.0
 
    # via pytest
 
@@ -123,13 +121,13 @@ paramiko==2.12.0
 
    #   -r requirements.in
 
    #   molecule
 
pathspec==0.12.1
 
    # via yamllint
 
pexpect==4.9.0
 
    # via molecule
 
pip-tools==7.4.0
 
pip-tools==7.4.1
 
    # via -r requirements.in
 
platformdirs==4.2.0
 
    # via virtualenv
 
pluggy==1.4.0
 
    # via pytest
 
pre-commit==1.21.0
roles/mail_forwarder/tasks/main.yml
Show inline comments
 
@@ -67,12 +67,44 @@
 
- name: Enable and start postfix service
 
  service:
 
    name: postfix
 
    state: started
 
    enabled: true
 

	
 
- name: Retrieve IPv4 addresses of SMTP relay host
 
  shell: "getent ahostsv4 '{{ smtp_relay_host }}' | awk '{ print $1 }' | sort -u"  # noqa 306
 
  # [306] Shells that use pipes should set the pipefail option
 
  #   The getent ahostsv4 command has non-zero exit code if the
 
  #   supplies name cannot be resolved. However, that is a valid
 
  #   use-case for extracting this information. It effectively means
 
  #   that no IPv4 firewall rules will be deployed for allowing
 
  #   incoming connections from the SMTP relay host.
 
  changed_when: false
 
  register: smtp_relay_host_ipv4
 

	
 
- name: Retrieve IPv6 addresses of SMTP relay host
 
  shell: "getent ahostsv6 '{{ smtp_relay_host }}' | awk '{ print $1 }' | grep -v '^::ffff:' | sort -u"  # noqa 306
 
  # [306] Shells that use pipes should set the pipefail option
 
  #   The getent ahostsv6 command has non-zero exit code if the
 
  #   supplies name cannot be resolved. However, that is a valid
 
  #   use-case for extracting this information. It effectively means
 
  #   that no IPv6 firewall rules will be deployed for allowing
 
  #   incoming connections from the SMTP relay host.
 
  changed_when: false
 
  register: smtp_relay_host_ipv6
 

	
 
- name: Normalise the SMTP relay host IPv4 addresses variable
 
  set_fact:
 
    smtp_relay_host_ipv4: "{{ smtp_relay_host_ipv4.stdout_lines | reject('equalto', '') | list }}"
 
  when: "smtp_relay_host | length != 0"
 

	
 
- name: Normalise the SMTP relay host IPv6 addresses variable
 
  set_fact:
 
    smtp_relay_host_ipv6: "{{ smtp_relay_host_ipv6.stdout_lines | reject('equalto', '') | list }}"
 
  when: "smtp_relay_host | length != 0"
 

	
 
- name: Deploy firewall configuration for mail forwader
 
  template:
 
    src: "ferm_mail.conf.j2"
 
    dest: "/etc/ferm/conf.d/20-mail.conf"
 
    owner: root
 
    group: root
roles/mail_forwarder/templates/ferm_mail.conf.j2
Show inline comments
 
{% if smtp_relay_host and smtp_from_relay_allowed %}
 
{% if smtp_relay_host_ipv4 %}
 
domain ip {
 
    # Accept incoming connections on port 25 from SMTP relay host.
 
    table filter {
 
        chain INPUT {
 
            # SMTP for server communication.
 
            proto tcp dport 25 {
 
                saddr {{ smtp_relay_host }} ACCEPT;
 
{% for address in smtp_relay_host_ipv4 %}
 
                saddr {{ address }} ACCEPT;
 
{% endfor %}
 
            }
 
        }
 
    }
 
}
 
{% endif %}
 

	
 
{% if lookup('dig', smtp_relay_host + '/AAAA') not in ['NXDOMAIN', ''] %}
 
{% if smtp_relay_host_ipv6 %}
 
domain ip6 {
 
    # Accept incoming connections on port 25 from SMTP relay host.
 
    table filter {
 
        chain INPUT {
 
            # SMTP for server communication.
 
            proto tcp dport 25 {
 
                saddr {{ smtp_relay_host }} ACCEPT;
 
{% for address in smtp_relay_host_ipv6 %}
 
                saddr {{ address }} ACCEPT;
 
{% endfor %}
 
            }
 
        }
 
    }
 
}
 
{% endif %}
 
{% endif %}
0 comments (0 inline, 0 general)