move roles, files and templates dirs out of playbook dir into root dir

Because of how Ansible local relative search paths work, the global
"files" and "templates" directories need to be next to the playbooks.
However its not intuitive to look into the "playbooks" directory to find
the files and templates for a host.
Therefore move them out of the "playbooks" directory into the root
directory and add symlinks so everything still works.

Similarly for local roles, they also need to be next to the playbooks.
So for a nicer structure, move the "roles" directory out into the root
directory as well and add a symlink so everything still works.

Also see:
https://docs.ansible.com/ansible/latest/playbook_guide/playbook_pathing.html#resolving-local-relative-paths
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#storing-and-finding-roles
This commit is contained in:
June 2024-12-02 03:34:55 +01:00
parent 2460c31e78
commit f16f8697c2
Signed by: june
SSH key fingerprint: SHA256:o9EAq4Y9N9K0pBQeBTqhSDrND5E7oB+60ZNx0U1yPe0
147 changed files with 3 additions and 0 deletions
roles
add_apt_repository
apt_update_and_upgrade
certbot
deploy_ssh_server_config
distribution_check
docker
docker_compose
dokuwiki
foobazdmx
infrastructure_authorized_keys
nextcloud
nginx
ola
prometheus_node_exporter

View file

@ -0,0 +1,25 @@
---
argument_specs:
main:
short_description: Add a 3rd party apt repository to the system
options:
add_apt_repository__https_repo:
description: The repository URL uses HTTPS
required: true
type: bool
add_apt_repository__keyring_url:
description: URL to the repository's keyring
required: false
type: str
add_apt_repository__keyring_path:
description: Path where to store the keyring
required: false
type: str
add_apt_repository__repo:
description: The apt source line
required: true
type: str
add_apt_repository__filename:
description: Filename in /etc/apt/sources.list.d/
required: true
type: str

View file

@ -0,0 +1,33 @@
---
- name: Check OS family
ansible.builtin.fail:
msg: "Can only add apt repositories on Debian-based systems!"
when: ansible_facts.os_family != "Debian"
- name: Install required apt packages for adding an apt repository
become: true
ansible.builtin.apt:
name:
- ca-certificates
- gnupg
- name: Install apt-transport-https if https repository
become: true
ansible.builtin.apt:
name: apt-transport-https
when: add_apt_repository__https_repo
- name: Add repository signing key to keychain
become: true
when: add_apt_repository__keyring_url is defined and add_apt_repository__keyring_path is defined
ansible.builtin.apt_key:
url: "{{ add_apt_repository__keyring_url }}"
keyring: "{{ add_apt_repository__keyring_path }}"
state: present
- name: Add repository and update cache
become: true
ansible.builtin.apt_repository:
repo: "{{ add_apt_repository__repo }}"
filename: "{{ add_apt_repository__filename }}"
update_cache: true

View file

@ -0,0 +1,11 @@
# Role `apt_update_and_upgrade`
This role does an `apt-get update`, `apt-get dist-upgrade` and a potential reboot (if packages got upgraded) on the specified hosts.
## `hosts`
The `hosts` for this role need to be the VMs, which should be updated and upgraded.
## Required Variables
This role doesn't have any required variables.

View file

@ -0,0 +1,3 @@
- name: reboot the system
become: true
ansible.builtin.reboot:

View file

@ -0,0 +1,13 @@
- name: update, upgrade and potentially reboot
become: true
block:
- name: apt-get update
ansible.builtin.apt:
update-cache: true
- name: apt-get dist-upgrade
ansible.builtin.apt:
upgrade: dist
register: apt_update_and_upgrade__upgrade_result
notify:
- reboot the system

15
roles/certbot/README.md Normal file
View file

@ -0,0 +1,15 @@
# Role `certbot`
A role for deploying Certbot and setting up certificates using it.
Note: This role doesn't take care of deleting certificates.
Also see the following documentation for a full How-to on how to get certificates using this role in the context of our infra: <https://wiki.ccchh.net/infrastructure:zertifikate>.
## Required Arguments
For the required arguments look at the [`argument_specs.yaml`](./meta/argument_specs.yaml).
## `hosts`
The `hosts` for this role need to be the machines on which you want to make sure Certbot is deployed and given certificates are set up.

View file

@ -0,0 +1,2 @@
certbot__http_01_port: 31820
certbot__new_cert_commands: [ ]

View file

@ -0,0 +1,36 @@
argument_specs:
main:
options:
certbot__version_spec:
description: >-
The version specification to use for installing the `certbot` package.
The provided version specification will be used like the following:
`cerbot={{ certbot__version_spec }}*`. This makes it possible to e.g.
specify until a minor version (like `1.3.`) and then have patch
versions be installed automatically (like `1.3.1` and so on).
type: str
required: true
certbot__acme_account_email_address:
description: The E-Mail address to give to certbot for the ACME account.
type: str
required: true
certbot__certificate_domains:
description: The domains for which to obtain a certificate.
type: list
elements: str
required: true
certbot__http_01_port:
description: |
The port number the bot listens on. Must be 80 if directly exposed to the internet.
Default is 31820 for the public-reverse-proxy setup.
type: str
required: false
default: 31820
certbot__new_cert_commands:
description: >-
A list of commands to execute after getting a new certificate.
Will be added into a bash script.
type: list
elements: str
required: false
default: [ ]

View file

@ -0,0 +1,9 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- 11
- 12

View file

@ -0,0 +1,11 @@
- name: ensure certbot installation
ansible.builtin.import_tasks:
file: main/install.yaml
- name: ensure new cert commands
ansible.builtin.import_tasks:
file: main/new_cert_commands.yaml
- name: ensure certificates
ansible.builtin.import_tasks:
file: main/certs.yaml

View file

@ -0,0 +1,24 @@
- name: get expiry date before
ansible.builtin.command: /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/{{ item }}/fullchain.pem
ignore_errors: true
become: true
changed_when: false
register: certbot__cert_expiry_before
- name: obtain the certificate using certbot
ansible.builtin.command: /usr/bin/certbot certonly --keep-until-expiring --agree-tos --non-interactive --email "{{ certbot__acme_account_email_address }}" --no-eff-email --standalone --http-01-port "{{ certbot__http_01_port }}" -d "{{ item }}"
become: true
changed_when: false
- name: get expiry date after
ansible.builtin.command: /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/{{ item }}/fullchain.pem
become: true
changed_when: false
register: certbot__cert_expiry_after
# Doesn't work anymore. Dunno why.
# TODO: Fix
# - name: potentially report changed
# ansible.builtin.debug:
# msg: "If this reports changed, then the certificate expiry date and therefore the certificate changed."
# changed_when: certbot__cert_expiry_before.stdout != certbot__cert_expiry_after.stdout

View file

@ -0,0 +1,4 @@
- name: obtain certificates
loop: "{{ certbot__certificate_domains }}"
ansible.builtin.include_tasks:
file: main/cert.yaml

View file

@ -0,0 +1,19 @@
- name: make sure the `openssl` package is installed
ansible.builtin.apt:
name: openssl
state: present
become: true
- name: make sure the `certbot` package is installed
ansible.builtin.apt:
name: certbot={{ certbot__version_spec }}*
state: present
allow_change_held_packages: true
update_cache: true
become: true
- name: apt-mark hold `certbot`
ansible.builtin.dpkg_selections:
name: certbot
selection: hold
become: true

View file

@ -0,0 +1,17 @@
- name: ensure existence of renewal deploy hooks directory
ansible.builtin.file:
path: /etc/letsencrypt/renewal-hooks/deploy
state: directory
owner: root
group: root
mode: "0755"
become: true
- name: ensure renewal deploy hook commands
ansible.builtin.template:
src: renewal_deploy_hook_commands.sh.j2
dest: /etc/letsencrypt/renewal-hooks/deploy/ansible_commands.sh
owner: root
group: root
mode: "0770"
become: true

View file

@ -0,0 +1,4 @@
#!/bin/bash
{% for command in certbot__new_cert_commands %}
{{ command }}
{% endfor %}

View file

@ -0,0 +1,17 @@
# Role `deploy_ssh_server_config`
This role deploys an SSH server config on the specified hosts.
## `hosts`
The `hosts` for this role need to be the machines, for which you want to deploy an SSH server config.
## Required Variables
This role doesn't have nay required variables.
## Links & Resources
- <https://infosec.mozilla.org/guidelines/openssh>
- Also see [Debian 11 cloud 2023-04-21 default /etc/ssh/sshd_config](docs/Debian_11_cloud_2023-04-21_default_etc_ssh_sshd_config).
- Also see [Debian 12 cloud 2023-07-25 default /etc/ssh/sshd_config](docs/Debian_12_cloud_2023-07-25_default_etc_ssh_sshd_config).

View file

@ -0,0 +1,124 @@
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
ClientAliveInterval 120

View file

@ -0,0 +1,123 @@
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
KbdInteractiveAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin prohibit-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
ClientAliveInterval 120

View file

@ -0,0 +1,3 @@
- name: reboot the system
become: true
ansible.builtin.reboot:

View file

@ -0,0 +1,36 @@
# Role and config created after: https://infosec.mozilla.org/guidelines/openssh
- name: deploy SSH server config
become: true
block:
- name: deploy `sshd_config`
ansible.builtin.template:
force: true
dest: /etc/ssh/sshd_config
mode: "0644"
owner: root
group: root
src: sshd_config.j2
notify:
# Reboot instead of just restarting the ssh service, since I don't know how Ansible reacts, when it restarts the service it probably needs for the connection.
- reboot the system
- name: deactivate short moduli
ansible.builtin.shell:
executable: /bin/bash
cmd: |
set -eo pipefail
awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.tmp
if diff /etc/ssh/moduli /etc/ssh/moduli.tmp; then
rm /etc/ssh/moduli.tmp
else
mv /etc/ssh/moduli.tmp /etc/ssh/moduli
echo "ansible-changed: changed /etc/ssh/moduli"
fi
register: result
changed_when:
- '"ansible-changed" in result.stdout'
notify:
# Reboot instead of just restarting the ssh service, since I don't know how Ansible reacts, when it restarts the service it probably needs for the connection.
- reboot the system

View file

@ -0,0 +1,97 @@
# This is the sshd server system-wide configuration file deployed and managed by
# Ansible.
# See sshd_config(5) and the "deploy_ssh_server_config" Ansible role for more
# information.
# This config doesn't set all options and leaves some to the sshd defaults.
# The sshd defaults should be alright, so this config is only really setting
# options in cases where we want to intentionally have an option a certain way
# for some reason or another. For example for hardening, improved loggin, etc.
## Use the HostKey preference, Ciphers and algorithms from Mozillas Modern
## guidelines.
# Supported HostKey algorithms by order of preference.
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
## Authentication Settings.
# Require only "publickey" for authentication.
# From Mozillas Modern guidelines.
AuthenticationMethods publickey
# Enable "PubkeyAuthentication" accordingly.
PubkeyAuthentication yes
# Don't do the other authentication types.
PasswordAuthentication no
{# If on Debian 12, use the new keyword (KbdInteractiveAuthentication instead of ChallengeResponseAuthentication). #}
{% if ansible_facts["distribution"] == "Debian" and ansible_facts["distribution_major_version"] == "12" %}
KbdInteractiveAuthentication no
{% else %}
ChallengeResponseAuthentication no
{% endif %}
KerberosAuthentication no
GSSAPIAuthentication no
# Don't allow root login.
PermitRootLogin no
{# If on Debian 12, use the new keyword (KbdInteractiveAuthentication instead of ChallengeResponseAuthentication). #}
{% if ansible_facts["distribution"] == "Debian" and ansible_facts["distribution_major_version"] == "12" %}
# Set this to "yes", but have "PasswordAuthentication" and
# "KbdInteractiveAuthentication" set to "no", to have account and session checks
# run.
{% else %}
# Set this to "yes", but have "PasswordAuthentication" and
# "ChallengeResponseAuthentication" set to "no", to have account and session
# checks run.
{% endif %}
# See "docs/Debian_11_cloud_2023-04-21_default_etc_ssh_sshd_config" for more
# information.
UsePAM yes
## Miscellaneous Settings.
# X11 forwarding shouldn't be needed.
X11Forwarding no
# Printing this isn't needed.
PrintMotd no
# Print time and date of last login, since that's nice.
PrintLastLog yes
# Disable general environment processing.
PermitUserEnvironment no
# Allow client to pass locale environment variables.
# From "docs/Debian_11_cloud_2023-04-21_default_etc_ssh_sshd_config".
AcceptEnv LANG LC_*
# Request response from client after 120 seconds of no communication.
# Taken from "docs/Debian_11_cloud_2023-04-21_default_etc_ssh_sshd_config".
ClientAliveInterval 120
## Logging
# Set "LogLevel" to "VERBOSE" to log users key fingerprints on login.
# This is needed for a clear audit track.
# From Mozillas Modern guidelines.
LogLevel VERBOSE
# Enable the sftp subsystem and log properly.
# From Mozillas Modern guidelines and
# "docs/Debian_11_cloud_2023-04-21_default_etc_ssh_sshd_config".
Subsystem sftp /usr/lib/openssh/sftp-server -f AUTHPRIV -l INFO

View file

@ -0,0 +1,13 @@
# Role `distribution_check`
This role checks if the distribution of the hosts is supported (part of the provided distribution support spec.) and fails if it's not.
If a hosts distribution and either an accompanying distribution version, major version or release is supported, the role doesn't fail for the host in question.
## Required Arguments
For the required arguments look at the [`argument_specs.yaml`](./meta/argument_specs.yaml).
## `hosts`
The `hosts` for this role need to be the machines for which you want to make sure their distribution is supported.

View file

@ -0,0 +1,28 @@
argument_specs:
main:
options:
distribution_check__distribution_support_spec:
description: A spec specifying the supported distribution.
type: list
elements: dict
required: true
options:
name:
description: The name of the supported distribution.
type: str
required: true
versions:
description: The supported versions of the supported distribution.
type: list
elements: str
required: false
major_versions:
description: The supported major versions of the supported distribution.
type: list
elements: str
required: false
releases:
description: The supported releases of the supported distribution.
type: list
elements: str
required: false

View file

@ -0,0 +1,53 @@
- name: set fact holding list of supported distribution names
ansible.builtin.set_fact:
distribution_check__supported_distribution_names: "{{ distribution_check__distribution_support_spec
| community.general.json_query('[].name') }}"
- name: fail on unsupported distribution (name)
ansible.builtin.fail:
msg: The hosts distribution (name) isn't supported.
when: ansible_facts['distribution'] not in distribution_check__supported_distribution_names
- name: set facts for holding lists of supported distribution versions, major versions and releases
block:
- name: set fact holding list of supported distribution versions
ansible.builtin.set_fact:
distribution_check__supported_distribution_versions: "{{ distribution_check__distribution_support_spec
| community.general.json_query(distribution_check__supported_distribution_versions_query) }}"
vars:
distribution_check__supported_distribution_versions_query: "[?name=='{{ ansible_facts['distribution'] }}'].versions | [].to_string(@)"
- name: set fact holding list of supported distribution major versions
ansible.builtin.set_fact:
distribution_check__supported_distribution_major_versions: "{{ distribution_check__distribution_support_spec
| community.general.json_query(distribution_check__supported_distribution_major_versions_query) }}"
vars:
distribution_check__supported_distribution_major_versions_query: "[?name=='{{ ansible_facts['distribution'] }}'].major_versions | [].to_string(@)"
- name: set fact holding list of supported distribution releases
ansible.builtin.set_fact:
distribution_check__supported_distribution_releases: "{{ distribution_check__distribution_support_spec
| community.general.json_query(distribution_check__supported_distribution_releases_query) }}"
vars:
distribution_check__supported_distribution_releases_query: "[?name=='{{ ansible_facts['distribution'] }}'].releases | [].to_string(@)"
- name: check for distribution version, major version and release support
block:
- name: set fact on whether the distribution version is supported
ansible.builtin.set_fact:
distribution_check__distribution_version_supported: "{{ ansible_facts['distribution_version'] in distribution_check__supported_distribution_versions }}"
- name: set fact on whether the distribution major version is supported
ansible.builtin.set_fact:
distribution_check__distribution_major_version_supported: "{{ ansible_facts['distribution_major_version'] in distribution_check__supported_distribution_major_versions }}" # noqa: yaml[line-length]
- name: set fact on whether the distribution release is supported
ansible.builtin.set_fact:
distribution_check__distribution_release_supported: "{{ ansible_facts['distribution_release'] in distribution_check__supported_distribution_releases }}"
- name: fail, if neither the distributions version, major version or release is supported
ansible.builtin.fail:
msg: Neither the hosts distribution version, major version or release is supported.
when: not (distribution_check__distribution_version_supported
or distribution_check__distribution_major_version_supported
or distribution_check__distribution_release_supported)

27
roles/docker/README.md Normal file
View file

@ -0,0 +1,27 @@
# Role `docker`
Makes sure Docker Engine and other related packages are installed from the Docker repos on the specified hosts.
For details see: [`tasks/main/02_docker_install.yaml`](./tasks/main/02_docker_install.yaml).
## Supported Distributions
The following distributions are supported:
- Debian 11
## Required Arguments
None.
## Updates
This role doesn't handle updates.
However it uses the system package manager for installing Docker Engine and the other related packages, so when you're making sure the system packages are up-to-date, you're handling updates for the packages installed by this role as well.
## `hosts`
The `hosts` for this role need to be the machines for which you want to make sure Docker Engine and other related packages are installed from the Docker repos.
## Links & Resources
- <https://docs.docker.com/engine/install/debian/>

View file

@ -0,0 +1,9 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- 11
- 12

View file

@ -0,0 +1,7 @@
- name: make sure the Docker repo is setup
ansible.builtin.import_tasks:
file: main/01_repo_setup.yaml
- name: make sure Docker Engine and other related packages are installed
ansible.builtin.import_tasks:
file: main/02_docker_install.yaml

View file

@ -0,0 +1,15 @@
- name: make sure Dockers GPG key is added
ansible.builtin.get_url:
url: https://download.docker.com/linux/debian/gpg
dest: /etc/apt/trusted.gpg.d/docker.asc
mode: "0644"
owner: root
group: root
become: true
- name: make sure Dockers APT repository is added
ansible.builtin.apt_repository:
repo: "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/docker.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
filename: docker
state: present
become: true

View file

@ -0,0 +1,11 @@
- name: make sure Docker Engine and other related packages are installed
ansible.builtin.apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: present
update_cache: true
become: true

View file

@ -0,0 +1,34 @@
# Role `docker_compose`
A role for deploying a Docker-Compose-based application.
It deploys the given Compose file as well as configuration files to the specified hosts and makes sure all services are up-to-date and running.
The Compose file gets deployed to `/ansible_docker_compose/compose.yaml` and the configuration files get deployed into the `/ansible_docker_compose/configs/` directory.
A use case for the deployment of the additional configuration files is Composes top-level element `configs` in conjunction with the `configs` option for services.
## Supported Distributions
The following distributions are supported:
- Debian 11
## Required Arguments
For the required arguments look at the [`argument_specs.yaml`](./meta/argument_specs.yaml).
## `hosts`
The `hosts` for this role need to be the machines, for which you want to make sure the given Compose file is deployed and all services of it are up-to-date and running.
## Links & Resources
- <https://docs.docker.com/compose/>
- <https://docs.docker.com/compose/compose-v2/>
- <https://docs.docker.com/compose/production/>
- <https://docs.docker.com/compose/startup-order/>
- <https://docs.docker.com/compose/compose-file/>
- <https://docs.docker.com/compose/compose-file/03-compose-file/>
- <https://docs.docker.com/compose/compose-file/08-configs/>
- <https://docs.docker.com/compose/compose-file/05-services/#configs>
- <https://docs.docker.com/engine/reference/commandline/compose_up/>
- <https://docs.docker.com/engine/reference/commandline/compose_ps/>
- <https://docs.docker.com/engine/reference/commandline/compose_down/>

View file

@ -0,0 +1 @@
docker_compose__configuration_files: [ ]

View file

@ -0,0 +1,6 @@
- name: docker compose down
ansible.builtin.command:
cmd: /usr/bin/docker compose down
chdir: /ansible_docker_compose
become: true
changed_when: true # This is always changed.

View file

@ -0,0 +1,26 @@
argument_specs:
main:
options:
docker_compose__compose_file_content:
description: >-
The content of the Compose file at
`/ansible_docker_compose/compose.yaml`.
type: str
required: true
docker_compose__configuration_files:
description: >-
A list of configuration files to be deployed in the
`/ansible_docker_compose/configs/` directory.
type: list
elements: dict
required: false
default: [ ]
options:
name:
description: The name of the configuration file.
type: str
required: true
content:
description: The content of the configuration file.
type: str
required: true

View file

@ -0,0 +1,10 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- 11
- 12
- role: docker

View file

@ -0,0 +1,121 @@
- name: make sure the `/ansible_docker_compose` directory exists
ansible.builtin.file:
path: /ansible_docker_compose
state: directory
mode: "0755"
owner: root
group: root
become: true
- name: deploy the Compose file
ansible.builtin.copy:
content: "{{ docker_compose__compose_file_content }}"
dest: /ansible_docker_compose/compose.yaml
mode: "0644"
owner: root
group: root
become: true
notify: docker compose down
- name: make sure the `/ansible_docker_compose/configs` directory exists
ansible.builtin.file:
path: /ansible_docker_compose/configs
state: directory
mode: "0755"
owner: root
group: root
become: true
- name: set `docker_compose__config_files_to_exist` fact initially to an empty list
ansible.builtin.set_fact:
docker_compose__config_files_to_exist: [ ]
- name: add names from `docker_compose__configuration_files` to `docker_compose__config_files_to_exist` fact
ansible.builtin.set_fact:
docker_compose__config_files_to_exist: "{{ docker_compose__config_files_to_exist + [ item.name ] }}" # noqa: jinja[spacing]
loop: "{{ docker_compose__configuration_files }}"
- name: find configuration files to remove
ansible.builtin.find:
paths: /ansible_docker_compose/configs/
recurse: false
excludes: "{{ docker_compose__config_files_to_exist }}"
register: docker_compose__config_files_to_remove
- name: remove all configuration files, which should be removed
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
become: true
loop: "{{ docker_compose__config_files_to_remove.files }}"
# notify: docker compose down
- name: make sure all given configuration files are deployed
ansible.builtin.copy:
content: "{{ item.content }}"
dest: "/ansible_docker_compose/configs/{{ item.name }}"
mode: "0644"
owner: root
group: root
become: true
loop: "{{ docker_compose__configuration_files }}"
# notify: docker compose down
- name: Flush handlers to make "docker compose down" handler run now
ansible.builtin.meta: flush_handlers
- name: docker compose ps --format json before docker compose up
ansible.builtin.command:
cmd: /usr/bin/docker compose ps --format json
chdir: /ansible_docker_compose
become: true
changed_when: false
register: docker_compose__ps_json_before_up
- name: docker compose up --detach --pull always --build
ansible.builtin.command:
cmd: /usr/bin/docker compose up --detach --pull always --build --remove-orphans
chdir: /ansible_docker_compose
become: true
changed_when: false
# The changed for this task is tried to be determined by the "potentially
# report changed" task together with the "docker compose ps --format json
# [...]" tasks.
- name: docker compose ps --format json after docker compose up
ansible.builtin.command:
cmd: /usr/bin/docker compose ps --format json
chdir: /ansible_docker_compose
become: true
changed_when: false
register: docker_compose__ps_json_after_up
# Doesn't work anymore. Dunno why.
# TODO: Fix
# - name: potentially report changed
# ansible.builtin.debug:
# msg: "If this reports changed, then the docker compose containers changed."
# changed_when: (docker_compose__ps_json_before_up.stdout | from_json | community.general.json_query('[].ID') | sort)
# != (docker_compose__ps_json_after_up.stdout | from_json | community.general.json_query('[].ID') | sort)
- name: Make sure anacron is installed
become: true
ansible.builtin.package:
name: anacron
state: present
- name: Install automatic update cron job
become: true
ansible.builtin.cron:
name: 'docker compose auto update'
minute: "0"
hour: "5"
job: "cd /ansible_docker_compose; docker compose pull && docker compose up -d"
- name: Install automatic cleanup cron job
become: true
ansible.builtin.cron:
name: 'docker compose auto update'
minute: "23"
hour: "4"
job: "docker system prune -a -f"

49
roles/dokuwiki/README.md Normal file
View file

@ -0,0 +1,49 @@
# Role `dokuwiki`
Makes sure that all required packages for a [DokuWiki](https://www.dokuwiki.org/dokuwiki) powered by php-fpm are installed.
The DokuWiki tarball has to be unpacked to `/var/www/dokuwiki` (see variable below) manually afterwards.
Please download it from https://download.dokuwiki.org.
## Supported Distributions
The following distributions are supported:
- Debian 11
## Required Arguments
None.
## Optional Argument
- `dokuwiki__installpath`: Where your DokiWiki lives, default `/var/www/dokuwiki`
- `dokuwiki__php_version`: Your PHP version, default `7.4`
- `dokuwiki__php_user`: User of your php-fpm process, default `www-data`
- `dokuwiki__nginx_user`: User of your nginx process, default `nginx`
## nginx Configuration
This role does not configure your nginx server.
Please take a look at https://www.dokuwiki.org/install:nginx for a starting point.
This role expects to work with our `nginx` role, which installs nginx from nginx's repo instead of Debian's package.
This means, that nginx will not run as the `www-data`, which is used by php-fpm.
So your `server` directive in the nginx configuration needs to use:
```conf
root /var/www/dokuwiki;
[...]
location ~ \.php$ {
[...]
fastcgi_pass unix:/var/run/php/php-fpm-dokuwiki.sock;
}
```
## Updates
This role doesn't handle updates.
Please use the updater from Dokuwiki's admin interface to install updates.

View file

@ -0,0 +1,5 @@
---
dokuwiki__installpath: "/var/www/dokuwiki"
dokuwiki__php_version: "7.4"
dokuwiki__php_user: "www-data"
dokuwiki__nginx_user: "nginx"

View file

@ -0,0 +1,5 @@
# See here: https://www.dokuwiki.org/mime
# Allow stl files.
stl !model/stl
asc application/pgp-keys

View file

@ -0,0 +1,5 @@
- name: Restart php-fpm
become: true
ansible.builtin.systemd:
name: "php{{ dokuwiki__php_version }}-fpm.service"
state: restarted

View file

@ -0,0 +1,8 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
versions:
- 11

View file

@ -0,0 +1,44 @@
- name: Install php-fpm
become: true
ansible.builtin.apt:
name:
- php-fpm
- php-xml
- php-mbstring
- php-zip
- php-intl
- php-gd
- php-sqlite3
diff: false
- name: Ensure `php-fpm` is enabled
become: true
ansible.builtin.systemd:
service: "php{{ dokuwiki__php_version }}-fpm.service"
enabled: true
- name: Create custom php-fpm pool
become: true
ansible.builtin.template:
src: "{{ role_path }}/templates/php-fpm-dokuwiki.conf"
dest: "/etc/php/{{ dokuwiki__php_version }}/fpm/pool.d/dokuwiki.conf"
mode: "0755"
notify: Restart php-fpm
- name: Create `/var/www` directory
become: true
ansible.builtin.file:
path: /var/www
state: directory
owner: "{{ dokuwiki__nginx_user }}"
group: "{{ dokuwiki__nginx_user }}"
mode: "0755"
- name: Allow more mime types to be uploaded
become: true
ansible.builtin.copy:
src: mime.local.conf
dest: /var/www/dokuwiki/conf/mime.local.conf
owner: root
group: root
mode: "0644"

View file

@ -0,0 +1,15 @@
[dokuwiki]
user = {{ dokuwiki__php_user }}
group = {{ dokuwiki__php_user }}
listen = /var/run/php/php-fpm-dokuwiki.sock
listen.owner = {{ dokuwiki__nginx_user }}
listen.group = {{ dokuwiki__nginx_user }}
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
php_admin_flag[allow_url_fopen] = on
; Choose how the process manager will control the number of child processes.
pm = dynamic
pm.max_children = 75
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.process_idle_timeout = 10s

View file

@ -0,0 +1 @@
foobazdmx_version: main

View file

@ -0,0 +1,6 @@
- name: Restart foobazdmx
become: true
ansible.builtin.systemd:
service: foobazdmx.service
state: restarted
daemon-reload: true

View file

@ -0,0 +1,16 @@
---
argument_specs:
main:
options:
foobazdmx_version:
description: git branch, tag, or commit to check out from the foobazdmx repo
type: str
default: main
foobazdmx_repo_url:
description: git repo to pull foobazdmx from
type: str
required: true
foobazdmx__art_net_host:
description: IP oder hostname of the Art-Net server
type: str
required: true

View file

@ -0,0 +1,8 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- "11"

View file

@ -0,0 +1,60 @@
- name: Ensure apt dependencies are installed
become: true
ansible.builtin.apt:
name:
- acl
- git
- python3
- python3-pip
- python3-setuptools
- name: Ensure python peotry is installed
become: true
ansible.builtin.pip:
name: poetry
- name: Ensure foobazdmx user exists
become: true
ansible.builtin.user:
name: foobazdmx
- name: Install foobazdmx
notify: Restart foobazdmx
block:
- name: Clone foobazdmx repository
become: true
ansible.builtin.git:
repo: "{{ foobazdmx_repo_url }}"
dest: /opt/foobazdmx
version: "{{ foobazdmx_version }}"
- name: Install python dependencies
become: true
become_user: foobazdmx
ansible.builtin.command:
cmd: poetry install
chdir: /opt/foobazdmx
changed_when: false
- name: Generate foobazdmx service file
become: true
ansible.builtin.template:
src: foobazdmx.service.j2
dest: /etc/systemd/system/foobazdmx.service
mode: "0755"
- name: Enable and start foobazdmx service
become: true
ansible.builtin.systemd:
service: foobazdmx.service
state: started
enabled: true
- name: Generate foobazdmx-shop service file
become: true
ansible.builtin.template:
src: foobazdmx-shop.service.j2
dest: /etc/systemd/system/foobazdmx-shop.service
mode: "0755"
- name: Enable and start foobazdmx-shop service
become: true
ansible.builtin.systemd:
service: foobazdmx-shop.service
state: started
enabled: true

View file

@ -0,0 +1,10 @@
[Unit]
Description=Foobaz-Shop DMX
[Service]
ExecStart=poetry run python foobaz.py -a {{ foobazdmx__art_net_host }} -l 8081 -r shop -u 2
WorkingDirectory=/opt/foobazdmx
User=foobazdmx
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,10 @@
[Unit]
Description=Foobaz DMX
[Service]
ExecStart=poetry run python foobaz.py -a {{ foobazdmx__art_net_host }} -r big
WorkingDirectory=/opt/foobazdmx
User=foobazdmx
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,3 @@
# Role `infrastructure_authorized_keys`
A role for deploying the infrastructure authorized keys from [this repo](https://gitlab.hamburg.ccc.de/ccchh/infrastructure-authorized-keys).

View file

@ -0,0 +1,6 @@
- name: deploy infrastructure authorized keys
ansible.posix.authorized_key:
state: present
user: chaos
exclusive: true
key: https://git.hamburg.ccc.de/CCCHH/infrastructure-authorized-keys/raw/branch/trunk/authorized_keys

11
roles/nextcloud/README.md Normal file
View file

@ -0,0 +1,11 @@
# Role `nextcloud`
A role for deploying Nextcloud.
Note: PostgreSQL upgrades need manual migration steps.
## Links & Resources
- <https://github.com/nextcloud/docker>
- <https://docs.nextcloud.com/server/latest/admin_manual/index.html>
- <https://github.com/nextcloud/docker/tree/master/.examples/dockerfiles/cron/apache>

View file

@ -0,0 +1,5 @@
nextcloud__nginx_version_spec: ""
nextcloud__certbot_version_spec: ""
nextcloud__extra_configuration: ""
nextcloud__use_custom_new_user_skeleton: false
nextcloud__custom_new_user_skeleton_directory: ""

View file

@ -0,0 +1,22 @@
[supervisord]
nodaemon=true
logfile=/var/log/supervisord/supervisord.log
pidfile=/var/run/supervisord/supervisord.pid
childlogdir=/var/log/supervisord/
logfile_maxbytes=50MB ; maximum size of logfile before rotation
logfile_backups=10 ; number of backed up logfiles
loglevel=error
[program:apache2]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=apache2-foreground
[program:cron]
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
command=/cron.sh

View file

@ -0,0 +1,63 @@
argument_specs:
main:
options:
nextcloud__version:
description: The version label to use for the Nextcloud Docker image.
type: str
required: true
nextcloud__postgres_version:
description: The version label to use for the PostgreSQL Docker image.
type: str
required: true
nextcloud__nginx_version_spec:
description: The version spec. to pass to nginx to use for the nginx version spec.
type: str
required: false
default: ""
nextcloud__certbot_version_spec:
description: The version spec. to pass to certbot to use for the certbot version spec.
type: str
required: false
default: ""
nextcloud__fqdn:
description: The FQDN to use for Nextcloud.
type: str
required: true
nextcloud__data_dir:
description: The directory where to store the Nextcloud data.
type: str
required: true
nextcloud__admin_password:
description: The password to use for the Admin user.
type: str
required: true
nextcloud__extra_configuration:
description: Additional nextcloud configuration.
type: str
required: false
default: ""
nextcloud__use_custom_new_user_skeleton:
description: >-
Enable to make use of the given custom new user skeleton directory.
type: bool
required: false
default: false
nextcloud__custom_new_user_skeleton_directory:
description: >-
Path of to a custom new user skeleton directory to be used by this
role via ansible.builtin.copy.
type: str
required: false
default: ""
nextcloud__postgres_password:
description: The password to use for the nextcloud PostgreSQL user.
type: str
required: true
nextcloud__proxy_protocol_reverse_proxy_ip:
description: The IP of the reverse proxy to do proxy protocol with.
type: str
required: true
nextcloud__certbot_acme_account_email_address:
description: The E-Mail address to pass to certbot to use for the ACME account.
type: str
required: true

View file

@ -0,0 +1,20 @@
---
dependencies:
- role: certbot
vars:
certbot__version_spec: "{{ nextcloud__certbot_version_spec }}"
certbot__acme_account_email_address: "{{ nextcloud__certbot_acme_account_email_address }}"
certbot__certificate_domains:
- "{{ nextcloud__fqdn }}"
certbot__new_cert_commands:
- "systemctl reload nginx.service"
- role: nginx
vars:
nginx__version_spec: "{{ nextcloud__nginx_version_spec }}"
nginx__configurations:
- name: "{{ nextcloud__fqdn }}"
content: "{{ lookup('ansible.builtin.template', 'nginx_nextcloud.conf.j2') }}"
- role: docker_compose
vars:
docker_compose__compose_file_content: "{{ lookup('ansible.builtin.template', 'compose.yaml.j2') }}"
docker_compose__configuration_files: [ ]

View file

@ -0,0 +1,58 @@
---
- name: wait for existence of config directory
ansible.builtin.wait_for:
path: /ansible_docker_compose/nextcloud_var_www_html/config
state: present
become: true
- name: extra Nextcloud configuration
ansible.builtin.copy:
content: "{{ nextcloud__extra_configuration }}"
dest: /ansible_docker_compose/nextcloud_var_www_html/config/ansible_nextcloud_extra_config.config.php
mode: "0644"
owner: www-data
group: www-data
become: true
- name: fail, if nextcloud__use_custom_new_user_skeleton is set, but nextcloud__custom_new_user_skeleton_directory isn't
ansible.builtin.fail:
msg: If you set nextcloud__use_custom_new_user_skeleton, you also need to set nextcloud__custom_new_user_skeleton_directory.
when: nextcloud__use_custom_new_user_skeleton and nextcloud__custom_new_user_skeleton_directory == ""
- name: ensure custom new user skeleton
when: nextcloud__use_custom_new_user_skeleton
block:
- name: ensure `rsync` package is installed
ansible.builtin.apt:
name: rsync
state: present
become: true
- name: ensure custom new user skeleton directory
ansible.posix.synchronize:
src: "{{ nextcloud__custom_new_user_skeleton_directory }}"
dest: /ansible_docker_compose/custom_new_user_skeleton
delete: true
recursive: true
use_ssh_args: true
become: true
- name: ensure custom new user skeleton config
ansible.builtin.copy:
content: |
<?php
$CONFIG = array (
'skeletondirectory' => '/custom_new_user_skeleton'
);
dest: /ansible_docker_compose/nextcloud_var_www_html/config/ansible_nextcloud_custom_new_user_skeleton.config.php
mode: "0644"
owner: www-data
group: www-data
become: true
- name: ensure absence of custom new user skeleton config
ansible.builtin.file:
path: /ansible_docker_compose/nextcloud_var_www_html/config/ansible_nextcloud_custom_new_user_skeleton.config.php
state: absent
become: true
when: not nextcloud__use_custom_new_user_skeleton

View file

@ -0,0 +1,58 @@
---
services:
nextcloud:
image: git.hamburg.ccc.de/ccchh/oci-images/nextcloud:{{ nextcloud__version }}
pull_policy: always
restart: unless-stopped
ports:
- "8080:80"
depends_on:
- db
- redis
networks:
- nextcloud
volumes:
{% if nextcloud__use_custom_new_user_skeleton %}
- "./custom_new_user_skeleton:/custom_new_user_skeleton"
{% endif %}
- "./nextcloud_var_www_html:/var/www/html"
- "{{ nextcloud__data_dir }}:/var/www/html/data"
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: "{{ nextcloud__postgres_password }}"
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: "{{ nextcloud__admin_password }}"
REDIS_HOST: redis
NEXTCLOUD_TRUSTED_DOMAINS: "{{ nextcloud__fqdn }}"
# See here: https://github.com/nextcloud/docker#using-the-apache-image-behind-a-reverse-proxy-and-auto-configure-server-host-and-protocol
APACHE_DISABLE_REWRITE_IP: 1
TRUSTED_PROXIES: 127.0.0.1
OVERWRITECLIURL: "https://{{ nextcloud__fqdn }}/"
OVERWRITEHOST: "{{ nextcloud__fqdn }}"
OVERWRITEPROTOCOL: "https"
db:
image: postgres:{{ nextcloud__postgres_version }}
restart: unless-stopped
#ports:
# - 127.0.0.1:5432:5432
networks:
- nextcloud
volumes:
- "./database:/var/lib/postgresql/data"
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: "{{ nextcloud__postgres_password }}"
redis:
image: redis:alpine
restart: unless-stopped
networks:
- nextcloud
networks:
nextcloud:
external: false

View file

@ -0,0 +1,61 @@
# also see here:
# - https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/
# - https://nginx.org/en/docs/http/ngx_http_realip_module.html
server {
# Listen on a custom port for the proxy protocol.
listen 8443 ssl http2 proxy_protocol;
# Make use of the ngx_http_realip_module to set the $remote_addr and
# $remote_port to the client address and client port, when using proxy
# protocol.
# First set our proxy protocol proxy as trusted.
set_real_ip_from {{ nextcloud__proxy_protocol_reverse_proxy_ip }};
# Then tell the realip_module to get the addreses from the proxy protocol
# header.
real_ip_header proxy_protocol;
# This should work, but isn't needed for now.
# # Still listen for https on 443 as usual.
# listen 443 ssl http2;
# #listen [::]:443 ssl http2;
server_name {{ nextcloud__fqdn }};
ssl_certificate /etc/letsencrypt/live/{{ nextcloud__fqdn }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ nextcloud__fqdn }}/privkey.pem;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /etc/letsencrypt/live/{{ nextcloud__fqdn }}/chain.pem;
# replace with the IP address of your resolver
resolver 1.1.1.1;
# allow uploads of any size
client_max_body_size 0;
location /.well-known/carddav {
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
return 301 $scheme://$host/remote.php/dav;
}
location /.well-known/caldav {
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
return 301 $scheme://$host/remote.php/dav;
}
location / {
proxy_set_header Host $host;
# This is https in any case.
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
add_header Front-End-Https on;
proxy_pass http://127.0.0.1:8080;
}
}

59
roles/nginx/README.md Normal file
View file

@ -0,0 +1,59 @@
# Role `nginx`
Makes sure the `nginx` package is installed from the NGINX repos on the specified hosts.
Also makes sure a desirable baseline of NGINX configs is deployed on the specified hosts.
For the NGINX site configurations the config template below can be used.
## Entry Points
The entry points available for external use are:
- `main`
## Supported Distributions
The following distributions are supported:
- Debian 11
## Required Arguments
For the required arguments look at the [`argument_specs.yaml`](./meta/argument_specs.yaml).
## Updates
This role updates NGINX to the latest version covered by the provided version spec., if needed.
## `hosts`
The `hosts` for this role need to be the machines, for which you want to make sure the `nginx` package is installed from the NGINX repos and a desirable baseline of NGINX configs is deployed.
## Config Template
Here's a config template, which can be used for new NGINX site configs, which you can supply to this role using the `nginx__configurations` argument.
Just replace the placeholder values with real ones and extend and edit it as needed.
```
# partly generated 2022-01-08, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6
server {
listen 443 ssl http2;
#listen [::]:443 ssl http2;
server_name replace_me;
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# replace with the IP address of your resolver
resolver 127.0.0.1;
}
```
## Links & Resources
- <https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/#installing-prebuilt-debian-packages>

View file

@ -0,0 +1,5 @@
nginx__deploy_redirect_conf: true
nginx__deploy_tls_conf: true
nginx__configurations: [ ]
nginx__use_custom_nginx_conf: false
nginx__custom_nginx_conf: ""

View file

@ -0,0 +1,14 @@
# partly generated 2022-01-08, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6
server {
listen 80 default_server;
#listen [::]:80 default_server;
location / {
return 301 https://$host$request_uri;
}
location /.well-known/acme-challenge/ {
proxy_pass http://127.0.0.1:31820/.well-known/acme-challenge/;
}
}

View file

@ -0,0 +1,19 @@
# partly generated 2022-01-08, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam /etc/nginx-mozilla-dhparam;
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;

View file

@ -0,0 +1,10 @@
- name: Restart `nginx.service`
ansible.builtin.systemd:
name: nginx.service
state: restarted
become: true
- name: apt-get update
ansible.builtin.apt:
update_cache: true
become: true

View file

@ -0,0 +1,64 @@
argument_specs:
main:
options:
nginx__version_spec:
description: >-
The version specification to use for installing the `nginx` package. The
provided version specification will be used like the following: `nginx={{
nginx__version_spec }}*`. This makes it possible to e.g. specify
until a minor version (like `1.3.`) and then have patch versions be
installed automatically (like `1.3.1` and so on).
type: str
required: true
nginx__deploy_redirect_conf:
description: >-
Whether or not to deploy a `redirect.conf` to
`/etc/nginx/conf.d/redirect.conf`.
type: bool
required: false
default: true
nginx__deploy_tls_conf:
description: >-
Whether or not to deploy a `tls.conf` to `/etc/nginx/conf.d/tls.conf`.
type: bool
required: false
default: true
nginx__configurations:
description: A list of nginx configurations.
type: list
elements: dict
required: false
default: [ ]
options:
name:
description: >-
The name of the configuration file, where the configuration should
be deployed to. The file will be placed under `/etc/nginx/conf.d/`
and `.conf` will be appended to the given name. So in the end the
path will be like this: `/etc/nginx/conf.d/\{\{ name \}\}.conf`.
Note that the names `tls` and `redirect` aren't allowed.
type: str
required: true
content:
description: The content of the configuration.
type: str
required: true
nginx__use_custom_nginx_conf:
description: >-
Whether or not to use a custom `/etc/nginx/nginx.conf`. If set to
true, you must provide a custom `nginx.conf` via
`nginx__custom_nginx_conf`.
type: bool
required: false
default: false
nginx__custom_nginx_conf:
description: >-
The value for a `nginx.conf` to be placed at `/etc/nginx/nginx.conf`.
You must set `nginx__use_custom_nginx_conf` to true for this value to
be used.
You should probably make sure that your custom `nginx.conf` still
includes `/etc/nginx/conf.d/*.conf` so that the configuration provided
using `nginx__configurations` still work.
type: str
required: false
default: ""

View file

@ -0,0 +1,9 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- "11"
- "12"

View file

@ -0,0 +1,19 @@
- name: make sure nginx configuration names are valid
ansible.builtin.include_role:
name: nginx
tasks_from: make_sure_nginx_configuration_names_are_valid
- name: make sure NGINX repos are setup
ansible.builtin.include_role:
name: nginx
tasks_from: main/repo_setup
- name: make sure NGINX is installed
ansible.builtin.include_role:
name: nginx
tasks_from: main/nginx_install
- name: make sure desirable NGINX configs are deployed
ansible.builtin.include_role:
name: nginx
tasks_from: main/config_deploy

View file

@ -0,0 +1,132 @@
- name: check, if a save of a previous `nginx.conf` is present
ansible.builtin.stat:
path: /etc/nginx/nginx.conf.ansiblesave
register: nginx__nginx_conf_ansiblesave_stat_result
- name: handle the case, where a custom `nginx.conf` is to be used
when: nginx__use_custom_nginx_conf
block:
- name: when no `nginx.conf.ansiblesave` is present, save the current `nginx.conf`
when: not nginx__nginx_conf_ansiblesave_stat_result.stat.exists
ansible.builtin.copy:
force: true
dest: /etc/nginx/nginx.conf.ansiblesave
mode: "0644"
owner: root
group: root
remote_src: true
src: /etc/nginx/nginx.conf
become: true
- name: deploy the custom `nginx.conf`
ansible.builtin.copy:
content: "{{ nginx__custom_nginx_conf }}"
dest: "/etc/nginx/nginx.conf"
mode: "0644"
owner: root
group: root
become: true
notify: Restart `nginx.service`
- name: handle the case, where no custom `nginx.conf` is to be used
when: not nginx__use_custom_nginx_conf
block:
- name: when a `nginx.conf.ansiblesave` is present, copy it to `nginx.conf`
when: nginx__nginx_conf_ansiblesave_stat_result.stat.exists
ansible.builtin.copy:
force: true
dest: /etc/nginx/nginx.conf
mode: "0644"
owner: root
group: root
remote_src: true
src: /etc/nginx/nginx.conf.ansiblesave
become: true
notify: Restart `nginx.service`
- name: delete the `nginx.conf.ansiblesave`, if it is present
when: nginx__nginx_conf_ansiblesave_stat_result.stat.exists
ansible.builtin.file:
path: /etc/nginx/nginx.conf.ansiblesave
state: absent
become: true
- name: make sure mozilla dhparam is deployed
ansible.builtin.get_url:
force: true
dest: /etc/nginx-mozilla-dhparam
mode: "0644"
url: https://ssl-config.mozilla.org/ffdhe2048.txt
become: true
notify: Restart `nginx.service`
- name: set `nginx__config_files_to_exist` fact initially to an empty list
ansible.builtin.set_fact:
nginx__config_files_to_exist: [ ]
- name: handle the case, where tls.conf should be deployed
when: nginx__deploy_tls_conf
block:
- name: make sure tls.conf is deployed
ansible.builtin.copy:
force: true
dest: /etc/nginx/conf.d/tls.conf
mode: "0644"
owner: root
group: root
src: tls.conf
become: true
notify: Restart `nginx.service`
- name: add tls.conf to nginx__config_files_to_exist
ansible.builtin.set_fact:
nginx__config_files_to_exist: "{{ nginx__config_files_to_exist + [ 'tls.conf' ] }}" # noqa: jinja[spacing]
- name: handle the case, where redirect.conf should be deployed
when: nginx__deploy_redirect_conf
block:
- name: make sure redirect.conf is deployed
ansible.builtin.copy:
force: true
dest: /etc/nginx/conf.d/redirect.conf
mode: "0644"
owner: root
group: root
src: redirect.conf
become: true
notify: Restart `nginx.service`
- name: add redirect.conf to nginx__config_files_to_exist
ansible.builtin.set_fact:
nginx__config_files_to_exist: "{{ nginx__config_files_to_exist + [ 'redirect.conf' ] }}" # noqa: jinja[spacing]
- name: make sure all given configuration files are deployed
ansible.builtin.copy:
content: "{{ item.content }}"
dest: "/etc/nginx/conf.d/{{ item.name }}.conf"
mode: "0644"
owner: root
group: root
become: true
loop: "{{ nginx__configurations }}"
notify: Restart `nginx.service`
- name: add names plus suffix from `nginx__configurations` to `nginx__config_files_to_exist` fact
ansible.builtin.set_fact:
nginx__config_files_to_exist: "{{ nginx__config_files_to_exist + [ item.name + '.conf' ] }}" # noqa: jinja[spacing]
loop: "{{ nginx__configurations }}"
- name: find configuration files to remove
ansible.builtin.find:
paths: /etc/nginx/conf.d/
recurse: false
excludes: "{{ nginx__config_files_to_exist }}"
register: nginx__config_files_to_remove
- name: remove all configuration file, which should be removed
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
become: true
loop: "{{ nginx__config_files_to_remove.files }}"
notify: Restart `nginx.service`

View file

@ -0,0 +1,13 @@
- name: make sure the `nginx` package is installed
ansible.builtin.apt:
name: nginx={{ nginx__version_spec }}*
state: present
allow_change_held_packages: true
update_cache: true
become: true
- name: apt-mark hold `nginx`
ansible.builtin.dpkg_selections:
name: nginx
selection: hold
become: true

View file

@ -0,0 +1,51 @@
- name: gather package facts
ansible.builtin.package_facts:
manager: apt
- name: make sure `gnupg` package is installed
ansible.builtin.apt:
name: gnupg
state: present
update_cache: true
become: true
when: "'gnupg' not in ansible_facts.packages"
- name: make sure NGINX signing key is added
ansible.builtin.get_url:
url: https://nginx.org/keys/nginx_signing.key
dest: /etc/apt/trusted.gpg.d/nginx.asc
mode: "0644"
owner: root
group: root
become: true
notify: apt-get update
- name: make sure NGINX APT repository is added
ansible.builtin.apt_repository:
repo: "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/nginx.asc] https://nginx.org/packages/debian/ {{ ansible_distribution_release }} nginx"
state: present
become: true
notify: apt-get update
- name: make sure NGINX APT source repository is added
ansible.builtin.apt_repository:
repo: "deb-src [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/nginx.asc] https://nginx.org/packages/debian/ {{ ansible_distribution_release }} nginx"
state: present
become: true
notify: apt-get update
- name: set up repository pinning to make sure nginx package gets installed from NGINX repositories
ansible.builtin.copy:
content: |
Package: *
Pin: origin nginx.org
Pin: release o=nginx
Pin-Priority: 900
dest: /etc/apt/preferences.d/99nginx
owner: root
group: root
mode: "0644"
become: true
- name: Flush handlers to make sure "apt-get update" handler runs, if needed
ansible.builtin.meta: flush_handlers

View file

@ -0,0 +1,6 @@
- name: make sure nginx configuration names are valid
ansible.builtin.fail:
msg: "You used the following name: `{{ item.name }}`. Please make sure to not use the following names: `tls`, `redirect`."
when: item.name == "tls"
or item.name == "redirect"
loop: "{{ nginx__configurations }}"

View file

@ -0,0 +1,6 @@
- name: Restart olad
become: true
ansible.builtin.systemd:
service: olad.service
state: restarted
daemon-reload: true

View file

@ -0,0 +1,22 @@
---
argument_specs:
main:
options:
ola__configs:
description: A list of ola configurations.
type: list
elements: dict
required: true
options:
name:
description: >-
The name of the configuration file, where the configuration should
be deployed to. The file will be placed under `/etc/ola/` and
`.conf` will be appended to the given name. So in the end the path
will be like this: `/etc/ola/\{\ name \}\}.conf`.
type: str
required: true
content:
description: The content of the configuration.
type: str
required: true

8
roles/ola/meta/main.yaml Normal file
View file

@ -0,0 +1,8 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- "11"

22
roles/ola/tasks/main.yaml Normal file
View file

@ -0,0 +1,22 @@
- name: Install ola
become: true
ansible.builtin.apt:
name: ola
- name: Ensure all given configuraton files are deployed
become: true
ansible.builtin.copy:
content: "{{ item.content }}"
dest: /etc/ola/{{ item.name }}.conf
mode: "644"
owner: olad
group: olad
loop: "{{ ola__configs }}"
notify: Restart olad
- name: Enable and start ola service
become: true
ansible.builtin.systemd:
name: olad.service
state: started
enabled: true

View file

@ -0,0 +1,2 @@
enabled = {{ ola__enable_ftdi | string | lower }}
frequency = 30

View file

@ -0,0 +1,9 @@
---
dependencies:
- role: distribution_check
vars:
distribution_check__distribution_support_spec:
- name: Debian
major_versions:
- "11"
- "12"

View file

@ -0,0 +1,14 @@
- name: make sure the `prometheus-node-exporter` package is installed
ansible.builtin.apt:
name: prometheus-node-exporter
state: present
allow_change_held_packages: true
update_cache: true
become: true
- name: make sure `prometheus-node-exporter.service` is started and ansibled
ansible.builtin.systemd:
name: prometheus-node-exporter.service
state: started
enabled: true
become: true