aboutsummaryrefslogtreecommitdiffstats
path: root/playbooks/util
diff options
context:
space:
mode:
authorStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:23:43 -0500
committerStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:52:13 -0500
commit0261e875679f1bf63c8d689da7fc7e014597885d (patch)
tree3f19cd74a0c1070944f75437f30b098d6ef2ffcb /playbooks/util
downloadselfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.tar.gz
selfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.zip
initial commit
Diffstat (limited to 'playbooks/util')
-rw-r--r--playbooks/util/backup.yml606
-rw-r--r--playbooks/util/client_cert.yml71
-rw-r--r--playbooks/util/decomission_host.yml56
-rw-r--r--playbooks/util/restore.yml477
-rw-r--r--playbooks/util/wireguard_config.yml49
5 files changed, 1259 insertions, 0 deletions
diff --git a/playbooks/util/backup.yml b/playbooks/util/backup.yml
new file mode 100644
index 0000000..0c99eea
--- /dev/null
+++ b/playbooks/util/backup.yml
@@ -0,0 +1,606 @@
+#################
+# Set backup name
+#################
+- hosts: localhost
+ tags: always
+ tasks:
+ - name: get current timestamp
+ setup:
+ filter: ansible_date_time
+
+ - name: create backup directory
+ file:
+ path: '{{ backup_path }}'
+ state: directory
+
+- hosts: all:localhost:!unmanaged
+ tags: always
+ tasks:
+ - name: set backup name
+ set_fact:
+ backup_name: '{{ backup_name | default(hostvars.localhost.ansible_date_time.iso8601_basic_short) }}'
+
+
+################
+# IMAP Mailboxes
+################
+- name: backup dovecot mailboxes
+ hosts: imap_servers
+ vars_files: ../../roles/dovecot/vars/main.yml
+ vars:
+ dovecot_backup_dir: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-mailboxes
+ dovecot_backup_tarball: '{{ dovecot_backup_dir }}.tar.gz'
+ dovecot_backup_sieve_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-sieve.tar.gz
+ tags: dovecot,imap
+ tasks:
+ - name: create backup directory
+ file:
+ path: '{{ dovecot_backup_dir }}'
+ owner: '{{ dovecot_vmail_user }}'
+ group: '{{ dovecot_vmail_user }}'
+ mode: 0770
+ state: directory
+
+ - name: collect dovecot users
+ command: doveadm user *
+ register: dovecot_users
+ changed_when: no
+
+ - name: export mailboxes
+ command: >-
+ doveadm -o plugin/quota= backup -n inbox -f -u {{ item | quote }}
+ mdbox:{{ dovecot_backup_dir | quote }}/{{ item | quote }}/mdbox:LAYOUT=fs
+ loop: '{{ dovecot_users.stdout_lines }}'
+
+ - name: compress backup directory
+ archive:
+ path: '{{ dovecot_backup_dir }}'
+ dest: '{{ dovecot_backup_tarball }}'
+ mode: 0400
+ remove: yes
+
+ - name: fetch mailbox tarball
+ fetch:
+ src: '{{ dovecot_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete mailbox tarball from remote host
+ file:
+ path: '{{ dovecot_backup_tarball }}'
+ state: absent
+
+ - name: compress sieve scripts
+ archive:
+ path:
+ - '{{ dovecot_vmail_dir }}/*/sieve'
+ - '{{ dovecot_vmail_dir }}/*/.dovecot.sieve'
+ dest: '{{ dovecot_backup_sieve_tarball }}'
+ mode: 0400
+
+ - name: fetch sieve tarball
+ fetch:
+ src: '{{ dovecot_backup_sieve_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete sieve tarball from remote host
+ file:
+ path: '{{ dovecot_backup_sieve_tarball }}'
+ state: absent
+
+
+##################
+# Rspamd Databases
+##################
+- name: backup rspamd databases
+ hosts: rspamd_servers
+ vars_files:
+ - ../../roles/redis/vars/main.yml
+ - ../../roles/rspamd/vars/main.yml
+ vars:
+ rspamd_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-rspamd.tar.gz
+ tags: rspamd
+ tasks:
+ - name: dump redis databases to disk
+ command:
+ cmd: redis-cli -p {{ item }}
+ stdin: save
+ loop:
+ - '{{ rspamd_redis_port }}'
+ - '{{ rspamd_redis_bayes_port }}'
+
+ - name: compress redis directory
+ archive:
+ path: '{{ redis_home }}'
+ dest: '{{ rspamd_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ rspamd_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ rspamd_backup_tarball }}'
+ state: absent
+
+
+###################
+# ZNC Configuration
+###################
+- name: backup znc configuration
+ hosts: znc_servers
+ vars_files: ../../roles/znc/vars/main.yml
+ vars:
+ znc_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-znc.tar.gz
+ tags: znc
+ tasks:
+ - name: compress znc directory
+ archive:
+ path: '{{ znc_home }}'
+ dest: '{{ znc_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ znc_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ znc_backup_tarball }}'
+ state: absent
+
+
+#########################
+# Syncthing Configuration
+#########################
+- name: backup syncthing configuration
+ hosts: syncthing_servers
+ vars_files: ../../roles/syncthing/vars/main.yml
+ vars:
+ syncthing_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-syncthing.tar.gz
+ tags: syncthing
+ tasks:
+ - name: compress syncthing directory
+ archive:
+ path: '{{ syncthing_home }}'
+ dest: '{{ syncthing_backup_tarball }}'
+ exclusion_patterns:
+ - '*/index-*.db*'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ syncthing_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ syncthing_backup_tarball }}'
+ state: absent
+
+
+##################
+# Git Repositories
+##################
+- name: backup git respositories
+ hosts: git_servers
+ vars_files: ../../roles/gitolite/vars/main.yml
+ vars:
+ git_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-git.tar.gz
+ tags: git
+ tasks:
+ - name: compress git directory
+ archive:
+ path: '{{ gitolite_home }}'
+ dest: '{{ git_backup_tarball }}'
+ exclusion_patterns:
+ - git/.ansible*
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ git_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ git_backup_tarball }}'
+ state: absent
+
+
+######################
+# PostgreSQL Databases
+######################
+- name: backup postgresql databases
+ hosts: postgresql_servers
+ vars_files: ../../roles/postgresql_server/vars/main.yml
+ vars:
+ postgresql_backup_file: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-pg_dumpall.sql
+ postgresql_backup_gzip: '{{ postgresql_backup_file }}.gz'
+ tags: postgres,postgresql
+ tasks:
+ - name: dump databases
+ command: pg_dumpall -f {{ postgresql_backup_file | quote }}
+ become: yes
+ become_user: '{{ postgresql_user }}'
+
+ - name: compress sql file
+ archive:
+ path: '{{ postgresql_backup_file }}'
+ dest: '{{ postgresql_backup_gzip }}'
+ mode: 0400
+ remove: yes
+
+ - name: fetch backup gzip
+ fetch:
+ src: '{{ postgresql_backup_gzip }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup gzip from remote
+ file:
+ path: '{{ postgresql_backup_gzip }}'
+ state: absent
+
+
+
+########################
+# Jellyfin Configuration
+########################
+- name: backup jellyfin configuration
+ hosts: jellyfin_servers
+ vars_files: ../../roles/jellyfin/vars/main.yml
+ vars:
+ jellyfin_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-jellyfin.tar.gz
+ tags: jellyfin
+ tasks:
+ - name: compress jellyfin directories
+ archive:
+ path:
+ - '{{ jellyfin_home }}/data'
+ - '{{ jellyfin_home }}/metadata'
+ - '{{ jellyfin_home }}/plugins'
+ - '{{ jellyfin_home }}/root'
+ - '{{ jellyfin_conf_dir }}'
+ dest: '{{ jellyfin_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ jellyfin_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ jellyfin_backup_tarball }}'
+ state: absent
+
+
+##################
+# Mediawiki Images
+##################
+- name: backup mediawiki images
+ hosts: wiki_servers
+ vars_files: ../../roles/mediawiki/vars/main.yml
+ vars:
+ mediawiki_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-mediawiki.tar.gz
+ tags: mediawiki,wiki
+ tasks:
+ - name: compress images directory
+ archive:
+ path: '{{ mediawiki_home }}/images'
+ dest: '{{ mediawiki_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ mediawiki_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ mediawiki_backup_tarball }}'
+ state: absent
+
+
+#########################
+# Photostructure Database
+#########################
+- name: backup photostructure database
+ hosts: photostructure_servers
+ vars_files: ../../roles/photostructure/vars/main.yml
+ vars:
+ photostructure_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-photostructure.tar
+ tags: photostructure
+ tasks:
+ - name: stop photostructure
+ systemd:
+ name: photostructure
+ state: stopped
+
+ - name: archive photostructure library
+ archive:
+ path: '{{ photostructure_library }}'
+ dest: '{{ photostructure_backup_tarball }}'
+ format: tar
+ mode: 0400
+
+ - name: start photostructure
+ systemd:
+ name: photostructure
+ state: started
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ photostructure_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+ validate_checksum: no # The tarball is way too big.
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ photostructure_backup_tarball }}'
+ state: absent
+
+
+###############
+# Asterisk Data
+###############
+- name: backup asterisk data
+ hosts: asterisk_servers
+ vars_files: ../../roles/asterisk/vars/main.yml
+ vars:
+ asterisk_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-asterisk.tar.gz
+ tags: asterisk
+ tasks:
+ - name: stop asterisk
+ systemd:
+ name: asterisk
+ state: stopped
+
+ - name: compress asterisk directory
+ archive:
+ path: '{{ asterisk_data_dir }}'
+ dest: '{{ asterisk_backup_tarball }}'
+ mode: 0400
+
+ - name: start asterisk
+ systemd:
+ name: asterisk
+ state: started
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ asterisk_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ asterisk_backup_tarball }}'
+ state: absent
+
+
+####################
+# Cups Configuration
+####################
+- name: backup cups configuration
+ hosts: cups_servers
+ vars:
+ cups_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-cups.tar.gz
+ tags: cups
+ tasks:
+ - name: compress cups configuration
+ archive:
+ path:
+ - /etc/cups/ppd
+ - /etc/cups/printers.conf
+ dest: '{{ cups_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ cups_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ cups_backup_tarball }}'
+ state: absent
+
+
+####################
+# WebDAV Directories
+####################
+- name: backup webdav directories
+ hosts: dav_servers
+ vars_files: ../../roles/sabredav/vars/main.yml
+ vars:
+ sabredav_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-webdav.tar.gz
+ tags: dav,sabredav,webdav
+ tasks:
+ - name: compress webdav directory
+ archive:
+ path: '{{ sabredav_home }}/webdav'
+ dest: '{{ sabredav_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ sabredav_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ sabredav_backup_tarball }}'
+ state: absent
+
+
+###############
+# Hastebin Data
+###############
+- name: backup hastebin data
+ hosts: pastebin_servers
+ vars_files: ../../roles/hastebin/vars/main.yml
+ vars:
+ hastebin_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-hastebin.tar.gz
+ tags: pastebin,hastebin
+ tasks:
+ - name: compress paste directory
+ archive:
+ path: '{{ hastebin_data_dir }}'
+ dest: '{{ hastebin_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ hastebin_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ hastebin_backup_tarball }}'
+ state: absent
+
+
+##################
+# Psitransfer Data
+##################
+- name: backup psitransfer data
+ hosts: filedrop_servers
+ vars_files: ../../roles/psitransfer/vars/main.yml
+ vars:
+ psitransfer_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-psitransfer.tar.gz
+ tags: psitransfer
+ tasks:
+ - name: compress files directory
+ archive:
+ path: '{{ psitransfer_data_dir }}'
+ dest: '{{ psitransfer_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ psitransfer_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ psitransfer_backup_tarball }}'
+ state: absent
+
+
+##################
+# Apache WWW files
+##################
+- name: backup public apache files
+ hosts: web_servers
+ vars_files:
+ - ../../roles/apache/vars/main.yml
+ vars:
+ apache_backup_tarball: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-www.tar.gz
+ tags: apache,www
+ tasks:
+ - when: apache_backup_dirs | default([]) | length > 0
+ block:
+ - name: compress www directory
+ archive:
+ path: "{{ apache_backup_dirs | map('regex_replace', '^', apache_public_dir~'/') }}"
+ dest: '{{ apache_backup_tarball }}'
+ mode: 0400
+
+ - name: fetch backup tarball
+ fetch:
+ src: '{{ apache_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup tarball from remote host
+ file:
+ path: '{{ apache_backup_tarball }}'
+ state: absent
+
+
+####################
+# Unifi Controllers
+####################
+- name: backup unifi controllers
+ hosts: unifi_controllers
+ vars_files: ../../roles/unifi/vars/main.yml
+ tags: unifi
+ tasks:
+ - name: collect autobackup files
+ find:
+ paths: '{{ unifi_autobackup_dir }}'
+ patterns: '*.unf'
+ file_type: file
+ register: unifi_autobackups
+
+ - name: fetch most recent autobackup file
+ fetch:
+ src: "{{ unifi_autobackups.files | sort(attribute='mtime') | map(attribute='path') | last }}"
+ dest: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-unifi.unf'
+ flat: yes
+
+
+################
+# FreeIPA Domain
+################
+- name: backup freeipa domain
+ hosts: freeipa_master
+ vars_files: ../../roles/freeipa_server/vars/main.yml
+ vars:
+ freeipa_backup_tarball: /var/tmp/{{ backup_name }}-ipa-{{ freeipa_realm }}.tar.gz
+ tags: ipa,freeipa
+ tasks:
+ - name: create full ipa backup
+ command: ipa-backup
+
+ - name: collect files in backup directory
+ find:
+ paths: '{{ freeipa_backup_dir }}'
+ patterns: ipa-full-*
+ file_type: directory
+ register: freeipa_backups
+
+ - name: compress latest backup
+ archive:
+ path: "{{ freeipa_backups.files | sort(attribute='mtime') | map(attribute='path') | last }}"
+ dest: '{{ freeipa_backup_tarball }}'
+ mode: 0400
+ remove: yes
+
+ - name: fetch backup archive
+ fetch:
+ src: '{{ freeipa_backup_tarball }}'
+ dest: '{{ backup_path }}/'
+ flat: yes
+
+ - name: delete backup archive from remote host
+ file:
+ path: '{{ freeipa_backup_tarball }}'
+ state: absent
+
+
+###############
+# Print summary
+###############
+- hosts: localhost
+ tags: always
+ tasks:
+ - debug:
+ msg: Backup {{ backup_name }} written to {{ backup_path }}.
diff --git a/playbooks/util/client_cert.yml b/playbooks/util/client_cert.yml
new file mode 100644
index 0000000..c81b298
--- /dev/null
+++ b/playbooks/util/client_cert.yml
@@ -0,0 +1,71 @@
+- name: generate client certificate
+ hosts: localhost
+ connection: local
+ become: no
+ vars_prompt:
+ - name: username
+ prompt: Enter username for the certificate subject
+ private: no
+ - name: passphrase
+ prompt: Enter password for the p12 file
+ private: yes
+ vars:
+ cert_dir: "{{ lookup('env', 'HOME') }}/pki"
+ key_size: 2048
+ key_path: '{{ cert_dir }}/{{ username }}.key'
+ csr_path: '{{ cert_dir }}/{{ username }}.csr'
+ crt_path: '{{ cert_dir }}/{{ username }}.crt'
+ p12_path: '{{ cert_dir }}/{{ username }}.p12'
+ profile_id: caIPAclientAuth
+ tasks:
+ - name: create output directory
+ file:
+ path: '{{ cert_dir }}'
+ state: directory
+
+ - name: generate private key
+ openssl_privatekey:
+ path: '{{ key_path }}'
+ size: '{{ key_size }}'
+ mode: 0600
+
+ - name: generate CSR
+ openssl_csr:
+ path: '{{ csr_path }}'
+ privatekey_path: '{{ key_path }}'
+ common_name: '{{ username }}'
+ use_common_name_for_san: no
+
+ - name: request certificate from IPA
+ shell:
+ cmd: >
+ ipa cert-request {{ csr_path }}
+ --principal {{ username }}
+ --profile-id {{ profile_id }}
+ --chain
+ --certificate-out {{ crt_path }}
+
+ # The openssl_pkcs12 ansible module seems to generate files that can't be
+ # decrypted by Android clients. The openssl CLI works fine though.
+ - name: generate PKCS#12 file
+ command:
+ cmd: >
+ openssl pkcs12 -export
+ -out {{ p12_path }}
+ -inkey {{ key_path }}
+ -in {{ crt_path }}
+ -name {{ username }}@{{ domain }}
+ -password pass:{{ passphrase | quote }}
+ creates: '{{ p12_path }}'
+
+ - name: cleanup files
+ file:
+ path: '{{ item }}'
+ state: absent
+ loop:
+ - '{{ key_path }}'
+ - '{{ csr_path }}'
+ - '{{ crt_path }}'
+
+ - debug:
+ msg: 'PKCS#12 file written to {{ p12_path }}. Passphrase: {{ passphrase }}'
diff --git a/playbooks/util/decomission_host.yml b/playbooks/util/decomission_host.yml
new file mode 100644
index 0000000..dae4b16
--- /dev/null
+++ b/playbooks/util/decomission_host.yml
@@ -0,0 +1,56 @@
+- name: decomission host
+ hosts: '{{ host }}'
+ tasks:
+ - name: delete A record
+ ipadnsrecord:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ zone_name: '{{ domain }}'
+ record_name: '{{ host }}'
+ record_type: A
+ record_value: '{{ ip }}'
+ state: absent
+ delegate_to: '{{ freeipa_master }}'
+
+ - name: delete PTR record
+ ipadnsrecord:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ zone_name: "{{ ip | ansible.utils.ipaddr('revdns') | regex_replace('^[^.]+\\.', '') }}"
+ record_name: '{{ ip.split(".") | last }}'
+ record_type: PTR
+ record_value: '{{ fqdn ~ "." }}'
+ state: absent
+ delegate_to: '{{ freeipa_master }}'
+
+ - name: delete CNAME records
+ ipadnsrecord:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ zone_name: "{{ domain }}"
+ record_name: '{{ item.split(".") | first }}'
+ record_type: CNAME
+ record_value: '{{ fqdn ~ "." }}'
+ state: absent
+ delegate_to: '{{ freeipa_master }}'
+ loop: '{{ cnames }}'
+
+ - name: delete host object
+ ipahost:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ name: '{{ fqdn }}'
+ state: absent
+ delegate_to: '{{ ipa_host }}'
+
+ - name: delete proxmox vm
+ proxmox_kvm:
+ node: '{{ proxmox_node }}'
+ api_host: localhost
+ api_user: '{{ proxmox_api_user }}'
+ api_password: '{{ proxmox_api_password }}'
+ name: '{{ inventory_hostname }}'
+ force: yes
+ state: absent
+ delegate_to: '{{ proxmox_api_host }}'
+ when: "'proxmox_instances' in group_names"
diff --git a/playbooks/util/restore.yml b/playbooks/util/restore.yml
new file mode 100644
index 0000000..3a0154c
--- /dev/null
+++ b/playbooks/util/restore.yml
@@ -0,0 +1,477 @@
+################
+# IMAP Mailboxes
+################
+- name: restore dovecot mailboxes
+ hosts: imap_servers
+ vars_files: ../../roles/dovecot/vars/main.yml
+ vars:
+ dovecot_temp_dir: /var/tmp/{{ backup_name }}-{{ inventory_hostname }}-mailboxes
+ dovecot_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-mailboxes.tar.gz'
+ dovecot_backup_sieve_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-sieve.tar.gz'
+ tags: dovecot,imap
+ tasks:
+ - name: create temporary directory
+ file:
+ path: '{{ dovecot_temp_dir }}'
+ owner: '{{ dovecot_vmail_user }}'
+ group: '{{ dovecot_vmail_user }}'
+ mode: 0770
+ state: directory
+
+ - name: extract mailbox tarball
+ unarchive:
+ src: '{{ dovecot_backup_tarball }}'
+ dest: '{{ dovecot_temp_dir }}'
+ extra_opts:
+ - --same-owner
+ - --strip-components=1
+
+ - name: collect dovecot users
+ command: doveadm user *
+ register: dovecot_users
+ changed_when: no
+
+ - name: import mailboxes
+ command: >-
+ doveadm -o plugin/quota= sync -u {{ item | quote }}
+ mdbox:{{ dovecot_temp_dir }}/{{ item | quote }}/mdbox
+ loop: '{{ dovecot_users.stdout_lines }}'
+
+ - name: drop FTS indexes
+ command: doveadm fts rescan -A
+
+ - name: reindex mailboxes
+ command: doveadm index -A -q *
+
+ - name: delete temporary directory
+ file:
+ path: '{{ dovecot_temp_dir }}'
+ state: absent
+
+ - name: extract sieve scripts
+ unarchive:
+ src: '{{ dovecot_backup_sieve_tarball }}'
+ dest: '{{ dovecot_vmail_dir }}'
+ extra_opts:
+ - --same-owner
+
+
+##################
+# Rspamd Databases
+##################
+- name: restore rspamd databases
+ hosts: rspamd_servers
+ vars_files:
+ - ../../roles/redis/vars/main.yml
+ - ../../roles/rspamd/vars/main.yml
+ vars:
+ rspamd_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-rspamd.tar.gz'
+ tags: rspamd
+ tasks:
+ - name: stop redis instances
+ systemd:
+ name: redis@{{ item }}
+ state: stopped
+ loop:
+ - '{{ rspamd_redis_port }}'
+ - '{{ rspamd_redis_bayes_port }}'
+
+ - name: stop rspamd
+ systemd:
+ name: rspamd
+ state: stopped
+
+ - name: extract redis tarballs
+ unarchive:
+ src: '{{ rspamd_backup_tarball }}'
+ dest: '{{ redis_home }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: start redis instances
+ systemd:
+ name: redis@{{ item }}
+ state: started
+ loop:
+ - '{{ rspamd_redis_port }}'
+ - '{{ rspamd_redis_bayes_port }}'
+
+ - name: start rspamd
+ systemd:
+ name: rspamd
+ state: started
+
+
+###################
+# ZNC Configuration
+###################
+- name: restore znc configuration
+ hosts: znc_servers
+ vars_files: ../../roles/znc/vars/main.yml
+ vars:
+ znc_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-znc.tar.gz'
+ tags: znc
+ tasks:
+ - name: stop znc
+ systemd:
+ name: znc
+ state: stopped
+
+ - name: extract config tarball
+ unarchive:
+ src: '{{ znc_backup_tarball }}'
+ dest: '{{ znc_home }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: start znc
+ systemd:
+ name: znc
+ state: started
+
+
+#########################
+# Syncthing Configuration
+#########################
+- name: restore syncthing configuration
+ hosts: syncthing_servers
+ vars_files: ../../roles/syncthing/vars/main.yml
+ vars:
+ syncthing_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-syncthing.tar.gz'
+ tags: syncthing
+ tasks:
+ - name: stop syncthing daemons
+ command: systemctl stop syncthing-user@*
+
+ - name: extract config tarball
+ unarchive:
+ src: '{{ syncthing_backup_tarball }}'
+ dest: '{{ syncthing_home }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: collect syncthing users
+ find:
+ paths: '{{ syncthing_home }}'
+ recurse: no
+ file_type: directory
+ register: syncthing_users
+
+ - name: start syncthing daemons
+ systemd:
+ name: syncthing-user@{{ item }}
+ state: started
+ loop: "{{ syncthing_users.files | map(attribute='path') | map('basename') }}"
+
+
+##################
+# Git Repositories
+##################
+- name: restore git repositories
+ hosts: git_servers
+ vars_files:
+ - ../../roles/gitolite/vars/main.yml
+ - ../../roles/cgit/vars/main.yml
+ vars:
+ git_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-git.tar.gz'
+ tags: git
+ tasks:
+ - name: extract git tarball
+ unarchive:
+ src: '{{ git_backup_tarball }}'
+ dest: '{{ gitolite_home }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: clear cgit cache
+ file:
+ path: '{{ cgit_cache_dir }}'
+ owner: apache
+ mode: 0755
+ setype: _default
+ state: '{{ item }}'
+ loop:
+ - absent
+ - directory
+
+
+######################
+# PostgreSQL Databases
+######################
+- name: restore postgresql databases
+ hosts: postgresql_servers
+ vars_files: ../../roles/postgresql_server/vars/main.yml
+ vars:
+ postgresql_backup_gzip: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-pg_dumpall.sql.gz'
+ postgresql_remote_gzip: /var/tmp/{{ postgresql_backup_gzip | basename }}
+ tags: postgres,postgresql
+ tasks:
+ - name: copy backup gzip to remote host
+ copy:
+ src: '{{ postgresql_backup_gzip }}'
+ dest: '{{ postgresql_remote_gzip }}'
+ owner: '{{ postgresql_user }}'
+ group: '{{ postgresql_user }}'
+ mode: 0400
+
+ - name: import database backup
+ shell: gunzip {{ postgresql_remote_gzip | quote }} --to-stdout | psql
+ become: yes
+ become_user: '{{ postgresql_user }}'
+
+ - name: delete gzip file from remote host
+ file:
+ path: '{{ postgresql_remote_gzip }}'
+ state: absent
+
+
+########################
+# Jellyfin Configuration
+########################
+- name: restore jellyfin configuration
+ hosts: jellyfin_servers
+ vars_files: ../../roles/jellyfin/vars/main.yml
+ vars:
+ jellyfin_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-jellyfin.tar.gz'
+ tags: jellyfin
+ tasks:
+ - name: stop jellyfin
+ systemd:
+ name: jellyfin
+ state: stopped
+
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ jellyfin_backup_tarball }}'
+ dest: /
+ extra_opts:
+ - --same-owner
+
+ - name: start jellyfin
+ systemd:
+ name: jellyfin
+ state: started
+
+
+##################
+# Mediawiki Images
+##################
+- name: restore mediawiki images
+ hosts: wiki_servers
+ vars_files: ../../roles/mediawiki/vars/main.yml
+ vars:
+ mediawiki_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-mediawiki.tar.gz'
+ tags: mediawiki,wiki
+ tasks:
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ mediawiki_backup_tarball }}'
+ dest: '{{ mediawiki_home }}/images'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+
+#########################
+# Photostructure Database
+#########################
+- name: restore photostructure database
+ hosts: photostructure_servers
+ vars_files:
+ - ../../roles/photostructure/vars/main.yml
+ vars:
+ photostructure_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-photostructure.tar'
+ tags: photostructure
+ tasks:
+ - name: stop photostructure
+ systemd:
+ name: photostructure
+ state: stopped
+
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ photostructure_backup_tarball }}'
+ dest: '{{ photostructure_library }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: start photostructure
+ systemd:
+ name: photostructure
+ state: started
+
+
+####################
+# Cups Configuration
+####################
+- name: restore cups configuration
+ hosts: cups_servers
+ vars:
+ cups_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-cups.tar.gz'
+ tags: cups
+ tasks:
+ - name: stop cups
+ systemd:
+ name: cups
+ state: stopped
+
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ cups_backup_tarball }}'
+ dest: /etc/cups
+ extra_opts:
+ - --same-owner
+
+ - name: start cups
+ systemd:
+ name: cups
+ state: started
+
+
+###############
+# Asterisk Data
+###############
+- name: restore asterisk data
+ hosts: asterisk_servers
+ vars_files: ../../roles/asterisk/vars/main.yml
+ vars:
+ asterisk_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-asterisk.tar.gz'
+ tags: asterisk
+ tasks:
+ - name: stop asterisk
+ systemd:
+ name: asterisk
+ state: stopped
+
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ asterisk_backup_tarball }}'
+ dest: '{{ asterisk_data_dir }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: start asterisk
+ systemd:
+ name: asterisk
+ state: started
+
+
+####################
+# WebDAV Directories
+####################
+- name: restore webdav directories
+ hosts: dav_servers
+ vars_files: ../../roles/sabredav/vars/main.yml
+ vars:
+ sabredav_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-webdav.tar.gz'
+ tags: sabredav,dav,webdav
+ tasks:
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ sabredav_backup_tarball }}'
+ dest: '{{ sabredav_home }}/webdav'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+
+###############
+# Hastebin Data
+###############
+- name: restore hastebin data
+ hosts: pastebin_servers
+ vars_files: ../../roles/hastebin/vars/main.yml
+ vars:
+ hastebin_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-hastebin.tar.gz'
+ tags: hastebin,pastebin
+ tasks:
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ hastebin_backup_tarball }}'
+ dest: '{{ hastebin_data_dir }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+
+##################
+# Psitransfer Data
+##################
+- name: restore psitransfer data
+ hosts: filedrop_servers
+ vars_files: ../../roles/psitransfer/vars/main.yml
+ vars:
+ psitransfer_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-psitransfer.tar.gz'
+ tags: psitransfer
+ tasks:
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ psitransfer_backup_tarball }}'
+ dest: '{{ psitransfer_data_dir }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+
+##################
+# Apache WWW Files
+##################
+- name: restore public apache files
+ hosts: web_servers
+ vars_files: ../../roles/apache/vars/main.yml
+ vars:
+ apache_backup_tarball: '{{ backup_path }}/{{ backup_name }}-{{ inventory_hostname }}-www.tar.gz'
+ tags: apache,www
+ tasks:
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ apache_backup_tarball }}'
+ dest: '{{ apache_public_dir }}'
+ extra_opts:
+ - --same-owner
+
+
+################
+# FreeIPA Domain
+################
+- name: restore freeipa domain
+ hosts: freeipa_master
+ vars_files: ../../roles/freeipa_server/vars/main.yml
+ vars:
+ freeipa_backup_tarball: '{{ backup_path }}/{{ backup_name }}-ipa-{{ freeipa_realm }}.tar.gz'
+ freeipa_remote_backup_path: '{{ freeipa_backup_dir }}/{{ backup_name }}'
+ tags: ipa,freeipa
+ tasks:
+ # Only restore FreeIPA when explicitly requested - it is quite disruptive.
+ - when: ansible_run_tags | intersect(['ipa','freeipa']) | length > 0
+ block:
+ - name: create backup directory on remote host
+ file:
+ path: '{{ freeipa_remote_backup_path }}'
+ state: directory
+ mode: 0700
+
+ - name: extract backup tarball
+ unarchive:
+ src: '{{ freeipa_backup_tarball }}'
+ dest: '{{ freeipa_remote_backup_path }}'
+ extra_opts:
+ - --strip-components=1
+ - --same-owner
+
+ - name: restore freeipa domain from backup
+ command: ipa-restore {{ backup_name | quote }} --unattended --password={{ freeipa_ds_password | quote }}
+
+ - name: clear sssd cache
+ command: sss_cache -E
+
+ - name: delete backup files from remote host
+ file:
+ path: '{{ freeipa_remote_backup_path }}'
+ state: absent
diff --git a/playbooks/util/wireguard_config.yml b/playbooks/util/wireguard_config.yml
new file mode 100644
index 0000000..fb98ca4
--- /dev/null
+++ b/playbooks/util/wireguard_config.yml
@@ -0,0 +1,49 @@
+- name: generate client certificate
+ hosts: localhost
+ connection: local
+ become: no
+ vars_prompt:
+ - name: client_ip
+ prompt: Enter client ip address
+ private: no
+ vars:
+ config_path: "{{ lookup('env', 'HOME') }}/{{ organization | replace(' ', '-') | lower }}-wg.conf"
+ server_pubkey: '{{ wireguard_pubkey }}'
+ server_port: '{{ wireguard_port | default(51820) }}'
+ server_host: '{{ wireguard_host }}'
+ gateway: '{{ vlans.vpn.gateway }}'
+ dns_server: "{{ vlans.vpn.dns_servers | join(',') }}"
+ tasks:
+ - name: generate private key
+ command:
+ cmd: wg genkey
+ register: wg_genkey
+ changed_when: no
+
+ - name: generate public key
+ command:
+ cmd: wg pubkey
+ stdin: '{{ wg_genkey.stdout }}'
+ register: wg_pubkey
+ changed_when: no
+
+ - name: generate wireguard config file
+ copy:
+ dest: '{{ config_path }}'
+ mode: 0600
+ content: |
+ [Interface]
+ Address = {{ client_ip }}/32
+ PrivateKey = {{ wg_genkey.stdout }}
+ DNS = {{ dns_server }}
+
+ [Peer]
+ PublicKey = {{ server_pubkey }}
+ AllowedIPs = 0.0.0.0/0
+ Endpoint = {{ server_host }}:{{ server_port }}
+
+ - debug:
+ msg: 'wireguard client config written to {{ config_path }}'
+
+ - debug:
+ msg: 'Add the following client to the wireguard server: {{ client_ip }}/32 {{ wg_pubkey.stdout }}'