diff --git a/host_vars/dev-mail-01.yml b/host_vars/dev-mail-01.yml index bb04081..4583306 100644 --- a/host_vars/dev-mail-01.yml +++ b/host_vars/dev-mail-01.yml @@ -1,3 +1,16 @@ --- hetzner_server_labels: "stage={{ stage }} service=mail" + +postfix_mynetworks: + - '127.0.0.0/8' # default + - '[::ffff:127.0.0.0]/104' # default + - '[::1]/128' # default + - '10.2.0.0/24' # private cloud subnet +postfix_hostname: 'dev-mail-01.smardigo.digital' +postfix_mailname: 'dev-mail-01.smardigo.digital' +postfix_smtpd_banner: '$myhostname ESMTP $mail_name' +postfix_smtpd_recipient_restrictions: + - permit_mynetworks + - permit_sasl_authenticated + - reject_unauth_destination diff --git a/provisioning.yml b/provisioning.yml index 32397b4..dbb2682 100644 --- a/provisioning.yml +++ b/provisioning.yml @@ -24,6 +24,8 @@ register: hetzner_firewalls_response delegate_to: 127.0.0.1 run_once: true + tags: + - update_networks - name: "Gather current server infos" hcloud_server_info: @@ -31,17 +33,23 @@ register: hetzner_server_infos delegate_to: 127.0.0.1 become: false + tags: + - update_networks - name: "Set current server infos as fact: hetzner_server_infos_json" set_fact: hetzner_server_infos_json: "{{ hetzner_server_infos.hcloud_server_info }}" delegate_to: 127.0.0.1 become: false + tags: + - update_networks - name: Save firewall entries as variable (fact) set_fact: hetzner_firewalls_response_json: "{{ hetzner_firewalls_response.json }}" run_once: true + tags: + - update_networks - name: Parse firewall entries set_fact: @@ -49,11 +57,15 @@ vars: jmesquery: '[*].{id: id, name: name}' run_once: true + tags: + - update_networks - name: Print firewall entries debug: msg: "{{ firewall_records }}" run_once: true + tags: + - update_networks roles: - role: hcloud diff --git a/roles/hcloud/tasks/configure-firewall.yml b/roles/hcloud/tasks/configure-firewall.yml index 4900de9..56a2942 100644 --- a/roles/hcloud/tasks/configure-firewall.yml +++ b/roles/hcloud/tasks/configure-firewall.yml @@ -2,15 +2,19 @@ ### tags: -- name: Read firewall entry for {{ current_firewall_name }} +- name: Read firewall entry for <{{ current_firewall_name }}> set_fact: firewall_record: "{{ firewall_records | selectattr('name', 'equalto', current_firewall_name) | list | first | default({'name': '-', 'id': '-'}) }}" + tags: + - update_networks -- name: Print firewall entry for {{ current_firewall_name }} +- name: Print firewall entry for <{{ current_firewall_name }}> debug: msg: "{{ firewall_record }}" + tags: + - update_networks -- name: Save firewall entry {{ current_firewall_name }} +- name: Save firewall entry <{{ current_firewall_name }}> uri: method: POST url: "https://api.hetzner.cloud/v1/firewalls" @@ -23,9 +27,11 @@ status_code: 201 when: firewall_records | selectattr("name", "equalto", current_firewall_name) | list | length == 0 delegate_to: 127.0.0.1 + tags: + - update_networks # TODO port changes are not written corectly -- name: Update firewall entry {{ current_firewall_name }} +- name: Update firewall entry <{{ current_firewall_name }}> uri: method: PUT url: "https://api.hetzner.cloud/v1/firewalls/{{ firewall_record.id }}" @@ -38,3 +44,5 @@ status_code: 200 when: firewall_records | selectattr("name", "equalto", current_firewall_name) | list | length == 1 delegate_to: 127.0.0.1 + tags: + - update_networks diff --git a/roles/hcloud/tasks/main.yml b/roles/hcloud/tasks/main.yml index 8a4a8e6..3500af6 100644 --- a/roles/hcloud/tasks/main.yml +++ b/roles/hcloud/tasks/main.yml @@ -1,6 +1,7 @@ --- ### tags: +### update_networks - name: Create new server {{ inventory_hostname }} hetzner.hcloud.hcloud_server: @@ -24,6 +25,8 @@ - 'monitoring' loop_control: loop_var: current_firewall + tags: + - update_networks - name: Read ip for {{ inventory_hostname }} set_fact: diff --git a/roles/hcloud/templates/firewall-default.json.j2 b/roles/hcloud/templates/firewall-default.json.j2 index 0a33e5c..9877e34 100644 --- a/roles/hcloud/templates/firewall-default.json.j2 +++ b/roles/hcloud/templates/firewall-default.json.j2 @@ -21,7 +21,6 @@ "source_ips": [ "149.233.6.129/32", "212.121.131.106/32", - "5.9.148.23/32", "87.150.34.206/32" ], "destination_ips": [ @@ -34,7 +33,6 @@ "source_ips": [ "149.233.6.129/32", "212.121.131.106/32", - "5.9.148.23/32", "87.150.34.206/32" ], "destination_ips": [ @@ -47,13 +45,11 @@ "source_ips": [ "149.233.6.129/32", "212.121.131.106/32", - "5.9.148.23/32", "87.150.34.206/32" ], "destination_ips": [ ] } ], - "applied_to": [ - ] + "applied_to": "{{ firewall_default_servers | default([]) }}" } diff --git a/roles/hcloud/templates/firewall-kibana.json.j2 b/roles/hcloud/templates/firewall-kibana.json.j2 index 401005b..6f09ece 100644 --- a/roles/hcloud/templates/firewall-kibana.json.j2 +++ b/roles/hcloud/templates/firewall-kibana.json.j2 @@ -10,13 +10,11 @@ "source_ips": [ "149.233.6.129/32", "212.121.131.106/32", - "5.9.148.23/32", "87.150.34.206/32" ], "destination_ips": [ ] } ], - "applied_to": [ - ] + "applied_to": "{{ firewall_kibana_servers | default([]) }}" } diff --git a/roles/hcloud/templates/firewall-mail.json.j2 b/roles/hcloud/templates/firewall-mail.json.j2 new file mode 100644 index 0000000..55ca334 --- /dev/null +++ b/roles/hcloud/templates/firewall-mail.json.j2 @@ -0,0 +1,18 @@ +{ + "name": "mail", + "labels": { + }, + "rules": [ + { + "direction": "in", + "protocol": "tcp", + "port": "25", + "source_ips": [ + "149.233.6.129/32", + ], + "destination_ips": [ + ] + } + ], + "applied_to": "{{ firewall_mail_servers | default([]) }}" +} diff --git a/roles/hcloud/templates/firewall-monitoring.json.j2 b/roles/hcloud/templates/firewall-monitoring.json.j2 index 2041770..1580bb2 100644 --- a/roles/hcloud/templates/firewall-monitoring.json.j2 +++ b/roles/hcloud/templates/firewall-monitoring.json.j2 @@ -16,6 +16,5 @@ ] } ], - "applied_to": [ - ] + "applied_to": "{{ firewall_monitoring_servers | default([]) }}" } diff --git a/roles/postfix/.ansible-lint b/roles/postfix/.ansible-lint new file mode 100644 index 0000000..6b21768 --- /dev/null +++ b/roles/postfix/.ansible-lint @@ -0,0 +1,6 @@ +--- +warn_list: + - '106' + - '204' + - '405' + - '601' diff --git a/roles/postfix/.github/workflows/ci.yml b/roles/postfix/.github/workflows/ci.yml new file mode 100644 index 0000000..e8a0475 --- /dev/null +++ b/roles/postfix/.github/workflows/ci.yml @@ -0,0 +1,80 @@ +--- +name: CI +'on': + pull_request: + push: + branches: + - master + schedule: + - cron: '30 1 * * 3' + +jobs: + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Check out the codebase + uses: actions/checkout@v2 + + - name: Set up Python 3 + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install test dependencies + run: pip install ansible-lint[community,yamllint] + + - name: Lint code + run: | + yamllint . + ansible-lint + + molecule: + name: Molecule + runs-on: ubuntu-latest + defaults: + run: + working-directory: "${{ github.repository }}" + needs: + - lint + strategy: + fail-fast: false + matrix: + include: + - distro: debian8 + - distro: debian9 + - distro: debian10 + - distro: ubuntu1604 + ansible-version: '>=2.8, <2.9' + - distro: ubuntu1604 + ansible-version: '>=2.9, <2.10' + - distro: ubuntu1604 + ansible-version: '>=2.10, <2.11' + - distro: ubuntu1604 + - distro: ubuntu1804 + - distro: ubuntu2004 + + steps: + - name: Check out the codebase + uses: actions/checkout@v2 + with: + path: "${{ github.repository }}" + + - name: Set up Python 3 + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install test dependencies + run: pip install 'ansible${{ matrix.ansible-version }}' molecule[docker] docker + + - name: Run Molecule tests + run: | + molecule test + env: + ANSIBLE_FORCE_COLOR: '1' + ANSIBLE_VERBOSITY: '2' + MOLECULE_DEBUG: '1' + MOLECULE_DISTRO: "${{ matrix.distro }}" + PY_COLORS: '1' diff --git a/roles/postfix/.github/workflows/release.yml b/roles/postfix/.github/workflows/release.yml new file mode 100644 index 0000000..2354e68 --- /dev/null +++ b/roles/postfix/.github/workflows/release.yml @@ -0,0 +1,20 @@ +--- +name: Release +'on': + push: + tags: + - '*' + +jobs: + + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Check out the codebase + uses: actions/checkout@v2 + + - name: Publish to Galaxy + uses: robertdebock/galaxy-action@1.1.0 + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} diff --git a/roles/postfix/.gitignore b/roles/postfix/.gitignore new file mode 100644 index 0000000..f74c83a --- /dev/null +++ b/roles/postfix/.gitignore @@ -0,0 +1,30 @@ +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db + +# IDE files # +################# +/.settings +/.buildpath +/.project +/nbproject +*.komodoproject +*.kpf +/.idea + +# Vagrant files # +.virtualbox/ +.vagrant/ +vagrant_ansible_inventory_* +ansible.cfg + +# Other files # +############### +!empty diff --git a/roles/postfix/.yamllint b/roles/postfix/.yamllint new file mode 100644 index 0000000..894450c --- /dev/null +++ b/roles/postfix/.yamllint @@ -0,0 +1,15 @@ +--- +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + line-length: disable + truthy: disable + +ignore: | + .tox/ diff --git a/roles/postfix/Dockerfile b/roles/postfix/Dockerfile new file mode 100644 index 0000000..b179278 --- /dev/null +++ b/roles/postfix/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 +MAINTAINER Mischa ter Smitten + +# python +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y python-minimal python-dev curl && \ + apt-get clean +RUN curl -sL https://bootstrap.pypa.io/pip/2.7/get-pip.py | python - +RUN rm -rf $HOME/.cache + +# ansible +RUN DEBIAN_FRONTEND=noninteractive apt-get install -y gcc libffi-dev libssl-dev && \ + apt-get clean +RUN pip install ansible==2.9.15 +RUN rm -rf $HOME/.cache + +# provision +COPY . /etc/ansible/roles/ansible-role +WORKDIR /etc/ansible/roles/ansible-role +RUN ansible-playbook -i tests/inventory tests/test.yml --connection=local diff --git a/roles/postfix/LICENSE.txt b/roles/postfix/LICENSE.txt new file mode 100644 index 0000000..5708f35 --- /dev/null +++ b/roles/postfix/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) Oefenweb.nl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/roles/postfix/README.md b/roles/postfix/README.md new file mode 100644 index 0000000..ab10ab6 --- /dev/null +++ b/roles/postfix/README.md @@ -0,0 +1,264 @@ +## postfix + +[![CI](https://github.com/Oefenweb/ansible-postfix/workflows/CI/badge.svg)](https://github.com/Oefenweb/ansible-postfix/actions?query=workflow%3ACI) +[![Ansible Galaxy](http://img.shields.io/badge/ansible--galaxy-postfix-blue.svg)](https://galaxy.ansible.com/oefenweb/postfix) + +Set up a postfix server in Debian-like systems. + +#### Requirements + +None + +#### Variables + + * `postfix_install` [default: `[postfix, mailutils, libsasl2-2, sasl2-bin, libsasl2-modules]`]: Packages to install + * `postfix_hostname` [default: `{{ ansible_fqdn }}`]: Host name, used for `myhostname` and in `mydestination` + * `postfix_mailname` [default: `{{ ansible_fqdn }}`]: Mail name (in `/etc/mailname`), used for `myorigin` + + * `postfix_compatibility_level` [optional]: With backwards compatibility turned on (the compatibility_level value is less than the Postfix built-in value), Postfix looks for settings that are left at their implicit default value, and logs a message when a backwards-compatible default setting is required (e.g. `2`, `Postfix >= 3.0`) + + * `postfix_default_database_type` [default: `hash`]: The default database type for use in `newaliases`, `postalias` and `postmap` commands + * `postfix_aliases` [default: `[]`]: Aliases to ensure present in `/etc/aliases` + * `postfix_virtual_aliases` [default: `[]`]: Virtual aliases to ensure present in `/etc/postfix/virtual` + * `postfix_sender_canonical_maps` [default: `[]`]: Sender address rewriting in `/etc/postfix/sender_canonical_maps` ([see](http://www.postfix.org/postconf.5.html#transport_maps)) + * `postfix_sender_canonical_maps_database_type` [default: `"{{ postfix_default_database_type }}"`]: The database type for use in `postfix_sender_canonical_maps` + * `postfix_recipient_canonical_maps` [default: `[]`]: Recipient address rewriting in `/etc/postfix/recipient_canonical_maps` ([see](http://www.postfix.org/postconf.5.html#sender_dependent_relayhost_maps)) + * `postfix_recipient_canonical_maps_database_type` [default: `"{{ postfix_default_database_type }}"`]: The database type for use in `postfix_recipient_canonical_maps` + * `postfix_transport_maps` [default: `[]`]: Transport mapping based on recipient address `/etc/postfix/transport_maps` ([see](http://www.postfix.org/postconf.5.html#recipient_canonical_maps)) + * `postfix_transport_maps_database_type` [default: `"{{ postfix_default_database_type }}"`]: The database type for use in `postfix_transport_maps` + * `postfix_sender_dependent_relayhost_maps` [default: `[]`]: Transport mapping based on sender address `/etc/postfix/sender_dependent_relayhost_maps` ([see](http://www.postfix.org/postconf.5.html#recipient_canonical_maps)) + * `postfix_header_checks` [default: `[]`]: Lookup tables for content inspection of primary non-MIME message headers `/etc/postfix/header_checks` ([see](http://www.postfix.org/postconf.5.html#header_checks)) + * `postfix_header_checks_database_type` [default: `regexp`]: The database type for use in `header_checks` + * `postfix_generic` [default: `postfix_smtp_generic_maps`]: **Deprecated**, use `postfix_smtp_generic_maps` + * `postfix_smtp_generic_maps` [default: `[]`]: Generic table address mapping in `/etc/postfix/generic` ([see](http://www.postfix.org/generic.5.html)) + * `postfix_smtp_generic_maps_database_type` [default: `"{{ postfix_default_database_type }}"`]: The database type for use in `smtp_generic_maps` + + * `postfix_mydestination` [default: `["{{ postfix_hostname }}", 'localdomain', 'localhost', 'localhost.localdomain']`]: Specifies what domains this machine will deliver locally, instead of forwarding to another machine + * `postfix_mynetworks` [default: `['127.0.0.0/8', '[::ffff:127.0.0.0]/104', '[::1]/128']`]: The list of "trusted" remote SMTP clients that have more privileges than "strangers" + * `postfix_inet_interfaces` [default: `all`]: Network interfaces to bind ([see](http://www.postfix.org/postconf.5.html#inet_interfaces)) + * `postfix_inet_protocols` [default: `all`]: The Internet protocols Postfix will attempt to use when making or accepting connections ([see](http://www.postfix.org/postconf.5.html#inet_protocols)) + + * `postfix_relayhost` [default: `''` (no relay host)]: Hostname to relay all email to + * `postfix_relayhost_mxlookup` [default: `false` (not using mx lookup)]: Lookup for MX record instead of A record for relayhost + * `postfix_relayhost_port` [default: 587]: Relay port (on `postfix_relayhost`, if set) + * `postfix_relaytls` [default: `false`]: Use TLS when sending with a relay host + + * `postfix_smtpd_client_restrictions` [optional]: List of client restrictions ([see](http://www.postfix.org/postconf.5.html#smtpd_client_restrictions)) + * `postfix_smtpd_helo_restrictions` [optional]: List of helo restrictions ([see](http://www.postfix.org/postconf.5.html#smtpd_helo_restrictions)) + * `postfix_smtpd_sender_restrictions` [optional]: List of sender restrictions ([see](http://www.postfix.org/postconf.5.html#smtpd_sender_restrictions)) + * `postfix_smtpd_recipient_restrictions` [optional]: List of recipient restrictions ([see](http://www.postfix.org/postconf.5.html#smtpd_recipient_restrictions)) + * `postfix_smtpd_relay_restrictions` [optional]: List of access restrictions for mail relay control ([see](http://www.postfix.org/postconf.5.html#smtpd_relay_restrictions)) + * `postfix_smtpd_data_restrictions` [optional]: List of data restrictions ([see](http://www.postfix.org/postconf.5.html#smtpd_data_restrictions)) + + * `postfix_sasl_auth_enable` [default: `true`]: Enable SASL authentication in the SMTP client + * `postfix_sasl_user` [default: `postmaster@{{ ansible_domain }}`]: SASL relay username + * `postfix_sasl_password` [default: `k8+haga4@#pR`]: SASL relay password **Make sure to change!** + * `postfix_sasl_security_options` [default: `noanonymous`]: SMTP client SASL security options + * `postfix_sasl_tls_security_option` [default: `noanonymous`]: SMTP client SASL TLS security options + * `postfix_sasl_mechanism_filter` [default: `''`]: SMTP client SASL authentication mechanism filter ([see](http://www.postfix.org/postconf.5.html#smtp_sasl_mechanism_filter)) + + * `postfix_smtp_tls_security_level` [default: `encrypt`]: The default SMTP TLS security level for the Postfix SMTP client ([see](http://www.postfix.org/postconf.5.html#smtp_tls_security_level)) + * `postfix_smtp_tls_note_starttls_offer` [default: `true`]: Log the hostname of a remote SMTP server that offers STARTTLS, when TLS is not already enabled for that server ([see](http://www.postfix.org/postconf.5.html#smtp_tls_note_starttls_offer)) + * `postfix_smtp_tls_cafile` [optional]: A file containing CA certificates of root CAs trusted to sign either remote SMTP server certificates or intermediate CA certificates (e.g. `/etc/ssl/certs/ca-certificates.crt`) + + * `postfix_smtpd_banner` [default: `$myhostname ESMTP $mail_name (Ubuntu)`]: Greeting banner **You MUST specify $myhostname at the start of the text. This is required by the SMTP protocol.** + * `postfix_disable_vrfy_command` [default: `false`]: Disable the `SMTP VRFY` command. This stops some techniques used to harvest email addresses + * `postfix_message_size_limit` [default: `10240000`]: The maximal size in bytes of a message, including envelope information + + * `postfix_smtpd_tls_cert_file` [default: `/etc/ssl/certs/ssl-cert-snakeoil.pem`]: Path to certificate file + * `postfix_smtpd_tls_key_file` [default: `/etc/ssl/certs/ssl-cert-snakeoil.key`]: Path to key file + + * `postfix_raw_options` [default: `[]`]: List of lines (to pass extra (unsupported) configuration) + +## Dependencies + +* `debconf` +* `debconf-utils` + +#### Example(s) + +A simple example that doesn't use SASL relaying: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_aliases: + - user: root + alias: you@yourdomain.org +``` + +A simple example with virtual aliases for mail forwarding that doesn't use SASL relaying: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_mydestination: + - "{{ postfix_hostname }}" + - '$mydomain' + - localdomain + - localhost + - localhost.localdomain + postfix_virtual_aliases: + - virtual: webmaster@yourdomain.com + alias: personal_email@gmail.com + - virtual: billandbob@yourdomain.com + alias: bill@gmail.com, bob@gmail.com +``` + +A simple example that rewrites the sender address: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_sender_canonical_maps: + - sender: root + rewrite: postmaster@yourdomain.org +``` + +Provide the relay host name if you want to enable relaying: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_aliases: + - user: root + alias: you@yourdomain.org + postfix_relayhost: mail.yourdomain.org +``` + +Provide the relay domain name and use MX records if you want to enable relaying to DNS MX records of a domain: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_aliases: + - user: root + alias: you@yourdomain.org + postfix_relayhost: yourdomain.org + postfix_relayhost_mxlookup: true +``` + +Conditional relaying: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_transport_maps: + - pattern: 'root@yourdomain.org' + result: ':' + - pattern: '*' + result: "smtp:{{ ansible_lo['ipv4']['address'] }}:1025" + postfix_sender_dependent_relayhost_maps: + - pattern: 'logcheck@yourdomain.org' + result: 'DUNNO' + - pattern: 'pflogsumm@yourdomain.org' + result: 'DUNNO' + - pattern: '*' + result: "smtp:{{ ansible_lo['ipv4']['address'] }}:1025" +``` + +For AWS SES support: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_aliases: + - user: root + alias: sesverified@yourdomain.org + postfix_relayhost: email-smtp.us-east-1.amazonaws.com + postfix_relaytls: true + # AWS IAM SES credentials (not access key): + postfix_sasl_user: AKIXXXXXXXXXXXXXXXXX + postfix_sasl_password: ASDFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +``` + +For MailHog support: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_aliases: + - user: root + alias: you@yourdomain.org + postfix_relayhost: "{{ ansible_lo['ipv4']['address'] }}" + postfix_relayhost_port: 1025 + postfix_sasl_auth_enable: false +``` + +For Gmail support: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_aliases: + - user: root + alias: you@yourdomain.org + postfix_relayhost: smtp.gmail.com + postfix_relaytls: true + postfix_smtp_tls_cafile: /etc/ssl/certs/ca-certificates.crt + postfix_sasl_user: 'foo' + postfix_sasl_password: 'bar' +``` + +If you configure your Google account for extra security to use the 2-step verification, then +postfix won't send out emails anymore and you might notice error messages in the `/var/log/mail.log` file + +To fix this issue, you need to visit the ([Authorizing applications & sites](http://www.google.com/accounts/IssuedAuthSubTokens?hide_authsub=1)) +page under your Google Account settings. On this page enter the name of the application to be authorized (Postfix) and click on Generate button. +Set the `postfix_sasl_password` variable with the password generated by this page. + +A simple example that shows how to add some raw config: + +```yaml +--- +- hosts: all + roles: + - postfix + vars: + postfix_raw_options: + - | + milter_default_action = accept + milter_protocol = 6 + smtpd_milters = unix:opendkim/opendkim.sock unix:opendmarc/opendmarc.sock unix:spamass/spamass.sock unix:clamav/clamav-milter.ctl + milter_connect_macros = "i j {daemon_name} v {if_name} _" + policyd-spf_time_limit = 3600 +``` + +#### License + +MIT + +#### Author Information + +Mischa ter Smitten + +#### Feedback, bug-reports, requests, ... + +Are [welcome](https://github.com/Oefenweb/ansible-postfix/issues)! diff --git a/roles/postfix/Vagrantfile b/roles/postfix/Vagrantfile new file mode 100644 index 0000000..a0182a0 --- /dev/null +++ b/roles/postfix/Vagrantfile @@ -0,0 +1,70 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby ts=2 sw=2 tw=0 et : + +role = File.basename(File.expand_path(File.dirname(__FILE__))) + +boxes = [ + { + :name => "ubuntu-1604", + :box => "bento/ubuntu-16.04", + :ip => '10.0.0.12', + :cpu => "50", + :ram => "256" + }, + { + :name => "ubuntu-1804", + :box => "bento/ubuntu-18.04", + :ip => '10.0.0.13', + :cpu => "50", + :ram => "384" + }, + { + :name => "ubuntu-2004", + :box => "bento/ubuntu-20.04", + :ip => '10.0.0.14', + :cpu => "50", + :ram => "384" + }, + { + :name => "debian-8", + :box => "bento/debian-8", + :ip => '10.0.0.16', + :cpu => "50", + :ram => "256" + }, + { + :name => "debian-9", + :box => "bento/debian-9", + :ip => '10.0.0.17', + :cpu => "50", + :ram => "256" + }, + { + :name => "debian-10", + :box => "bento/debian-10", + :ip => '10.0.0.18', + :cpu => "50", + :ram => "256" + }, +] + +Vagrant.configure("2") do |config| + boxes.each do |box| + config.vm.define box[:name] do |vms| + vms.vm.box = box[:box] + vms.vm.hostname = "ansible-#{role}-#{box[:name]}" + + vms.vm.provider "virtualbox" do |v| + v.customize ["modifyvm", :id, "--cpuexecutioncap", box[:cpu]] + v.customize ["modifyvm", :id, "--memory", box[:ram]] + end + + vms.vm.network :private_network, ip: box[:ip] + + vms.vm.provision :ansible do |ansible| + ansible.playbook = "tests/vagrant.yml" + ansible.verbose = "vv" + end + end + end +end diff --git a/roles/postfix/defaults/main.yml b/roles/postfix/defaults/main.yml new file mode 100644 index 0000000..6c2e5f7 --- /dev/null +++ b/roles/postfix/defaults/main.yml @@ -0,0 +1,63 @@ +# defaults file +--- +postfix_install: + - postfix + - mailutils + - libsasl2-2 + - sasl2-bin + - libsasl2-modules + +postfix_hostname: "{{ ansible_fqdn }}" +postfix_mailname: "{{ ansible_fqdn }}" + +postfix_default_database_type: hash +postfix_aliases: [] +postfix_virtual_aliases: [] +postfix_sender_canonical_maps: [] +postfix_sender_canonical_maps_database_type: "{{ postfix_default_database_type }}" +postfix_recipient_canonical_maps: [] +postfix_recipient_canonical_maps_database_type: "{{ postfix_default_database_type }}" +postfix_transport_maps: [] +postfix_transport_maps_database_type: "{{ postfix_default_database_type }}" +postfix_sender_dependent_relayhost_maps: [] +postfix_header_checks: [] +postfix_header_checks_database_type: regexp +postfix_generic: "{{ postfix_smtp_generic_maps }}" +postfix_smtp_generic_maps: [] +postfix_smtp_generic_maps_database_type: "{{ postfix_default_database_type }}" + +postfix_relayhost: '' +postfix_relayhost_mxlookup: false +postfix_relayhost_port: 587 +postfix_relaytls: false + +postfix_sasl_auth_enable: true +postfix_sasl_user: "postmaster@{{ ansible_domain }}" +postfix_sasl_password: 'k8+haga4@#pR' +postfix_sasl_security_options: noanonymous +postfix_sasl_tls_security_options: noanonymous +postfix_sasl_mechanism_filter: '' + +postfix_smtp_tls_security_level: encrypt +postfix_smtp_tls_note_starttls_offer: true + +postfix_inet_interfaces: all +postfix_inet_protocols: all +postfix_mydestination: + - "{{ postfix_hostname }}" + - localdomain + - localhost + - localhost.localdomain +postfix_mynetworks: + - 127.0.0.0/8 + - '[::ffff:127.0.0.0]/104' + - '[::1]/128' + +postfix_smtpd_banner: '$myhostname ESMTP $mail_name (Ubuntu)' +postfix_disable_vrfy_command: false +postfix_message_size_limit: 10240000 + +postfix_smtpd_tls_cert_file: /etc/ssl/certs/ssl-cert-snakeoil.pem +postfix_smtpd_tls_key_file: /etc/ssl/private/ssl-cert-snakeoil.key + +postfix_raw_options: [] diff --git a/roles/postfix/files/empty b/roles/postfix/files/empty new file mode 100644 index 0000000..e69de29 diff --git a/roles/postfix/handlers/main.yml b/roles/postfix/handlers/main.yml new file mode 100644 index 0000000..d4da700 --- /dev/null +++ b/roles/postfix/handlers/main.yml @@ -0,0 +1,47 @@ +# handlers file +--- +- name: new aliases + command: newaliases + when: postfix_default_database_type != 'regexp' + +- name: new virtual aliases + command: postmap {{ postfix_default_database_type }}:{{ postfix_virtual_aliases_file }} + when: postfix_default_database_type != 'regexp' + +- name: postmap sasl_passwd + command: postmap -p {{ postfix_default_database_type }}:{{ postfix_sasl_passwd_file }} + when: postfix_default_database_type != 'regexp' + +- name: postmap sender_canonical_maps + command: postmap {{ postfix_sender_canonical_maps_database_type }}:{{ postfix_sender_canonical_maps_file }} + when: postfix_sender_canonical_maps_database_type != 'regexp' + +- name: postmap recipient_canonical_maps + command: postmap {{ postfix_recipient_canonical_maps_database_type }}:{{ postfix_recipient_canonical_maps_file }} + when: postfix_recipient_canonical_maps_database_type != 'regexp' + +- name: postmap transport_maps + command: postmap {{ postfix_transport_maps_database_type }}:{{ postfix_transport_maps_file }} + when: postfix_transport_maps_database_type != 'regexp' + +- name: postmap sender_dependent_relayhost_maps + command: postmap {{ postfix_default_database_type }}:{{ postfix_sender_dependent_relayhost_maps_file }} + when: postfix_default_database_type != 'regexp' + +- name: postmap generic + command: postmap {{ postfix_smtp_generic_maps_database_type }}:{{ postfix_smtp_generic_maps_file }} + when: postfix_smtp_generic_maps_database_type != 'regexp' + +- name: remove pid + file: + path: "~postfix/pid/master.pid" + state: absent + listen: restart postfix + when: is_docker_guest + +- name: restart service + service: + name: postfix + state: restarted + listen: restart postfix + when: service_default_state | default('started') == 'started' diff --git a/roles/postfix/meta/main.yml b/roles/postfix/meta/main.yml new file mode 100644 index 0000000..348f2ba --- /dev/null +++ b/roles/postfix/meta/main.yml @@ -0,0 +1,25 @@ +# meta file +--- +galaxy_info: + namespace: oefenweb + role_name: postfix + author: Mischa ter Smitten + company: Oefenweb.nl B.V. + description: Set up a postfix server in Debian-like systems + license: MIT + min_ansible_version: 2.8.0 + platforms: + - name: Ubuntu + versions: + - xenial + - bionic + - focal + - name: Debian + versions: + - jessie + - stretch + - buster + galaxy_tags: + - system + - web +dependencies: [] diff --git a/roles/postfix/molecule/default/converge.yml b/roles/postfix/molecule/default/converge.yml new file mode 100644 index 0000000..be762b2 --- /dev/null +++ b/roles/postfix/molecule/default/converge.yml @@ -0,0 +1,6 @@ +--- +- name: Converge + hosts: all + become: true + roles: + - ../../../ diff --git a/roles/postfix/molecule/default/molecule.yml b/roles/postfix/molecule/default/molecule.yml new file mode 100644 index 0000000..fbb7120 --- /dev/null +++ b/roles/postfix/molecule/default/molecule.yml @@ -0,0 +1,19 @@ +--- +dependency: + name: galaxy +driver: + name: docker +platforms: + - name: instance + image: "geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu1604}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true +provisioner: + name: ansible + playbooks: + prepare: prepare.yml + converge: converge.yml + verify: verify.yml diff --git a/roles/postfix/molecule/default/prepare.yml b/roles/postfix/molecule/default/prepare.yml new file mode 100644 index 0000000..9a6673d --- /dev/null +++ b/roles/postfix/molecule/default/prepare.yml @@ -0,0 +1,5 @@ +--- +- name: Prepare + hosts: all + become: true + tasks: [] diff --git a/roles/postfix/molecule/default/verify.yml b/roles/postfix/molecule/default/verify.yml new file mode 100644 index 0000000..44debad --- /dev/null +++ b/roles/postfix/molecule/default/verify.yml @@ -0,0 +1,5 @@ +--- +- name: Verify + hosts: all + become: true + tasks: [] diff --git a/roles/postfix/tasks/main.yml b/roles/postfix/tasks/main.yml new file mode 100644 index 0000000..69aac5d --- /dev/null +++ b/roles/postfix/tasks/main.yml @@ -0,0 +1,244 @@ +# tasks file +--- +- name: facts | set + set_fact: + is_docker_guest: "{{ ansible_virtualization_role | default('host') == 'guest' and ansible_virtualization_type | default('none') == 'docker' }}" + tags: + - configuration + - postfix + - postfix-facts + +- name: configure debconf + debconf: + name: "{{ item.name }}" + question: "{{ item.question }}" + value: "{{ item.value }}" + vtype: "{{ item.vtype }}" + with_items: "{{ postfix_debconf_selections }}" + tags: + - configuration + - postfix + - postfix-install + +- name: install package + apt: + name: "{{ postfix_install }}" + state: "{{ apt_install_state | default('latest') }}" + update_cache: true + cache_valid_time: "{{ apt_update_cache_valid_time | default(3600) }}" + tags: + - configuration + - postfix + - postfix-install + +- name: configure mailname + template: + src: "{{ postfix_mailname_file.lstrip('/') }}.j2" + dest: "{{ postfix_mailname_file }}" + owner: root + group: root + mode: 0644 + notify: restart postfix + tags: + - configuration + - postfix + - postfix-mailname + +- name: update configuration file + template: + src: "{{ postfix_main_cf.lstrip('/') }}.j2" + dest: "{{ postfix_main_cf }}" + owner: root + group: root + mode: 0644 + notify: restart postfix + tags: + - configuration + - postfix + - postfix-configuration + +- name: configure sasl username/password + template: + src: "{{ postfix_sasl_passwd_file.lstrip('/') }}.j2" + dest: "{{ postfix_sasl_passwd_file }}" + owner: root + group: root + mode: 0600 + when: + - postfix_relayhost | length + - postfix_sasl_auth_enable | bool + no_log: "{{ not ansible_check_mode }}" + notify: + - postmap sasl_passwd + - restart postfix + tags: + - configuration + - postfix + - postfix-sasl-passwd + +- name: configure aliases + template: + src: "{{ postfix_aliases_file.lstrip('/') }}.j2" + dest: "{{ postfix_aliases_file }}" + owner: root + group: root + mode: 0644 + notify: + - new aliases + - restart postfix + tags: + - configuration + - postfix + - postfix-aliases + +- name: check if aliases.db exists + stat: + path: "{{ postfix_aliases_file }}.db" + register: _aliasesdb + changed_when: not _aliasesdb.stat.exists + when: postfix_default_database_type == 'hash' + notify: + - new aliases + - restart postfix + tags: + - configuration + - postfix + - postfix-aliases + +- name: configure virtual aliases + lineinfile: + dest: "{{ postfix_virtual_aliases_file }}" + regexp: '^{{ item.virtual | regex_escape }}\s.*' + line: '{{ item.virtual }} {{ item.alias }}' + owner: root + group: root + mode: 0644 + create: true + state: present + with_items: "{{ postfix_virtual_aliases }}" + notify: + - new virtual aliases + - restart postfix + tags: + - configuration + - postfix + - postfix-virtual-aliases + +- name: configure sender canonical maps + lineinfile: + dest: "{{ postfix_sender_canonical_maps_file }}" + regexp: '^{{ item.sender | regex_escape }}\s.*' + line: '{{ item.sender }} {{ item.rewrite }}' + owner: root + group: root + mode: 0644 + create: true + state: present + with_items: "{{ postfix_sender_canonical_maps }}" + notify: + - postmap sender_canonical_maps + - restart postfix + tags: + - configuration + - postfix + - postfix-sender-canonical-maps + +- name: configure recipient canonical maps + lineinfile: + dest: "{{ postfix_recipient_canonical_maps_file }}" + regexp: '^{{ item.recipient | regex_escape }}\s.*' + line: '{{ item.recipient }} {{ item.rewrite }}' + owner: root + group: root + mode: 0644 + create: true + state: present + with_items: "{{ postfix_recipient_canonical_maps }}" + notify: + - postmap recipient_canonical_maps + - restart postfix + tags: + - configuration + - postfix + - postfix-recipient-canonical-maps + +- name: configure transport maps + lineinfile: + dest: "{{ postfix_transport_maps_file }}" + regexp: '^{{ item.pattern | regex_escape }}\s.*' + line: '{{ item.pattern }} {{ item.result }}' + owner: root + group: root + mode: 0644 + create: true + state: present + with_items: "{{ postfix_transport_maps }}" + notify: + - postmap transport_maps + - restart postfix + tags: + - configuration + - postfix + - postfix-transport-maps + +- name: configure sender dependent relayhost maps + lineinfile: + dest: "{{ postfix_sender_dependent_relayhost_maps_file }}" + regexp: '^{{ item.pattern | regex_escape }}\s.*' + line: '{{ item.pattern }} {{ item.result }}' + owner: root + group: root + mode: 0644 + create: true + state: present + with_items: "{{ postfix_sender_dependent_relayhost_maps }}" + notify: + - postmap sender_dependent_relayhost_maps + - restart postfix + tags: + - configuration + - postfix + - postfix-sender-dependent-relayhost-maps + +- name: configure generic table + lineinfile: + dest: "{{ postfix_smtp_generic_maps_file }}" + regexp: '^{{ item.pattern | regex_escape }}\s.*' + line: '{{ item.pattern }} {{ item.result }}' + owner: root + group: root + mode: 0644 + create: true + state: present + with_items: "{{ postfix_smtp_generic_maps }}" + notify: + - postmap generic + - restart postfix + tags: + - configuration + - postfix + - postfix-generic-table + +- name: configure header checks + template: + src: "{{ postfix_header_checks_file.lstrip('/') }}.j2" + dest: "{{ postfix_header_checks_file }}" + owner: root + group: root + mode: 0644 + notify: + - restart postfix + tags: + - configuration + - postfix + - postfix-header-checks-table + +- name: start and enable service + service: + name: postfix + state: "{{ service_default_state | default('started') }}" + enabled: "{{ service_default_enabled | default(true) | bool }}" + tags: + - configuration + - postfix + - postfix-start-enable-service diff --git a/roles/postfix/templates/etc/aliases.j2 b/roles/postfix/templates/etc/aliases.j2 new file mode 100644 index 0000000..8dedf5e --- /dev/null +++ b/roles/postfix/templates/etc/aliases.j2 @@ -0,0 +1,7 @@ +{{ ansible_managed | comment }} +# See man 5 aliases for format + +postmaster: root +{% for alias in postfix_aliases %} +{{ alias.user }}: {{ alias.alias }} +{% endfor %} diff --git a/roles/postfix/templates/etc/mailname.j2 b/roles/postfix/templates/etc/mailname.j2 new file mode 100644 index 0000000..3cba78c --- /dev/null +++ b/roles/postfix/templates/etc/mailname.j2 @@ -0,0 +1 @@ +{{ postfix_mailname }} \ No newline at end of file diff --git a/roles/postfix/templates/etc/postfix/header_checks.j2 b/roles/postfix/templates/etc/postfix/header_checks.j2 new file mode 100644 index 0000000..521c1c6 --- /dev/null +++ b/roles/postfix/templates/etc/postfix/header_checks.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} +{% for rule in postfix_header_checks | default([]) %} +{{ rule.pattern }} {{ rule.action }} {% if rule.text is defined %}{{ rule.text }}{% endif %} + +{% endfor %} diff --git a/roles/postfix/templates/etc/postfix/main.cf.j2 b/roles/postfix/templates/etc/postfix/main.cf.j2 new file mode 100644 index 0000000..ba9431c --- /dev/null +++ b/roles/postfix/templates/etc/postfix/main.cf.j2 @@ -0,0 +1,126 @@ +# {{ ansible_managed }} + +# See /usr/share/postfix/main.cf.dist for a commented, more complete version + +# Debian specific: Specifying a file name will cause the first +# line of that file to be used as the name. The Debian default +# is /etc/mailname. +myorigin = {{ postfix_mailname_file }} + +smtpd_banner = {{ postfix_smtpd_banner }} +biff = no + +# appending .domain is the MUA's job. +append_dot_mydomain = no + +# Uncomment the next line to generate "delayed mail" warnings +#delay_warning_time = 4h + +readme_directory = no + +{% if postfix_compatibility_level is defined %} +compatibility_level = {{ postfix_compatibility_level }} +{% endif %} + +# TLS parameters +smtpd_tls_cert_file = {{ postfix_smtpd_tls_cert_file }} +smtpd_tls_key_file = {{ postfix_smtpd_tls_key_file }} +smtpd_use_tls=yes +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +myhostname = {{ postfix_hostname }} +default_database_type = {{ postfix_default_database_type }} +alias_maps = {{ postfix_default_database_type }}:{{ postfix_aliases_file }} +alias_database = {{ postfix_default_database_type }}:{{ postfix_aliases_file }} +{% if postfix_virtual_aliases %} +virtual_alias_maps = {{ postfix_default_database_type }}:{{ postfix_virtual_aliases_file }} +{% endif %} +{% if postfix_sender_canonical_maps %} +sender_canonical_maps = {{ postfix_sender_canonical_maps_database_type }}:{{ postfix_sender_canonical_maps_file }} +{% endif %} +{% if postfix_recipient_canonical_maps %} +recipient_canonical_maps = {{ postfix_recipient_canonical_maps_database_type }}:{{ postfix_recipient_canonical_maps_file }} +{% endif %} +{% if postfix_transport_maps %} +transport_maps = {{ postfix_transport_maps_database_type }}:{{ postfix_transport_maps_file }} +{% endif %} +{% if postfix_sender_dependent_relayhost_maps %} +sender_dependent_relayhost_maps = {{ postfix_default_database_type }}:{{ postfix_sender_dependent_relayhost_maps_file }} +{% endif %} +{% if postfix_smtp_generic_maps %} +smtp_generic_maps = {{ postfix_smtp_generic_maps_database_type }}:{{ postfix_smtp_generic_maps_file }} +{% endif %} +{% if postfix_header_checks %} +smtp_header_checks = {{ postfix_header_checks_database_type }}:{{ postfix_header_checks_file }} +{% endif %} +mydestination = {{ postfix_mydestination | join(', ') }} +mynetworks = {{ postfix_mynetworks | join(' ') }} +mailbox_size_limit = 0 +recipient_delimiter = + +{% if postfix_inet_interfaces is string %} +inet_interfaces = {{ postfix_inet_interfaces }} +{% else %} +inet_interfaces = {{ postfix_inet_interfaces | join(', ') }} +{% endif %} +{% if postfix_inet_protocols is string %} +inet_protocols = {{ postfix_inet_protocols }} +{% else %} +inet_protocols = {{ postfix_inet_protocols | join(', ') }} +{% endif %} + +{% if postfix_relayhost %} +{% if postfix_relayhost_mxlookup %} +relayhost = {{ postfix_relayhost }}:{{ postfix_relayhost_port }} +{% else %} +relayhost = [{{ postfix_relayhost }}]:{{ postfix_relayhost_port }} +{% endif %} +{% if postfix_sasl_auth_enable %} +smtp_sasl_auth_enable = {{ postfix_sasl_auth_enable | bool | ternary('yes', 'no') }} +smtp_sasl_password_maps = {{ postfix_default_database_type }}:{{ postfix_sasl_passwd_file }} +smtp_sasl_security_options = {{ postfix_sasl_security_options }} +smtp_sasl_tls_security_options = {{ postfix_sasl_tls_security_options }} +smtp_sasl_mechanism_filter = {{ postfix_sasl_mechanism_filter }} +{% endif %} +{% if postfix_relaytls %} +smtp_use_tls = {{ postfix_relaytls | bool | ternary('yes', 'no') }} +smtp_tls_security_level = {{ postfix_smtp_tls_security_level }} +smtp_tls_note_starttls_offer = {{ postfix_smtp_tls_note_starttls_offer | bool | ternary('yes', 'no') }} +{% if postfix_smtp_tls_cafile is defined %} +smtp_tls_CAfile = {{ postfix_smtp_tls_cafile }} +{% endif %} +{% endif %} +{% else %} +relayhost = +{% endif %} + +{% if postfix_smtpd_client_restrictions is defined %} +smtpd_client_restrictions = {{ postfix_smtpd_client_restrictions | join(', ') }} +{% endif %} +{% if postfix_smtpd_helo_restrictions is defined %} +smtpd_helo_restrictions = {{ postfix_smtpd_helo_restrictions | join(', ') }} +{% endif %} +{% if postfix_smtpd_sender_restrictions is defined %} +smtpd_sender_restrictions = {{ postfix_smtpd_sender_restrictions | join(', ') }} +{% endif %} +{% if postfix_smtpd_recipient_restrictions is defined %} +smtpd_recipient_restrictions = {{ postfix_smtpd_recipient_restrictions | join(', ') }} +{% endif %} +{% if postfix_smtpd_relay_restrictions is defined %} +smtpd_relay_restrictions = {{ postfix_smtpd_relay_restrictions | join(', ') }} +{% endif %} +{% if postfix_smtpd_data_restrictions is defined %} +smtpd_data_restrictions = {{ postfix_smtpd_data_restrictions | join(', ') }} +{% endif %} + +message_size_limit = {{ postfix_message_size_limit }} + +# Disable the SMTP VRFY command. This stops some techniques used to harvest email addresses. +disable_vrfy_command = {{ postfix_disable_vrfy_command | bool | ternary('yes', 'no') }} + +{% for raw_option in postfix_raw_options | default([]) %} +{{ raw_option }} +{% endfor %} diff --git a/roles/postfix/templates/etc/postfix/sasl_passwd.j2 b/roles/postfix/templates/etc/postfix/sasl_passwd.j2 new file mode 100644 index 0000000..2afe498 --- /dev/null +++ b/roles/postfix/templates/etc/postfix/sasl_passwd.j2 @@ -0,0 +1,7 @@ +# {{ ansible_managed }} + +{% if postfix_relayhost_mxlookup %} +{{ postfix_relayhost }}:{{ postfix_relayhost_port }} {{ postfix_sasl_user }}:{{ postfix_sasl_password }} +{% else %} +[{{ postfix_relayhost }}]:{{ postfix_relayhost_port }} {{ postfix_sasl_user }}:{{ postfix_sasl_password }} +{% endif %} diff --git a/roles/postfix/tests/inventory b/roles/postfix/tests/inventory new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/roles/postfix/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/roles/postfix/tests/test.yml b/roles/postfix/tests/test.yml new file mode 100644 index 0000000..be2b897 --- /dev/null +++ b/roles/postfix/tests/test.yml @@ -0,0 +1,7 @@ +# test file +--- +- hosts: localhost + connection: local + become: true + roles: + - ../../ diff --git a/roles/postfix/tests/vagrant.yml b/roles/postfix/tests/vagrant.yml new file mode 100644 index 0000000..afdaebc --- /dev/null +++ b/roles/postfix/tests/vagrant.yml @@ -0,0 +1,7 @@ +# test file +--- +- hosts: all + remote_user: vagrant + become: true + roles: + - ../../ diff --git a/roles/postfix/vars/main.yml b/roles/postfix/vars/main.yml new file mode 100644 index 0000000..615436b --- /dev/null +++ b/roles/postfix/vars/main.yml @@ -0,0 +1,19 @@ +# vars file +--- +postfix_debconf_selections: + - name: postfix + question: postfix/main_mailer_type + value: No configuration + vtype: select + +postfix_main_cf: /etc/postfix/main.cf +postfix_mailname_file: /etc/mailname +postfix_aliases_file: /etc/aliases +postfix_virtual_aliases_file: /etc/postfix/virtual +postfix_sasl_passwd_file: /etc/postfix/sasl_passwd +postfix_sender_canonical_maps_file: /etc/postfix/sender_canonical_maps +postfix_recipient_canonical_maps_file: /etc/postfix/recipient_canonical_maps +postfix_transport_maps_file: /etc/postfix/transport_maps +postfix_sender_dependent_relayhost_maps_file: /etc/postfix/sender_dependent_relayhost_maps +postfix_smtp_generic_maps_file: /etc/postfix/generic +postfix_header_checks_file: /etc/postfix/header_checks diff --git a/smardigo.yml b/smardigo.yml index 3113375..62982ba 100644 --- a/smardigo.yml +++ b/smardigo.yml @@ -48,5 +48,7 @@ when: "'connect' in group_names" - role: keycloak when: "'keycloak' in group_names" + - role: postfix + when: "'postfix' in group_names" - role: prometheus when: "'prometheus' in group_names" diff --git a/stage-dev b/stage-dev index 49f4b1f..a4c4de6 100644 --- a/stage-dev +++ b/stage-dev @@ -13,7 +13,7 @@ dev-elastic-stack-03 [keycloak] dev-keycloak-01 -[mail] +[postfix] dev-mail-01 [prometheus] @@ -24,7 +24,7 @@ connect docker_registry elastic keycloak -mail +postfix prometheus [all:children]