feat: added mail server

master
Sven Ketelsen 5 years ago
parent b438a9c12a
commit ebcab733ef

@ -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

@ -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

@ -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

@ -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:

@ -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([]) }}"
}

@ -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([]) }}"
}

@ -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([]) }}"
}

@ -16,6 +16,5 @@
]
}
],
"applied_to": [
]
"applied_to": "{{ firewall_monitoring_servers | default([]) }}"
}

@ -0,0 +1,6 @@
---
warn_list:
- '106'
- '204'
- '405'
- '601'

@ -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'

@ -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 }}

@ -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

@ -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/

@ -0,0 +1,20 @@
FROM ubuntu:16.04
MAINTAINER Mischa ter Smitten <mtersmitten@oefenweb.nl>
# 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

@ -0,0 +1,19 @@
Copyright (c) Oefenweb.nl <https://github.com/Oefenweb>
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.

@ -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)!

@ -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

@ -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: []

@ -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'

@ -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: []

@ -0,0 +1,6 @@
---
- name: Converge
hosts: all
become: true
roles:
- ../../../

@ -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

@ -0,0 +1,5 @@
---
- name: Prepare
hosts: all
become: true
tasks: []

@ -0,0 +1,5 @@
---
- name: Verify
hosts: all
become: true
tasks: []

@ -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

@ -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 %}

@ -0,0 +1 @@
{{ postfix_mailname }}

@ -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 %}

@ -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 %}

@ -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 %}

@ -0,0 +1,7 @@
# test file
---
- hosts: localhost
connection: local
become: true
roles:
- ../../

@ -0,0 +1,7 @@
# test file
---
- hosts: all
remote_user: vagrant
become: true
roles:
- ../../

@ -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

@ -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"

@ -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]

Loading…
Cancel
Save