Extract playbook actions to roles
This commit is contained in:
parent
311d6ce925
commit
5ee8b48ff7
|
@ -1,3 +1,3 @@
|
||||||
# Ansible configuration files
|
# Ansible configuration files
|
||||||
ansible/inventory.yml
|
ansible/inventory.yml
|
||||||
ansible/vars.yml
|
vars-*.yml
|
||||||
|
|
116
README.md
116
README.md
|
@ -4,88 +4,27 @@ This repository contains the scripts, configuration files, and Ansible playbooks
|
||||||
|
|
||||||
Feel free to read, copy, use, and suggest improvements.
|
Feel free to read, copy, use, and suggest improvements.
|
||||||
|
|
||||||
## Configuration
|
## Ansible configurations
|
||||||
|
|
||||||
Ansible is used for configuration. The playbooks use a `vars.yml` file for settings. This file contains sensitive information, so it is not included in the repository. Below is an example of its structure:
|
Available roles:
|
||||||
|
|
||||||
```yml
|
- firewall - configures firewall
|
||||||
---
|
- initial-setup
|
||||||
ssh_public_key: "ssh-rsa AAAAB3...ak4EsUU="
|
- applies available system patches
|
||||||
mx1_domains:
|
- upgrades all installed packages
|
||||||
- mx1.pikami.org
|
- installs nano and curl
|
||||||
mx2_domains:
|
- disables ssh password logins
|
||||||
- mx2.pikami.org
|
- adds ssh public key
|
||||||
mx1_mail_domain: mx1.pikami.org
|
- mail-primary - installs and configures opensmtpd with dovecot and sive
|
||||||
mx2_mail_domain: mx2.pikami.org
|
- mail-secondary - installs and configures opensmtpd as a backup mail receiver
|
||||||
mail_domains:
|
- prometheus-exporters - installs prometheus exporters
|
||||||
- pikami.net
|
- ssl - generates ssl certificates and adds renew cron job
|
||||||
- pikami.org
|
- vpn - configures wireguard vpn
|
||||||
mail_users:
|
|
||||||
- user: bob@pikami.org
|
|
||||||
password: Password123
|
|
||||||
virtuals:
|
|
||||||
- "bob@pikami.net"
|
|
||||||
- "bob.coolman@pikami.net"
|
|
||||||
- user: alice@pikami.org
|
|
||||||
password: Password123
|
|
||||||
virtuals:
|
|
||||||
- "alice@pikami.net"
|
|
||||||
|
|
||||||
mx1_wg:
|
Available playbooks:
|
||||||
private_key: <wireguard private key>
|
|
||||||
address: <hosts address inside vpn>
|
|
||||||
port: 21841
|
|
||||||
interface: wg0
|
|
||||||
peers:
|
|
||||||
- name: Gateway
|
|
||||||
public_key: <vpn gateway public key>
|
|
||||||
endpoint: <gateway ip>:21841
|
|
||||||
allowed_ips: 10.2.0.1/32
|
|
||||||
mx2_wg:
|
|
||||||
private_key: <wireguard private key>
|
|
||||||
address: <hosts address inside vpn>
|
|
||||||
port: 21841
|
|
||||||
interface: wg0
|
|
||||||
peers:
|
|
||||||
- name: Gateway
|
|
||||||
public_key: <vpn gateway public key>
|
|
||||||
endpoint: <gateway ip>:21841
|
|
||||||
allowed_ips: 10.2.0.1/32
|
|
||||||
|
|
||||||
mx1_fw:
|
- primary-mail.yml - sets up a primary mail server, uses `vars-mx1.yml` for configuration
|
||||||
interfaces:
|
- secondary-mail.yml - sets up a secondary mail server, uses `vars-mx2.yml` for configuration
|
||||||
- name: vio0
|
|
||||||
allowed_tcp:
|
|
||||||
- 22 # SSH
|
|
||||||
- 80 # HTTP
|
|
||||||
- 443 # HTTPS
|
|
||||||
- 25 # SMTP Relay
|
|
||||||
- 587 # SMTP Submission
|
|
||||||
- 465 # SMTPS Submission
|
|
||||||
- 143 # IMAP
|
|
||||||
- 993 # IMAPS
|
|
||||||
- 4190 # Sive
|
|
||||||
allowed_udp:
|
|
||||||
- 21841 # Wireguard
|
|
||||||
- name: wg0
|
|
||||||
allowed_tcp:
|
|
||||||
- 22 # SSH
|
|
||||||
- 9100 # Prometheus node exporter
|
|
||||||
mx2_fw:
|
|
||||||
interfaces:
|
|
||||||
- name: vio0
|
|
||||||
allowed_tcp:
|
|
||||||
- 22 # SSH
|
|
||||||
- 80 # HTTP
|
|
||||||
- 443 # HTTPS
|
|
||||||
- 25 # SMTP Relay
|
|
||||||
allowed_udp:
|
|
||||||
- 21841 # Wireguard
|
|
||||||
- name: wg0
|
|
||||||
allowed_tcp:
|
|
||||||
- 22 # SSH
|
|
||||||
- 9100 # Prometheus node exporter
|
|
||||||
```
|
|
||||||
|
|
||||||
The hosts are taken from the `inventory.yml` file:
|
The hosts are taken from the `inventory.yml` file:
|
||||||
|
|
||||||
|
@ -93,7 +32,7 @@ The hosts are taken from the `inventory.yml` file:
|
||||||
all:
|
all:
|
||||||
hosts:
|
hosts:
|
||||||
mx1:
|
mx1:
|
||||||
ansible_host: <mail server ip>
|
ansible_host: <primary mail server ip>
|
||||||
mx2:
|
mx2:
|
||||||
ansible_host: <secondary mail server ip>
|
ansible_host: <secondary mail server ip>
|
||||||
```
|
```
|
||||||
|
@ -117,21 +56,6 @@ ansible-galaxy collection install community.general
|
||||||
Run playbooks
|
Run playbooks
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# replace "01-initial_setup.yml" with the playbook you want to run
|
# replace "secondary.yml" with the playbook you want to run
|
||||||
ansible-playbook -i inventory.yml 01-initial_setup.yml
|
ansible-playbook -i inventory.yml secondary.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Current ansible playbooks:
|
|
||||||
|
|
||||||
- 01-initial_setup.yml
|
|
||||||
- applies available system patches
|
|
||||||
- upgrades all installed packages
|
|
||||||
- installs nano, curl and git
|
|
||||||
- disables ssh password logins
|
|
||||||
- adds ssh public key
|
|
||||||
- configures firewall
|
|
||||||
- 02-ssl.yml - generates ssl certificates and adds a renew cron job
|
|
||||||
- 03-mail.yml - installs and configures dovecot and opensmtpd
|
|
||||||
- 04-secondary-mail.yml - installs and configures opensmtpd as a backup mail receiver
|
|
||||||
- 05-vpn.yml - configures wireguard vpn
|
|
||||||
- 06-prometheus-exporters.yml - installs prometheus exporters
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
- name: Initial System Setup
|
|
||||||
hosts:
|
|
||||||
- mx1
|
|
||||||
- mx2
|
|
||||||
remote_user: root
|
|
||||||
become: true
|
|
||||||
become_method: su
|
|
||||||
vars_files:
|
|
||||||
- vars.yml
|
|
||||||
tasks:
|
|
||||||
- name: Apply all available system patches
|
|
||||||
command: syspatch
|
|
||||||
register: syspatch
|
|
||||||
failed_when: syspatch.rc != 0 and syspatch.rc != 2
|
|
||||||
changed_when: syspatch.rc == 0
|
|
||||||
|
|
||||||
- name: Update package list and upgrade all packages
|
|
||||||
command: pkg_add -u
|
|
||||||
|
|
||||||
- name: Install essential packages
|
|
||||||
community.general.openbsd_pkg:
|
|
||||||
name:
|
|
||||||
- nano
|
|
||||||
- curl
|
|
||||||
- git
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Disable SSH password authentication
|
|
||||||
ansible.builtin.lineinfile:
|
|
||||||
path: /etc/ssh/sshd_config
|
|
||||||
regexp: "^#?PasswordAuthentication"
|
|
||||||
line: "PasswordAuthentication no"
|
|
||||||
state: present
|
|
||||||
register: sshd_config
|
|
||||||
|
|
||||||
- name: Restart SSH service to apply changes
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: sshd
|
|
||||||
state: restarted
|
|
||||||
when: sshd_config.changed
|
|
||||||
|
|
||||||
- name: Add SSH public key to authorized_keys
|
|
||||||
ansible.posix.authorized_key:
|
|
||||||
user: root
|
|
||||||
key: "{{ ssh_public_key }}"
|
|
||||||
|
|
||||||
- name: Configure firewall
|
|
||||||
template:
|
|
||||||
src: "templates/pf.conf.j2"
|
|
||||||
dest: /etc/pf.conf
|
|
||||||
validate: pfctl -n -f %s
|
|
||||||
register: pf
|
|
||||||
|
|
||||||
- name: Load config to pf if needed
|
|
||||||
command: pfctl -f /etc/pf.conf
|
|
||||||
when: pf.changed
|
|
|
@ -1,52 +0,0 @@
|
||||||
- name: SSL Setup
|
|
||||||
hosts:
|
|
||||||
- mx1
|
|
||||||
- mx2
|
|
||||||
remote_user: root
|
|
||||||
vars_files:
|
|
||||||
- vars.yml
|
|
||||||
tasks:
|
|
||||||
- name: Create vhost directories
|
|
||||||
file:
|
|
||||||
path: "/var/www/vhosts/{{ item }}"
|
|
||||||
state: directory
|
|
||||||
owner: www
|
|
||||||
with_items: "{{ lookup('vars', inventory_hostname + '_domains') }}"
|
|
||||||
|
|
||||||
- name: Install httpd.conf
|
|
||||||
template:
|
|
||||||
src: "templates/httpd.conf"
|
|
||||||
dest: "/etc/httpd.conf"
|
|
||||||
|
|
||||||
- name: Enable and start httpd
|
|
||||||
service:
|
|
||||||
name: httpd
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
||||||
|
|
||||||
- name: Install acme-client.conf
|
|
||||||
template:
|
|
||||||
src: "templates/acme-client.conf"
|
|
||||||
dest: "/etc/acme-client.conf"
|
|
||||||
|
|
||||||
- name: Initial acme-client run
|
|
||||||
command: "/usr/sbin/acme-client {{ item }}"
|
|
||||||
args:
|
|
||||||
creates: "/etc/ssl/{{ item }}.fullchain.pem"
|
|
||||||
with_items: "{{ lookup('vars', inventory_hostname + '_domains') }}"
|
|
||||||
notify:
|
|
||||||
- reload httpd
|
|
||||||
|
|
||||||
- name: Renew certificates via root crontab
|
|
||||||
cron:
|
|
||||||
name: "acme-client renew {{ item }}"
|
|
||||||
minute: "0"
|
|
||||||
job: "sleep $((RANDOM \\% 2048)) && acme-client {{ item }} && rcctl reload httpd"
|
|
||||||
user: root
|
|
||||||
with_items: "{{ lookup('vars', inventory_hostname + '_domains') }}"
|
|
||||||
|
|
||||||
handlers:
|
|
||||||
- name: reload httpd
|
|
||||||
service:
|
|
||||||
name: httpd
|
|
||||||
state: reloaded
|
|
|
@ -1,121 +0,0 @@
|
||||||
- name: OpenSMTPD Installation and Configuration
|
|
||||||
hosts:
|
|
||||||
- mx1
|
|
||||||
remote_user: root
|
|
||||||
vars_files:
|
|
||||||
- vars.yml
|
|
||||||
tasks:
|
|
||||||
- name: Install Packages
|
|
||||||
community.general.openbsd_pkg:
|
|
||||||
name:
|
|
||||||
- opensmtpd-filter-dkimsign
|
|
||||||
- dovecot
|
|
||||||
- dovecot-pigeonhole
|
|
||||||
- opensmtpd-extras
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Create the vmail group
|
|
||||||
group:
|
|
||||||
name: vmail
|
|
||||||
gid: 2000
|
|
||||||
|
|
||||||
- name: Create vmail user
|
|
||||||
user:
|
|
||||||
name: vmail
|
|
||||||
group: vmail
|
|
||||||
shell: /sbin/nologin
|
|
||||||
createhome: yes
|
|
||||||
home: /var/mail/vmail
|
|
||||||
uid: 2000
|
|
||||||
|
|
||||||
- name: Generate dkim keys
|
|
||||||
shell: |
|
|
||||||
KEYLEN=1024
|
|
||||||
DOMAIN={{ mx1_mail_domain }}
|
|
||||||
|
|
||||||
mkdir -p /etc/mail/dkim
|
|
||||||
if [ -f /etc/mail/dkim/$DOMAIN.key ]; then
|
|
||||||
echo "$DOMAIN.key already exists."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /etc/mail/dkim
|
|
||||||
(umask 337; openssl genrsa -out $DOMAIN.key $KEYLEN)
|
|
||||||
openssl rsa -in $DOMAIN.key -pubout -out $DOMAIN.pub
|
|
||||||
group info _dkimsign >/dev/null && chgrp _dkimsign $DOMAIN.key
|
|
||||||
echo "add the $DOMAIN.dns to the zone file"
|
|
||||||
echo "selector1._domainkey.$DOMAIN. 3600 IN TXT \"v=DKIM1; k=rsa; p=$(sed -e '1d' -e '$d' $DOMAIN.pub | tr -d '\n')\"" > ~/$DOMAIN.dns
|
|
||||||
|
|
||||||
- name: Configure OpenSMTPD smtpd.conf
|
|
||||||
template:
|
|
||||||
src: "templates/smtpd.conf"
|
|
||||||
dest: /etc/mail/smtpd.conf
|
|
||||||
notify:
|
|
||||||
- reload smtpd
|
|
||||||
|
|
||||||
- name: Enable and start OpenSMTPD service
|
|
||||||
service:
|
|
||||||
name: smtpd
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
||||||
|
|
||||||
- name: Delete default dovecot configs
|
|
||||||
shell: |
|
|
||||||
if [ -f /etc/dovecot/conf.d/10-ssl.conf ]; then
|
|
||||||
cd /etc/dovecot/
|
|
||||||
rm -rf *
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Install dovecot.conf
|
|
||||||
template:
|
|
||||||
src: "templates/dovecot.conf"
|
|
||||||
dest: "/etc/dovecot/dovecot.conf"
|
|
||||||
notify:
|
|
||||||
- reload dovecot
|
|
||||||
|
|
||||||
- name: Configure users
|
|
||||||
block:
|
|
||||||
- name: Remove existing
|
|
||||||
shell: |
|
|
||||||
echo "" > /etc/dovecot/users
|
|
||||||
chmod 640 /etc/dovecot/users
|
|
||||||
chown _smtpd:_dovecot /etc/dovecot/users
|
|
||||||
|
|
||||||
echo "" > /etc/mail/accounts
|
|
||||||
chmod 640 /etc/mail/accounts
|
|
||||||
chown _smtpd: /etc/mail/accounts
|
|
||||||
|
|
||||||
echo "" > /etc/mail/virtuals
|
|
||||||
chown _smtpd: /etc/mail/virtuals
|
|
||||||
|
|
||||||
- name: Add user accounts
|
|
||||||
loop: "{{ mail_users }}"
|
|
||||||
no_log: true
|
|
||||||
shell: |
|
|
||||||
DOVECOT_PASS=$(doveadm pw -p {{ item.password }})
|
|
||||||
SMTP_PASS=$(smtpctl encrypt {{ item.password }})
|
|
||||||
|
|
||||||
echo "{{ item.user }}:$DOVECOT_PASS::::" >> /etc/dovecot/users
|
|
||||||
echo "{{ item.user }}:$SMTP_PASS::::" >> /etc/mail/accounts
|
|
||||||
|
|
||||||
- name: Install dovecot.conf
|
|
||||||
template:
|
|
||||||
src: "templates/virtuals.conf"
|
|
||||||
dest: "/etc/mail/virtuals"
|
|
||||||
|
|
||||||
- name: Enable dovecot service
|
|
||||||
service:
|
|
||||||
name: dovecot
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
|
|
||||||
handlers:
|
|
||||||
- name: reload smtpd
|
|
||||||
service:
|
|
||||||
name: smtpd
|
|
||||||
state: restarted
|
|
||||||
|
|
||||||
- name: reload dovecot
|
|
||||||
service:
|
|
||||||
name: dovecot
|
|
||||||
state: reloaded
|
|
|
@ -1,25 +0,0 @@
|
||||||
- name: Secondary MX OpenSMTPD Configuration
|
|
||||||
hosts:
|
|
||||||
- mx2
|
|
||||||
remote_user: root
|
|
||||||
vars_files:
|
|
||||||
- vars.yml
|
|
||||||
tasks:
|
|
||||||
- name: Configure OpenSMTPD smtpd.conf
|
|
||||||
template:
|
|
||||||
src: "templates/secondary-smtpd.conf"
|
|
||||||
dest: /etc/mail/smtpd.conf
|
|
||||||
notify:
|
|
||||||
- reload smtpd
|
|
||||||
|
|
||||||
- name: Enable and start OpenSMTPD service
|
|
||||||
service:
|
|
||||||
name: smtpd
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
||||||
|
|
||||||
handlers:
|
|
||||||
- name: reload smtpd
|
|
||||||
service:
|
|
||||||
name: smtpd
|
|
||||||
state: restarted
|
|
|
@ -1,37 +0,0 @@
|
||||||
- name: VPN Setup
|
|
||||||
hosts:
|
|
||||||
- mx1
|
|
||||||
- mx2
|
|
||||||
remote_user: root
|
|
||||||
vars_files:
|
|
||||||
- vars.yml
|
|
||||||
tasks:
|
|
||||||
- name: Install wireguard
|
|
||||||
community.general.openbsd_pkg:
|
|
||||||
name:
|
|
||||||
- wireguard-tools
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Ensures /etc/wireguard dir exists
|
|
||||||
file:
|
|
||||||
path: "/etc/wireguard"
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: Create wireguard config
|
|
||||||
template:
|
|
||||||
src: "templates/wireguard.conf.j2"
|
|
||||||
dest: "/etc/wireguard/{{ lookup('vars', inventory_hostname + '_wg').interface }}.conf"
|
|
||||||
owner: root
|
|
||||||
group: wheel
|
|
||||||
mode: "0600"
|
|
||||||
register: wg_config
|
|
||||||
|
|
||||||
- name: Create wireguard interface
|
|
||||||
template:
|
|
||||||
src: "templates/wireguard.if.j2"
|
|
||||||
dest: "/etc/hostname.{{ lookup('vars', inventory_hostname + '_wg').interface }}"
|
|
||||||
register: iface_config
|
|
||||||
|
|
||||||
- name: Apply network configuration if changed
|
|
||||||
shell: sh /etc/netstart {{ lookup('vars', inventory_hostname + '_wg').interface }}
|
|
||||||
when: wg_config.changed or iface_config.changed
|
|
|
@ -1,19 +0,0 @@
|
||||||
- name: VPN Setup
|
|
||||||
hosts:
|
|
||||||
- mx1
|
|
||||||
- mx2
|
|
||||||
remote_user: root
|
|
||||||
vars_files:
|
|
||||||
- vars.yml
|
|
||||||
tasks:
|
|
||||||
- name: Install node-exporter
|
|
||||||
community.general.openbsd_pkg:
|
|
||||||
name:
|
|
||||||
- node_exporter
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Enable and start node_exporter
|
|
||||||
service:
|
|
||||||
name: node_exporter
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
- name: Primary server configuration
|
||||||
|
hosts:
|
||||||
|
- mx1
|
||||||
|
remote_user: root
|
||||||
|
vars_files:
|
||||||
|
- vars-{{ inventory_hostname }}.yml
|
||||||
|
roles:
|
||||||
|
- initial-setup
|
||||||
|
- firewall
|
||||||
|
- ssl
|
||||||
|
- mail-primary
|
||||||
|
- vpn
|
||||||
|
- prometheus-exporters
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
firewall_interfaces:
|
||||||
|
- name: vio0
|
||||||
|
allowed_tcp:
|
||||||
|
- 22 # SSH
|
||||||
|
- 80 # HTTP
|
||||||
|
- 443 # HTTPS
|
||||||
|
allowed_udp:
|
||||||
|
- 21841 # Wireguard
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
- name: Configure firewall
|
||||||
|
template:
|
||||||
|
src: templates/pf.conf.j2
|
||||||
|
dest: /etc/pf.conf
|
||||||
|
validate: pfctl -n -f %s
|
||||||
|
register: pf
|
||||||
|
|
||||||
|
- name: Load config to pf if needed
|
||||||
|
command: pfctl -f /etc/pf.conf
|
||||||
|
when: pf.changed
|
|
@ -1,4 +1,3 @@
|
||||||
{% set _fw = lookup('vars', inventory_hostname + '_fw') %}
|
|
||||||
# {{ ansible_managed }}
|
# {{ ansible_managed }}
|
||||||
# Skip filtering on the loopback interface
|
# Skip filtering on the loopback interface
|
||||||
set skip on lo
|
set skip on lo
|
||||||
|
@ -12,7 +11,7 @@ block return in on ! lo0 proto tcp to port 6000:6010
|
||||||
# Port build user does not need network
|
# Port build user does not need network
|
||||||
block return out log proto {tcp udp} user _pbuild
|
block return out log proto {tcp udp} user _pbuild
|
||||||
|
|
||||||
{% for interface in _fw.interfaces %}
|
{% for interface in firewall_interfaces %}
|
||||||
# Pass rules for the specific ports on the {{ interface.name }} interface
|
# Pass rules for the specific ports on the {{ interface.name }} interface
|
||||||
{% if (interface.allowed_tcp is defined) and interface.allowed_tcp %}
|
{% if (interface.allowed_tcp is defined) and interface.allowed_tcp %}
|
||||||
{% for port in interface.allowed_tcp %}
|
{% for port in interface.allowed_tcp %}
|
|
@ -0,0 +1,2 @@
|
||||||
|
---
|
||||||
|
ssh_public_key: "ssh-rsa AAAAB3...ak4EsUU="
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
- name: Apply all available system patches
|
||||||
|
command: syspatch
|
||||||
|
register: syspatch
|
||||||
|
failed_when: syspatch.rc != 0 and syspatch.rc != 2
|
||||||
|
changed_when: syspatch.rc == 0
|
||||||
|
|
||||||
|
- name: Update package list and upgrade all packages
|
||||||
|
command: pkg_add -u
|
||||||
|
|
||||||
|
- name: Install essential packages
|
||||||
|
community.general.openbsd_pkg:
|
||||||
|
name:
|
||||||
|
- nano
|
||||||
|
- curl
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Disable SSH password authentication
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: /etc/ssh/sshd_config
|
||||||
|
regexp: "^#?PasswordAuthentication"
|
||||||
|
line: "PasswordAuthentication no"
|
||||||
|
state: present
|
||||||
|
register: sshd_config
|
||||||
|
|
||||||
|
- name: Restart SSH service to apply changes
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: sshd
|
||||||
|
state: restarted
|
||||||
|
when: sshd_config.changed
|
||||||
|
|
||||||
|
- name: Add SSH public key to authorized_keys
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: root
|
||||||
|
key: "{{ ssh_public_key }}"
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
server_domain: mx1.example.com
|
||||||
|
mail_receive_domains:
|
||||||
|
- example.net
|
||||||
|
- example.com
|
||||||
|
mail_users:
|
||||||
|
- user: bob@example.com
|
||||||
|
password: Password123
|
||||||
|
virtuals:
|
||||||
|
- "bob@example.net"
|
||||||
|
- "bob.coolman@example.net"
|
||||||
|
- user: alice@example.com
|
||||||
|
password: Password123
|
||||||
|
virtuals:
|
||||||
|
- "alice@example.net"
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
- name: reload smtpd
|
||||||
|
service:
|
||||||
|
name: smtpd
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: reload dovecot
|
||||||
|
service:
|
||||||
|
name: dovecot
|
||||||
|
state: reloaded
|
|
@ -0,0 +1,104 @@
|
||||||
|
---
|
||||||
|
- name: Install Packages
|
||||||
|
community.general.openbsd_pkg:
|
||||||
|
name:
|
||||||
|
- opensmtpd-filter-dkimsign
|
||||||
|
- dovecot
|
||||||
|
- dovecot-pigeonhole
|
||||||
|
- opensmtpd-extras
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create the vmail group
|
||||||
|
group:
|
||||||
|
name: vmail
|
||||||
|
gid: 2000
|
||||||
|
|
||||||
|
- name: Create vmail user
|
||||||
|
user:
|
||||||
|
name: vmail
|
||||||
|
group: vmail
|
||||||
|
shell: /sbin/nologin
|
||||||
|
createhome: yes
|
||||||
|
home: /var/mail/vmail
|
||||||
|
uid: 2000
|
||||||
|
|
||||||
|
- name: Generate dkim keys
|
||||||
|
shell: |
|
||||||
|
KEYLEN=1024
|
||||||
|
DOMAIN={{ server_domain }}
|
||||||
|
|
||||||
|
mkdir -p /etc/mail/dkim
|
||||||
|
if [ -f /etc/mail/dkim/$DOMAIN.key ]; then
|
||||||
|
echo "$DOMAIN.key already exists."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd /etc/mail/dkim
|
||||||
|
(umask 337; openssl genrsa -out $DOMAIN.key $KEYLEN)
|
||||||
|
openssl rsa -in $DOMAIN.key -pubout -out $DOMAIN.pub
|
||||||
|
group info _dkimsign >/dev/null && chgrp _dkimsign $DOMAIN.key
|
||||||
|
echo "add the $DOMAIN.dns to the zone file"
|
||||||
|
echo "selector1._domainkey.$DOMAIN. 3600 IN TXT \"v=DKIM1; k=rsa; p=$(sed -e '1d' -e '$d' $DOMAIN.pub | tr -d '\n')\"" > ~/$DOMAIN.dns
|
||||||
|
|
||||||
|
- name: Configure OpenSMTPD smtpd.conf
|
||||||
|
template:
|
||||||
|
src: "templates/smtpd.conf"
|
||||||
|
dest: /etc/mail/smtpd.conf
|
||||||
|
notify:
|
||||||
|
- reload smtpd
|
||||||
|
|
||||||
|
- name: Enable and start OpenSMTPD service
|
||||||
|
service:
|
||||||
|
name: smtpd
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Delete default dovecot configs
|
||||||
|
shell: |
|
||||||
|
if [ -f /etc/dovecot/conf.d/10-ssl.conf ]; then
|
||||||
|
cd /etc/dovecot/
|
||||||
|
rm -rf *
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install dovecot.conf
|
||||||
|
template:
|
||||||
|
src: "templates/dovecot.conf"
|
||||||
|
dest: "/etc/dovecot/dovecot.conf"
|
||||||
|
notify:
|
||||||
|
- reload dovecot
|
||||||
|
|
||||||
|
- name: Configure users
|
||||||
|
block:
|
||||||
|
- name: Remove existing
|
||||||
|
shell: |
|
||||||
|
echo "" > /etc/dovecot/users
|
||||||
|
chmod 640 /etc/dovecot/users
|
||||||
|
chown _smtpd:_dovecot /etc/dovecot/users
|
||||||
|
|
||||||
|
echo "" > /etc/mail/accounts
|
||||||
|
chmod 640 /etc/mail/accounts
|
||||||
|
chown _smtpd: /etc/mail/accounts
|
||||||
|
|
||||||
|
echo "" > /etc/mail/virtuals
|
||||||
|
chown _smtpd: /etc/mail/virtuals
|
||||||
|
|
||||||
|
- name: Add user accounts
|
||||||
|
loop: "{{ mail_users }}"
|
||||||
|
no_log: true
|
||||||
|
shell: |
|
||||||
|
DOVECOT_PASS=$(doveadm pw -p {{ item.password }})
|
||||||
|
SMTP_PASS=$(smtpctl encrypt {{ item.password }})
|
||||||
|
|
||||||
|
echo "{{ item.user }}:$DOVECOT_PASS::::" >> /etc/dovecot/users
|
||||||
|
echo "{{ item.user }}:$SMTP_PASS::::" >> /etc/mail/accounts
|
||||||
|
|
||||||
|
- name: Install dovecot.conf
|
||||||
|
template:
|
||||||
|
src: "templates/virtuals.conf"
|
||||||
|
dest: "/etc/mail/virtuals"
|
||||||
|
|
||||||
|
- name: Enable dovecot service
|
||||||
|
service:
|
||||||
|
name: dovecot
|
||||||
|
enabled: true
|
||||||
|
state: started
|
|
@ -1,7 +1,8 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
# Enable ssl
|
# Enable ssl
|
||||||
ssl = required
|
ssl = required
|
||||||
ssl_cert = < /etc/ssl/{{ mx1_mail_domain }}.fullchain.pem
|
ssl_cert = < /etc/ssl/{{ server_domain }}.fullchain.pem
|
||||||
ssl_key = < /etc/ssl/private/{{ mx1_mail_domain }}.key
|
ssl_key = < /etc/ssl/private/{{ server_domain }}.key
|
||||||
|
|
||||||
ssl_min_protocol = TLSv1.2
|
ssl_min_protocol = TLSv1.2
|
||||||
ssl_prefer_server_ciphers = yes
|
ssl_prefer_server_ciphers = yes
|
|
@ -0,0 +1,25 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
|
pki {{ server_domain }} cert "/etc/ssl/{{ server_domain }}.fullchain.pem"
|
||||||
|
pki {{ server_domain }} key "/etc/ssl/private/{{ server_domain }}.key"
|
||||||
|
|
||||||
|
table aliases file:/etc/mail/aliases
|
||||||
|
table users passwd:/etc/mail/accounts
|
||||||
|
table virtuals file:/etc/mail/virtuals
|
||||||
|
|
||||||
|
filter dkimsign_rsa proc-exec "filter-dkimsign -d {{ server_domain }} -s selector1 \
|
||||||
|
-k /etc/mail/dkim/{{ server_domain }}.key" user _dkimsign group _dkimsign
|
||||||
|
|
||||||
|
listen on socket filter dkimsign_rsa
|
||||||
|
listen on all tls pki {{ server_domain }}
|
||||||
|
listen on all port submission tls-require pki {{ server_domain }} auth <users> filter dkimsign_rsa
|
||||||
|
listen on all port smtps tls-require pki {{ server_domain }} auth <users> filter dkimsign_rsa
|
||||||
|
|
||||||
|
action "local_mail" lmtp "/var/dovecot/lmtp" rcpt-to virtual <virtuals>
|
||||||
|
action "outbound" relay
|
||||||
|
|
||||||
|
{% for domain in mail_receive_domains %}
|
||||||
|
match from any for domain {{ domain }} action "local_mail"
|
||||||
|
{% endfor %}
|
||||||
|
match from local for local action "local_mail"
|
||||||
|
match from local for any action "outbound"
|
||||||
|
match auth from any for any action "outbound"
|
|
@ -1,3 +1,4 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
{% for user in mail_users %}
|
{% for user in mail_users %}
|
||||||
{{ user.user }}: vmail
|
{{ user.user }}: vmail
|
||||||
{% if (user.virtuals is defined) and user.virtuals %}
|
{% if (user.virtuals is defined) and user.virtuals %}
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
primary_mail_server: mx1.example.com
|
||||||
|
server_domain: mx1.example.com
|
||||||
|
mail_receive_domains:
|
||||||
|
- example.net
|
||||||
|
- example.com
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: reload smtpd
|
||||||
|
service:
|
||||||
|
name: smtpd
|
||||||
|
state: restarted
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
- name: Configure OpenSMTPD smtpd.conf
|
||||||
|
template:
|
||||||
|
src: templates/smtpd.conf
|
||||||
|
dest: /etc/mail/smtpd.conf
|
||||||
|
notify:
|
||||||
|
- reload smtpd
|
||||||
|
|
||||||
|
- name: Enable and start OpenSMTPD service
|
||||||
|
service:
|
||||||
|
name: smtpd
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
|
@ -0,0 +1,16 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
|
pki {{ server_domain }} cert "/etc/ssl/{{ server_domain }}.fullchain.pem"
|
||||||
|
pki {{ server_domain }} key "/etc/ssl/private/{{ server_domain }}.key"
|
||||||
|
|
||||||
|
listen on all tls pki {{ server_domain }}
|
||||||
|
|
||||||
|
table aliases file:/etc/mail/aliases
|
||||||
|
|
||||||
|
action "local" mbox alias <aliases>
|
||||||
|
action "relay" relay host {{ primary_mail_server }}
|
||||||
|
|
||||||
|
{% for domain in mail_receive_domains %}
|
||||||
|
match from any for domain {{ domain }} action "relay"
|
||||||
|
{% endfor %}
|
||||||
|
match from local for local action "local"
|
||||||
|
match from local for any action "relay"
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
- name: Install node-exporter
|
||||||
|
community.general.openbsd_pkg:
|
||||||
|
name:
|
||||||
|
- node_exporter
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Enable and start node_exporter
|
||||||
|
service:
|
||||||
|
name: node_exporter
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
|
@ -0,0 +1,2 @@
|
||||||
|
domains:
|
||||||
|
- mx1.example.com
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: reload httpd
|
||||||
|
ansible.builtin.service:
|
||||||
|
name: httpd
|
||||||
|
state: reloaded
|
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
- name: Create vhost directories
|
||||||
|
file:
|
||||||
|
path: "/var/www/vhosts/{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: www
|
||||||
|
with_items: "{{ domains }}"
|
||||||
|
|
||||||
|
- name: Install httpd.conf
|
||||||
|
template:
|
||||||
|
src: "templates/httpd.conf"
|
||||||
|
dest: "/etc/httpd.conf"
|
||||||
|
|
||||||
|
- name: Enable and start httpd
|
||||||
|
service:
|
||||||
|
name: httpd
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Install acme-client.conf
|
||||||
|
template:
|
||||||
|
src: "templates/acme-client.conf"
|
||||||
|
dest: "/etc/acme-client.conf"
|
||||||
|
|
||||||
|
- name: Initial acme-client run
|
||||||
|
command: "/usr/sbin/acme-client {{ item }}"
|
||||||
|
args:
|
||||||
|
creates: "/etc/ssl/{{ item }}.fullchain.pem"
|
||||||
|
with_items: "{{ domains }}"
|
||||||
|
notify:
|
||||||
|
- reload httpd
|
||||||
|
|
||||||
|
- name: Renew certificates via root crontab
|
||||||
|
cron:
|
||||||
|
name: "acme-client renew {{ item }}"
|
||||||
|
minute: "0"
|
||||||
|
job: "sleep $((RANDOM \\% 2048)) && acme-client {{ item }} && rcctl reload httpd"
|
||||||
|
user: root
|
||||||
|
with_items: "{{ domains }}"
|
|
@ -1,9 +1,10 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
authority letsencrypt {
|
authority letsencrypt {
|
||||||
api url "https://acme-v02.api.letsencrypt.org/directory"
|
api url "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
account key "/etc/acme/letsencrypt-privkey.pem"
|
account key "/etc/acme/letsencrypt-privkey.pem"
|
||||||
}
|
}
|
||||||
|
|
||||||
{% for domain in lookup('vars', inventory_hostname + '_domains') %}
|
{% for domain in domains %}
|
||||||
domain "{{ domain }}" {
|
domain "{{ domain }}" {
|
||||||
domain key "/etc/ssl/private/{{ domain }}.key"
|
domain key "/etc/ssl/private/{{ domain }}.key"
|
||||||
domain full chain certificate "/etc/ssl/{{ domain }}.fullchain.pem"
|
domain full chain certificate "/etc/ssl/{{ domain }}.fullchain.pem"
|
|
@ -1,3 +1,4 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
server "{{ inventory_hostname }}" {
|
server "{{ inventory_hostname }}" {
|
||||||
listen on * port 80
|
listen on * port 80
|
||||||
location "/.well-known/acme-challenge/*" {
|
location "/.well-known/acme-challenge/*" {
|
||||||
|
@ -9,7 +10,7 @@ server "{{ inventory_hostname }}" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{% for vhost in lookup('vars', inventory_hostname + '_domains') %}
|
{% for vhost in domains %}
|
||||||
server "{{ vhost }}" {
|
server "{{ vhost }}" {
|
||||||
listen on * tls port 443
|
listen on * tls port 443
|
||||||
tls {
|
tls {
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
wireguard:
|
||||||
|
private_key: <wireguard private key>
|
||||||
|
address: <hosts address inside vpn>
|
||||||
|
port: 21841
|
||||||
|
interface: wg0
|
||||||
|
peers:
|
||||||
|
- name: Gateway
|
||||||
|
public_key: <vpn gateway public key>
|
||||||
|
endpoint: <gateway ip>:21841
|
||||||
|
allowed_ips: 10.2.0.1/32
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
- name: Install wireguard
|
||||||
|
community.general.openbsd_pkg:
|
||||||
|
name:
|
||||||
|
- wireguard-tools
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensures /etc/wireguard dir exists
|
||||||
|
file:
|
||||||
|
path: /etc/wireguard
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Create wireguard config
|
||||||
|
template:
|
||||||
|
src: templates/wireguard.conf.j2
|
||||||
|
dest: /etc/wireguard/{{ wireguard.interface }}.conf
|
||||||
|
owner: root
|
||||||
|
group: wheel
|
||||||
|
mode: "0600"
|
||||||
|
register: wg_config
|
||||||
|
|
||||||
|
- name: Create wireguard interface
|
||||||
|
template:
|
||||||
|
src: "templates/wireguard.if.j2"
|
||||||
|
dest: "/etc/hostname.{{ wireguard.interface }}"
|
||||||
|
register: iface_config
|
||||||
|
|
||||||
|
- name: Apply network configuration if changed
|
||||||
|
shell: sh /etc/netstart {{ wireguard.interface }}
|
||||||
|
when: wg_config.changed or iface_config.changed
|
|
@ -1,10 +1,9 @@
|
||||||
{% set _wg = lookup('vars', inventory_hostname + '_wg') %}
|
|
||||||
# {{ ansible_managed }}
|
# {{ ansible_managed }}
|
||||||
[Interface]
|
[Interface]
|
||||||
PrivateKey = {{ _wg.private_key }}
|
PrivateKey = {{ wireguard.private_key }}
|
||||||
ListenPort = {{ _wg.port }}
|
ListenPort = {{ wireguard.port }}
|
||||||
|
|
||||||
{% for peer in _wg.peers %}
|
{% for peer in wireguard.peers %}
|
||||||
[Peer]
|
[Peer]
|
||||||
# {{ peer.name }}
|
# {{ peer.name }}
|
||||||
PublicKey = {{ peer.public_key }}
|
PublicKey = {{ peer.public_key }}
|
|
@ -0,0 +1,5 @@
|
||||||
|
# {{ ansible_managed }}
|
||||||
|
inet {{ wireguard.address }} 255.255.255.0 NONE
|
||||||
|
up
|
||||||
|
|
||||||
|
!/usr/local/bin/wg setconf {{ wireguard.interface }} /etc/wireguard/{{ wireguard.interface }}.conf
|
|
@ -0,0 +1,13 @@
|
||||||
|
- name: Secondary server configuration
|
||||||
|
hosts:
|
||||||
|
- mx2
|
||||||
|
remote_user: root
|
||||||
|
vars_files:
|
||||||
|
- vars-{{ inventory_hostname }}.yml
|
||||||
|
roles:
|
||||||
|
- initial-setup
|
||||||
|
- firewall
|
||||||
|
- ssl
|
||||||
|
- mail-secondary
|
||||||
|
- vpn
|
||||||
|
- prometheus-exporters
|
|
@ -1,16 +0,0 @@
|
||||||
{% set _mx_domain = lookup('vars', inventory_hostname + '_mail_domain') %}
|
|
||||||
pki {{ _mx_domain }} cert "/etc/ssl/{{ _mx_domain }}.fullchain.pem"
|
|
||||||
pki {{ _mx_domain }} key "/etc/ssl/private/{{ _mx_domain }}.key"
|
|
||||||
|
|
||||||
listen on all tls pki {{ _mx_domain }}
|
|
||||||
|
|
||||||
table aliases file:/etc/mail/aliases
|
|
||||||
|
|
||||||
action "local" mbox alias <aliases>
|
|
||||||
action "relay" relay host {{ mx1_mail_domain }}
|
|
||||||
|
|
||||||
{% for domain in mail_domains %}
|
|
||||||
match from any for domain {{ domain }} action "relay"
|
|
||||||
{% endfor %}
|
|
||||||
match from local for local action "local"
|
|
||||||
match from local for any action "relay"
|
|
|
@ -1,24 +0,0 @@
|
||||||
pki {{ mx1_mail_domain }} cert "/etc/ssl/{{ mx1_mail_domain }}.fullchain.pem"
|
|
||||||
pki {{ mx1_mail_domain }} key "/etc/ssl/private/{{ mx1_mail_domain }}.key"
|
|
||||||
|
|
||||||
table aliases file:/etc/mail/aliases
|
|
||||||
table users passwd:/etc/mail/accounts
|
|
||||||
table virtuals file:/etc/mail/virtuals
|
|
||||||
|
|
||||||
filter dkimsign_rsa proc-exec "filter-dkimsign -d {{ mx1_mail_domain }} -s selector1 \
|
|
||||||
-k /etc/mail/dkim/{{ mx1_mail_domain }}.key" user _dkimsign group _dkimsign
|
|
||||||
|
|
||||||
listen on socket filter dkimsign_rsa
|
|
||||||
listen on all tls pki {{ mx1_mail_domain }}
|
|
||||||
listen on all port submission tls-require pki {{ mx1_mail_domain }} auth <users> filter dkimsign_rsa
|
|
||||||
listen on all port smtps tls-require pki {{ mx1_mail_domain }} auth <users> filter dkimsign_rsa
|
|
||||||
|
|
||||||
action "local_mail" lmtp "/var/dovecot/lmtp" rcpt-to virtual <virtuals>
|
|
||||||
action "outbound" relay
|
|
||||||
|
|
||||||
{% for domain in mail_domains %}
|
|
||||||
match from any for domain {{ domain }} action "local_mail"
|
|
||||||
{% endfor %}
|
|
||||||
match from local for local action "local_mail"
|
|
||||||
match from local for any action "outbound"
|
|
||||||
match auth from any for any action "outbound"
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% set _wg = lookup('vars', inventory_hostname + '_wg') %}
|
|
||||||
# {{ ansible_managed }}
|
|
||||||
inet {{ _wg.address }} 255.255.255.0 NONE
|
|
||||||
up
|
|
||||||
|
|
||||||
!/usr/local/bin/wg setconf {{ _wg.interface }} /etc/wireguard/{{ _wg.interface }}.conf
|
|
Loading…
Reference in New Issue