From baa7f33e091f7d9d814061c66c66d145d3e14a50 Mon Sep 17 00:00:00 2001 From: Blallo Date: Sun, 21 Feb 2021 00:45:22 +0100 Subject: [PATCH] Init --- files/verify_ip.sh | 25 ++++ handlers/main.yml | 23 ++++ tasks/firewall.yml | 114 ++++++++++++++++++ tasks/ivacy.yml | 58 +++++++++ tasks/letsencrypt.yml | 19 +++ tasks/main.yml | 11 ++ tasks/nginx.yml | 72 +++++++++++ tasks/nginx_ssl.yml | 22 ++++ tasks/wg_link.yml | 35 ++++++ templates/firewalld/pptp.xml.j2 | 6 + templates/firewalld/wireguard.xml.j2 | 6 + templates/ivacy/chap-secrets.j2 | 3 + templates/ivacy/ivacy-ppp.service.j2 | 14 +++ templates/ivacy/ivacy_config | 6 + templates/ivacy/options.pptp.j2 | 8 ++ .../nginx/custom_configs/letsencrypt.conf | 10 ++ templates/nginx/sites.conf.j2 | 42 +++++++ templates/nginx/sites_ssl.conf.j2 | 53 ++++++++ templates/nginx/ssl.conf.j2 | 8 ++ templates/wireguard/wireguard.netdev.j2 | 16 +++ templates/wireguard/wireguard.network.j2 | 20 +++ 21 files changed, 571 insertions(+) create mode 100755 files/verify_ip.sh create mode 100644 handlers/main.yml create mode 100644 tasks/firewall.yml create mode 100644 tasks/ivacy.yml create mode 100644 tasks/letsencrypt.yml create mode 100644 tasks/main.yml create mode 100644 tasks/nginx.yml create mode 100644 tasks/nginx_ssl.yml create mode 100644 tasks/wg_link.yml create mode 100644 templates/firewalld/pptp.xml.j2 create mode 100644 templates/firewalld/wireguard.xml.j2 create mode 100644 templates/ivacy/chap-secrets.j2 create mode 100644 templates/ivacy/ivacy-ppp.service.j2 create mode 100644 templates/ivacy/ivacy_config create mode 100644 templates/ivacy/options.pptp.j2 create mode 100644 templates/nginx/custom_configs/letsencrypt.conf create mode 100644 templates/nginx/sites.conf.j2 create mode 100644 templates/nginx/sites_ssl.conf.j2 create mode 100644 templates/nginx/ssl.conf.j2 create mode 100644 templates/wireguard/wireguard.netdev.j2 create mode 100644 templates/wireguard/wireguard.network.j2 diff --git a/files/verify_ip.sh b/files/verify_ip.sh new file mode 100755 index 0000000..b0adaae --- /dev/null +++ b/files/verify_ip.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +RETRY=3 +CURL_SLEEP_TIME=10 # These are seconds +EXPECTED_IP=172.94.25.17 + +sleep 10 # Wait these seconds for ppp to come up + +while [ $RETRY -ne 0 ]; do + IP_RESULT=$(curl -s ifconfig.co) + if [ $? -ne 0 ]; then + RETRY=$(( $RETRY - 1 )) + echo "curl failed - retrying ${RETRY} times." + sleep $CURL_SLEEP_TIME + else + break + fi +done + +if [ "${EXPECTED_IP}" != "${IP_RESULT}" ]; then + echo "Expected ip (${EXPECTED_IP}) different from the one got (${IP_RESULT})" + exit 1 +fi + +# vim: set ft=sh et sw=0 ts=2 sts=0: diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..3fc7eed --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,23 @@ +--- +- name: reload_nginx + systemd: + name: nginx + daemon_reload: true + state: reloaded + +- name: restart_ivacy + systemd: + name: ivacy-ppp + state: restarted + +- name: reload_and_restart_ivacy + systemd: + name: ivacy-ppp + daemon_reload: true + state: restarted + +- name: restart networking + systemd: + name: systemd-networkd + daemon_reload: true + state: restarted diff --git a/tasks/firewall.yml b/tasks/firewall.yml new file mode 100644 index 0000000..e138d0b --- /dev/null +++ b/tasks/firewall.yml @@ -0,0 +1,114 @@ +--- +- name: Require firewalld + apt: + name: firewalld + state: latest + +- name: Add wireguard firewalld service + template: + src: firewalld/wireguard.xml.j2 + dest: "/etc/firewalld/services/{{ gateway.vpn.name }}.xml" + owner: root + group: root + mode: 0644 + +# - name: Ensure firewalld is enabled +# systemd: +# name: firewalld.service +# enabled: yes +# masked: no +# state: started + +- name: Force all notified handlers to run at this point, not waiting for normal sync points + meta: flush_handlers + +- name: Add zones + ansible.posix.firewalld: + zone: "{{ item }}" + state: present + permanent: yes + with_items: + - home + - public + - trusted + +- name: Add home interface + ansible.posix.firewalld: + zone: home + interface: "{{ gateway.firewall.home_iface }}" + permanent: yes + immediate: yes + state: enabled + +- name: Add public interface + ansible.posix.firewalld: + zone: public + interface: "{{ gateway.firewall.public_iface|default(ppp0) }}" + permanent: yes + immediate: yes + state: enabled + +- name: Add vm interface + ansible.posix.firewalld: + zone: trusted + interface: "{{ gateway.firewall.vm_iface }}" + permanent: yes + immediate: yes + state: enabled + +- name: Enable masquerade on public interface + ansible.posix.firewalld: + zone: public + masquerade: yes + permanent: yes + immediate: yes + state: enabled + +- name: Enable masquerade on vm interface + ansible.posix.firewalld: + zone: trusted + masquerade: yes + permanent: yes + immediate: yes + state: enabled + +- name: Add services to public interface + ansible.posix.firewalld: + zone: public + service: "{{ item }}" + permanent: yes + immediate: yes + state: enabled + with_items: + - dhcpv6-client + - http + - https + - ssh + +- name: Add services to home interface + ansible.posix.firewalld: + zone: home + service: "{{ item }}" + permanent: yes + immediate: yes + state: enabled + with_items: + - dhcpv6-client + - http + - https + - ssh + - "{{ gateway.vpn.name }}" + - mdns + - samba-client + - samba + +- name: Forward ports to hosts + ansible.posix.firewalld: + rich_rule: "rule family=ipv4 forward-port protocol={{ item.proto }} port={{ item.from.port }} to-addr=\"{{ item.to.addr }}\" to-port={{ item.to.port|default(item.from.port) }}" + zone: "{{ item.zone }}" + permanent: yes + immediate: yes + state: enabled + when: gateway.firewall.forwarded_ports is defined + with_items: "{{ gateway.firewall.forwarded_ports }}" + diff --git a/tasks/ivacy.yml b/tasks/ivacy.yml new file mode 100644 index 0000000..a510cb6 --- /dev/null +++ b/tasks/ivacy.yml @@ -0,0 +1,58 @@ +--- +- name: Require ppp installed + apt: + name: ['pptp-linux', 'pptpd'] + state: latest + +- name: Ensure pptp options + template: + src: ivacy/options.pptp.j2 + dest: /etc/ppp/options.pptp + owner: root + group: root + mode: 0644 + notify: restart_ivacy + +- name: Ensure ivacy configuration + template: + src: ivacy/ivacy_config + dest: "/etc/ppp/peers/{{ gateway.ivacy.config_name|default('ivacy') }}" + owner: root + group: root + mode: 0644 + notify: restart_ivacy + +- name: Ensure ppp chap secrets + template: + src: ivacy/chap-secrets.j2 + dest: /etc/ppp/chap-secrets + owner: root + group: root + mode: 0644 + notify: restart_ivacy + +- name: Ensure script to verify ip is present + copy: + src: files/verify_ip.sh + dest: /usr/local/bin/verify_ip.sh + owner: root + group: root + mode: 0755 + notify: restart_ivacy + +- name: Ensure ivacy service unit + template: + src: ivacy/ivacy-ppp.service.j2 + dest: /etc/systemd/system/ivacy-ppp.service + owner: root + group: root + mode: 0644 + notify: reload_and_restart_ivacy + +- name: Ensure ivacy service is enabled and running + systemd: + name: ivacy-ppp.service + enabled: yes + masked: no + state: started + notify: restart_ivacy diff --git a/tasks/letsencrypt.yml b/tasks/letsencrypt.yml new file mode 100644 index 0000000..064f405 --- /dev/null +++ b/tasks/letsencrypt.yml @@ -0,0 +1,19 @@ +--- +- name: ensure letsencrypt is up-to-date + apt: + name: certbot + state: latest + +- name: create letsencrypt webroot + file: + path: /var/www/letsencrypt + state: directory + owner: root + group: www-data + mode: '0775' + +- name: ensure all the domains have a tls certificate + shell: "[ -f /etc/letsencrypt/live/{{ item.domain_name }}/fullchain.pem ] || certbot certonly --agree-tos -m {{ item.cert_email }} --webroot -w /var/www/letsencrypt -d {{ item.domain_name }}" + when: item.cert_email is defined + with_items: "{{ gateway.proxied_services }}" + notify: reload_nginx diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..907af10 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: install passlib + apt: + name: python3-passlib + state: present +- include_tasks: wg_link.yml +- include_tasks: firewall.yml +# - include_tasks: ivacy.yml +- include_tasks: nginx.yml +- include_tasks: letsencrypt.yml +- include_tasks: nginx_ssl.yml diff --git a/tasks/nginx.yml b/tasks/nginx.yml new file mode 100644 index 0000000..f6fcfdf --- /dev/null +++ b/tasks/nginx.yml @@ -0,0 +1,72 @@ +--- +- name: ensure nginx is at the latest version + apt: + name: nginx-full + state: latest + +- name: ensure default nginx site is disabled + file: + path: /etc/nginx/sites-enabled/default + state: absent + +# - name: start nginx +# systemd: +# name: nginx.service +# state: started +# enabled: true + +- name: copy custom configuration + template: + src: "{{ item.src }}" + dest: /etc/nginx + owner: root + group: root + mode: '0644' + with_filetree: templates/nginx/custom_configs/ + when: item.state == "file" + notify: reload_nginx + +- name: add per-domain ssl configuration + template: + src: templates/nginx/ssl.conf.j2 + dest: "/etc/nginx/ssl_{{ item.domain_name }}.conf" + owner: root + group: root + mode: '0644' + vars: + domain_name: "{{ item.domain_name }}" + with_items: "{{ gateway.proxied_services }}" + +- name: add password file for sites that are password-protected + htpasswd: + path: "{{ item.password_file }}" + name: "{{ item.username }}" + password: "{{ item.password }}" + owner: "{{ item.owner|default('root') }}" + group: "{{ item.group|default('www-data') }}" + mode: 0640 + when: item.password_protect|default(false) + loop: "{{ gateway.proxied_services }}" + +- name: add nginx configuration (only http) + template: + src: templates/nginx/sites.conf.j2 + dest: "/etc/nginx/sites-available/{{ item.domain_name }}.conf" + owner: root + group: root + mode: '0644' + vars: + service: "{{ item }}" + with_items: "{{ gateway.proxied_services }}" + notify: reload_nginx + +- name: enable nginx http configuration + file: + src: "/etc/nginx/sites-available/{{ item.domain_name }}.conf" + dest: "/etc/nginx/sites-enabled/{{ item.domain_name }}.conf" + state: link + with_items: "{{ gateway.proxied_services }}" + notify: reload_nginx + +- name: Force all notified handlers to run at this point, not waiting for normal sync points + meta: flush_handlers diff --git a/tasks/nginx_ssl.yml b/tasks/nginx_ssl.yml new file mode 100644 index 0000000..33e4135 --- /dev/null +++ b/tasks/nginx_ssl.yml @@ -0,0 +1,22 @@ +--- +- name: add nginx configuration (https) + template: + src: templates/nginx/sites_ssl.conf.j2 + dest: "/etc/nginx/sites-available/{{ item.domain_name }}-ssl.conf" + owner: root + group: root + mode: '0644' + vars: + service: "{{ item }}" + when: item.cert_email is defined + with_items: "{{ gateway.proxied_services }}" + notify: reload_nginx + +- name: enable nginx https configuration + file: + src: "/etc/nginx/sites-available/{{ item.domain_name }}-ssl.conf" + dest: "/etc/nginx/sites-enabled/{{ item.domain_name }}-ssl.conf" + state: link + when: item.cert_email is defined + with_items: "{{ gateway.proxied_services }}" + notify: reload_nginx diff --git a/tasks/wg_link.yml b/tasks/wg_link.yml new file mode 100644 index 0000000..4e81874 --- /dev/null +++ b/tasks/wg_link.yml @@ -0,0 +1,35 @@ +--- +- name: Ensure wireguard is present + apt: + name: wireguard-tools + state: present + default_release: buster-backports + register: wireguard + +- name: Ensure wireguard netdev configuration is present + template: + src: templates/wireguard/wireguard.netdev.j2 + dest: "/etc/systemd/network/{{ gateway.vpn.name }}.netdev" + owner: root + group: root + mode: 0644 + notify: restart networking + +- name: Ensure wireguard network configuration is present + template: + src: templates/wireguard/wireguard.network.j2 + dest: "/etc/systemd/network/{{ gateway.vpn.name }}.network" + owner: root + group: root + mode: 0644 + notify: restart networking + +- name: Reboot to allow wireguard to start + reboot: + when: wireguard.changed + +- name: Ensure systemd-networkd is enabled and running + systemd: + name: systemd-networkd.service + state: started + enabled: yes diff --git a/templates/firewalld/pptp.xml.j2 b/templates/firewalld/pptp.xml.j2 new file mode 100644 index 0000000..fd79ca2 --- /dev/null +++ b/templates/firewalld/pptp.xml.j2 @@ -0,0 +1,6 @@ + + + PPTP + Allow GRE through PPP tunnel. + + diff --git a/templates/firewalld/wireguard.xml.j2 b/templates/firewalld/wireguard.xml.j2 new file mode 100644 index 0000000..2ff0df0 --- /dev/null +++ b/templates/firewalld/wireguard.xml.j2 @@ -0,0 +1,6 @@ + + + PPTP + Allow GRE through PPP tunnel. + + diff --git a/templates/ivacy/chap-secrets.j2 b/templates/ivacy/chap-secrets.j2 new file mode 100644 index 0000000..d1b5bd6 --- /dev/null +++ b/templates/ivacy/chap-secrets.j2 @@ -0,0 +1,3 @@ +# Secrets for authentication using CHAP +# client server secret IP addresses +{{ gateway.ivacy.username }} PPTP {{ gateway.ivacy.password }} * diff --git a/templates/ivacy/ivacy-ppp.service.j2 b/templates/ivacy/ivacy-ppp.service.j2 new file mode 100644 index 0000000..c913e09 --- /dev/null +++ b/templates/ivacy/ivacy-ppp.service.j2 @@ -0,0 +1,14 @@ +[Unit] +Description=PPTP Ivacy VPN +After=network-online.target + +[Service] +Type=forking +ExecStart=/usr/sbin/pppd call {{ gateway.ivacy.config_name|default('ivacy') }} +ExecStartPost=/usr/local/bin/verify_ip.sh +TimeoutStartSec=120 +Restart=on-failure +RestartSec=600 + +[Install] +WantedBy=multi-user.target diff --git a/templates/ivacy/ivacy_config b/templates/ivacy/ivacy_config new file mode 100644 index 0000000..7791d8e --- /dev/null +++ b/templates/ivacy/ivacy_config @@ -0,0 +1,6 @@ +pty "pptp de-ded-3.dns2use.com --nolaunchpppd" +name "ivacy0d8560848" +remotename PPTP +file /etc/ppp/options.pptp +require-mppe-128 +refuse-eap noauth diff --git a/templates/ivacy/options.pptp.j2 b/templates/ivacy/options.pptp.j2 new file mode 100644 index 0000000..55c0cbc --- /dev/null +++ b/templates/ivacy/options.pptp.j2 @@ -0,0 +1,8 @@ +lock +noauth +refuse-pap +refuse-eap +refuse-chap +refuse-mschap +nobsdcomp +nodeflate diff --git a/templates/nginx/custom_configs/letsencrypt.conf b/templates/nginx/custom_configs/letsencrypt.conf new file mode 100644 index 0000000..c7882d9 --- /dev/null +++ b/templates/nginx/custom_configs/letsencrypt.conf @@ -0,0 +1,10 @@ +location ^~ /.well-known/acme-challenge/ { + default_type "text/plain"; + root /var/www/letsencrypt; + allow all; +} +# esattamente questa riga: proibisce l'accesso alla dir (per non far leggere +# quali challenge aperti ci sono) +location = /.well-known/acme-challenge/ { + return 404; +} diff --git a/templates/nginx/sites.conf.j2 b/templates/nginx/sites.conf.j2 new file mode 100644 index 0000000..a32793f --- /dev/null +++ b/templates/nginx/sites.conf.j2 @@ -0,0 +1,42 @@ +server { + listen {{ service.port | default(80) }}; + + server_name {{ service.domain_name }}; + access_log /var/log/nginx/{{ service.domain_name }}-access.log; + error_log /var/log/nginx/{{ service.domain_name }}-error.log; + + include letsencrypt.conf; + + {% if service.redirect_to_https %} + location / { + return 301 https://$host$request_uri; + } + {% else %} + location / { + proxy_pass http://{{ service.internal_ip }}:{{ service.internal_port }}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + {% if service.http_opts is defined %} + {% for opt in service.http_opts %} + {{ opt }} + {% endfor %} + {% endif %} + } + {% endif %} + {% if service.http_custom_locations is defined %} + {% for location in service.http_custom_locations %} + location {{ location.rule }} { + {% for conf_line in location.conf_lines %} + {{ conf_line }}; + {% endfor %} + } + {% endfor %} + {% endif %} + {% if service.http_custom_configurations is defined %} + {% for conf in service.http_custom_configurations %} + {{ conf }}; + {% endfor %} + {% endif %} +} diff --git a/templates/nginx/sites_ssl.conf.j2 b/templates/nginx/sites_ssl.conf.j2 new file mode 100644 index 0000000..c70e873 --- /dev/null +++ b/templates/nginx/sites_ssl.conf.j2 @@ -0,0 +1,53 @@ +server { + listen {{ service.ssl_port | default(443) }}; + + server_name {{ service.domain_name }}; + access_log /var/log/nginx/{{ service.domain_name }}-ssl-access.log; + error_log /var/log/nginx/{{ service.domain_name }}-ssl-error.log; + + include ssl_{{ service.domain_name }}.conf; + + {% if service.password_protect|default(false) %} + auth_basic "{{ service.domain_name }} is password protected"; + auth_basic_user_file {{ service.password_file }}; + {% endif %} + + location / { + proxy_pass http://{{ service.internal_ip }}:{{ service.internal_port }}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + {% if service.https_opts is defined %} + {% for opt in service.https_opts %} + {{ opt }} + {% endfor %} + {% endif %} + } + + {% if service.websockets is defined %} + location {{ service.websockets.path }} { + proxy_pass http://{{ service.websockets.internal_ip }}:{{ service.websockets.internal_port }}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + {% endif %} + {% if service.https_custom_locations is defined %} + {% for location in service.https_custom_locations %} + location {{ location.rule }} { + {% for conf_line in location.conf_lines %} + {{ conf_line }}; + {% endfor %} + } + {% endfor %} + {% endif %} + {% if service.https_custom_configurations is defined %} + {% for conf in service.https_custom_configurations %} + {{ conf }}; + {% endfor %} + {% endif %} +} diff --git a/templates/nginx/ssl.conf.j2 b/templates/nginx/ssl.conf.j2 new file mode 100644 index 0000000..3b23523 --- /dev/null +++ b/templates/nginx/ssl.conf.j2 @@ -0,0 +1,8 @@ +ssl on; +ssl_certificate /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/{{ domain_name }}/privkey.pem; +ssl_session_cache builtin:1000 shared:SSL:10m; +ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; +ssl_prefer_server_ciphers on; + diff --git a/templates/wireguard/wireguard.netdev.j2 b/templates/wireguard/wireguard.netdev.j2 new file mode 100644 index 0000000..e33b4df --- /dev/null +++ b/templates/wireguard/wireguard.netdev.j2 @@ -0,0 +1,16 @@ +[NetDev] +Name={{ gateway.vpn.name }} +Kind=wireguard +Description=WireGuard tunnel {{ gateway.vpn.name }} + +[WireGuard] +ListenPort={{ gateway.vpn.listen_port|default(51714) }} +PrivateKey={{ gateway.vpn.private_key }} + +[WireGuardPeer] +PublicKey={{ gateway.vpn.endpoint.public_key }} +# The following will route all the traffic through the vpn endpoint +AllowedIPs=0.0.0.0/0 +Endpoint={{ gateway.vpn.endpoint.url }}:{{ gateway.vpn.endpoint.port }} + +# vim: set ft=dosini: diff --git a/templates/wireguard/wireguard.network.j2 b/templates/wireguard/wireguard.network.j2 new file mode 100644 index 0000000..2290807 --- /dev/null +++ b/templates/wireguard/wireguard.network.j2 @@ -0,0 +1,20 @@ +[Match] +Name={{ gateway.vpn.name }} + +[Network] +Address={{ gateway.vpn.this_ip }}/32 + +[Route] +Destination={{ gateway.vpn.endpoint.this_ip }}/32 +Scope=link + +[Route] +Destination=0.0.0.0/1 +Gateway={{ gateway.vpn.endpoint.this_ip }} + +[Route] +Destination=128.0.0.0/1 +Gateway={{ gateway.vpn.endpoint.this_ip }} + + +# vim: set ft=dosini: