From c1b500a7036ecc065a4ba36a8f02771fea1614ea Mon Sep 17 00:00:00 2001 From: Wolfgang Date: Mon, 1 Nov 2021 10:16:05 +0100 Subject: [PATCH] Add PiHole and Unbound, RPi configuration, etc. --- .gitignore | 4 +- group_vars/all/vars.yml | 4 + roles/containers/deluge/tasks/main.yml | 2 +- roles/containers/ikev2/tasks/main.yml | 12 ++- roles/containers/pihole/tasks/main.yml | 24 ++++-- roles/containers/pihole/templates/unbound.j2 | 70 ++++++++++++++++ roles/docker/tasks/main.yml | 64 ++++++++++++++- roles/docker/vars/{Ubuntu.yml => Debian.yml} | 3 +- roles/essential/tasks/main.yml | 26 +++--- .../essential/vars/{Ubuntu.yml => Debian.yml} | 0 run.yml | 81 ++++++++----------- tasks/ssh_juggle_port.yml | 21 +++++ tasks/user.yml | 9 +-- 13 files changed, 241 insertions(+), 79 deletions(-) create mode 100644 roles/containers/pihole/templates/unbound.j2 rename roles/docker/vars/{Ubuntu.yml => Debian.yml} (77%) rename roles/essential/vars/{Ubuntu.yml => Debian.yml} (100%) diff --git a/.gitignore b/.gitignore index aaa7b223..f22b7d50 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ .DS_Store secret.yml /group_vars/ +/host_vars/ +!/host_vars/.gitkeep !/group_vars/all/vars.yml -mountsraspi \ No newline at end of file +mountsraspi diff --git a/group_vars/all/vars.yml b/group_vars/all/vars.yml index e9310650..57199833 100644 --- a/group_vars/all/vars.yml +++ b/group_vars/all/vars.yml @@ -11,6 +11,8 @@ timezone: Europe/Amsterdam dns_nameservers: [9.9.9.9, 149.112.112.112] +dot_nameservers: [185.95.218.42@853#dns.digitale-gesellschaft.ch, 94.140.15.140@853#dns-unfiltered.adguard.com] + host: "{{ duckdns_domain }}.duckdns.org" ntp_timezone: "{{ timezone }}" @@ -147,6 +149,8 @@ enable_timemachine: true # ikev2_ondemand: true + + # # Samba # diff --git a/roles/containers/deluge/tasks/main.yml b/roles/containers/deluge/tasks/main.yml index cbbfa785..9ca77fc7 100644 --- a/roles/containers/deluge/tasks/main.yml +++ b/roles/containers/deluge/tasks/main.yml @@ -30,7 +30,7 @@ "PGID": "{{ guid }}" "TZ": "{{ timezone }}" ports: - - "0.0.0.0:8112:8112" + - "8112:8112" - "58846:58846" volumes: - "{{ docker_dir }}/{{ container_name }}/data:/data" diff --git a/roles/containers/ikev2/tasks/main.yml b/roles/containers/ikev2/tasks/main.yml index b631c0ea..fe3add9f 100644 --- a/roles/containers/ikev2/tasks/main.yml +++ b/roles/containers/ikev2/tasks/main.yml @@ -1,8 +1,18 @@ --- +- name: Set the architecture variable + set_fact: + arch: "armhf" + when: '"armv" in ansible_architecture' + +- name: Set the architecture variable + set_fact: + arch: "amd64" + when: '"x86_64" in ansible_architecture' + - name: Make sure the {{ container_name }} container is created and running docker_container: name: 'ikev2' - image: "notthebee/ikev2" + image: "notthebee/ikev2:{{ arch }}" privileged: yes pull: yes state: 'started' diff --git a/roles/containers/pihole/tasks/main.yml b/roles/containers/pihole/tasks/main.yml index 03725b52..d72d16cb 100644 --- a/roles/containers/pihole/tasks/main.yml +++ b/roles/containers/pihole/tasks/main.yml @@ -1,4 +1,16 @@ --- +- name: Create the configuration directory + file: + path: "{{ docker_dir }}/{{ container_name }}/unbound.conf.d/" + state: directory + recurse: yes + +- name: Copy the unbound configuration file + template: + src: unbound.j2 + dest: "{{ docker_dir }}/{{ container_name }}/unbound.conf.d/pi-hole.conf" + + - name: Make sure the {{ container_name }} container is created and running docker_container: name: 'pihole' @@ -13,19 +25,19 @@ "TZ": "{{ timezone }}" "WEBPASSWORD": "{{ pihole_password }}" "REV_SERVER": "true" - "REV_SERVER_DOMAIN": "local" + "REV_SERVER_DOMAIN": "box" "REV_SERVER_TARGET": "{{ ansible_default_ipv4.gateway }}" "REV_SERVER_CIDR": "{{ '.'.join(ansible_default_ipv4.address.split('.')[0:3]) }}.0/24" "DNS1": "127.0.0.1#5335" # Hardcoded to our Unbound server "DNS2": "127.0.0.1#5335" # Hardcoded to our Unbound server "DNSSEC": "true" # Enable DNSSEC - "DOMAIN_NAME": "pihole.local" + "DOMAIN_NAME": "pihole.box" volumes: - "{{ docker_dir }}/{{ container_name }}/pihole:/etc/pihole" - "{{ docker_dir }}/{{ container_name }}/dnmasq-unbound:/etc/dnsmasq.d" + - "{{ docker_dir }}/{{ container_name }}/unbound.conf.d/pi-hole.conf:/etc/unbound/unbound.conf.d/pi-hole.conf" ports: - - 443:443/tcp - - 81:80/tcp - - 53:53/tcp - - 53:53/udp + - "81:80/tcp" + - "53:53/tcp" + - "53:53/udp" restart_policy: unless-stopped \ No newline at end of file diff --git a/roles/containers/pihole/templates/unbound.j2 b/roles/containers/pihole/templates/unbound.j2 new file mode 100644 index 00000000..63cbfcbf --- /dev/null +++ b/roles/containers/pihole/templates/unbound.j2 @@ -0,0 +1,70 @@ +# Config pulled from https://docs.pi-hole.net/guides/unbound/ + +server: + # If no logfile is specified, syslog is used + # logfile: "/var/log/unbound/unbound.log" + + + logfile: "/var/log/unbound.log" + verbosity: 3 + + hide-identity: yes + hide-version: yes + qname-minimisation: yes + rrset-roundrobin: yes + ssl-upstream: yes + ssl-cert-bundle: /etc/ssl/certs/ca-certificates.crt + + interface: 127.0.0.1 + port: 5335 + do-ip4: yes + do-udp: yes + do-tcp: yes + + # May be set to yes if you have IPv6 connectivity + do-ip6: no + + # You want to leave this to no unless you have *native* IPv6. With 6to4 and + # Terredo tunnels your web browser should favor IPv4 for the same reasons + prefer-ip6: no + + # Use this only when you downloaded the list of primary root servers! + # If you use the default dns-root-data package, unbound will find it automatically + #root-hints: "/var/lib/unbound/root.hints" + + # Trust glue only if it is within the server's authority + harden-glue: yes + + # Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS + harden-dnssec-stripped: yes + + # Don't use Capitalization randomization as it known to cause DNSSEC issues sometimes + # see https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 for further details + use-caps-for-id: no + + # Reduce EDNS reassembly buffer size. + # Suggested by the unbound man page to reduce fragmentation reassembly problems + edns-buffer-size: 1472 + + msg-cache-size: 50m + rrset-cache-size: 100m + + # Perform prefetching of close to expired message cache entries + # This only applies to domains that have been frequently queried + prefetch: yes + + # One thread should be sufficient, can be increased on beefy machines. In reality for most users running on small networks or on a single machine, it should be unnecessary to seek performance enhancement by increasing num-threads above 1. + so-reuseport: yes + + # Ensure kernel buffer is large enough to not lose messages in traffic spikes + so-rcvbuf: 1m + + # Ensure privacy of local IP ranges + private-address: {{ '.'.join(ansible_default_ipv4.address.split('.')[0:3]) }}.0/24 + +forward-zone: + # forward all queries to these DNS servers: + name: "." + {% for item in dot_nameservers %} + forward-addr: {{ item }} + {% endfor %} \ No newline at end of file diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml index d8913c45..e9b62b2c 100644 --- a/roles/docker/tasks/main.yml +++ b/roles/docker/tasks/main.yml @@ -1,13 +1,13 @@ --- - name: Include OS-specific variables - include_vars: "{{ ansible_facts['distribution'] }}.yml" + include_vars: "{{ ansible_facts['os_family'] }}.yml" - name: Install required system packages package: state: latest name: "{{ docker_packages }}" -- name: Install Docker packages +- name: Install Docker (Ubuntu) when: ansible_facts['distribution'] == 'Ubuntu' block: - name: Add Docker GPG apt Key @@ -20,12 +20,68 @@ repo: deb https://download.docker.com/linux/ubuntu bionic stable state: present - - name: Update apt and install docker-ce +- name: Install Docker (Raspbian) + when: ansible_facts['distribution'] == 'Debian' + block: + - name: Add Docker GPG apt Key + apt_key: + url: https://download.docker.com/linux/raspbian/gpg + state: present + + - name: Add Docker Repository + apt_repository: + repo: deb https://download.docker.com/linux/raspbian buster stable + state: present + + - name: Add buster-backports GPG key (for libseccomp2) + apt_key: + keyserver: keyserver.ubuntu.com + id: "{{ item }}" + loop: + - 04EE7237B7D453EC + - 648ACFD622F3D138 + + - name: Add buster-backports repository + apt_repository: + repo: deb http://deb.debian.org/debian buster-backports main contrib non-free + + - name: Update to the latest version of libseccomp2 apt: update_cache: yes - name: docker-ce + name: libseccomp2 + default_release: buster-backports state: latest + - name: Switch to iptables-legacy + alternatives: + name: iptables + path: /usr/sbin/iptables-legacy + + - name: Switch to ip6tables-legacy + alternatives: + name: ip6tables + path: /usr/sbin/ip6tables-legacy + + - name: Switch to pip3 + alternatives: + name: pip + link: /usr/bin/pip + path: /usr/bin/pip3 + + - name: Switch to python3 + alternatives: + name: python + link: /usr/bin/python + path: /usr/bin/python3 + + +- name: Update apt and install docker-ce + when: ansible_facts['os_family'] == 'Debian' + apt: + update_cache: yes + name: docker-ce + state: latest + - name: Ensure group docker exists group: name: docker diff --git a/roles/docker/vars/Ubuntu.yml b/roles/docker/vars/Debian.yml similarity index 77% rename from roles/docker/vars/Ubuntu.yml rename to roles/docker/vars/Debian.yml index 371f7016..235b2786 100644 --- a/roles/docker/vars/Ubuntu.yml +++ b/roles/docker/vars/Debian.yml @@ -6,4 +6,5 @@ docker_packages: - 'software-properties-common' - 'python3-pip' - 'virtualenv' - - 'python3-setuptools' \ No newline at end of file + - 'python3-setuptools' + - 'python3-pip' \ No newline at end of file diff --git a/roles/essential/tasks/main.yml b/roles/essential/tasks/main.yml index 423db96f..3a845850 100644 --- a/roles/essential/tasks/main.yml +++ b/roles/essential/tasks/main.yml @@ -1,6 +1,6 @@ --- - name: Include OS-specific variables - include_vars: "{{ ansible_facts['distribution'] }}.yml" + include_vars: "{{ ansible_facts['os_family'] }}.yml" - name: Ubuntu specific tasks become: yes @@ -11,11 +11,6 @@ name: cloud-config state: absent - - name: Generate the locale - locale_gen: - name: "{{ locale }}" - state: present - - name: Make sure iSCSId and Open-iSCSId services are disabled service: name: "{{ item }}" @@ -34,12 +29,19 @@ group: root mode: 0644 tags: mirrors - - - name: Update and upgrade apt packages - apt: - upgrade: "yes" - update_cache: yes - cache_valid_time: 86400 + +- name: Generate the locale (Debian and Ubuntu) + when: ansible_os_family == 'Debian' + locale_gen: + name: "{{ locale }}" + state: present + +- name: Update and upgrade apt packages (Debian and Ubuntu) + when: ansible_os_family == 'Debian' + apt: + upgrade: "yes" + update_cache: yes + cache_valid_time: 86400 - name: Alpine specific tasks become: yes diff --git a/roles/essential/vars/Ubuntu.yml b/roles/essential/vars/Debian.yml similarity index 100% rename from roles/essential/vars/Ubuntu.yml rename to roles/essential/vars/Debian.yml diff --git a/run.yml b/run.yml index 5944a336..a20b2663 100644 --- a/run.yml +++ b/run.yml @@ -1,5 +1,5 @@ --- -- hosts: all +- hosts: home gather_facts: no pre_tasks: @@ -7,13 +7,14 @@ tags: - port -- hosts: all +- hosts: home tasks: - import_tasks: tasks/user.yml tags: - user -# Router + +# PiHole/IKEv2 server - hosts: coda become: yes roles: @@ -25,54 +26,42 @@ tags: - docker - - role: containers/ikev2 + # MSMTP (for SMART notifications) + - role: chriswayg.msmtp-mailer tags: - - ikev2 + - msmtp + + - role: oefenweb.dns + tags: + - dns + + - role: containers/duckdns + when: enable_duckdns | default(False) + tags: + - duckdns - containers - when: enable_ikev2 | default(False) - role: containers/pihole - tags: - - pihole - - containers when: enable_pihole | default(False) + tags: + - pihole + - containers - - role: containers/duckdns - tags: - - duckdns + - role: containers/ikev2 + when: enable_ikev2 | default(False) + tags: - containers - when: enable_duckdns | default(False) + - ikev2 - tasks: - - name: Update SSH configuration to be more secure. - register: ssh_conf - lineinfile: - dest: "/etc/ssh/sshd_config" - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - state: present - validate: 'sshd -T -f %s' - mode: 0644 - with_items: - - regexp: "^PasswordAuthentication" - line: "PasswordAuthentication no" - - regexp: "^PermitRootLogin" - line: "PermitRootLogin no" - - regexp: "^Port" - line: "Port {{ security_ssh_port }}" - - regexp: "^PermitEmptyPasswords" - line: "PermitEmptyPasswords no" - - regexp: "^ChallengeResponseAuthentication" - line: "ChallengeResponseAuthentication yes" - - regexp: "^X11Forwarding" - line: "X11Forwarding no" - - - name: restart SSHD service - service: - name: sshd - state: restarted - when: ssh_conf.changed + # NTP + - role: geerlingguy.ntp + tags: + - ntp + # SSH security (at the end because it breaks SSH connection) + - role: geerlingguy.security + tags: + - security # Home server/NAS - hosts: fragile @@ -88,10 +77,6 @@ tags: - mounts - - role: oefenweb.dns - tags: - - dns - - role: essential tags: - essential @@ -105,6 +90,10 @@ tags: - docker + - role: oefenweb.dns + tags: + - dns + - role: filesystems/mergerfs tags: - mergerfs diff --git a/tasks/ssh_juggle_port.yml b/tasks/ssh_juggle_port.yml index d48b0c79..e49f015f 100644 --- a/tasks/ssh_juggle_port.yml +++ b/tasks/ssh_juggle_port.yml @@ -40,9 +40,30 @@ when: - _ssh_port_result is failed + +- name: SSH Port Juggle | Set the ansible_port to the fallback default port and credentials + set_fact: + ansible_ssh_port: "22" + ansible_ssh_user: "pi" + ansible_ssh_password: "raspberry" + when: + - _ssh_port_result is failed + - _ssh_port_default_result is failed + +- name: Try default credentials (for Raspberry Pi) + wait_for_connection: + timeout: 5 + ignore_errors: true + register: _ssh_port_default_cred_result + when: + - _ssh_port_result is failed + - _ssh_port_default_result is failed + - name: SSH Port Juggle | Fail fail: msg="Neither the configured ansible_port {{ ansible_port }} nor the fallback port 22 were reachable" when: - _ssh_port_result is failed - _ssh_port_default_result is defined - _ssh_port_default_result is failed + - _ssh_port_default_cred_result is defined + - _ssh_port_default_cred_result is failed \ No newline at end of file diff --git a/tasks/user.yml b/tasks/user.yml index 0d81ec4e..4d85b840 100644 --- a/tasks/user.yml +++ b/tasks/user.yml @@ -1,14 +1,8 @@ --- - name: Set the name of a sudo group - when: ansible_distribution == 'Ubuntu' set_fact: sudo_group: sudo -- name: Set the name of a sudo group - when: ansible_distribution == 'Alpine' - set_fact: - sudo_group: wheel - - name: Create a login user become: yes user: @@ -28,7 +22,7 @@ state: present - name: Append the samba group - when: ansible_distribution == 'Ubuntu' + when: enable_samba | default(False) become: yes user: name: "{{ username }}" @@ -46,6 +40,7 @@ validate: '/usr/sbin/visudo -cf %s' - name: Copy the public SSH key + become: yes authorized_key: user: "{{ username }}" state: present