From b8dd7efad2e4701d2cd0016dd24c98304360b26e Mon Sep 17 00:00:00 2001 From: Sebastian Schlicht Date: Sat, 24 Sep 2022 15:48:48 +0200 Subject: [PATCH] Add restic backups with OpenVPN * restic backups to local and remote repositories * wrapper script to create local backups and copy them to remote repositories * SSH setup for NAS to NAS access * OpenVPN setup for NAS to NAS connection * rootless * automatic reconnection * helper script and documentation for CA setup and certificate flow * Makefile to simplify playbook usage and OpenVPN setup * various improvements * rootless miniDLNA * ddclient for DynV6 dynamic IP service * split vaults into machine-specific and global --- .gitignore | 7 + Makefile | 76 +++++ README.md | 158 +++++----- files/bendorf/id_nas_bendorf | 26 ++ files/bendorf/id_nas_koblenz.pub | 1 + files/bendorf/openvpn/ca.crt | 20 ++ files/bendorf/openvpn/client.crt | 84 +++++ files/id_maspc.pub | 1 + files/id_pi_windows.pub | 11 +- files/id_sebschlicht_mobile.pub | 10 + files/ko/id_nas_bendorf.pub | 1 + files/ko/id_nas_koblenz | 26 ++ files/ko/openvpn/ca.crt | 20 ++ files/ko/openvpn/server.crt | 87 ++++++ group_vars/all.yml | 58 ++-- group_vars/nas/vault | 69 ++--- inventories/bendorf/group_vars/nas/vars.yml | 45 +++ inventories/bendorf/group_vars/nas/vault | 30 ++ inventories/bendorf/hosts.yml | 5 + inventories/custom/group_vars/vars.yml | 70 ----- inventories/example/group_vars/vars.yml | 72 +++++ inventories/example/hosts.yml | 6 + inventories/ko/group_vars/nas/vars.yml | 44 +++ inventories/ko/group_vars/nas/vault | 32 ++ inventories/ko/hosts.yml | 9 + inventories/nas/hosts.yml | 11 - openvpn-helper.sh | 98 ++++++ roles/aftercare/tasks/main.yml | 7 + roles/backups/defaults/main.yml | 2 - roles/backups/meta/main.yml | 2 - roles/backups/tasks/main.yml | 23 -- roles/dynv6/tasks/main.yml | 30 +- roles/dynv6/templates/dynv6.sh.j2 | 49 --- roles/minidlna/tasks/main.yml | 16 +- roles/mount/tasks/main.yml | 23 +- roles/mount/tasks/mirror.yml | 7 - roles/mount/tasks/mount.yml | 27 +- roles/nextcloud/tasks/apache.yml | 6 + roles/openvpn-init/tasks/main.yml | 4 + roles/openvpn/defaults/main.yml | 15 + roles/openvpn/tasks/client.yml | 33 ++ roles/openvpn/tasks/init-server.yml | 17 ++ roles/openvpn/tasks/init.yml | 40 +++ roles/openvpn/tasks/main.yml | 22 ++ roles/openvpn/tasks/server.yml | 51 ++++ roles/openvpn/templates/client.conf | 53 ++++ roles/openvpn/templates/server.conf | 321 ++++++++++++++++++++ roles/os/tasks/main.yml | 23 ++ roles/restic/defaults/main.yml | 9 + roles/restic/meta/main.yml | 2 + roles/restic/tasks/main.yml | 90 ++++++ roles/restic/templates/restic-wrapper.sh | 256 ++++++++++++++++ roles/restic/templates/ssh/config | 6 + roles/samba/tasks/main.yml | 7 +- roles/samba/templates/smb.conf.j2 | 2 +- roles/sshd/meta/main.yml | 2 - roles/sshd/tasks/main.yml | 10 +- roles/ssmtp/tasks/main.yml | 8 +- roles/ufw/tasks/main.yml | 31 +- roles/userdata/defaults/main.yml | 2 + roles/userdata/tasks/main.yml | 23 ++ setup.yml | 20 +- 62 files changed, 1925 insertions(+), 391 deletions(-) create mode 100644 Makefile create mode 100644 files/bendorf/id_nas_bendorf create mode 100644 files/bendorf/id_nas_koblenz.pub create mode 100644 files/bendorf/openvpn/ca.crt create mode 100644 files/bendorf/openvpn/client.crt create mode 100644 files/id_maspc.pub create mode 100644 files/id_sebschlicht_mobile.pub create mode 100644 files/ko/id_nas_bendorf.pub create mode 100644 files/ko/id_nas_koblenz create mode 100644 files/ko/openvpn/ca.crt create mode 100644 files/ko/openvpn/server.crt create mode 100644 inventories/bendorf/group_vars/nas/vars.yml create mode 100644 inventories/bendorf/group_vars/nas/vault create mode 100644 inventories/bendorf/hosts.yml delete mode 100644 inventories/custom/group_vars/vars.yml create mode 100644 inventories/example/group_vars/vars.yml create mode 100644 inventories/example/hosts.yml create mode 100644 inventories/ko/group_vars/nas/vars.yml create mode 100644 inventories/ko/group_vars/nas/vault create mode 100644 inventories/ko/hosts.yml delete mode 100644 inventories/nas/hosts.yml create mode 100755 openvpn-helper.sh create mode 100644 roles/aftercare/tasks/main.yml delete mode 100644 roles/backups/defaults/main.yml delete mode 100644 roles/backups/meta/main.yml delete mode 100644 roles/backups/tasks/main.yml delete mode 100644 roles/dynv6/templates/dynv6.sh.j2 delete mode 100644 roles/mount/tasks/mirror.yml create mode 100644 roles/openvpn-init/tasks/main.yml create mode 100644 roles/openvpn/defaults/main.yml create mode 100644 roles/openvpn/tasks/client.yml create mode 100644 roles/openvpn/tasks/init-server.yml create mode 100644 roles/openvpn/tasks/init.yml create mode 100644 roles/openvpn/tasks/main.yml create mode 100644 roles/openvpn/tasks/server.yml create mode 100644 roles/openvpn/templates/client.conf create mode 100644 roles/openvpn/templates/server.conf create mode 100644 roles/restic/defaults/main.yml create mode 100644 roles/restic/meta/main.yml create mode 100644 roles/restic/tasks/main.yml create mode 100755 roles/restic/templates/restic-wrapper.sh create mode 100644 roles/restic/templates/ssh/config delete mode 100644 roles/sshd/meta/main.yml create mode 100644 roles/userdata/defaults/main.yml create mode 100644 roles/userdata/tasks/main.yml diff --git a/.gitignore b/.gitignore index f0a755c..2a46599 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,11 @@ /*.retry /.vault_pass +# default certificate authority location +/ca/ +# files in transit to/from the certificate authority +/files-ca-transit/ +# sensitive files distributed to OpenVPN clients +/files/*/openvpn/ta.key + /wiki diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f94b2da --- /dev/null +++ b/Makefile @@ -0,0 +1,76 @@ +ANSIBLE_VAULT_PASSWORD_FILE = .vault_pass +ANSIBLE_INVENTORY = ko +EASYRSA_DIR = ca +EASYRSA_PKI_DIR = ${EASYRSA_DIR}/pki +CA_TRANSFER_FILES_DIR = files-ca-transit +REQUESTS_ARCHIVE = ${CA_TRANSFER_FILES_DIR}/requests.zip +CERTS_ARCHIVE = ${CA_TRANSFER_FILES_DIR}/certificates.zip + +koblenz: + @$(eval ANSIBLE_INVENTORY=ko) + +bendorf: + @$(eval ANSIBLE_INVENTORY=bendorf) + +openvpn-initialize: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags openvpn-init + +openvpn-pack-requests: + @./openvpn-helper.sh pack-requests + +openvpn-distribute-server-files: + @./openvpn-helper.sh copy-files "${ANSIBLE_VAULT_PASSWORD_FILE}" + +openvpn-extract-certificates: + @[ -f "${CERTS_ARCHIVE}" ] || ( echo 'Certificates archive path invalid or unknown, use `make openvpn-extract-certificates CERTS_ARCHIVE=/path/to/certificates.zip`'; exit 2 ) + @./openvpn-helper.sh extract-certificates "${CERTS_ARCHIVE}" + +openvpn-configure: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags openvpn-config + +# for usage on a secure, offline CA device +openvpn-ca-init: export EASYRSA_PKI = ${EASYRSA_PKI_DIR} +openvpn-ca-init: + @echo '[WARN] Ensure to have your certificate authority reside on an offline device, due to security!' + @[ ! -f "${EASYRSA_PKI}/ca.crt" ] || ( echo 'CA is already fully initialized'; exit 3 ) + @dpkg -s easy-rsa | grep Status | grep -q installed || sudo apt install -y easy-rsa + make-cadir "${EASYRSA_DIR}" + "${EASYRSA_DIR}/easyrsa" init-pki + @dd if=/dev/urandom of="${EASYRSA_PKI}/.rnd" bs=256 count=1 + "${EASYRSA_DIR}/easyrsa" build-ca +openvpn-ca-sign-requests: + @[ -f "${REQUESTS_ARCHIVE}" ] || ( echo 'Requests archive path unknown, use `make openvpn-ca-sign-requests REQUESTS_ARCHIVE=/path/to/requests.zip`'; exit 2 ) + @./openvpn-helper.sh sign-requests "${REQUESTS_ARCHIVE}" + +setup-all: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml + +setup-base-without-mount: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags os,sshd,ufw,userdata + +setup-base-with-mount: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags os,sshd,ufw,mount,userdata + +setup-auto-upgrade: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags auto-upgrade + +setup-backup: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags backup + +setup-dynv6: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags ddns + +setup-minidlna: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags dlna + +setup-mumble: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags mumble + +setup-samba: + ansible-playbook --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} -i inventories/${ANSIBLE_INVENTORY} setup.yml --tags samba + +vault-edit-global-nas: + ansible-vault edit --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} group_vars/nas/vault + +vault-edit-inventory-nas: + ansible-vault edit --vault-password-file=${ANSIBLE_VAULT_PASSWORD_FILE} inventories/${ANSIBLE_INVENTORY}/group_vars/nas/vault diff --git a/README.md b/README.md index 49ada7a..060c265 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,27 @@ # NAS Playbook This repository contains Ansible playbooks and roles to transform your RaspberryPi (or another system based on Debian/Ubuntu) into a NAS. -At the very heart, the term NAS refers to an OpenSSH server to securely backup user data to: +At the very heart, the term NAS refers to a machine with: -* secure OpenSSH server to automatically backup files +* a secure OpenSSH server to automatically backup files * encrypted file transfer (SSH) * key-based authentication (e.g. [backupnas](https://github.com/sebschlicht/backupnas) for UNIX clients, [FreeFileSync](https://freefilesync.org/) for Windows clients) - * with all users created automatically and their SSH keys in place -* with `fail2ban` enabled + * with all users created and configured automatically +* `fail2ban` enabled However, this playbook supports a variety of services (e.g. Samba, DLNA, Nextcloud) that can be plugged in by specifying one or more [tags](#tags). While most configuration options are hard-coded to fit the recommendations for the respective service, you can configure (among others): -* the users, their SSH keys and passwords (individually for all services) -* the storage locations (for SSH-based backups and the Nextcloud instance) -* which folders to expose via DLNA -* the mail account to use for notifications +* users, their SSH keys and passwords +* storage locations +* folders accessible via DLNA +* mail account used for system notifications ## Tags -* `mount`: automatically mount an external hard drive to extent storage capabilities +* `mount`: automatically mount external hard drives to store user data/backups at +* `backup`: schedule [restic](https://restic.net/) to securely backup the entire user data (at 2 a.m.) to a local directory / external hard drive or remote location (SFTP) * `cloud`: [Nextcloud](https://nextcloud.com/) server to upload and share files in a personal cloud * encrypted file transfer (HTTPS) * automatically renewed SSL certificates (Let's Encrypt) @@ -28,10 +29,10 @@ While most configuration options are hard-coded to fit the recommendations for t * fully installed and configured * including all required components and users * applying performance recommendations and hardening -* `samba`: [Samba](https://www.samba.org/) server to access stored files from any desktop or mobile device +* `samba`: [Samba](https://www.samba.org/) server to access stored files from any desktop or mobile device in your network * password authentication for users, optional guest shares * *unencrypted file transfer* -* `dlna`: [DLNA](https://en.wikipedia.org/wiki/Digital_Living_Network_Alliance) server to access stored media files from smartTVs etc. +* `dlna`: [DLNA](https://en.wikipedia.org/wiki/Digital_Living_Network_Alliance) server to access stored media files from a SmartTV etc. * automatically discover and play videos and/or music * *unencrypted file transfer* * `mumble`: [Mumble](https://www.mumble.info/) server (aka. Murmur) for low-latency voice chats @@ -39,97 +40,104 @@ While most configuration options are hard-coded to fit the recommendations for t * hourly (and on reboot) reports the device's IP address to DynV6, to have it accessible via a domain * `auto-upgrade`: keep installed software up-to-date * `ufw`: firewall to restrict incoming traffic to the selected services (i.e. specified tags) +* `openvpn-config`: make the device an [OpenVPN client/server](#openvpn-setup) to form a network with another device ## Usage In order to apply this playbook to one of your machines, there are basically two steps required: 1. [configure the inventory](#inventory-configuration) to your needs -1. Run the playbook: - 1. Use the named [tags](#tags) to precisely choose which services to install, e.g. only Samba and Nextcloud: +2. Run the playbook, using [tags](#tags) to precisely choose which services to install: - ansible-playbook -i inventories/custom setup.yml --tags samba,nextcloud + ansible-playbook -i inventories/example setup.yml --tags samba,nextcloud - 1. Omit tags to install all available services: +## Configuration - ansible-playbook -i inventories/custom setup.yml +The configuration consists of +1. global variables at `group_vars/all.yml` +2. an Ansible inventory containing + 1. the address of the remote machine(s) at `hosts.yml` + 2. specific variables at `group_vars/nas/vars.yml` + 3. specific credentials in an [Ansible vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html) at `group_vars/nas/vault` +3. files to be copied to the remote machine in the `files` folder -## Inventory Configuration +The example inventory at `inventories/example` can be copied and fully adapted to your needs. -The inventory `inventories/custom` is intended to be used when running this playbook and can be fully adapted to your needs. +The configuration variables are loosely structured by the features that this playbook offers. +If you use tags to selectively enable features, you only have to adapt their variables and may omit others. -Within this inventory, you *must* adapt the first two files and *should* make use of the third, though it's not technically required: +Check existing files for available variables and their meaning. -Path | Defines ------------------------------ | ------- -`hosts.yml` | [hosts](#hosts) that the playbook is running against -`group_vars/custom/vars.yml` | [variables](#variables) that are used in the playbook -`group_vars/custom/vault.yml` | [vault](#vault) for credential variables +## Port Forwarding -### Hosts +> **_Note:_** Instead of forwarding relevant ports from your router to the NAS, strongly consider using a VPN to avoid any unencrypted file transfer (e.g. Samba) via internet. -The hosts file `hosts.yml` defines the machine that will be configured by this playbook. +The NAS runs different services that operate on various ports. +When operating the NAS behind a router (i.e. firewall), these ports have to be accessible. -Simply edit the file and place your machine's address/hostname (e.g. `pi3`): +In case you insist on using port forwarding, the following ports are used by the respective services: - all: - children: - nas: - hosts: - pi3 +| Service | TCP | UDP | +| --------- | -------- | -------- | +| Samba | 139, 445 | 137, 138 | +| OpenSSH | 22 | +| Nextcloud | 80, 443 | -### Variables +These are the default ports. +Strongly-consider to expose the services at non-default ports to prevent the load and risk caused by bots. +An execption are the ports 80 and 443, as they are required for the automatic certificate renewal. -All variables of this playbook that have to be customized are defined in the YAML file `group_vars/custom/vars.yml`. -There are additional variables that usually do not need to be changed but are included in the table below. +## OpenVPN Setup -The variables are loosely structured by the different features that this playbook offers and should be quite self-explanatory already. -The table below lists which variables are available for each feature. -You only need to care about the variables of features that you are going to install. +This repository contains make goals (scripts) to setup a permanent OpenVPN connection between machines with internet access. +One of them acts as the server and thus must be reachable via internet (e.g. dynamic DNS). -| Role | Variable | Description -| ---- | -------- | ----------- -| * | `setup_user` | remote user to login and use for the setup process -| * | `nas.hostname` | desired hostname of the NAS -| * | `nas.user.name` | name of the artificial NAS user that is used for service tasks (will be created if missing) -| * | `backup_location` | path to store all user data at. defaults to the primary mount, if specified -| * | `sshd.allow_additional_users` | list of users that are allowed to SSH into the NAS, in addition to the individual users -| * | `sshd.enable_password_authentication` | flag to enable the password-based authentication for SSH clients (default: `false`). strongly discouraged, specify authorized keys per user instead -| * | `users` | list of individual users, each having a user `name`, an `initial_password` hash, a `nextcloud_password` and a `samba_password` (if the respective features are used). you may also specify a `backup_folder_name` (defaults to username) and additional group assignments (`groups`) on the OS level. you may as well specify a list of `authorized_keys` for passwordless SSH access -| mount | `mounts_base_dir` | directory for mount points for external storage devices -| mount | `mounts.primary.*` | primary mount point that all user data will be stored at, by default. mounted via the `uuid` field. use `fstype` and `opts` to specify the filesystem and options of the mount (defaults fit NTFS-formatted drives) -| mount | `mounts.secondary.*` | optional secondary mount point, that the primary mount point will be mirrored to (same configuration options available) -| auto-upgrade, cloud | `mailing.*` | `server`, `user` name, `address`, `password` and `sender_name` for the mail account to be used for sending mails (e.g. notifications, password resets) -| auto-upgrade, cloud | `mail_recipient` | recipient for administrator mails (e.g. performed upgrades) -| cloud | `nas.domain` | public domain to access the machine -| cloud | `dynv6.token` | token to update the current IP address of the NAS domain on DynV6 -| samba | `samba.internal_shares` | internal Samba shares, each having a `name` and a `path`, that are accessible with any account -| samba | `samba.public_shares` | public Samba shares, each having a `name` and a `path`, that are accessible even without an account -| dlna | `minidlna.*` | `display_name` to be shown in client devices, `directories` to list paths that should be accessible for clients -| mumble | `mumble.password` | password that is required by clients to connect (may be empty) +### Participants -### Vault +There are multiple participants in such an OpenVPN setup: -An Ansible vault is a place for storing credentials and sensitive information alike in an encrypted manner. Please refer to the [official documentation](https://docs.ansible.com/ansible/latest/user_guide/vault.html) if you want to learn how to create and use one. +1. certificate authority (CA): owns the key that will sign server and client certificates; may be an offline machine (more secure but requires manually copying files) or your Ansible host +2. server: accepts OpenVPN connections by clients; must be accessible via internet (best to use dynamic DNS) +3. clients: connect to the server; must have internet access to reach the server -Using a vault is mandatory if you want to have your credentials under version control, for example. -For simplicity, you may choose to not use a vault and assign your credentials to the variables of this playbook directly. -However, you should always strongly consider to use a vault for security reasons. +### Configuration -## Port Forwarding +Depending on a machine's role (i.e. type of participant), a different property has to be used in the respective Ansible inventory. -> **_NOTE:_** Instead of forwarding the relevant ports from your router to the NAS, you should strongly consider to use a VPN to avoid any unencrypted file transfer in the internet. +Use the `openvpn.server` property in the inventory of the machine that will act as the server and use the `openvpn.client` property for all remaining machines. -The NAS runs different services that operate on various ports. -When operating the NAS behind a router (i.e. firewall), these ports have to be accessible. +### Setup instructions -In case you insist on using port forwarding, the following ports are used by the respective services: +On the CA machine, initialize the CA, generating key and certificate: -Service | TCP | UDP ---------- |----------|--------- -Samba | 139, 445 | 137, 138 -OpenSSH | 22 | -Nextcloud | 80, 443 | + make openvpn-ca-init -These are the default ports. Strongly-consider to expose the services at non-default ports to prevent the load and risk that is caused by bots. -An execption are the ports 80 and 443, as they are required for the automatic certificate renewal. +On the Ansible host and for each participant, install OpenVPN, create a certificate request and retrieve it: + + make ANSIBLE_INVENTORY= openvpn-initialize + +On the Ansible host, pack the retrieved requests: + + make openvpn-pack-requests + +>If you use a dedicated offline machine as CA: +>This will create a ZIP file including all retrieved requests at `./files-ca-transit/requests.zip`. +>Copy this archive file to the same relative path on the CA machine now. + +On the CA machine, import and sign all requests: + + make openvpn-ca-sign-requests + +>If you use a dedicated offline machine as CA: +>This will create a ZIP file including all certificates at `./files-ca-transit/certificates.zip`. +>Copy this archive file to the same relative path on the Ansible host now. + +Extract the certificate archive + + make openvpn-extract-certificates + +and distribute the certificates to each OpenVPN participant via + + make ANSIBLE_INVENTORY= openvpn-configure + +This will also start the OpenVPN service on each machine and should leave you with a working OpenVPN setup (wait a few minutes). diff --git a/files/bendorf/id_nas_bendorf b/files/bendorf/id_nas_bendorf new file mode 100644 index 0000000..b748a79 --- /dev/null +++ b/files/bendorf/id_nas_bendorf @@ -0,0 +1,26 @@ +$ANSIBLE_VAULT;1.1;AES256 +39616637313631303837646632383036656463666438666165313738383238396166633535616337 +6633393433633435343263623432333532373433323931610a313038383934363832353430646666 +61353338623563666530333061386233396261386536326437646461383862623638393166346333 +6130303130323661340a326363656433316638643264646238643863346130383862633362306134 +32343231316339313035346366623137666434333939323138646335343430663731303732343537 +62333864303966303935363036383434663062646330353164393766373637633135353862363737 +34633262666538633634663064333331306239346234346365303931343832316461343533313230 +65353135376561623264353738396639353033643134666166356430383234356535353130373434 +35346265333438363362396132313566306337323738383966376464313865353737313536646634 +31623537653336383638363932636131393733313034353533323038336363383235363663306666 +31356537656235616266306632626331373736663661326131666165666366303265613836303464 +38316264633732373837656365663138356230306633613362386233646436333131333130343636 +65383539333863626635626439323261353664633135363133376436656433633666643936313436 +30626565653537336631346465653030393933333466663166633734396331366466336463626533 +36646466316161386435353163366433336330386362663638336534376430366138643734626565 +38626531306365356461383562323738343534636533613238633230663336386464343763643466 +62306239383735303631656161643931653634323235393436666330663162316362343135623736 +39623236373866633734303761326365356630366362336638306362313536613165613261386636 +64386537666637366532366430383239343334306531383437383635326533613466396463353338 +65313237343361616530626231326165653835633037343036613333613338633331356537336437 +31316364373233356337326638643136386430363831613138666136626231346664326565383164 +38643938396664623866343866306434616333666631343333633136323439366261336263366365 +30363331336531366132623662376531366432653232646661656563363762613934623064366238 +39333236626238356134383236613663663961653631383866633032653364653761633035303137 +64393930653839363837363437313837653038303130616637616166333536396635 diff --git a/files/bendorf/id_nas_koblenz.pub b/files/bendorf/id_nas_koblenz.pub new file mode 100644 index 0000000..6585c7d --- /dev/null +++ b/files/bendorf/id_nas_koblenz.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzsiAPArvlwUlxyxkrHyUaggQgs8hgXr0EtuPfBvKKv sebschlicht@bastis-ideapad-5i diff --git a/files/bendorf/openvpn/ca.crt b/files/bendorf/openvpn/ca.crt new file mode 100644 index 0000000..55c403c --- /dev/null +++ b/files/bendorf/openvpn/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIUCXf4iOTjEYDtMBvdEc2RQD+9mlMwDQYJKoZIhvcNAQEL +BQAwFTETMBEGA1UEAwwKU2NobGljaHRDQTAeFw0yMjEwMDIxMDQxNTNaFw0zMjA5 +MjkxMDQxNTNaMBUxEzARBgNVBAMMClNjaGxpY2h0Q0EwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDOex7CxSbbYMmSSpucRi62sTaJkwj2YbTJ822Ukrw7 +H+hxzPP74Sz6bGl0aW92uHINkWknROrgnH1XRVRRmTtETcn6beKMjr5ztDJdahwf +7C9Av+okhnIUULdWk/ScAhX8R0K9Ev11kut2jUNpdt/d/j6444XqzTd8JsQhTyAt +a4FEj8lYX74pCs4T6ac+8otenpN48xBL1WSZSp89aWo32iZs2MfbCSpjkpCOAXMI +gxCc1Yi6j+8V1q02K6IKI784X29jkHmqCMBXghT+91sVmMS0Amct0BQuH5exxoOO +PwaLCHATh1UaE56Ozat09ErjX3zUJq4sY8lngYBO5aGbAgMBAAGjgY8wgYwwHQYD +VR0OBBYEFK1QRN5BV0eRp5QjQlfjdmIbDppdMFAGA1UdIwRJMEeAFK1QRN5BV0eR +p5QjQlfjdmIbDppdoRmkFzAVMRMwEQYDVQQDDApTY2hsaWNodENBghQJd/iI5OMR +gO0wG90RzZFAP72aUzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG +9w0BAQsFAAOCAQEALrmyiuVxpSfPxgwLDiyEdEccjGqrQftbn623m/Z9gUAtolvl +2BwalR80rfnIaDzjhDWZ67JpAN0m3xHuutNGBd4URSBdOh5gBhjXYPXEpHKeX0aP +SLNgu1XmXDZh5DAfO9cE4SVDoeeL6uJi2FPr+9MtTFBVmJpyFXI48foVoLP1svMy +FbklsB9Z5uHWKTfnilDJPK9sYNMRSgJy9HZ5UjRR/Yy3tudRrDdTCzvYd9IyflP2 +CTZUR/lEUqWSr4gG1BnPY76v+1hzRzCRASx/1q2ktwp4k5T8LUlNmo6zxWyqOM4T +W4CwZyvxXxOKSsiVvI9iSSTcVaAQ/SkZaq4yiQ== +-----END CERTIFICATE----- diff --git a/files/bendorf/openvpn/client.crt b/files/bendorf/openvpn/client.crt new file mode 100644 index 0000000..2e71274 --- /dev/null +++ b/files/bendorf/openvpn/client.crt @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 53:7b:0c:59:fe:b8:22:1b:89:db:02:33:3a:43:97:a0 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=SchlichtCA + Validity + Not Before: Aug 8 20:04:30 2023 GMT + Not After : Jul 23 20:04:30 2026 GMT + Subject: CN=client-bendorf + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:c7:9c:30:51:cc:91:9d:19:4f:8e:12:9a:09:75: + 04:df:a4:07:a7:c3:cc:97:7a:99:88:f6:d4:37:05: + b5:0a:80:94:96:bf:cd:e6:63:b9:af:c3:a9:f8:cb: + 17:7f:a4:be:49:75:0b:6e:54:43:8a:a3:67:67:7b: + 2d:90:60:ca:d7:75:9e:dd:0b:a0:9d:00:d6:10:53: + 55:31:6a:c4:84:70:c6:32:4e:f4:93:c8:32:03:be: + f9:68:1a:79:13:f0:0a:b3:53:60:55:20:d4:42:28: + b5:82:32:0f:85:4f:d1:49:82:33:e4:f6:42:66:68: + e8:fc:ea:38:23:71:c5:75:0d:5f:33:0b:9d:f4:57: + c9:55:c4:55:14:26:02:08:1b:62:b9:2c:c4:5f:35: + 81:75:45:63:04:36:68:d7:6a:96:28:a2:2d:f8:1a: + 96:bd:34:80:15:17:62:ce:03:b0:27:40:70:ef:5b: + ba:7f:9d:b7:96:f5:19:b1:eb:db:60:50:61:c2:0c: + c4:46:93:f8:3d:cf:be:ea:21:a3:cc:69:3d:07:18: + b9:32:4c:52:ff:72:a3:63:06:7e:62:36:c8:50:96: + 11:0b:0b:0e:61:b9:4f:ee:54:40:94:e1:b6:d5:f0: + 38:6c:25:c5:db:09:1d:a2:a2:0e:f0:8e:c0:1b:22: + 8d:41 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + EF:00:1E:BA:2D:50:AD:6B:23:AE:E1:4C:D1:EC:0F:18:1C:13:59:FD + X509v3 Authority Key Identifier: + keyid:AD:50:44:DE:41:57:47:91:A7:94:23:42:57:E3:76:62:1B:0E:9A:5D + DirName:/CN=SchlichtCA + serial:09:77:F8:88:E4:E3:11:80:ED:30:1B:DD:11:CD:91:40:3F:BD:9A:53 + + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Signature Algorithm: sha256WithRSAEncryption + 39:22:4d:b0:72:f8:f8:51:ce:cd:a0:82:6f:b1:23:8e:c9:9d: + 88:16:69:e4:4e:e8:54:4a:4e:78:25:11:d7:c7:08:ac:1b:14: + 93:38:63:50:af:da:d9:9f:2d:e0:b6:e5:92:0a:62:3c:f0:a2: + ec:50:ca:40:50:71:ee:a3:47:21:6c:d1:31:56:68:c8:8f:c3: + 03:7b:2b:69:84:c7:81:e8:7c:f4:78:11:17:d1:ca:d4:a0:2c: + 4c:95:ce:6e:22:07:fb:d6:8b:e4:e4:08:1a:fd:33:17:c4:cb: + c4:b7:9d:24:d2:d9:e4:6d:95:84:7b:81:3f:3d:a1:52:d3:b7: + 8c:61:52:fd:c1:8e:e2:e9:78:28:33:3a:d5:05:61:9d:78:52: + 56:a4:9a:34:25:2e:57:5f:22:00:94:7a:c0:7c:26:f3:09:0d: + 75:0b:1d:f2:12:f2:c9:0d:0c:09:8e:7d:90:4a:c4:26:77:65: + 24:51:c3:18:db:8e:63:37:7d:5b:17:12:0d:db:34:e0:dd:2f: + 74:2a:07:26:92:50:bf:ee:c5:b5:ae:60:29:71:6d:df:27:72: + 93:94:25:4b:31:cf:47:fc:e3:85:95:4e:89:42:6a:db:a1:08: + 3b:6b:5f:5e:29:2f:f4:49:17:33:28:51:40:67:94:8a:53:47: + ff:a9:94:3a +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIQU3sMWf64IhuJ2wIzOkOXoDANBgkqhkiG9w0BAQsFADAV +MRMwEQYDVQQDDApTY2hsaWNodENBMB4XDTIzMDgwODIwMDQzMFoXDTI2MDcyMzIw +MDQzMFowGTEXMBUGA1UEAwwOY2xpZW50LWJlbmRvcmYwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDHnDBRzJGdGU+OEpoJdQTfpAenw8yXepmI9tQ3BbUK +gJSWv83mY7mvw6n4yxd/pL5JdQtuVEOKo2dney2QYMrXdZ7dC6CdANYQU1UxasSE +cMYyTvSTyDIDvvloGnkT8AqzU2BVINRCKLWCMg+FT9FJgjPk9kJmaOj86jgjccV1 +DV8zC530V8lVxFUUJgIIG2K5LMRfNYF1RWMENmjXapYooi34Gpa9NIAVF2LOA7An +QHDvW7p/nbeW9Rmx69tgUGHCDMRGk/g9z77qIaPMaT0HGLkyTFL/cqNjBn5iNshQ +lhELCw5huU/uVECU4bbV8DhsJcXbCR2iog7wjsAbIo1BAgMBAAGjgaEwgZ4wCQYD +VR0TBAIwADAdBgNVHQ4EFgQU7wAeui1QrWsjruFM0ewPGBwTWf0wUAYDVR0jBEkw +R4AUrVBE3kFXR5GnlCNCV+N2YhsOml2hGaQXMBUxEzARBgNVBAMMClNjaGxpY2h0 +Q0GCFAl3+Ijk4xGA7TAb3RHNkUA/vZpTMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAsG +A1UdDwQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAOSJNsHL4+FHOzaCCb7Ejjsmd +iBZp5E7oVEpOeCUR18cIrBsUkzhjUK/a2Z8t4LblkgpiPPCi7FDKQFBx7qNHIWzR +MVZoyI/DA3sraYTHgeh89HgRF9HK1KAsTJXObiIH+9aL5OQIGv0zF8TLxLedJNLZ +5G2VhHuBPz2hUtO3jGFS/cGO4ul4KDM61QVhnXhSVqSaNCUuV18iAJR6wHwm8wkN +dQsd8hLyyQ0MCY59kErEJndlJFHDGNuOYzd9WxcSDds04N0vdCoHJpJQv+7Fta5g +KXFt3ydyk5QlSzHPR/zjhZVOiUJq26EIO2tfXikv9EkXMyhRQGeUilNH/6mUOg== +-----END CERTIFICATE----- diff --git a/files/id_maspc.pub b/files/id_maspc.pub new file mode 100644 index 0000000..bfdf8d7 --- /dev/null +++ b/files/id_maspc.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDiRNLLEHtXjX/ggRh7RXKZSXrudL1loND4lYpLSF4Q3P0kGCuTrweXGwezJtpQM0nStGkMP0Yy7bi/pwseV1/KuCeWouhMpeFwphxycuCkSY2sCe0bto6wSSyH6Gq6pX25AULRnxn7qDskI7BVL7ePvH3mS1X6rUMOpwYKFUsjgK0ewkSfXyw1lyL7vllCLrY9ZfJLcfTNEPoH+jeDi9JexyOZ2HVTVvHIZ3QcxrfsVfRqY4ZY3nCrfX0j6jLeE2aXOj3Vvp4Uc0m4JjTEbzbWIZyk93hHyEHITPJeCc24USW+aHG4iuYsP+zkPMcZ/jgessP6Cr/unzvPS5TBduKHb3mtGiV8Kpf8+egcFyTVtDFFBEe7h3A9Zqz6LKeGkLjL3wiwShnP8CxxgN/umpNRQF0A0h0XqPo1+Rz52IOBOITGgOImOgAK7/TQGK9kEP3Ycf5c3G+Rn8U5pci5KQ/WqqriguSvyBHiiIZy4l7tm1Lz/Lfn7Ghvzcp837vAT8Jaj41M/vBQ/YwqL3C75scaECJMoi/Zzy/gSdJpcyFPM6+vO/euiSXjnrf0JyOPG9vw7dgAW4unUJJKqb5tnGr+mj2oxFFJ8Aeej3a3VSO9DexzW3MZH0UmELmqXX4jk/bFCMNjUMbczoVzZhTzTDqUAtjwrbiV+VXZxssf+IyvCQ== NAS-Schlüssel diff --git a/files/id_pi_windows.pub b/files/id_pi_windows.pub index d98958c..689eadd 100644 --- a/files/id_pi_windows.pub +++ b/files/id_pi_windows.pub @@ -1 +1,10 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVGTvGXC8glSEc+Bz+8WdwW2XyqWBECM96Y9B9n8HrJ id_pi_windows@sschlicht.de +$ANSIBLE_VAULT;1.1;AES256 +39343730306334623961626334656335666235633534616137633437343163653362383361636163 +6134613339323333663332313665616163326330616661390a373133353531303433386139393364 +66666432666165633162333439666633306438373863303938353163626230303135393535643561 +6164666264323261620a386264643333333931353332303362653164346334303263323563333734 +38643731373166373337383264303564346337353630336239336235356138353634333639393462 +65346236643031356439356266626633316330623635383039373762626138396135616562326465 +62383264616164366633636630303834323266656433376130616532633939646661643737306461 +62613361666531356561643833626433356333666631643330373734353134373232313131333835 +32653830373931326131383037306636343438323834653464626435313664383438 diff --git a/files/id_sebschlicht_mobile.pub b/files/id_sebschlicht_mobile.pub new file mode 100644 index 0000000..f6ff6bb --- /dev/null +++ b/files/id_sebschlicht_mobile.pub @@ -0,0 +1,10 @@ +$ANSIBLE_VAULT;1.1;AES256 +62653730383534626562306263353039336432376232613866613861663330363239303965313361 +6431363763363732303036393838313333383261323532660a326139313034313936366464613137 +65636365653931376536623463396630366331343735316664653634353536663131353365376431 +6261336638653363300a633564383362373065333232663761643532343934646632613132623666 +66626138656139623031336363356566313434663638333335613766313365663230343133313163 +31386161323762353839356665363032313636353561636533386637636632373832323537373136 +39383731303364363539313333636131386231373365346431313661663865333239623730303663 +64303739646233353433616130373233356266653334336636643237396661303966633266363561 +32653932336564313137616166333261633561623636396435303236656566343565 diff --git a/files/ko/id_nas_bendorf.pub b/files/ko/id_nas_bendorf.pub new file mode 100644 index 0000000..78ac6d9 --- /dev/null +++ b/files/ko/id_nas_bendorf.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXsxPRvnok4jWIIqL1kYobQBxi+q/dWSrl7x+ShpeFp sebschlicht@bastis-ideapad-5i diff --git a/files/ko/id_nas_koblenz b/files/ko/id_nas_koblenz new file mode 100644 index 0000000..9fdc30d --- /dev/null +++ b/files/ko/id_nas_koblenz @@ -0,0 +1,26 @@ +$ANSIBLE_VAULT;1.1;AES256 +38356236663862656637393964363433316339353636343931643463386136613863373235393537 +3665313362623334373138653366363831346433623766370a636166386431656239623762383237 +33663932626262616664333965626339633539326165336262306130326466336636313163343638 +3937313461353336350a303837623434343634346533396236653966343536343065343762623135 +66663637303030353962343638636634353838636332356437663461353233616131336138306533 +62386532343537646436623063393432316263633339663537643261366331366465653136346365 +63363538366532616437653031313530656565643165313466323434353261653932333937636534 +30366234373934326137333438366630373262663831346532333737326630363864393739636364 +39373438333238643731646634633332343161623135653039633561336563353635303962633333 +33323538396230393435363363393734383332333366363731356365363765383764383933643239 +39346439353063333061396661316636326434643665363032646233623665303566366636396464 +36353834306635636562313138623636356133333165666134613462306536636432376334623666 +66383337303234393035653131366236306436346263386430386135666534353339636237316332 +38353066336533303339643032626261663565356366666431383062616337653761366135633031 +61396434393935343038353232646330333536656433303538303165386132643839633330383361 +31326431613261333930653165303762633535643137383462636638306135653561353631326639 +32393762393564383537323264623432303166333065363264313731656633636333393761393334 +66373762653764323934646166383239633633636562353064393733396666633166303965653430 +32666166656332313361343062613538643463346530353431663863326134613532656438643364 +39333030333335303639616237626164383564343530323233643435343335393234646639616331 +64633037326566306363303165303139343830323738323264306261646635316166346439353366 +32346438376363346162643963306136316137323733363438333832306138616138326238306532 +65653033663262646663333432616136666362346362616531626433393330336665383536386466 +66316439343231663462386437396335646134363162373831316333323364653036336534666439 +33623238353331333065396239383434663334363034393163336665613663663331 diff --git a/files/ko/openvpn/ca.crt b/files/ko/openvpn/ca.crt new file mode 100644 index 0000000..55c403c --- /dev/null +++ b/files/ko/openvpn/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIUCXf4iOTjEYDtMBvdEc2RQD+9mlMwDQYJKoZIhvcNAQEL +BQAwFTETMBEGA1UEAwwKU2NobGljaHRDQTAeFw0yMjEwMDIxMDQxNTNaFw0zMjA5 +MjkxMDQxNTNaMBUxEzARBgNVBAMMClNjaGxpY2h0Q0EwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDOex7CxSbbYMmSSpucRi62sTaJkwj2YbTJ822Ukrw7 +H+hxzPP74Sz6bGl0aW92uHINkWknROrgnH1XRVRRmTtETcn6beKMjr5ztDJdahwf +7C9Av+okhnIUULdWk/ScAhX8R0K9Ev11kut2jUNpdt/d/j6444XqzTd8JsQhTyAt +a4FEj8lYX74pCs4T6ac+8otenpN48xBL1WSZSp89aWo32iZs2MfbCSpjkpCOAXMI +gxCc1Yi6j+8V1q02K6IKI784X29jkHmqCMBXghT+91sVmMS0Amct0BQuH5exxoOO +PwaLCHATh1UaE56Ozat09ErjX3zUJq4sY8lngYBO5aGbAgMBAAGjgY8wgYwwHQYD +VR0OBBYEFK1QRN5BV0eRp5QjQlfjdmIbDppdMFAGA1UdIwRJMEeAFK1QRN5BV0eR +p5QjQlfjdmIbDppdoRmkFzAVMRMwEQYDVQQDDApTY2hsaWNodENBghQJd/iI5OMR +gO0wG90RzZFAP72aUzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG +9w0BAQsFAAOCAQEALrmyiuVxpSfPxgwLDiyEdEccjGqrQftbn623m/Z9gUAtolvl +2BwalR80rfnIaDzjhDWZ67JpAN0m3xHuutNGBd4URSBdOh5gBhjXYPXEpHKeX0aP +SLNgu1XmXDZh5DAfO9cE4SVDoeeL6uJi2FPr+9MtTFBVmJpyFXI48foVoLP1svMy +FbklsB9Z5uHWKTfnilDJPK9sYNMRSgJy9HZ5UjRR/Yy3tudRrDdTCzvYd9IyflP2 +CTZUR/lEUqWSr4gG1BnPY76v+1hzRzCRASx/1q2ktwp4k5T8LUlNmo6zxWyqOM4T +W4CwZyvxXxOKSsiVvI9iSSTcVaAQ/SkZaq4yiQ== +-----END CERTIFICATE----- diff --git a/files/ko/openvpn/server.crt b/files/ko/openvpn/server.crt new file mode 100644 index 0000000..deeb761 --- /dev/null +++ b/files/ko/openvpn/server.crt @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c1:10:fe:bc:a8:b8:11:b7:67:a5:cb:16:98:42:46:71 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=SchlichtCA + Validity + Not Before: Oct 2 12:34:24 2022 GMT + Not After : Sep 16 12:34:24 2025 GMT + Subject: CN=server-ko + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:cc:73:ae:c6:25:97:34:b2:7c:50:80:5f:aa:c8: + d7:82:44:40:40:32:66:d5:bb:b6:bc:11:2f:d4:1c: + a1:c5:37:6b:45:ad:b6:4f:be:f4:8f:8c:e8:68:45: + 66:1a:55:d8:76:a5:4c:75:9b:3f:f1:ec:6f:e9:6d: + 3b:ed:8c:a2:de:b7:f3:b0:b0:04:29:a4:bf:26:fd: + ed:2a:2d:56:e8:c9:b7:77:3a:7a:ce:87:02:17:cf: + de:26:1f:dc:f0:36:40:75:01:7b:6b:7f:a1:4c:6f: + eb:d5:2d:9c:6e:5d:5b:76:29:6a:f0:e9:21:08:55: + 92:ea:a4:73:7a:bf:c0:51:d7:cf:fd:ec:c6:5c:ca: + 30:93:cf:bb:79:7d:c7:79:a3:f8:4e:e9:52:12:47: + ab:2f:79:55:89:48:a6:95:68:db:82:ec:ef:2f:35: + 1c:1c:f7:54:3f:6d:4e:7e:e4:6f:c5:4f:6c:8a:6c: + 45:f9:fe:36:0e:cd:5e:17:b7:de:8b:c9:38:c4:1f: + 96:44:8f:6c:f5:17:43:7e:c4:3d:87:a4:6e:69:3e: + cd:3e:7a:2d:07:27:f6:d1:5e:5a:76:c9:d3:b2:4a: + be:2e:fe:e8:9d:98:9e:fe:f6:55:df:b9:11:71:12: + 42:96:f7:b2:61:4c:1b:20:0f:08:88:63:46:90:7b: + 19:85 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + E9:D1:E0:D2:8E:E6:E4:FA:65:85:29:6C:86:73:14:BE:75:05:EE:47 + X509v3 Authority Key Identifier: + keyid:AD:50:44:DE:41:57:47:91:A7:94:23:42:57:E3:76:62:1B:0E:9A:5D + DirName:/CN=SchlichtCA + serial:09:77:F8:88:E4:E3:11:80:ED:30:1B:DD:11:CD:91:40:3F:BD:9A:53 + + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Key Usage: + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + DNS:server-ko + Signature Algorithm: sha256WithRSAEncryption + 0a:56:90:84:bd:e9:c4:90:eb:a9:89:35:65:9c:28:89:bf:c5: + b7:3a:fe:61:ec:bd:7e:14:21:42:e5:2b:06:25:86:e0:cc:5d: + 2a:54:8a:2b:c6:b6:40:93:d4:83:98:b3:bf:0c:65:a1:07:87: + 47:96:44:49:8e:1d:d5:ec:e3:60:29:36:c1:3a:22:b6:f9:67: + ec:67:60:20:04:f1:c3:f2:c8:42:51:f9:f5:0f:ca:19:fa:32: + 6a:d0:cf:39:9c:b7:6a:67:3c:6c:70:b8:6f:27:51:4e:38:78: + 73:d4:b2:ee:d0:a0:d4:25:89:b6:3f:a7:86:dd:e8:dc:91:e7: + 05:c3:e3:7a:f2:63:6e:20:c4:72:9a:bb:a4:56:d0:e8:d4:9b: + e5:d9:6d:fb:b8:6c:56:3d:a3:da:7c:28:72:41:ad:e5:e7:a3: + e7:62:28:33:ee:3d:8d:74:d3:5d:1f:45:38:eb:23:55:10:ef: + 6a:8e:8d:a3:2e:6f:67:6f:8c:32:e8:61:1c:54:e6:1e:f4:d9: + 01:b4:b3:b3:e9:fb:66:e0:d1:bb:33:cd:cb:d9:4a:74:aa:66: + 2a:8f:e1:aa:4b:59:b7:f5:e4:29:34:66:de:85:61:c5:e5:2c: + 33:53:80:56:0c:60:41:66:b3:c7:2d:46:49:89:af:d8:ac:f3: + b2:1c:fe:a9 +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIRAMEQ/ryouBG3Z6XLFphCRnEwDQYJKoZIhvcNAQELBQAw +FTETMBEGA1UEAwwKU2NobGljaHRDQTAeFw0yMjEwMDIxMjM0MjRaFw0yNTA5MTYx +MjM0MjRaMBQxEjAQBgNVBAMMCXNlcnZlci1rbzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMxzrsYllzSyfFCAX6rI14JEQEAyZtW7trwRL9QcocU3a0Wt +tk++9I+M6GhFZhpV2HalTHWbP/Hsb+ltO+2Mot6387CwBCmkvyb97SotVujJt3c6 +es6HAhfP3iYf3PA2QHUBe2t/oUxv69UtnG5dW3YpavDpIQhVkuqkc3q/wFHXz/3s +xlzKMJPPu3l9x3mj+E7pUhJHqy95VYlIppVo24Ls7y81HBz3VD9tTn7kb8VPbIps +Rfn+Ng7NXhe33ovJOMQflkSPbPUXQ37EPYekbmk+zT56LQcn9tFeWnbJ07JKvi7+ +6J2Ynv72Vd+5EXESQpb3smFMGyAPCIhjRpB7GYUCAwEAAaOBtzCBtDAJBgNVHRME +AjAAMB0GA1UdDgQWBBTp0eDSjubk+mWFKWyGcxS+dQXuRzBQBgNVHSMESTBHgBSt +UETeQVdHkaeUI0JX43ZiGw6aXaEZpBcwFTETMBEGA1UEAwwKU2NobGljaHRDQYIU +CXf4iOTjEYDtMBvdEc2RQD+9mlMwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0P +BAQDAgWgMBQGA1UdEQQNMAuCCXNlcnZlci1rbzANBgkqhkiG9w0BAQsFAAOCAQEA +ClaQhL3pxJDrqYk1ZZwoib/Ftzr+Yey9fhQhQuUrBiWG4MxdKlSKK8a2QJPUg5iz +vwxloQeHR5ZESY4d1ezjYCk2wToitvln7GdgIATxw/LIQlH59Q/KGfoyatDPOZy3 +amc8bHC4bydRTjh4c9Sy7tCg1CWJtj+nht3o3JHnBcPjevJjbiDEcpq7pFbQ6NSb +5dlt+7hsVj2j2nwockGt5eej52IoM+49jXTTXR9FOOsjVRDvao6Noy5vZ2+MMuhh +HFTmHvTZAbSzs+n7ZuDRuzPNy9lKdKpmKo/hqktZt/XkKTRm3oVhxeUsM1OAVgxg +QWazxy1GSYmv2Kzzshz+qQ== +-----END CERTIFICATE----- diff --git a/group_vars/all.yml b/group_vars/all.yml index 4a367f1..6bdc4f8 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -1,72 +1,72 @@ -mounts_base_dir: /mnt/nas -backup_location: "{{ mounts_base_dir }}/primary/backup" +# metadata to exclude steps in certain scenarios running_in_container: no uninstall: no nextcloud: version: 20.0.0 path: /var/www/nextcloud - data_path: "{{ mounts_base_dir }}/primary/nextcloud/data" + data_path: "{{ nas.path }}/nextcloud/data" dynv6: - token: "{{ vault_dynv6_token }}" + # token to update the current IP address of the NAS domain on DynV6 + password: "{{ vault_dynv6_password }}" +nas_ssh_dir: "/home/{{ nas.user.name }}/.ssh" sshd: + # users allowed to SSH into the NAS, in addition to the individual users allow_additional_users: - "{{ setup_user }}" - + - "{{ nas.user.name }}" + # enable password-based authentication (strongly discouraged, specify authorized keys per user instead) + enable_password_authentication: no server_locales: - de_DE.UTF-8 server_timezone: Europe/Berlin -setup_user: sebschlicht -nas: - hostname: pi - domain: koblenz.dns.sschlicht.de - user: - name: pi - -mounts: - primary: - uuid: 18A302FC66F67B28 - -mail_recipient: pimon@sschlicht.de +# recipient for administrator mails (e.g. performed upgrades) +mail_recipient: "{{ vault_mail_recipient_address }}" mailing: + # mail server connection details server: mx2f3e.netcup.net port: 465 - user: pi-ko@sschlicht.de - from_address: pi-ko@sschlicht.de + # mail server credentials + user: "{{ vault_mailing_sender_address }}" password: "{{ vault_mailing_password }}" - sender_name: "Pi4 (Koblenz)" + # custom address / sender name to be used when sending mails + from_address: "{{ vault_mailing_sender_address }}" + sender_name: "{{ mailing_sender_name }}" samba: + # shares accesible with any account, each having `name` and `path` internal_shares: - - { name: videos, path: "{{ mounts_base_dir }}/primary/videos" } - - { name: secdev, path: "{{ mounts_base_dir }}/primary/secdev" } + - { name: videos, path: "{{ nas.path }}/videos" } + - { name: secdev, path: "{{ nas.path }}/secdev" } + # shares accessible with and without an account public_shares: - - { name: software, path: "{{ mounts_base_dir }}/primary/software" } - -minidlna: - display_name: SchlichtNAS - directories: - - "{{ mounts_base_dir }}/primary/videos" + - { name: software, path: "{{ nas.path }}/software" } mumble: + # password required by clients to connect (may be empty) password: "{{ vault_mumble_server_password }}" +# OS users for individuals users: - name: sebschlicht full_name: Sebastian Schlicht mail_address: "{{ vault_sebschlicht_mail_address }}" + # name of the backup folder (defaults to username) backup_folder_name: sebastian + # hash of the initial password initial_password: $6$bvWKhsKfYQL8FH$FBXZZLp2ylLIEFjpj6c7vq.pCaJCH3nn3daYG3kEAhfhOxPoE6Y1kIux9VAiTQ8m1BPbmdYQ7OnCJNgm8h9VE1 + # additional group assignments groups: sudo samba_password: "{{ vault_sebschlicht_smbpasswd }}" nextcloud_user: sebastian nextcloud_password: "{{ vault_sebschlicht_nextcloud_password }}" authorized_keys: - id_sebschlicht.pub + - id_sebschlicht_mobile.pub - id_pi_windows.pub - name: isspek full_name: Ipek Baris Schlicht @@ -82,3 +82,5 @@ users: initial_password: $6$IieSj6WUcNC$Hlw.UkdS0fqoCaGibNLUCp5sCGm/Jb9KSBWOqtyq6QY.rEPuG5sZyjcYeVqQ0IVdssrUqHK4xgteW3f12S9Fa1 samba_password: "{{ vault_mas_smbpasswd }}" nextcloud_password: "{{ vault_mas_nextcloud_password }}" + authorized_keys: + - id_maspc.pub diff --git a/group_vars/nas/vault b/group_vars/nas/vault index 31cb223..510abd6 100644 --- a/group_vars/nas/vault +++ b/group_vars/nas/vault @@ -1,44 +1,27 @@ $ANSIBLE_VAULT;1.1;AES256 -32363766633435663436616436363361313963366331313739366561636664333434623931326664 -6136666362653230633930373031393433653233633933660a636131633934646432626665363635 -31376237653761313066343031626663383262303432376531353935303365366466626633323737 -3536646632356632380a643736386631393363666665656561613331633837343732333838353465 -34326337383064643531383064393364613934626565313730613564313430383732633236616532 -62636637343236306539353136393031353430363637343734663564643036653461613038626162 -35636532633535383438353033313832393531323662306163346430376534393030303539643036 -32363031623262383937313162323231346362383666646233386239633964303038623335363964 -34623738363734386238643633646563653961373534343139613336613932633630616539393461 -38306266646337373733623535363461363661373331343339616538623638643665303963626162 -36343962316264373665313839396565303539643236333938386534353137356536373366623334 -61326431343961653631363937343036336530633861306465636664333935376136326163376365 -61313830646136623362306137386530353361626431643662656337633533343733623165653361 -32373639373365376635326632386535363062353066383162333562303632656136343631336531 -32313961323132303163626364343637343438626334386463366639633532316530646434613166 -38646138643330346134393362306533646439646165653061346438636638383430376330326566 -66366632346333343338316230363339663131613534353961653164343632636562626436656236 -66356164646138666233323836393437333366636465306663373537663839326265363330386132 -31393834313464636365636332323737343061306532613064306462386164326538346465663865 -61363761323730323732383636396138623336386637383637366531323564396336393336613338 -30383661653937376439313866663634343764373232626465653036353035383330653631643263 -66323064323164393466373064343533383966363061663530666239623564333434363533633265 -66326237393361393861343736313838376137343864366664636561386636656536613333626531 -37356235663735633163646234643461643864353834393937303863623363633961326561393961 -37373935393631663336346261383765316539623731323964386333653733343064323632343237 -62633430306439616264393066373361343330616264636262303966343636323935653530383566 -37323564376463656365373936353939323234353861636161323836653963316230643563623636 -33663835396134656663303461643539663137623335636131646563633933303933653933666632 -39306636333864626434633333663061323365366239356166666236373461643963366263656631 -64383066343230316465353766633236373530646437333339393266353263326264663465353563 -36613165643333656263313762373766396465653234313334366330393364613864306463646230 -30313939626231616137386232383361366138643839353331633262343666613863343332393261 -61656433656134623266326131663639626266633061396461626365376436633738353832356630 -35643864363235356532396335616163366131363066363465343462373763313263343762313333 -35303636313237613138643536363661373432363331343936346133623163643465383833333139 -61613833313836313631623031363835613163356363376463366537303537633638383337633639 -35646335656337653036356562396438383036623364666338333261643039643831366239663135 -64616533393337333137383231356663636236653934396633663365333361353437613464356438 -35616161376533626531396633636639376431323265323534353366363564306161643733303730 -36643762353565333261373432646538303064636563333866303136383061636561326265386533 -39396636343931623338356261313135303831653635633466323561393665373564636230353264 -32323735353465383164643863326337376164646361393633333762303862323966303964373833 -366339353461636331383534653631323964 +38653135306337333839313964353263616439346331326335333031326638323935313964613531 +3534333431306230656665333435316539356638643362350a313066646365326331313562636330 +30376134303037383334616530393537303638646564613634616335336331653565316661626536 +3261653135656164320a653238386639303639633639343730663936613134306465396561366339 +35383634333035353661303335613836373635663934303663326261663832323834353330343838 +66363463653230626439623139313134316264666239643335303065366566343230303934336666 +34333362363936306632303965653534346639383265663238343262633037353035313966353034 +30623539323630336333613065643036353362376366383665346361323436343966636539653035 +63616131346266326434303331646536663263656339383130636531613932353036666430373065 +66363437313563393532333237616132373837623831336264663333396561383538386131333266 +37656564616630306633646530633537306534653839633238303635626432643230646262333334 +38316531393133646631663439626264666262626666666438326330333237303338353739383163 +38623130646232666637316562376636326536653339313333326635646661343931333562646334 +38326432366430623133383036366638353738353261386363646336363932613866303436313030 +37323337636161373132633265343330366262646538346237346263316432373033653435346232 +64343535346338316337343030356264383261346434373762626662353036653636313235623735 +37356162393635633036353766316430303430376136313062376430616236643238336265303139 +36393163383437303465383865326437303066393439323562346631363762663235636433386166 +35343061643835316432323235626262616562653831646161376530326235326632343566313536 +64353262663665393666663965666334313739323166333834376130313235626337636562656634 +63393031393966363439313136636235363532643830626332656164383933356230336263623832 +38323864326661366233363537376536303666376161613564656665636130653135343534616563 +65633937363532346566303363363366383037336330376265393534323365303030633230303564 +36373463316339633162663661343434343835363864663631616339643761333066373137623033 +64363964636535396533313936356237656461356335333639313062633834366238343137633836 +6338663265386461363863363536613335323666646663376238 diff --git a/inventories/bendorf/group_vars/nas/vars.yml b/inventories/bendorf/group_vars/nas/vars.yml new file mode 100644 index 0000000..dcc8556 --- /dev/null +++ b/inventories/bendorf/group_vars/nas/vars.yml @@ -0,0 +1,45 @@ +setup_user: pi + +nas: + user: + name: nas + hostname: pi + path: /mnt/nas-storage + domain: "{{ vault_nas_domain }}" + userdata_path: "/mnt/nas-storage/userdata" + mount: + uuid: ce96ec39-ec70-4944-ab87-6e714c19ba0c + fstype: ext4 + opts: defaults + ssh_keys: + - bendorf/id_nas_bendorf + authorized_keys: + - bendorf/id_nas_koblenz.pub + +openvpn: + files: bendorf/openvpn + client: + server: + address: "{{ vault_openvpn_server_address }}" + port: 11194 + +backup: + source_directory: "{{ nas.path }}" + local_repository: /mnt/nas-backup/backups/bendorf + local_foreign_repositories: + - /mnt/nas-backup/backups/koblenz + mount: + path: /mnt/nas-backup + uuid: 8b75e963-f42c-479a-b429-28ee6f8de2b8 + fstype: ext4 + opts: defaults + remote_host: 192.168.1.4 + remote_repository: "sftp:{{ nas.user.name }}@192.168.1.4:/mnt/nas-backup/backups/bendorf" + remote_ssh_key_id: id_nas_bendorf + +mailing_sender_name: "Pi (Bendorf)" + +minidlna: + display_name: SchlichtNAS (Bendorf) + directories: + - "{{ nas.path }}/videos" diff --git a/inventories/bendorf/group_vars/nas/vault b/inventories/bendorf/group_vars/nas/vault new file mode 100644 index 0000000..9a39c04 --- /dev/null +++ b/inventories/bendorf/group_vars/nas/vault @@ -0,0 +1,30 @@ +$ANSIBLE_VAULT;1.1;AES256 +33336335656661623062666264646561353766623435346465366236383363303762366636363963 +6364636234653538313639623333366464653664323438330a353536336630663235633434333431 +39333230626161303034333165396638633666326236366137353565323938333234383136633663 +6335323136316662350a333866626561646136306439336638663163333838326136363463313362 +38386632313330333437333931326235323136306138396538666436373736393434316132616136 +61383165633933626631363630383030616235616135353930396662633637626230303832353439 +32303233303838343530306335613733313038623665633530313838646138313065373531373737 +65323239333665376166363763666263373532373233643034323562333931646362376561613632 +62666137653937346538343965353335663261663962393739666638366465373363653766633065 +30383965626363333835303966393364633665656364393335623564366333653433663934396435 +39613531323636636635373061326461643333356163653738623330333838336666303064336264 +30303933623664313439376531386436343836613865386464653932323866333839316164303837 +66336332323635396333363730656630366131613864343531373964326466653031333832396539 +63653532393838303736636437633566643436393038356538626662653632636131313137616463 +61356261663331363035343239306437666362653433663461663033333563363132356332643238 +62653636663038353166616166613433346339326530383530646438333265393831336237656562 +66626163626532306333326635653166663365313061383230643661343133383562643833383365 +62363233303364353135303233303034303235616334383163656236656534666362363966316434 +64306431646463646663633931366161666136303134356234356562363233393238323039356532 +63633533383435363536623831386164646336653238393932623936616463623535653966396430 +63643630383832316535636337333939656166346432323638616463663033616334333237626639 +64356332653834333461313266303261303762333763393461633038666437323666306635393661 +66663934636636373265313164313762326532643130303030646636326634656330303937313563 +37326661663061623239343430656135343532666561626437666564623138633264366435363833 +66366334636461303539366439663630396337343934353362333237333163303161353633353834 +35626564333264616637616664656139303337353136383664396165663566613265306331343436 +64333738636230346233373037636636616233373533303964356530386631616364366138383935 +66303830633136356363323832343035396363323937353032393965333666363636366339646661 +36633432623462636363363765646436346361363234343565663831383037626563 diff --git a/inventories/bendorf/hosts.yml b/inventories/bendorf/hosts.yml new file mode 100644 index 0000000..00e3fbf --- /dev/null +++ b/inventories/bendorf/hosts.yml @@ -0,0 +1,5 @@ +all: + children: + nas: + hosts: + 192.168.178.3: diff --git a/inventories/custom/group_vars/vars.yml b/inventories/custom/group_vars/vars.yml deleted file mode 100644 index 9f6f333..0000000 --- a/inventories/custom/group_vars/vars.yml +++ /dev/null @@ -1,70 +0,0 @@ -nas: - hostname: pi - domain: koblenz.dns.sschlicht.de - user: - name: pi - -setup_user: sebschlicht - -server_locales: - - de_DE.UTF-8 -server_timezone: Europe/Berlin - -mounts_base_dir: /mnt/nas - -mounts: - primary: - uuid: 18A302FC66F67B28 - -mail_recipient: pimon@sschlicht.de -mailing: - server: mx2f3e.netcup.net:465 - user: pi-ko@sschlicht.de - address: pi-ko@sschlicht.de - password: "{{ vault_mailing_password }}" - sender_name: "Pi (Koblenz)" - -nextcloud: - version: 20.0.0 - path: /var/www/nextcloud - data_path: "{{ mounts_base_dir }}/primary/nextcloud/data" - -samba: - internal_shares: - - { name: videos, path: "{{ mounts_base_dir }}/primary/videos" } - - { name: secdev, path: "{{ mounts_base_dir }}/primary/secdev" } - public_shares: - - { name: software, path: "{{ mounts_base_dir }}/primary/software" } - -minidlna: - display_name: SchlichtNAS - directories: - - "{{ mounts_base_dir }}/primary/videos" - -users: - - name: sebschlicht - full_name: Sebastian Schlicht - mail_address: "{{ vault_sebschlicht_mail_address }}" - backup_folder_name: sebastian - initial_password: $6$bvWKhsKfYQL8FH$FBXZZLp2ylLIEFjpj6c7vq.pCaJCH3nn3daYG3kEAhfhOxPoE6Y1kIux9VAiTQ8m1BPbmdYQ7OnCJNgm8h9VE1 - groups: sudo - samba_password: "{{ vault_sebschlicht_smbpasswd }}" - nextcloud_user: sebastian - nextcloud_password: "{{ vault_sebschlicht_nextcloud_password }}" - authorized_keys: - - id_sebschlicht.pub - - id_pi_windows.pub - - name: isspek - full_name: Ipek Baris Schlicht - mail_address: "{{ vault_isspek_mail_address }}" - backup_folder_name: ipek - initial_password: $6$AupSaBcLM5QMskO$FOVMKV.xMaNlcGsabZEoI7Hdmk9XxVF0bPBbcn2hsUizL0NQeOiIbdtfZGXDowKaP9acY5iDjIp13Y8upcvRr/ - samba_password: "{{ vault_isspek_smbpasswd }}" - nextcloud_password: "{{ vault_isspek_nextcloud_password }}" - - name: mas - full_name: Michael und Andrea Schlicht - mail_address: "{{ vault_mas_mail_address }}" - backup_folder_name: andrea-michael - initial_password: $6$IieSj6WUcNC$Hlw.UkdS0fqoCaGibNLUCp5sCGm/Jb9KSBWOqtyq6QY.rEPuG5sZyjcYeVqQ0IVdssrUqHK4xgteW3f12S9Fa1 - samba_password: "{{ vault_mas_smbpasswd }}" - nextcloud_password: "{{ vault_mas_nextcloud_password }}" diff --git a/inventories/example/group_vars/vars.yml b/inventories/example/group_vars/vars.yml new file mode 100644 index 0000000..55e33b5 --- /dev/null +++ b/inventories/example/group_vars/vars.yml @@ -0,0 +1,72 @@ +# remote user to login to and use for the setup process (must exist on the device) +setup_user: sebschlicht + +nas: + user: + # name of the system NAS user (e.g. used for service tasks) to be created + name: nas + # desired hostname of the NAS + hostname: pi + # path to store all NAS data + path: /mnt/nas-storage + # public domain to access the machine + domain: "{{ vault_nas_domain }}" + # path to store the user data + userdata_path: "/mnt/nas-storage/userdata" + # mount an external storage device to the NAS data path to store all data on it + mount: + # UUID of the external storage device + uuid: 4C1E05C31E05A6D4 + # file system type (see fstab for valid options) + fstype: ntfs-3g + # mount options (see fstab for valid options) + opts: defaults,windows_names,permissions,nofail,x-systemd.device-timeout=30,locale=de_DE.utf8 + # paths (relative to `files` folder) to private SSH keys to be copied to the NAS + ssh_keys: + - ko/id_nas_koblenz + # authorized public keys for SSH access to the NAS user + authorized_keys: + - ko/id_nas_bendorf.pub + +openvpn: + # path (relative to the `files` folder) for OpenVPN files of this machine + files: ko/openvpn + server: + # OpenVPN declaration (network, port) + network: 192.168.1.0 + port: 11194 + # OpenVPN client network declaration (name, network, submask) + client_networks: + - common_name: client-bendorf + network: 192.168.178.0 + subnetMask: 255.255.255.0 + +backup: + # path to be backed up + source_directory: "{{ nas.path }}" + # path to the local restic repository + local_repository: /mnt/nas-backup/backups/koblenz + # paths to local copies of remote backups + local_foreign_repositories: + - /mnt/nas-backup/backups/bendorf + mount: + # mount path of the external storage device to store backups + path: /mnt/nas-backup + # UUID of the external storage device + uuid: 2604C61626F2DB4E + # optional: file system (fstype) and mount options (opts); see fstab for possible values + # host of the remote restic repository (i.e. backup copy) + remote_host: 192.168.178.3 + # URI to the remote restic repository + remote_repository: "sftp:{{ nas.user.name }}@192.168.178.3:/mnt/nas-backup/backups/koblenz" + # name of the public key for SSH access to the remote restic repository ho + remote_ssh_key_id: id_nas_koblenz + +mailing_sender_name: "Pi (Koblenz)" + +minidlna: + # server name shown on client devices + display_name: SchlichtNAS (KO) + # paths accessible to clients + directories: + - "{{ nas.path }}/videos" diff --git a/inventories/example/hosts.yml b/inventories/example/hosts.yml new file mode 100644 index 0000000..173f8a7 --- /dev/null +++ b/inventories/example/hosts.yml @@ -0,0 +1,6 @@ +all: + children: + nas: + hosts: + # hosts to setup the NAS + 192.168.178.3: diff --git a/inventories/ko/group_vars/nas/vars.yml b/inventories/ko/group_vars/nas/vars.yml new file mode 100644 index 0000000..6443ab7 --- /dev/null +++ b/inventories/ko/group_vars/nas/vars.yml @@ -0,0 +1,44 @@ +setup_user: sebschlicht + +nas: + user: + name: nas + hostname: pi + path: /mnt/nas-storage + domain: "{{ vault_nas_domain }}" + userdata_path: "/mnt/nas-storage/userdata" + mount: + uuid: 4C1E05C31E05A6D4 + ssh_keys: + - ko/id_nas_koblenz + authorized_keys: + - ko/id_nas_bendorf.pub + +openvpn: + files: ko/openvpn + server: + network: 192.168.1.0 + port: 11194 + client_networks: + - common_name: client-bendorf + network: 192.168.178.0 + subnetMask: 255.255.255.0 + +backup: + source_directory: "{{ nas.path }}" + local_repository: /mnt/nas-backup/backups/koblenz + local_foreign_repositories: + - /mnt/nas-backup/backups/bendorf + mount: + path: /mnt/nas-backup + uuid: 2604C61626F2DB4E + remote_host: 192.168.178.3 + remote_repository: "sftp:{{ nas.user.name }}@192.168.178.3:/mnt/nas-backup/backups/koblenz" + remote_ssh_key_id: id_nas_koblenz + +mailing_sender_name: "Pi (Koblenz)" + +minidlna: + display_name: SchlichtNAS (KO) + directories: + - "{{ nas.path }}/videos" diff --git a/inventories/ko/group_vars/nas/vault b/inventories/ko/group_vars/nas/vault new file mode 100644 index 0000000..0d1f63b --- /dev/null +++ b/inventories/ko/group_vars/nas/vault @@ -0,0 +1,32 @@ +$ANSIBLE_VAULT;1.1;AES256 +31633134343638646432613035333730333730333634363632396132643261613333653532313162 +3264373266396234313434656438383634303439313436370a373534653330373466366434346233 +34313435623264646661623735333337616435316133643734616363636232636433366361643235 +3461393031363637370a316230643833613734613933363935393537396662386264613661666539 +65373537666337626562653663396231363331316237383533346563393461633862353066386537 +66316435323430373439306330656265633561666463313261353233323537353263383861393435 +62656234643335356164346335316539316233616439636333313065313538316636653663613238 +66306161353565393165623464633138363030653764303864626635663262656231316237363533 +62616665363062363637393132333931613934373730653835616432363031333334376536643265 +35623264646334336138393166653638616464383231386130656536636636316233316236333263 +64383263616634373934656634326231383935383263613032313538353536336433636333633662 +66323266353939333466613765326361396633663635613235323732393066303933323063653862 +37653230386261363638613936396239386639663937363962656332356262353039613733343261 +39363136633632336639613238663333333430336661643636313036626262396532643334626537 +39386536393336313864333663653331373866343366656531333565623731303462336363663864 +34383263386139363933623131353434666436373863613136633565653338383163323362636630 +65633432663664383861313636326365303665653535346433623037383334363830613736336435 +38346664316233313731333933333138373463376339393832313034373062643238616630353266 +38376663363865393564313535636631343239373431616432343738306333353062396565666530 +31336362336533643161636336323736616136393236366132383336633734653934343862613063 +61323561653664326236356430636538363234623030386262353761656432313536306638646336 +39313536366434356365383063373365383438333139373465383532346236666162313937366461 +31393862343633653932336336376639333538386337393438323261333131393837633930343434 +39393864326364646562353931666263653636643239306663323132316638646566383062303237 +38303437323361303361616363323165333330643230643830333738326634333365653264636366 +38613333616333396166303232396631626461336163633333353430656339343136666266393538 +34333836626537393864633438613230616666643964306164326635303964633761396462376361 +32633436383264666364316661626336396633346364366239326235626631633339383232393662 +61376432343930373636663364303735643366353161356464383661383965396135393135343665 +32633531306362643661343135343636393339326633613965646133656164623837336233333061 +663066616332626539623765356133386331 diff --git a/inventories/ko/hosts.yml b/inventories/ko/hosts.yml new file mode 100644 index 0000000..95813db --- /dev/null +++ b/inventories/ko/hosts.yml @@ -0,0 +1,9 @@ +all: + children: + nas: + hosts: + 192.168.1.4: + ansible_sudo_pass: "{{ vault_ansible_sudo_pass }}" + # password of the initial system user to setup passwordless SSH access via playbook `prepare-pi.yml` + # ansible_become_pass: myraspberrypw + # ansible_ssh_pass: myraspberrypw diff --git a/inventories/nas/hosts.yml b/inventories/nas/hosts.yml deleted file mode 100644 index 3fd9058..0000000 --- a/inventories/nas/hosts.yml +++ /dev/null @@ -1,11 +0,0 @@ -all: - children: - pi: - hosts: - 192.168.1.4: - ansible_become_pass: raspberry - ansible_ssh_pass: raspberry - nas: - hosts: - 192.168.1.4: - ansible_sudo_pass: "{{ vault_ansible_sudo_pass }}" diff --git a/openvpn-helper.sh b/openvpn-helper.sh new file mode 100755 index 0000000..703b8c3 --- /dev/null +++ b/openvpn-helper.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# +# Part of the Ansible NAS setup repository at +# https://github.com/sebschlicht/ansible-nas +# +# Check its documentation on how to setup OpenVPN with this script. +# +EASYRSA_DIR=ca +EASYRSA_BIN="$EASYRSA_DIR/easyrsa" +EASYRSA_PKI_DIR="$EASYRSA_DIR/pki" + +TRANSIT_DIR=files-ca-transit +CLIENT_DISTRIBUTION_TRANSIT_DIR="$TRANSIT_DIR/to-clients" +SERVER_TA_KEY_PATH="$CLIENT_DISTRIBUTION_TRANSIT_DIR/ta.key" + +REQUESTS_DIR_NAME=requests +REQUESTS_DIR="$TRANSIT_DIR/$REQUESTS_DIR_NAME" +REQUESTS_ARCHIVE_NAME=requests.zip +REQUESTS_ARCHIVE_PATH="$TRANSIT_DIR/$REQUESTS_ARCHIVE_NAME" + +CERTS_DIR="$TRANSIT_DIR/certificates" +CERTS_ARCHIVE_NAME=certificates.zip +CERTS_ARCHIVE_PATH="$TRANSIT_DIR/$CERTS_ARCHIVE_NAME" + +ANSIBLE_FILES_DIR=files + +fc_pack_requests() { + rm -f "$REQUESTS_ARCHIVE_PATH" + pushd "$TRANSIT_DIR" >/dev/null + zip -Tq -r "$REQUESTS_ARCHIVE_NAME" "$REQUESTS_DIR_NAME" + popd >/dev/null + rm -rf "$REQUESTS_DIR" +} + +fc_sign_requests() { + local request_type="$1" + for inventory_dir in "$REQUESTS_DIR"/*; do + if [ ! -d "$inventory_dir" ]; then + continue + fi + local inventory_name="$(basename -- "$inventory_dir")" + local cert_id="$request_type-$inventory_name" + local certificate_request_path="$inventory_dir/$request_type.req" + local inventory_certs_dir="$CERTS_DIR/$inventory_name/openvpn" + + mkdir -p "$inventory_certs_dir" + cp "$EASYRSA_PKI_DIR/ca.crt" "$inventory_certs_dir/ca.crt" + + if [ -f "$certificate_request_path" ]; then + "$EASYRSA_BIN" --pki-dir="$EASYRSA_PKI_DIR" import-req "$certificate_request_path" "$cert_id" + "$EASYRSA_BIN" --pki-dir="$EASYRSA_PKI_DIR" --batch sign-req "$request_type" "$cert_id" + cp "$EASYRSA_PKI_DIR/issued/$cert_id.crt" "$inventory_certs_dir/$request_type.crt" + fi + done +} + +fc_sign_and_pack_certificates() { + unzip -q "$1" -d "$TRANSIT_DIR" + rm -f "$CERTS_ARCHIVE_PATH" + + rm -f "$EASYRSA_PKI_DIR/reqs"/* + fc_sign_requests server + fc_sign_requests client + + pushd "$CERTS_DIR" >/dev/null + zip -Tq -r "../$CERTS_ARCHIVE_NAME" . + popd >/dev/null +} + +fc_extract_certificates() { + unzip -q "$1" -d "$ANSIBLE_FILES_DIR" +} + +fc_copy_distribution_files() { + local vault_password_file="$1" + if [ -f "$SERVER_TA_KEY_PATH" ]; then + if ! head -1 "$SERVER_TA_KEY_PATH" | grep -q '^\$ANSIBLE_VAULT;1.1;AES256$'; then + ansible-vault encrypt --vault-password-file="$vault_password_file" "$SERVER_TA_KEY_PATH" 1>/dev/null + fi + fi + + for inventory_dir in "$ANSIBLE_FILES_DIR"/*; do + local inventory_openvpn_files_dir="$inventory_dir/openvpn" + if [ -f "$inventory_openvpn_files_dir/client.crt" ]; then + cp "$TRANSIT_DIR/to-clients"/* "$inventory_openvpn_files_dir/" + fi + done +} + +if [ "$1" = 'pack-requests' ]; then + fc_pack_requests +elif [ "$1" = 'sign-requests' ]; then + fc_sign_and_pack_certificates "$2" +elif [ "$1" = 'extract-certificates' ]; then + fc_extract_certificates "$2" +elif [ "$1" = 'copy-files' ]; then + fc_copy_distribution_files "$2" +fi diff --git a/roles/aftercare/tasks/main.yml b/roles/aftercare/tasks/main.yml new file mode 100644 index 0000000..b7a1a5a --- /dev/null +++ b/roles/aftercare/tasks/main.yml @@ -0,0 +1,7 @@ +- name: words of advice + debug: + msg: "{{ item }}" + with_items: "{{ global_suggestions }}" + loop_control: + label: "see below" + when: global_suggestions is defined diff --git a/roles/backups/defaults/main.yml b/roles/backups/defaults/main.yml deleted file mode 100644 index ebefd3b..0000000 --- a/roles/backups/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ -nas_backup_directory_mode: 0755 -nas_personal_backup_directory_mode: 0750 diff --git a/roles/backups/meta/main.yml b/roles/backups/meta/main.yml deleted file mode 100644 index 0f9f777..0000000 --- a/roles/backups/meta/main.yml +++ /dev/null @@ -1,2 +0,0 @@ -dependencies: - - role: sshd diff --git a/roles/backups/tasks/main.yml b/roles/backups/tasks/main.yml deleted file mode 100644 index 2738118..0000000 --- a/roles/backups/tasks/main.yml +++ /dev/null @@ -1,23 +0,0 @@ -- name: create backup location - file: - path: "{{ backup_location }}" - state: directory - owner: "{{ nas.user.name }}" - group: "{{ nas.user.name }}" - mode: "{{ nas_backup_directory_mode }}" - force: yes - tags: nas - -- name: create user backup directories and enforce secure permissions - file: - path: "{{ backup_location }}/{{ user.backup_folder_name | default(user.name) }}" - state: directory - owner: "{{ user.name }}" - group: "{{ user.name }}" - mode: "{{ nas_personal_backup_directory_mode }}" - force: yes - loop: "{{ users }}" - loop_control: - loop_var: user - label: "{{ user.name }}" - tags: nas diff --git a/roles/dynv6/tasks/main.yml b/roles/dynv6/tasks/main.yml index 0468e12..577581a 100644 --- a/roles/dynv6/tasks/main.yml +++ b/roles/dynv6/tasks/main.yml @@ -1,15 +1,17 @@ -- name: copy script - template: - src: dynv6.sh.j2 - dest: /usr/local/bin/dynv6 - mode: 0755 +- name: install ddclient + apt: + name: + - ddclient + cache_valid_time: 600 -- name: register cron jobs - cron: - name: "dynv6 ({{ item }})" - job: "dynv6 {{ dynv6.hostname | default(nas.domain) }}" - special_time: "{{ item }}" - user: "{{ nas.user.name }}" - loop: - - hourly - - reboot +- name: configure ddclient + copy: + dest: /etc/ddclient.conf + content: | + protocol=dyndns2 + use=web, web=checkip.dyndns.com, web-skip='IP Address' + server=dynv6.com + ssl=yes + login=none + password='{{ dynv6.password }}' + {{ nas.domain }} diff --git a/roles/dynv6/templates/dynv6.sh.j2 b/roles/dynv6/templates/dynv6.sh.j2 deleted file mode 100644 index ea81876..0000000 --- a/roles/dynv6/templates/dynv6.sh.j2 +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -e -token={{ dynv6.token }} -hostname=$1 -device=$2 -file=$HOME/.dynv6.addr6 -[ -e $file ] && old=`cat $file` - -if [ -z "$hostname" -o -z "$token" ]; then - echo "Usage: token= [netmask=64] $0 your-name.dynv6.net [device]" - exit 1 -fi - -if [ -z "$netmask" ]; then - netmask=128 -fi - -if [ -n "$device" ]; then - device="dev $device" -fi -address=$(ip -6 addr list scope global $device | grep -v " fd" | sed -n 's/.*inet6 \([0-9a-f:]\+\).*/\1/p' | head -n 1) - -if [ -e /usr/bin/curl ]; then - bin="curl -fsS" -elif [ -e /usr/bin/wget ]; then - bin="wget -O-" -else - echo "neither curl nor wget found" - exit 1 -fi - -if [ -z "$address" ]; then - echo "no IPv6 address found" - exit 1 -fi - -# address with netmask -current=$address/$netmask - -if [ "$old" = "$current" ]; then - echo "IPv6 address unchanged" - exit -fi - -# send addresses to dynv6 -$bin "http://dynv6.com/api/update?hostname=$hostname&ipv6=$current&token=$token" -$bin "http://ipv4.dynv6.com/api/update?hostname=$hostname&ipv4=auto&token=$token" - -# save current address -echo $current > $file diff --git a/roles/minidlna/tasks/main.yml b/roles/minidlna/tasks/main.yml index c1da270..faf891e 100644 --- a/roles/minidlna/tasks/main.yml +++ b/roles/minidlna/tasks/main.yml @@ -7,14 +7,26 @@ blockinfile: path: /etc/minidlna.conf block: "{{ lookup('template', 'minidlna.conf.j2') }}" + register: minidlna_config - name: add miniDLNA user to NAS group user: name: minidlna groups: "{{ nas.user.name }}" -- name: start +- name: configure firewall + ufw: + rule: allow + proto: "{{ item.proto }}" + to_port: "{{ item.to_port }}" + with_items: + - to_port: 8200 + proto: tcp + - to_port: 1900 + proto: udp + +- name: enable service: name: minidlna - state: started + state: "{{ minidlna_config.changed | ternary('restarted', 'started') }}" enabled: yes diff --git a/roles/mount/tasks/main.yml b/roles/mount/tasks/main.yml index d14f9f6..9281a51 100644 --- a/roles/mount/tasks/main.yml +++ b/roles/mount/tasks/main.yml @@ -1,14 +1,13 @@ -- name: prepare base mount point - file: - path: "{{ mounts_base_dir }}" - state: directory - owner: "{{ nas.user.name }}" - group: "{{ nas.user.name }}" - mode: "{{ mount_directory_mode }}" +- name: mount external storage for NAS + include_tasks: mount.yml + vars: + mount: "{{ nas.mount }}" + mountpoint: "{{ nas.mount.path | default(nas.path) }}" + when: nas.mount is defined -- name: mount external storages +- name: mount external backup storage for NAS include_tasks: mount.yml - with_dict: "{{ mounts }}" - loop_control: - loop_var: mount - when: mounts is defined + vars: + mount: "{{ backup.mount }}" + mountpoint: "{{ backup.mount.path }}" + when: backup.mount is defined diff --git a/roles/mount/tasks/mirror.yml b/roles/mount/tasks/mirror.yml deleted file mode 100644 index 48d0bac..0000000 --- a/roles/mount/tasks/mirror.yml +++ /dev/null @@ -1,7 +0,0 @@ -- name: configure mirroring to secondary mount - cron: - name: "mirror NAS storages" - job: "rsync -ast --delete {{ mounts_base_dir }}/{{ mounts.primary.name }} {{ mounts_base_dir }}/{{ mounts.secondary.name }}" - special_time: daily - become_user: "{{ nas.user }}" - when: mounts.secondary is defined diff --git a/roles/mount/tasks/mount.yml b/roles/mount/tasks/mount.yml index bbc4676..3869575 100644 --- a/roles/mount/tasks/mount.yml +++ b/roles/mount/tasks/mount.yml @@ -1,22 +1,29 @@ - name: check if mounted shell: | - mountpoint -q "{{ mounts_base_dir }}/{{ mount.key }}" + mountpoint -q "{{ mountpoint }}" register: mounted changed_when: no failed_when: no -- name: create mount point with restrictive permissions +- name: create mount point file: - path: "{{ mounts_base_dir }}/{{ mount.key }}" - owner: "{{ nas.user.name }}" - group: "{{ nas.user.name }}" + path: "{{ mountpoint }}" + state: directory mode: "{{ mount_directory_mode }}" when: mounted.rc != 0 -- name: "mount {{ mount.key }} NTFS storage device" +- name: "mount {{ mountpoint }}" mount: - path: "{{ mounts_base_dir }}/{{ mount.key }}" - src: "UUID={{ mount.value.uuid }}" + path: "{{ mountpoint }}" + src: "UUID={{ mount.uuid }}" state: mounted - fstype: "{{ mount.value.fstype | default('ntfs-3g') }}" - opts: "{{ mount.value.opts | default('defaults,windows_names,permissions,nofail,x-systemd.device-timeout=30,locale=de_DE.utf8') }}" + fstype: "{{ mount.fstype | default('ntfs-3g') }}" + opts: "{{ mount.opts | default('defaults,windows_names,permissions,nofail,x-systemd.device-timeout=30,locale=de_DE.utf8') }}" + +- name: make mounted device accessible + file: + path: "{{ mountpoint }}" + state: directory + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: "{{ mount_directory_mode }}" diff --git a/roles/nextcloud/tasks/apache.yml b/roles/nextcloud/tasks/apache.yml index 2440653..f8b2245 100644 --- a/roles/nextcloud/tasks/apache.yml +++ b/roles/nextcloud/tasks/apache.yml @@ -30,3 +30,9 @@ name: apache2 state: restarted when: place_apache_sites.changed or apache_default_sites.changed + +- name: configure firewall + ufw: + rule: allow + proto: tcp + to_port: 80,443 diff --git a/roles/openvpn-init/tasks/main.yml b/roles/openvpn-init/tasks/main.yml new file mode 100644 index 0000000..b8b1f50 --- /dev/null +++ b/roles/openvpn-init/tasks/main.yml @@ -0,0 +1,4 @@ +- name: import OpenVPN initialization tasks + import_role: + name: openvpn + tasks_from: init.yml diff --git a/roles/openvpn/defaults/main.yml b/roles/openvpn/defaults/main.yml new file mode 100644 index 0000000..5e61cff --- /dev/null +++ b/roles/openvpn/defaults/main.yml @@ -0,0 +1,15 @@ +easyrsa_dir: /etc/easy-rsa +easyrsa_pki_dir: "{{ easyrsa_dir }}/pki" +easyrsa_host: "{{ ansible_inventory_sources | first | regex_search('[^/]+$') }}" +easyrsa_certificate_id: "{{ (openvpn.client is defined) | ternary('client', 'server') }}" +easyrsa_certificate_path: "{{ easyrsa_pki_dir }}/reqs/{{ easyrsa_certificate_id }}.req" + +transit_files_dir: "files-ca-transit" + +openvpn_user: openvpn +openvpn_config_dir: "/etc/openvpn/{{ easyrsa_certificate_id }}" +openvpn_server_ta_key_path: "{{ openvpn_config_dir }}/ta.key" +openvpn_server_dh_key_path: "{{ openvpn_config_dir }}/dh2048.pem" +openvpn_server_client_config_dir: "{{ openvpn_config_dir }}/ccd" +openvpn_server_suggest_port_forwarding: | + [OpenVPN] The OpenVPN server is now running. Don't forget to configure a port forwarding from your router to the OpenVPN server, on port {{ openvpn.server.port }}. diff --git a/roles/openvpn/tasks/client.yml b/roles/openvpn/tasks/client.yml new file mode 100644 index 0000000..07e5774 --- /dev/null +++ b/roles/openvpn/tasks/client.yml @@ -0,0 +1,33 @@ +- name: create configuration folder + file: + path: "{{ openvpn_config_dir }}" + state: directory + owner: root + group: root + +- name: configure client + template: + src: "client.conf" + dest: "{{ openvpn_config_dir }}/client.conf" + mode: 0644 + group: "{{ openvpn_user }}" + register: client_config + +- name: copy client files + copy: + src: "{{ openvpn.files }}/{{ item }}" + dest: "{{ openvpn_config_dir }}/" + owner: "{{ openvpn_user }}" + group: "{{ openvpn_user }}" + mode: 0600 + with_items: + - ca.crt + - ta.key + - client.crt + register: client_files + +- name: enable and start service + service: + name: openvpn-client@client.service + enabled: yes + state: "{{ (client_config.changed or client_files.changed) | ternary('restarted', 'started') }}" diff --git a/roles/openvpn/tasks/init-server.yml b/roles/openvpn/tasks/init-server.yml new file mode 100644 index 0000000..a75a659 --- /dev/null +++ b/roles/openvpn/tasks/init-server.yml @@ -0,0 +1,17 @@ +- name: generate DH key + command: + cmd: "openssl dhparam -out '{{ openvpn_server_dh_key_path }}' 2048" + creates: "{{ openvpn_server_dh_key_path }}" + async: 600 + poll: 5 + +- name: generate TLS key + command: + cmd: openvpn --genkey --secret '{{ openvpn_server_ta_key_path }}' + creates: "{{ openvpn_server_ta_key_path }}" + +- name: retrieve TLS key for redistribution + fetch: + dest: "{{ transit_files_dir }}/to-clients/" + flat: yes + src: "{{ openvpn_server_ta_key_path }}" diff --git a/roles/openvpn/tasks/init.yml b/roles/openvpn/tasks/init.yml new file mode 100644 index 0000000..15f6d7d --- /dev/null +++ b/roles/openvpn/tasks/init.yml @@ -0,0 +1,40 @@ +- name: install + apt: + name: + - openvpn + - easy-rsa + cache_valid_time: 600 + +- name: initialize easy-rsa + command: + cmd: "make-cadir '{{ easyrsa_dir }}'" + creates: "{{ easyrsa_dir }}" + +- name: initialize PKI + command: + cmd: "{{ easyrsa_dir }}/easyrsa --pki-dir='{{ easyrsa_pki_dir }}' init-pki" + creates: "{{ easyrsa_pki_dir }}" + +- name: create certificate request + command: + cmd: "{{ easyrsa_dir }}/easyrsa --pki-dir='{{ easyrsa_pki_dir }}' --batch gen-req '{{ easyrsa_certificate_id }}' nopass" + creates: "{{ easyrsa_certificate_path }}" + environment: + EASYRSA_REQ_CN: "{{ easyrsa_certificate_id }}-{{ easyrsa_host }}" + EASYRSA_BATCH: "yes" + +- name: retrieve certificate request + fetch: + dest: "{{ transit_files_dir }}/requests/{{ easyrsa_host }}/" + flat: true + src: "{{ easyrsa_certificate_path }}" + +- name: initialize server credentials + import_tasks: init-server.yml + when: openvpn.server is defined + +- name: copy private key + copy: + src: "{{ easyrsa_pki_dir }}/private/{{ easyrsa_certificate_id }}.key" + dest: "{{ openvpn_config_dir }}/" + remote_src: yes diff --git a/roles/openvpn/tasks/main.yml b/roles/openvpn/tasks/main.yml new file mode 100644 index 0000000..8f93380 --- /dev/null +++ b/roles/openvpn/tasks/main.yml @@ -0,0 +1,22 @@ +- name: create user + user: + name: "{{ openvpn_user }}" + home: /nonexistent + create_home: no + shell: /usr/sbin/nologin + +- name: prepare to run OpenVPN as root + blockinfile: + path: /etc/sudoers + block: | + openvpn ALL=(root) NOPASSWD: /usr/sbin/openvpn + validate: visudo -cf %s + marker: "# [ANSIBLE] {mark} grant NAS to run openvpn as root" + +- name: setup server + import_tasks: server.yml + when: openvpn.server is defined + +- name: setup client + import_tasks: client.yml + when: openvpn.client is defined diff --git a/roles/openvpn/tasks/server.yml b/roles/openvpn/tasks/server.yml new file mode 100644 index 0000000..193c9df --- /dev/null +++ b/roles/openvpn/tasks/server.yml @@ -0,0 +1,51 @@ +- name: create configuration folder + file: + path: "{{ openvpn_config_dir }}" + state: directory + owner: root + group: root + +- name: create client configuration folder + file: + path: "{{ openvpn_server_client_config_dir }}" + state: directory + +- name: configure iroute entries + copy: + dest: "{{ openvpn_server_client_config_dir }}/{{ openvpn_client.common_name }}" + content: "iroute {{ openvpn_client.network }} {{ openvpn_client.subnetMask | default('255.255.255.0') }}" + with_items: "{{ openvpn.server.client_networks | default([]) }}" + loop_control: + loop_var: openvpn_client + +- name: configure server + template: + src: "server.conf" + dest: "{{ openvpn_config_dir }}/server.conf" + group: "{{ openvpn_user }}" + mode: 0644 + register: server_config + +- name: copy server files + copy: + src: "{{ openvpn.files }}/{{ item }}" + dest: "{{ openvpn_config_dir }}/" + user: "{{ openvpn_user }}" + group: "{{ openvpn_user }}" + mode: 0600 + with_items: + - ca.crt + - server.crt + register: server_files + +- name: enable and (re)start service + service: + name: openvpn-server@server.service + enabled: yes + state: "{{ (server_config.changed or server_files.changed) | ternary('restarted', 'started') }}" + register: server_service + +- name: suggest port forwarding + set_fact: + global_suggestions: "{{ global_suggestions | default([]) + [ openvpn_server_suggest_port_forwarding ] }}" + when: server_service.changed diff --git a/roles/openvpn/templates/client.conf b/roles/openvpn/templates/client.conf new file mode 100644 index 0000000..157dac7 --- /dev/null +++ b/roles/openvpn/templates/client.conf @@ -0,0 +1,53 @@ +client + +dev tun +proto udp +remote {{ openvpn.client.server.address }} {{ openvpn.client.server.port }} +nobind + +# Downgrade privileges after initialization (non-Windows only) +user {{ openvpn_user }} +group {{ openvpn_user }} + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. +ca ca.crt +cert client.crt +key client.key + +# Verify server certificate by checking that the +# certicate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +remote-cert-tls server + +# If a tls-auth key is used on the server +# then every client must also have the key. +tls-auth ta.key 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC + +# Set log file verbosity. +verb 3 diff --git a/roles/openvpn/templates/server.conf b/roles/openvpn/templates/server.conf new file mode 100644 index 0000000..f8635fc --- /dev/null +++ b/roles/openvpn/templates/server.conf @@ -0,0 +1,321 @@ +################################################# +# Sample OpenVPN 2.0 config file for # +# multi-client server. # +# # +# This file is for the server side # +# of a many-clients <-> one-server # +# OpenVPN configuration. # +# # +# OpenVPN also supports # +# single-machine <-> single-machine # +# configurations (See the Examples page # +# on the web site for more info). # +# # +# This config should work on Windows # +# or Linux/BSD systems. Remember on # +# Windows to quote pathnames and use # +# double backslashes, e.g.: # +# "C:\\Program Files\\OpenVPN\\config\\foo.key" # +# # +# Comments are preceded with '#' or ';' # +################################################# + +# Which local IP address should OpenVPN +# listen on? (optional) +;local a.b.c.d + +# Which TCP/UDP port should OpenVPN listen on? +# If you want to run multiple OpenVPN instances +# on the same machine, use a different port +# number for each one. You will need to +# open up this port on your firewall. +port {{ openvpn.server.port }} + +# TCP or UDP server? +;proto tcp +proto udp + +# "dev tun" will create a routed IP tunnel, +# "dev tap" will create an ethernet tunnel. +# Use "dev tap0" if you are ethernet bridging +# and have precreated a tap0 virtual interface +# and bridged it with your ethernet interface. +# If you want to control access policies +# over the VPN, you must create firewall +# rules for the the TUN/TAP interface. +# On non-Windows systems, you can give +# an explicit unit number, such as tun0. +# On Windows, use "dev-node" for this. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +;dev tap +dev tun + +# Windows needs the TAP-Win32 adapter name +# from the Network Connections panel if you +# have more than one. On XP SP2 or higher, +# you may need to selectively disable the +# Windows firewall for the TAP adapter. +# Non-Windows systems usually don't need this. +;dev-node MyTap + +# SSL/TLS root certificate (ca), certificate +# (cert), and private key (key). Each client +# and the server must have their own cert and +# key file. The server and all clients will +# use the same ca file. +# +# See the "easy-rsa" directory for a series +# of scripts for generating RSA certificates +# and private keys. Remember to use +# a unique Common Name for the server +# and each of the client certificates. +# +# Any X509 key management system can be used. +# OpenVPN can also use a PKCS #12 formatted key file +# (see "pkcs12" directive in man page). +ca ca.crt +cert server.crt +key server.key # This file should be kept secret + +# Diffie hellman parameters. +# Generate your own with: +# openssl dhparam -out dh2048.pem 2048 +dh dh2048.pem + +# Network topology +# Should be subnet (addressing via IP) +# unless Windows clients v2.0.9 and lower have to +# be supported (then net30, i.e. a /30 per client) +# Defaults to net30 (not recommended) +;topology subnet + +# Configure server mode and supply a VPN subnet +# for OpenVPN to draw client addresses from. +# The server will take 10.8.0.1 for itself, +# the rest will be made available to clients. +# Each client will be able to reach the server +# on 10.8.0.1. Comment this line out if you are +# ethernet bridging. See the man page for more info. +server 10.8.0.0 255.255.255.0 + +# Maintain a record of client <-> virtual IP address +# associations in this file. If OpenVPN goes down or +# is restarted, reconnecting clients can be assigned +# the same virtual IP address from the pool that was +# previously assigned. +ifconfig-pool-persist /var/log/openvpn/ipp.txt + +# Configure server mode for ethernet bridging. +# You must first use your OS's bridging capability +# to bridge the TAP interface with the ethernet +# NIC interface. Then you must manually set the +# IP/netmask on the bridge interface, here we +# assume 10.8.0.4/255.255.255.0. Finally we +# must set aside an IP range in this subnet +# (start=10.8.0.50 end=10.8.0.100) to allocate +# to connecting clients. Leave this line commented +# out unless you are ethernet bridging. +;server-bridge 10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100 + +# Configure server mode for ethernet bridging +# using a DHCP-proxy, where clients talk +# to the OpenVPN server-side DHCP server +# to receive their IP address allocation +# and DNS server addresses. You must first use +# your OS's bridging capability to bridge the TAP +# interface with the ethernet NIC interface. +# Note: this mode only works on clients (such as +# Windows), where the client-side TAP adapter is +# bound to a DHCP client. +;server-bridge + +# Push routes to the client to allow it +# to reach other private subnets behind +# the server. Remember that these +# private subnets will also need +# to know to route the OpenVPN client +# address pool (10.8.0.0/255.255.255.0) +# back to the OpenVPN server. +push "route {{ openvpn.server.network }} {{ openvpn.server.subnetMask | default('255.255.255.0') }}" +{% for client_network in openvpn.server.client_networks %} +push "route {{ client_network.network }} {{ client_network.subnetMask | default('255.255.255.0') }}" +{% endfor %} + +;push "route 192.168.20.0 255.255.255.0" + +# To assign specific IP addresses to specific +# clients or if a connecting client has a private +# subnet behind it that should also have VPN access, +# use the subdirectory "ccd" for client-specific +# configuration files (see man page for more info). + +# EXAMPLE: Suppose the client +# having the certificate common name "Thelonious" +# also has a small subnet behind his connecting +# machine, such as 192.168.40.128/255.255.255.248. +# First, uncomment out these lines: +;client-config-dir ccd +;route 192.168.40.128 255.255.255.248 +# Then create a file ccd/Thelonious with this line: +# iroute 192.168.40.128 255.255.255.248 +# This will allow Thelonious' private subnet to +# access the VPN. This example will only work +# if you are routing, not bridging, i.e. you are +# using "dev tun" and "server" directives. + +# EXAMPLE: Suppose you want to give +# Thelonious a fixed VPN IP address of 10.9.0.1. +# First uncomment out these lines: +client-config-dir {{ openvpn_server_client_config_dir }} +{% for client_network in openvpn.server.client_networks %} +route {{ client_network.network }} {{ client_network.subnetMask | default('255.255.255.0') }} +{% endfor %} +# Then add this line to ccd/Thelonious: +# ifconfig-push 10.9.0.1 10.9.0.2 + +# Suppose that you want to enable different +# firewall access policies for different groups +# of clients. There are two methods: +# (1) Run multiple OpenVPN daemons, one for each +# group, and firewall the TUN/TAP interface +# for each group/daemon appropriately. +# (2) (Advanced) Create a script to dynamically +# modify the firewall in response to access +# from different clients. See man +# page for more info on learn-address script. +;learn-address ./script + +# If enabled, this directive will configure +# all clients to redirect their default +# network gateway through the VPN, causing +# all IP traffic such as web browsing and +# and DNS lookups to go through the VPN +# (The OpenVPN server machine may need to NAT +# or bridge the TUN/TAP interface to the internet +# in order for this to work properly). +;push "redirect-gateway def1 bypass-dhcp" + +# Certain Windows-specific network settings +# can be pushed to clients, such as DNS +# or WINS server addresses. CAVEAT: +# http://openvpn.net/faq.html#dhcpcaveats +# The addresses below refer to the public +# DNS servers provided by opendns.com. +;push "dhcp-option DNS 208.67.222.222" +;push "dhcp-option DNS 208.67.220.220" + +# Uncomment this directive to allow different +# clients to be able to "see" each other. +# By default, clients will only see the server. +# To force clients to only see the server, you +# will also need to appropriately firewall the +# server's TUN/TAP interface. +client-to-client + +# Uncomment this directive if multiple clients +# might connect with the same certificate/key +# files or common names. This is recommended +# only for testing purposes. For production use, +# each client should have its own certificate/key +# pair. +# +# IF YOU HAVE NOT GENERATED INDIVIDUAL +# CERTIFICATE/KEY PAIRS FOR EACH CLIENT, +# EACH HAVING ITS OWN UNIQUE "COMMON NAME", +# UNCOMMENT THIS LINE OUT. +;duplicate-cn + +# The keepalive directive causes ping-like +# messages to be sent back and forth over +# the link so that each side knows when +# the other side has gone down. +# Ping every 10 seconds, assume that remote +# peer is down if no ping received during +# a 120 second time period. +keepalive 10 60 + +# For extra security beyond that provided +# by SSL/TLS, create an "HMAC firewall" +# to help block DoS attacks and UDP port flooding. +# +# Generate with: +# openvpn --genkey --secret ta.key +# +# The server and each client must have +# a copy of this key. +# The second parameter should be '0' +# on the server and '1' on the clients. +tls-auth ta.key 0 # This file is secret + +# Select a cryptographic cipher. +# This config item must be copied to +# the client config file as well. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC + +# Enable compression on the VPN link and push the +# option to the client (v2.4+ only, for earlier +# versions see below) +;compress lz4-v2 +;push "compress lz4-v2" + +# For compression compatible with older clients use comp-lzo +# If you enable it here, you must also +# enable it in the client config file. +;comp-lzo + +# The maximum number of concurrently connected +# clients we want to allow. +;max-clients 100 + +# It's a good idea to reduce the OpenVPN +# daemon's privileges after initialization. +# +# You can uncomment this out on +# non-Windows systems. +user {{ openvpn_user }} +group {{ openvpn_user }} + +# The persist options will try to avoid +# accessing certain resources on restart +# that may no longer be accessible because +# of the privilege downgrade. +persist-key +persist-tun + +# Output a short status file showing +# current connections, truncated +# and rewritten every minute. +status /var/log/openvpn/openvpn-status.log + +# By default, log messages will go to the syslog (or +# on Windows, if running as a service, they will go to +# the "\Program Files\OpenVPN\log" directory). +# Use log or log-append to override this default. +# "log" will truncate the log file on OpenVPN startup, +# while "log-append" will append to it. Use one +# or the other (but not both). +;log /var/log/openvpn/openvpn.log +;log-append /var/log/openvpn/openvpn.log + +# Set the appropriate level of log +# file verbosity. +# +# 0 is silent, except for fatal errors +# 4 is reasonable for general usage +# 5 and 6 can help to debug connection problems +# 9 is extremely verbose +verb 3 + +# Silence repeating messages. At most 20 +# sequential messages of the same message +# category will be output to the log. +;mute 20 + +# Notify the client that when the server restarts so it +# can automatically reconnect. +explicit-exit-notify 1 diff --git a/roles/os/tasks/main.yml b/roles/os/tasks/main.yml index 3697c4d..5e24dda 100644 --- a/roles/os/tasks/main.yml +++ b/roles/os/tasks/main.yml @@ -1,3 +1,26 @@ +- name: create nas user + user: + name: "{{ nas.user.name }}" + password_lock: yes + shell: /bin/bash + +- name: create SSH directory of nas user + file: + path: "{{ nas_ssh_dir }}" + state: directory + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: 0700 + +- name: configure SSH keys of nas user + copy: + src: "{{ item }}" + dest: "{{ nas_ssh_dir }}/" + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: 0600 + with_items: "{{ nas.ssh_keys }}" + - name: create OS users user: append: yes diff --git a/roles/restic/defaults/main.yml b/roles/restic/defaults/main.yml new file mode 100644 index 0000000..12852fb --- /dev/null +++ b/roles/restic/defaults/main.yml @@ -0,0 +1,9 @@ +restic_repository_password: "{{ vault_restic_repository_password }}" +restic_config_dir: "/home/{{ nas.user.name }}/.config/restic" +restic_password_file_path: "{{ restic_config_dir }}/password" + +restic_wrapper_log_dir: /var/log/restic +restic_wrapper_script_dir: "/home/{{ nas.user.name }}/scripts" +restic_wrapper_script_path: "{{ restic_wrapper_script_dir }}/restic-wrapper.sh" + +restic_ssh_config_entry: restic.remote diff --git a/roles/restic/meta/main.yml b/roles/restic/meta/main.yml new file mode 100644 index 0000000..47c32c5 --- /dev/null +++ b/roles/restic/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - role: ssmtp diff --git a/roles/restic/tasks/main.yml b/roles/restic/tasks/main.yml new file mode 100644 index 0000000..e834d64 --- /dev/null +++ b/roles/restic/tasks/main.yml @@ -0,0 +1,90 @@ +- name: install restic + apt: + name: + - restic + cache_valid_time: 600 + register: restic_install + +- name: update restic + command: restic self-update + when: restic_install.changed + +- name: create restic configuration directory + file: + path: "{{ restic_config_dir }}" + state: directory + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + +- name: store restic password + copy: + content: "{{ restic_repository_password }}" + dest: "{{ restic_password_file_path }}" + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: 0600 + +- name: create local restic repository directory + file: + path: "{{ backup.local_repository }}" + state: directory + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + +- name: create foreign restic repository directories + file: + path: "{{ item }}" + state: directory + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + with_list: "{{ backup.local_foreign_repositories }}" + +- name: create script directory + file: + path: "{{ restic_wrapper_script_dir }}" + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + state: directory + +- name: create script log directory + file: + path: "{{ restic_wrapper_log_dir }}" + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + state: directory + +- name: template wrapper script + template: + src: restic-wrapper.sh + dest: "{{ restic_wrapper_script_path }}" + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: 0755 + +- name: prepare to backup as root + blockinfile: + path: /etc/sudoers + block: | + {{ nas.user.name }} ALL=(root) NOPASSWD: /usr/bin/restic backup * + {{ nas.user.name }} ALL=(root) NOPASSWD: /usr/bin/chown -R {{ nas.user.name }}\: {{ backup.local_repository }} + validate: visudo -cf %s + marker: "# [ANSIBLE] {mark} grant NAS to create backups as root" + +- name: create SSH configuration entry for remote repository host + blockinfile: + path: "{{ nas_ssh_dir }}/config" + block: "{{ lookup('template', 'ssh/config') }}" + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: 0600 + create: yes + marker: "# [ANSIBLE] {mark} access remote NAS to store backups" + +- name: schedule restic backup + cron: + name: "backup NAS" + job: "{{ restic_wrapper_script_path }} -u '{{ nas.user.name }}' -p '{{ restic_password_file_path }}' -r '{{ backup.local_repository }}' -b '{{ backup.remote_repository }}' -l '{{ restic_wrapper_log_dir }}' -m '{{ mail_recipient }}' {{ backup.source_directory }}" + user: "{{ nas.user.name }}" + minute: "0" + hour: "2" + weekday: "0" diff --git a/roles/restic/templates/restic-wrapper.sh b/roles/restic/templates/restic-wrapper.sh new file mode 100755 index 0000000..f219b46 --- /dev/null +++ b/roles/restic/templates/restic-wrapper.sh @@ -0,0 +1,256 @@ +#!/bin/bash +# +# This is a wrapper script to perform backups using (restic)[https://restic.net/] in a setup with two networks (e.g. side-to-side VPN). +# Its purpose is to create backups and store them on machines in both networks, ideally geo-spread. +# +# The backup process consists of three steps: +# * back up to a local (network) repository +# * verify the integrity of the local repository +# * push all local backups to a remote repository +# The process in aborted and a notification (including the log file), should any of the steps fail. +# +# Dependencies: +# * mail transfer agent installed and configured +# +PROGRAM_NAME='restic-wrapper' +QUIET=false + +################################# +# variable initialization section +################################# +OS_USER="$USER" +BACKUP_SOURCE_DIR= +LOG_FILE_DIR=. +LOCAL_REPOSITORY= +REMOTE_REPOSITORY= +PASSWORD_FILE= +NOTIFICATION_ADDRESS= + +################### +# constants section +################### +LOCAL_BACKUP_FAILED='[ERR] Backup failed' +INTEGRITY_LOSS='[ERR] Backup integrity failure' +PUSHING_BACKUP_FAILED='[WARN] Creating a copy of the backup failed' +BACKUP_SUCCEEDED='[INFO] Backup created' + +# Prints the usage of the script in case of using the help command. +printUsage() { + echo 'Usage: '"$PROGRAM_NAME"' [OPTIONS] BACKUP_SOURCE_DIRECTORY' + echo + echo 'Restic wrapper to add a snapshot in a repository, verify the repositories integrity and push all its snapshots to another.' + echo + echo 'Options:' + echo '-h, --help Display this help message and exit.' + echo '-u, --user Operating system user to instrument. Defaults to $USER.' + echo '-r, --local-repository Restic repository in the local network' + echo '-b, --remote-repository Restic repository in the remote network' + echo '-p, --password-file Restic password file' + echo '-l, --log-file-dir Path to the log file directory' + echo '-m, --notification-mail-address Mail address to send notifications to' +} + +# Echoes an error message to stderr. +fc_error() { + if [ "$QUIET" = false ]; then + echo >&2 -e "[ERROR] $1" + fi +} +# Echoes a warning to stderr. +fc_warn() { + if [ "$QUIET" = false ]; then + echo >&2 -e "[WARN] $1" + fi +} +# Echoes an info message to stdout. +fc_info() { + if [ "$QUIET" = false ]; then + echo -e "[INFO] $1" + fi +} + +# Parses the startup arguments into variables. +parseArguments() { + while [[ $# > 0 ]]; do + key="$1" + case $key in + # help + -h | --help) + printUsage + exit 0 + ;; + # quiet mode + -q | --quiet) + QUIET=true + ;; + # user + -u | --user) + shift + OS_USER="$1" + ;; + # local repository + -r | --local-repository) + shift + LOCAL_REPOSITORY="$1" + ;; + # remote repository + -b | --remote-repository) + shift + REMOTE_REPOSITORY="$1" + ;; + # password file + -p | --password-file) + shift + PASSWORD_FILE="$1" + ;; + # log file directory + -l | --log-file-dir) + shift + LOG_FILE_DIR="$1" + ;; + # notification mail address + -m | --notification-mail-address) + shift + NOTIFICATION_ADDRESS="$1" + ;; + # unknown option + -*) + fc_error "Unknown option '$key'!" + return 2 + ;; + # parameter + *) + if ! handleParameter "$1"; then + fc_error 'Too many arguments!' + return 2 + fi + ;; + esac + shift + done + + # check for valid number of parameters + if [ -z "$BACKUP_SOURCE_DIR" ]; then + fc_error 'Too few arguments!' + return 2 + fi + + ########################## + # check parameter validity + ########################## + if [ -z "$LOCAL_REPOSITORY" ]; then + fc_error 'No local backup repository specified!' + return 2 + fi + if [ -z "$REMOTE_REPOSITORY" ]; then + fc_error 'No remote backup repository specified!' + return 2 + fi + if [ -z "$PASSWORD_FILE" ]; then + fc_error 'No password file specified!' + return 2 + fi +} + +# Handles the parameters (arguments that aren't an option) and checks if their count is valid. +handleParameter() { + # 1. parameter: backup source directory + if [ -z "$BACKUP_SOURCE_DIR" ]; then + BACKUP_SOURCE_DIR="${1%/}" + else + # too many parameters + return 1 + fi +} + +############################## +# main script function section +############################## +fc_unlock_repository() { + restic unlock -q -r "$1" -p "$PASSWORD_FILE" +} +fc_init_repository() { + if ! fc_unlock_repository "$1"; then + fc_info "Initializing repository '$1'." + restic init -o sftp.command="ssh {{ restic_ssh_config_entry }} -s sftp" -r "$1" -p "$PASSWORD_FILE" + fi +} +fc_init_local_repository() { + sudo chown -R "$OS_USER:" "$LOCAL_REPOSITORY" + if ! fc_init_repository "$LOCAL_REPOSITORY"; then + fc_notify "$LOCAL_BACKUP_FAILED" "Initializing local repository '$LOCAL_REPOSITORY' failed!" + return 1 + fi +} +fc_init_remote_repository() { + if ! fc_init_repository "$REMOTE_REPOSITORY"; then + fc_notify "$PUSHING_BACKUP_FAILED" "Initializing remote repository '$REMOTE_REPOSITORY' failed!" + return 1 + fi +} +fc_create_local_backup() { + local rc=0 + fc_info "Backing up '$BACKUP_SOURCE_DIR' to repository '$LOCAL_REPOSITORY'." + if ! sudo restic backup -r "$LOCAL_REPOSITORY" -p "$PASSWORD_FILE" "$BACKUP_SOURCE_DIR"; then + rc=1 + fc_notify "$LOCAL_BACKUP_FAILED" "Creating the local backup for '$BACKUP_SOURCE_DIR' failed!" + fi + sudo chown -R "$OS_USER:" "$LOCAL_REPOSITORY" + return "$rc" +} +fc_check_local_repository() { + fc_info "Verifying the integrity of backups in repository '$LOCAL_REPOSITORY'." + if ! restic check -q -r "$LOCAL_REPOSITORY" -p "$PASSWORD_FILE"; then + fc_notify "$INTEGRITY_LOSS" "Integrity loss in backup repository '$LOCAL_REPOSITORY'!" + return 1 + fi +} +fc_push_local_backups_to_remote() { + fc_info "Pushing the backup to '$REMOTE_REPOSITORY'." + if ! restic copy -o sftp.command="ssh {{ restic_ssh_config_entry }} -s sftp" -q -r "$REMOTE_REPOSITORY" -p "$PASSWORD_FILE" --from-repo "$LOCAL_REPOSITORY" --from-password-file "$PASSWORD_FILE"; then + fc_notify "$PUSHING_BACKUP_FAILED" "Pushing the local backups of '$LOCAL_REPOSITORY' to '$REMOTE_REPOSITORY' failed!" + return 1 + fi +} +fc_notify() { + if [ -n "$NOTIFICATION_ADDRESS" ]; then + local mail_subject="$1" + local mail_introduction="$2" + if ! { + echo "$mail_introduction" + echo -e "\nLog:\n" + cat "$LOG_FILE" + } | mail -s "$mail_subject" -- "$NOTIFICATION_ADDRESS"; then + fc_error 'Failed to notify the user!' + fi + fi +} + +############# +# entry point +############# +parseArguments "$@" +SUCCESS=$? +if [ "$SUCCESS" -ne 0 ]; then + fc_error "Use the '-h' switch for help." + exit "$SUCCESS" +fi + +# create log file directory +if [ ! -d "$LOG_FILE_DIR" ]; then + mkdir -p "$LOG_FILE_DIR" +fi +LOG_FILE="$LOG_FILE_DIR/restic-$(date --iso-8601).log" + +echo >>"$LOG_FILE" 2>&1 +echo '---------------' >>"$LOG_FILE" 2>&1 +date >>"$LOG_FILE" 2>&1 + +# perform local backup; then copy it to the remote location +fc_init_local_repository >>"$LOG_FILE" 2>&1 && + fc_create_local_backup >>"$LOG_FILE" 2>&1 && + fc_check_local_repository >>"$LOG_FILE" 2>&1 && + fc_init_remote_repository >>"$LOG_FILE" 2>&1 && + fc_push_local_backups_to_remote >>"$LOG_FILE" 2>&1 && + fc_info 'Backup has been created successfully.' >>"$LOG_FILE" 2>&1 && + fc_notify "$BACKUP_SUCCEEDED" "Backup has been created successfully." diff --git a/roles/restic/templates/ssh/config b/roles/restic/templates/ssh/config new file mode 100644 index 0000000..47356a6 --- /dev/null +++ b/roles/restic/templates/ssh/config @@ -0,0 +1,6 @@ +Host {{ restic_ssh_config_entry }} + Hostname {{ backup.remote_host }} + User {{ nas.user.name }} + PubKeyAuthentication yes + IdentityFile {{ nas_ssh_dir }}/{{ backup.remote_ssh_key_id }} + IdentitiesOnly yes diff --git a/roles/samba/tasks/main.yml b/roles/samba/tasks/main.yml index 40ff41c..db5c0c5 100644 --- a/roles/samba/tasks/main.yml +++ b/roles/samba/tasks/main.yml @@ -25,7 +25,12 @@ block: "{{ lookup('template', 'smb.conf.j2') }}" validate: testparm -s %s -- name: configure service +- name: configure firewall + ufw: + rule: allow + name: Samba + +- name: enable service: name: smbd state: started diff --git a/roles/samba/templates/smb.conf.j2 b/roles/samba/templates/smb.conf.j2 index dd08d97..46e68e3 100644 --- a/roles/samba/templates/smb.conf.j2 +++ b/roles/samba/templates/smb.conf.j2 @@ -23,7 +23,7 @@ copy = template-private available = yes comment = Private share for user '{{ user.name }}'. - path = {{ backup_location }}/{{ user.backup_folder_name }} + path = {{ nas.userdata_path }}/{{ user.backup_folder_name | default(user.name) }} valid users = {{ user.name }} write list = {{ user.name }} {% endfor %} diff --git a/roles/sshd/meta/main.yml b/roles/sshd/meta/main.yml deleted file mode 100644 index 4dbac4a..0000000 --- a/roles/sshd/meta/main.yml +++ /dev/null @@ -1,2 +0,0 @@ -dependencies: - - role: os diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml index 322d7a3..109d927 100644 --- a/roles/sshd/tasks/main.yml +++ b/roles/sshd/tasks/main.yml @@ -1,4 +1,12 @@ -- name: "copy SSH keys" +- name: register SSH key of linked realms + include_tasks: ssh_id_copy.yml + vars: + user: + name: "{{ nas.user.name }}" + authorized_keys: + - "{{ nas.authorized_keys }}" + +- name: register SSH keys of users include_tasks: ssh_id_copy.yml with_items: "{{ users }}" loop_control: diff --git a/roles/ssmtp/tasks/main.yml b/roles/ssmtp/tasks/main.yml index 4f2b1c5..ee5a833 100644 --- a/roles/ssmtp/tasks/main.yml +++ b/roles/ssmtp/tasks/main.yml @@ -6,17 +6,19 @@ - bsd-mailx cache_valid_time: 600 -- name: configure +- name: configure msmtp template: src: "msmtprc.j2" dest: /etc/msmtprc owner: root - mode: 0600 + group: msmtp + mode: 0640 -- name: set alias +- name: set mail alias lineinfile: path: /etc/aliases line: "root:{{ mailing_from }}" + create: yes register: alias - name: set root name (mail sender) diff --git a/roles/ufw/tasks/main.yml b/roles/ufw/tasks/main.yml index 2e52ef6..a16caeb 100644 --- a/roles/ufw/tasks/main.yml +++ b/roles/ufw/tasks/main.yml @@ -18,37 +18,8 @@ rule: limit name: OpenSSH -- name: allow access to Samba - ufw: - rule: allow - name: Samba - when: "('samba' in ansible_run_tags and 'ufw' in ansible_run_tags) or ('all' in ansible_run_tags)" - register: ufw_samba - -- name: allow DLNA communication - ufw: - rule: allow - proto: "{{ item.proto }}" - to_port: "{{ item.to_port }}" - with_items: - - to_port: 8200 - proto: tcp - - to_port: 1900 - proto: udp - when: "('dlna' in ansible_run_tags and 'ufw' in ansible_run_tags) or ('all' in ansible_run_tags)" - register: ufw_dlna - -- name: allow HTTP(S) communication - ufw: - rule: allow - proto: tcp - to_port: 80,443 - when: "('cloud' in ansible_run_tags and 'ufw' in ansible_run_tags) or ('all' in ansible_run_tags)" - register: ufw_http - -- name: enable/reload service +- name: enable service service: name: ufw - state: "{{ (ufw_samba.changed or ufw_dlna.changed or ufw_http.changed) | ternary('restarted', omit) }}" enabled: yes when: not running_in_container diff --git a/roles/userdata/defaults/main.yml b/roles/userdata/defaults/main.yml new file mode 100644 index 0000000..2ac7932 --- /dev/null +++ b/roles/userdata/defaults/main.yml @@ -0,0 +1,2 @@ +nas_userdata_base_directory_mode: 0755 +nas_userdata_directory_mode: 0750 diff --git a/roles/userdata/tasks/main.yml b/roles/userdata/tasks/main.yml new file mode 100644 index 0000000..bcf97b8 --- /dev/null +++ b/roles/userdata/tasks/main.yml @@ -0,0 +1,23 @@ +- name: create userdata location + file: + path: "{{ nas.userdata_path }}" + state: directory + owner: "{{ nas.user.name }}" + group: "{{ nas.user.name }}" + mode: "{{ nas_userdata_base_directory_mode }}" + force: yes + tags: nas + +- name: create a directory for each user and enforce secure permissions + file: + path: "{{ nas.userdata_path }}/{{ user.backup_folder_name | default(user.name) }}" + state: directory + owner: "{{ user.name }}" + group: "{{ user.name }}" + mode: "{{ nas_userdata_directory_mode }}" + force: yes + loop: "{{ users }}" + loop_control: + loop_var: user + label: "{{ user.name }}" + tags: nas diff --git a/setup.yml b/setup.yml index 6e13614..8206798 100644 --- a/setup.yml +++ b/setup.yml @@ -6,14 +6,26 @@ vars: ansible_python_interpreter: /usr/bin/python3 roles: + - role: os + tags: os + - role: sshd + tags: sshd + - role: ufw + tags: ufw - role: mount tags: mount - - role: backups - tags: always + - role: userdata + tags: userdata + - role: restic + tags: backup - role: auto-upgrade tags: auto-upgrade - role: dynv6 tags: ddns + - role: openvpn-init + tags: openvpn-init + - role: openvpn + tags: openvpn-config - role: samba tags: samba - role: minidlna @@ -22,5 +34,5 @@ tags: mumble - role: nextcloud tags: cloud - - role: ufw - tags: ufw + - role: aftercare + tags: always