diff --git a/common.yml b/common.yml deleted file mode 100644 index ee2c952..0000000 --- a/common.yml +++ /dev/null @@ -1,104 +0,0 @@ -# vim:ft=ansible: ---- - -- name: Common tools - hosts: vpn-host - gather_facts: false - become: true - vars_files: - - config.cfg - - pre_tasks: - - name: Install prerequisites - raw: sudo apt-get update -qq && sudo apt-get install -qq -y python2.7 - - name: Configure defaults - raw: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 - - tasks: - - name: Wait for port 22 to become available - local_action: "wait_for port=22 host={{ inventory_hostname }}" - become: false - - - name: Gather Facts - setup: - - - name: Install software updates - apt: update_cache=yes upgrade=dist - - - name: Check if reboot is required - shell: > - if [[ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]]; then echo "required"; else echo "no"; fi - args: - executable: /bin/bash - register: reboot_required - - - name: Reboot - shell: sleep 2 && shutdown -r now "Ansible updates triggered" - async: 1 - poll: 0 - when: reboot_required is defined and reboot_required.stdout == 'required' - ignore_errors: true - - - name: Wait for shutdown - local_action: wait_for host={{ inventory_hostname }} port=22 state=stopped timeout=120 - when: reboot_required is defined and reboot_required.stdout == 'required' - become: false - - - name: Wait until SSH becomes ready... - local_action: wait_for host={{ inventory_hostname }} port=22 state=started timeout=120 - when: reboot_required is defined and reboot_required.stdout == 'required' - become: false - - # SSH fixes - - - name: SSH config - lineinfile: dest="{{ item.file }}" regexp="{{ item.regexp }}" line="{{ item.line }}" state=present - with_items: - - { regexp: '^PasswordAuthentication.*', line: 'PasswordAuthentication no', file: '/etc/ssh/sshd_config' } - - { regexp: '^PermitRootLogin.*', line: 'PermitRootLogin without-password', file: '/etc/ssh/sshd_config' } - - { regexp: '^UseDNS.*', line: 'UseDNS no', file: '/etc/ssh/sshd_config' } - - { regexp: '^Ciphers', line: 'Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com', file: '/etc/ssh/sshd_config' } - - { regexp: '^MACs', line: 'MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com', file: '/etc/ssh/sshd_config' } - - { regexp: '^KexAlgorithms', line: 'KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384', file: '/etc/ssh/sshd_config' } - notify: - - restart ssh - - - name: Disable MOTD on login and SSHD - replace: dest="{{ item.file }}" regexp="{{ item.regexp }}" replace="{{ item.line }}" - with_items: - - { regexp: '^session.*optional.*pam_motd.so.*', line: '# MOTD DISABLED', file: '/etc/pam.d/login' } - - { regexp: '^session.*optional.*pam_motd.so.*', line: '# MOTD DISABLED', file: '/etc/pam.d/sshd' } - - - name: Install tools - apt: name="{{ item }}" state=latest - with_items: - - git - - screen - - apparmor-utils - - uuid-runtime - - coreutils - - auditd - - rsyslog - - sendmail - - unattended-upgrades - - iptables-persistent - - - name: Configure unattended-upgrades - template: src=50unattended-upgrades.j2 dest=/etc/apt/apt.conf.d/50unattended-upgrades owner=root group=root mode=644 - - - name: Periodic upgrades configured - template: src=10periodic.j2 dest=/etc/apt/apt.conf.d/10periodic owner=root group=root mode=644 - - handlers: - - name: restart auditd - service: name=auditd state=restarted - - - name: restart rsyslog - service: name=rsyslog state=restarted - - - name: restart ssh - service: name=ssh state=restarted - - - name: flush routing cache - shell: echo 1 > /proc/sys/net/ipv4/route/flush - diff --git a/deploy.yml b/deploy.yml index 9e06c58..5d68069 100644 --- a/deploy.yml +++ b/deploy.yml @@ -1,8 +1,4 @@ --- - include: "{{ provider }}.yml" -- include: common.yml -- include: security.yml -- include: features.yml -- include: vpn.yml diff --git a/digitalocean.yml b/digitalocean.yml index d46c175..cce9a47 100644 --- a/digitalocean.yml +++ b/digitalocean.yml @@ -46,67 +46,24 @@ prompt: "Name the vpn server:\n" default: "algo.local" private: no - - tasks: - - name: "Getting your SSH key ID on Digital Ocean..." - digital_ocean: - state: present - command: ssh - name: "{{ do_ssh_name }}" - api_token: "{{ do_access_token }}" - register: do_ssh_key - - - name: "Creating a droplet..." - digital_ocean: - state: present - command: droplet - name: "{{ do_server_name }}" - region_id: "{{ regions[do_region] }}" - size_id: "512mb" - image_id: "ubuntu-16-04-x64" - ssh_key_ids: "{{ do_ssh_key.ssh_key.id }}" - unique_name: yes - api_token: "{{ do_access_token }}" - register: do - - - name: Add the droplet to an inventory group - add_host: - name: "{{ do.droplet.ip_address }}" - groups: vpn-host - ansible_ssh_user: root - ansible_python_interpreter: "/usr/bin/python2.7" - - - name: Wait for SSH to become available - local_action: "wait_for port=22 host={{ do.droplet.ip_address }} timeout=320" - - name: Enable IPv6 on the droplet - uri: - url: "https://api.digitalocean.com/v2/droplets/{{ do.droplet.id }}/actions" - method: POST - body: - type: enable_ipv6 - body_format: json - status_code: 201 - HEADER_Authorization: "Bearer {{ do_access_token }}" - HEADER_Content-Type: "application/json" - - - name: Get Droplet networks - uri: - url: "https://api.digitalocean.com/v2/droplets/{{ do.droplet.id }}" - method: GET - status_code: 200 - HEADER_Authorization: "Bearer {{ do_access_token }}" - HEADER_Content-Type: "application/json" - register: droplet_info + - name: "dns_enabled" + prompt: "Do you want to use a local DNS resolver to block ads while surfing? (Y or N):\n" + default: "Y" + private: no - - name: IPv6 template created - template: src=20-ipv6.cfg.j2 dest=configs/20-ipv6.tmp - with_items: "{{ droplet_info.json.droplet.networks.v6 }}" + - name: "auditd_enabled" + prompt: "Do you want to use auditd ? (Y or N):\n" + default: "Y" + private: no + + roles: + - digitalocean - name: Post-provisioning tasks hosts: vpn-host gather_facts: false - user: root + become: true vars_files: - config.cfg @@ -115,19 +72,54 @@ raw: sudo apt-get update -qq && sudo apt-get install -qq -y python2.7 - name: Configure defaults raw: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 - - tasks: + + - name: Enable IPv6 on the droplet + uri: + url: "https://api.digitalocean.com/v2/droplets/{{ do_droplet_id }}/actions" + method: POST + body: + type: enable_ipv6 + body_format: json + status_code: 201 + HEADER_Authorization: "Bearer {{ do_access_token }}" + HEADER_Content-Type: "application/json" + + - name: Get Droplet networks + uri: + url: "https://api.digitalocean.com/v2/droplets/{{ do_droplet_id }}" + method: GET + status_code: 200 + HEADER_Authorization: "Bearer {{ do_access_token }}" + HEADER_Content-Type: "application/json" + register: droplet_info + - name: IPv6 configured - copy: src=configs/20-ipv6.tmp dest=/etc/network/interfaces.d/20-ipv6.cfg owner=root group=root mode=0644 + template: src=20-ipv6.cfg.j2 dest=/etc/network/interfaces.d/20-ipv6.cfg owner=root group=root mode=0644 + with_items: "{{ droplet_info.json.droplet.networks.v6 }}" + notify: + - reload eth0 - name: IPv6 included into the network config lineinfile: dest=/etc/network/interfaces line='source /etc/network/interfaces.d/20-ipv6.cfg' state=present - - - name: IPV6 is running - shell: sh -c 'ifdown eth0; ip addr flush dev eth0; ifup eth0' + notify: + - reload eth0 + + - meta: flush_handlers - name: Wait for SSH to become available local_action: "wait_for port=22 host={{ inventory_hostname }} timeout=320" become: false + + roles: + - common + - security + - features + - vpn + + handlers: + - name: reload eth0 + shell: sh -c 'ifdown eth0; ip addr flush dev eth0; ifup eth0' + + diff --git a/ec2.yml b/ec2.yml index 486f991..1aa6c14 100644 --- a/ec2.yml +++ b/ec2.yml @@ -34,7 +34,17 @@ 10. eu-west-1 EU (Ireland) 11. sa-east-1 South America (São Paulo) default: "1" - private: no + private: no + + - name: "dns_enabled" + prompt: "Do you want to use a local DNS resolver to block ads while surfing? (Y or N):\n" + default: "Y" + private: no + + - name: "auditd_enabled" + prompt: "Do you want to use auditd ? (Y or N):\n" + default: "Y" + private: no tasks: @@ -107,14 +117,35 @@ register: ec2 - name: Add new instance to host group - add_host: hostname={{ item.public_ip }} groupname=vpn-host remote_user=ubuntu ansible_python_interpreter="/usr/bin/python2.7" + add_host: + hostname: "{{ item.public_ip }}" + groupname: vpn-host + remote_user: ubuntu + ansible_python_interpreter: "/usr/bin/python2.7" + dns_enabled: "{{ dns_enabled }}" + auditd_enabled: " {{ auditd_enabled }}" with_items: "{{ ec2.instances }}" - name: Wait for SSH to come up wait_for: host={{ item.public_dns_name }} port=22 delay=60 timeout=320 state=started with_items: "{{ ec2.instances }}" - - - name: accept new ssh fingerprints - shell: ssh-keyscan -H {{ item.public_ip }} >> ~/.ssh/known_hosts - with_items: "{{ ec2.instances }}" + +- name: Post-provisioning tasks + hosts: vpn-host + gather_facts: false + become: true + vars_files: + - config.cfg + + pre_tasks: + - name: Install prerequisites + raw: sudo apt-get update -qq && sudo apt-get install -qq -y python2.7 + - name: Configure defaults + raw: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 + + roles: + - common + - security + - features + - vpn diff --git a/features.yml b/features.yml deleted file mode 100644 index 3ab5aa0..0000000 --- a/features.yml +++ /dev/null @@ -1,160 +0,0 @@ ---- - -- name: Other features - hosts: vpn-host - become: true - vars_files: - - config.cfg - - tasks: - - name: Loopback for services configured - template: src=10-loopback-services.cfg.j2 dest=/etc/network/interfaces.d/10-loopback-services.cfg - - - name: Loopback included into the network config - lineinfile: dest=/etc/network/interfaces line='source /etc/network/interfaces.d/10-loopback-services.cfg' state=present - - - name: Loopback is running - shell: ifdown lo:100 && ifup lo:100 - - # Privoxy - - - name: Install privoxy - apt: name=privoxy state=latest - - - name: Privoxy configured - template: src=privoxy_config.j2 dest=/etc/privoxy/config - notify: - - restart privoxy - - - name: Privoxy profile for apparmor configured - template: src=usr.sbin.privoxy.j2 dest=/etc/apparmor.d/usr.sbin.privoxy owner=root group=root mode=600 - notify: - - restart privoxy - - - name: Enforce the privoxy AppArmor policy - shell: aa-enforce usr.sbin.privoxy - - - name: Privoxy enabled and started - service: name=privoxy state=started enabled=yes - - # PageSpeed - - - name: Apache installed - apt: name=apache2 state=latest - - - name: PageSpeed installed for x86_64 - apt: deb=https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb - when: ansible_architecture == "x86_64" - - - name: PageSpeed installed for i386 - apt: deb=https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_i386.deb - when: ansible_architecture != "x86_64" - - - name: PageSpeed configured - template: src=pagespeed.conf.j2 dest=/etc/apache2/mods-available/pagespeed.conf - notify: - - restart apache2 - - - name: Modules enabled - apache2_module: state=present name="{{ item }}" - with_items: - - proxy_http - - pagespeed - - cache - - proxy_connect - - proxy_html - - rewrite - notify: - - restart apache2 - - - name: VirtualHost configured for the PageSpeed module - template: src=000-default.conf.j2 dest=/etc/apache2/sites-enabled/000-default.conf - notify: - - restart apache2 - - - name: Apache ports configured - template: src=ports.conf.j2 dest=/etc/apache2/ports.conf - notify: - - restart apache2 - - # DNS - - - name: Install dnsmasq - apt: name=dnsmasq state=latest - - - name: Dnsmasq profile for apparmor configured - template: src=usr.sbin.dnsmasq.j2 dest=/etc/apparmor.d/usr.sbin.dnsmasq owner=root group=root mode=600 - notify: - - restart dnsmasq - - - name: Enforce the dnsmasq AppArmor policy - shell: aa-enforce usr.sbin.dnsmasq - - - name: Dnsmasq configured - template: src=dnsmasq.conf.j2 dest=/etc/dnsmasq.conf - notify: - - restart dnsmasq - - - name: Adblock script created - copy: src=templates/adblock.sh dest=/opt/adblock.sh owner=root group=root mode=755 - when: service_dns is defined and service_dns == "True" - - - name: Adblock script added to cron - cron: name="Adblock hosts update" minute="10" hour="2" job="/opt/adblock.sh" - when: service_dns is defined and service_dns == "True" - - - name: Update adblock hosts - shell: > - /opt/adblock.sh - when: service_dns is defined and service_dns == "True" - - - name: Forward all DNS requests to the local resolver - iptables: - table: nat - chain: PREROUTING - protocol: udp - destination_port: 53 - source: "{{ vpn_network }}" - jump: DNAT - to_destination: 172.16.0.1:53 - notify: - - save iptables - when: service_dns is defined and service_dns == "True" - - - name: Forward all DNS requests to the local resolver - iptables: - table: nat - chain: PREROUTING - protocol: udp - destination_port: 53 - source: "{{ vpn_network_ipv6 }}" - jump: DNAT - to_destination: fcaa::1:53 - ip_version: ipv6 - notify: - - save iptables - when: service_dns is defined and service_dns == "True" - - - name: Dnsmasq enabled and started - service: name=dnsmasq state=started enabled=yes - when: service_dns is defined and service_dns == "True" - - - name: Dnsmasq disabled and stopped - service: name=dnsmasq state=stopped enabled=no - when: service_dns is defined and service_dns == "False" - - handlers: - - name: restart privoxy - service: name=privoxy state=restarted - - - name: restart dnsmasq - service: name=dnsmasq state=restarted - - - name: restart apparmor - service: name=apparmor state=restarted - - - name: restart apache2 - service: name=apache2 state=restarted - - - name: save iptables - command: service netfilter-persistent save diff --git a/inventory_users b/inventory_users index 8e9e7af..3f92636 100644 --- a/inventory_users +++ b/inventory_users @@ -1,2 +1,4 @@ [user-management] +146.185.162.155 +37.139.21.209 37.139.0.99 diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml new file mode 100644 index 0000000..d7a822d --- /dev/null +++ b/roles/common/handlers/main.yml @@ -0,0 +1,9 @@ +- name: restart rsyslog + service: name=rsyslog state=restarted + +- name: restart ssh + service: name=ssh state=restarted + +- name: flush routing cache + shell: echo 1 > /proc/sys/net/ipv4/route/flush + diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..078726a --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,70 @@ +--- + +- name: Gather Facts + setup: + +- name: Install software updates + apt: update_cache=yes upgrade=dist + +- name: Check if reboot is required + shell: > + if [[ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]]; then echo "required"; else echo "no"; fi + args: + executable: /bin/bash + register: reboot_required + +- name: Reboot + shell: sleep 2 && shutdown -r now "Ansible updates triggered" + async: 1 + poll: 0 + when: reboot_required is defined and reboot_required.stdout == 'required' + ignore_errors: true + +- name: Wait for shutdown + local_action: wait_for host={{ inventory_hostname }} port=22 state=stopped timeout=120 + when: reboot_required is defined and reboot_required.stdout == 'required' + become: false + +- name: Wait until SSH becomes ready... + local_action: wait_for host={{ inventory_hostname }} port=22 state=started timeout=120 + when: reboot_required is defined and reboot_required.stdout == 'required' + become: false + +# SSH fixes + +- name: SSH config + lineinfile: dest="{{ item.file }}" regexp="{{ item.regexp }}" line="{{ item.line }}" state=present + with_items: + - { regexp: '^PasswordAuthentication.*', line: 'PasswordAuthentication no', file: '/etc/ssh/sshd_config' } + - { regexp: '^PermitRootLogin.*', line: 'PermitRootLogin without-password', file: '/etc/ssh/sshd_config' } + - { regexp: '^UseDNS.*', line: 'UseDNS no', file: '/etc/ssh/sshd_config' } + - { regexp: '^Ciphers', line: 'Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com', file: '/etc/ssh/sshd_config' } + - { regexp: '^MACs', line: 'MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com', file: '/etc/ssh/sshd_config' } + - { regexp: '^KexAlgorithms', line: 'KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384', file: '/etc/ssh/sshd_config' } + notify: + - restart ssh + +- name: Disable MOTD on login and SSHD + replace: dest="{{ item.file }}" regexp="{{ item.regexp }}" replace="{{ item.line }}" + with_items: + - { regexp: '^session.*optional.*pam_motd.so.*', line: '# MOTD DISABLED', file: '/etc/pam.d/login' } + - { regexp: '^session.*optional.*pam_motd.so.*', line: '# MOTD DISABLED', file: '/etc/pam.d/sshd' } + +- name: Install tools + apt: name="{{ item }}" state=latest + with_items: + - git + - screen + - apparmor-utils + - uuid-runtime + - coreutils + - rsyslog + - sendmail + - unattended-upgrades + - iptables-persistent + +- name: Configure unattended-upgrades + template: src=50unattended-upgrades.j2 dest=/etc/apt/apt.conf.d/50unattended-upgrades owner=root group=root mode=644 + +- name: Periodic upgrades configured + template: src=10periodic.j2 dest=/etc/apt/apt.conf.d/10periodic owner=root group=root mode=644 diff --git a/roles/digitalocean/handlers/main.yml b/roles/digitalocean/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/digitalocean/tasks/main.yml b/roles/digitalocean/tasks/main.yml new file mode 100644 index 0000000..8f0c20f --- /dev/null +++ b/roles/digitalocean/tasks/main.yml @@ -0,0 +1,39 @@ +- name: Set the DigitalOcean Access Token fact + set_fact: + do_token: "{{ do_access_token | default( lookup('env', 'DIGITALOCEAN_API_KEY') ) }}" + +- name: "Getting your SSH key ID on Digital Ocean..." + digital_ocean: + state: present + command: ssh + name: "{{ do_ssh_name }}" + api_token: "{{ do_access_token }}" + register: do_ssh_key + +- name: "Creating a droplet..." + digital_ocean: + state: present + command: droplet + name: "{{ do_server_name }}" + region_id: "{{ regions[do_region] }}" + size_id: "512mb" + image_id: "ubuntu-16-04-x64" + ssh_key_ids: "{{ do_ssh_key.ssh_key.id }}" + unique_name: yes + api_token: "{{ do_access_token }}" + register: do + +- name: Add the droplet to an inventory group + add_host: + name: "{{ do.droplet.ip_address }}" + groups: vpn-host + ansible_ssh_user: root + ansible_python_interpreter: "/usr/bin/python2.7" + do_access_token: "{{ do_access_token }}" + do_droplet_id: "{{ do.droplet.id }}" + dns_enabled: "{{ dns_enabled }}" + auditd_enabled: " {{ auditd_enabled }}" + +- name: Wait for SSH to become available + local_action: "wait_for port=22 host={{ do.droplet.ip_address }} timeout=320" + diff --git a/roles/features/handlers/main.yml b/roles/features/handlers/main.yml new file mode 100644 index 0000000..284064f --- /dev/null +++ b/roles/features/handlers/main.yml @@ -0,0 +1,17 @@ +- name: restart privoxy + service: name=privoxy state=restarted + +- name: restart dnsmasq + service: name=dnsmasq state=restarted + +- name: restart apparmor + service: name=apparmor state=restarted + +- name: restart apache2 + service: name=apache2 state=restarted + +- name: save iptables + command: service netfilter-persistent save + +- name: restart loopback + shell: ifdown lo:100 && ifup lo:100 diff --git a/roles/features/tasks/main.yml b/roles/features/tasks/main.yml new file mode 100644 index 0000000..b305b80 --- /dev/null +++ b/roles/features/tasks/main.yml @@ -0,0 +1,141 @@ +- name: Gather Facts + setup: + +- name: Loopback for services configured + template: src=10-loopback-services.cfg.j2 dest=/etc/network/interfaces.d/10-loopback-services.cfg + notify: + - restart loopback + +- name: Loopback included into the network config + lineinfile: dest=/etc/network/interfaces line='source /etc/network/interfaces.d/10-loopback-services.cfg' state=present + notify: + - restart loopback + +- meta: flush_handlers + +# Privoxy + +- name: Privoxy installed + apt: name=privoxy state=latest + +- name: Privoxy configured + template: src=privoxy_config.j2 dest=/etc/privoxy/config + notify: + - restart privoxy + +- name: Privoxy profile for apparmor configured + template: src=usr.sbin.privoxy.j2 dest=/etc/apparmor.d/usr.sbin.privoxy owner=root group=root mode=600 + notify: + - restart privoxy + +- name: Enforce the privoxy AppArmor policy + shell: aa-enforce usr.sbin.privoxy + +- name: Privoxy enabled and started + service: name=privoxy state=started enabled=yes + +# PageSpeed + +- name: Apache installed + apt: name=apache2 state=latest + +- name: PageSpeed installed for x86_64 + apt: deb=https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb + when: ansible_architecture == "x86_64" + +- name: PageSpeed installed for i386 + apt: deb=https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_i386.deb + when: ansible_architecture != "x86_64" + +- name: PageSpeed configured + template: src=pagespeed.conf.j2 dest=/etc/apache2/mods-available/pagespeed.conf + notify: + - restart apache2 + +- name: Modules enabled + apache2_module: state=present name="{{ item }}" + with_items: + - proxy_http + - pagespeed + - cache + - proxy_connect + - proxy_html + - rewrite + notify: + - restart apache2 + +- name: VirtualHost configured for the PageSpeed module + template: src=000-default.conf.j2 dest=/etc/apache2/sites-enabled/000-default.conf + notify: + - restart apache2 + +- name: Apache ports configured + template: src=ports.conf.j2 dest=/etc/apache2/ports.conf + notify: + - restart apache2 + +# DNS + +- name: Dnsmasq installed + apt: name=dnsmasq state=latest + +- name: Dnsmasq profile for apparmor configured + template: src=usr.sbin.dnsmasq.j2 dest=/etc/apparmor.d/usr.sbin.dnsmasq owner=root group=root mode=600 + notify: + - restart dnsmasq + +- name: Enforce the dnsmasq AppArmor policy + shell: aa-enforce usr.sbin.dnsmasq + +- name: Dnsmasq configured + template: src=dnsmasq.conf.j2 dest=/etc/dnsmasq.conf + notify: + - restart dnsmasq + +- name: Adblock script created + copy: src=templates/adblock.sh dest=/opt/adblock.sh owner=root group=root mode=755 + when: dns_enabled is defined and dns_enabled == "Y" + +- name: Adblock script added to cron + cron: name="Adblock hosts update" minute="10" hour="2" job="/opt/adblock.sh" + when: dns_enabled is defined and dns_enabled == "Y" + +- name: Update adblock hosts + shell: > + /opt/adblock.sh + when: dns_enabled is defined and dns_enabled == "Y" + +- name: Forward all DNS requests to the local resolver + iptables: + table: nat + chain: PREROUTING + protocol: udp + destination_port: 53 + source: "{{ vpn_network }}" + jump: DNAT + to_destination: 172.16.0.1:53 + notify: + - save iptables + when: dns_enabled is defined and dns_enabled == "Y" + +- name: Forward all DNS requests to the local resolver + iptables: + table: nat + chain: PREROUTING + protocol: udp + destination_port: 53 + source: "{{ vpn_network_ipv6 }}" + jump: DNAT + to_destination: fcaa::1:53 + ip_version: ipv6 + notify: + - save iptables + when: dns_enabled is defined and dns_enabled == "Y" + +- name: Dnsmasq enabled and started + service: name=dnsmasq state=started enabled=yes + when: dns_enabled is defined and dns_enabled == "Y" + +- name: Dnsmasq disabled and stopped + service: name=dnsmasq state=stopped enabled=no + when: dns_enabled is defined and dns_enabled != "Y" diff --git a/roles/security/handlers/main.yml b/roles/security/handlers/main.yml new file mode 100644 index 0000000..248066a --- /dev/null +++ b/roles/security/handlers/main.yml @@ -0,0 +1,8 @@ +- name: restart auditd + service: name=auditd state=restarted + +- name: restart rsyslog + service: name=rsyslog state=restarted + +- name: flush routing cache + shell: echo 1 > /proc/sys/net/ipv4/route/flush diff --git a/roles/security/tasks/main.yml b/roles/security/tasks/main.yml new file mode 100644 index 0000000..cfe41c5 --- /dev/null +++ b/roles/security/tasks/main.yml @@ -0,0 +1,124 @@ + + +# Using a two-pass approach for checking directories in order to support symlinks. +- name: Find directories for minimizing access + stat: + path: "{{ item }}" + register: minimize_access_directories + with_items: + - '/usr/local/sbin' + - '/usr/local/bin' + - '/usr/sbin' + - '/usr/bin' + - '/sbin' + - '/bin' + +- name: Minimize access + file: path='{{ item.stat.path }}' mode='go-w' recurse=yes + when: item.stat.isdir + with_items: "{{ minimize_access_directories.results }}" + no_log: True + +- name: Change shadow ownership to root and mode to 0600 + file: dest='/etc/shadow' owner=root group=root mode=0600 + +- name: change su-binary to only be accessible to user and group root + file: dest='/bin/su' owner=root group=root mode=0750 + +- name: Collect Use of privileged commands + shell: > + /usr/bin/find {/usr/local/sbin,/usr/local/bin,/sbin,/bin,/usr/sbin,/usr/bin} -xdev \( -perm -4000 -o -perm -2000 \) -type f | awk '{print "-a always,exit -F path=" $1 " -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged" }' + args: + executable: /bin/bash + register: privileged_programs + +# auditd + +- name: Auditd installed + apt: name=auditd state=latest + when: auditd_enabled is defined and auditd_enabled == 'Y' + +- name: Auditd rules configured + template: src=audit.rules.j2 dest=/etc/audit/audit.rules + notify: + - restart auditd + when: auditd_enabled is defined and auditd_enabled == 'Y' + +- name: Auditd configured + template: src=auditd.conf.j2 dest=/etc/audit/auditd.conf + notify: + - restart auditd + when: auditd_enabled is defined and auditd_enabled == 'Y' + +- name: Enable services + service: name=auditd enabled=yes + when: auditd_enabled is defined and auditd_enabled == 'Y' + +# Rsyslog + +- name: Rsyslog configured + template: src=rsyslog.conf.j2 dest=/etc/rsyslog.conf + notify: + - restart rsyslog + +- name: Rsyslog CIS configured + template: src=CIS.conf.j2 dest=/etc/rsyslog.d/CIS.conf owner=root group=root mode=0644 + notify: + - restart rsyslog + +- name: Enable services + service: name=rsyslog enabled=yes + +# Core dumps + +- name: Restrict core dumps (with PAM) + lineinfile: dest=/etc/security/limits.conf line="* hard core 0" state=present + +- name: Restrict core dumps (with sysctl) + sysctl: name=fs.suid_dumpable value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present + +# Kernel fixes + +- name: Disable Source Routed Packet Acceptance + sysctl: name="{{item}}" value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present + with_items: + - net.ipv4.conf.all.accept_source_route + - net.ipv4.conf.default.accept_source_route + notify: + - flush routing cache + +- name: Disable ICMP Redirect Acceptance + sysctl: name="{{item}}" value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present + with_items: + - net.ipv4.conf.all.accept_redirects + - net.ipv4.conf.default.accept_redirects + +- name: Disable Secure ICMP Redirect Acceptance + sysctl: name="{{item}}" value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present + with_items: + - net.ipv4.conf.all.secure_redirects + - net.ipv4.conf.default.secure_redirects + notify: + - flush routing cache + +- name: Enable Bad Error Message Protection + sysctl: name=net.ipv4.icmp_ignore_bogus_error_responses value=1 ignoreerrors=yes sysctl_set=yes reload=yes state=present + notify: + - flush routing cache + +- name: Enable RFC-recommended Source Route Validation + sysctl: name="{{item}}" value=1 ignoreerrors=yes sysctl_set=yes reload=yes state=present + with_items: + - net.ipv4.conf.all.rp_filter + - net.ipv4.conf.default.rp_filter + notify: + - flush routing cache + +- name: Enable packet forwarding for IPv4 + sysctl: name=net.ipv4.ip_forward value=1 + +- name: Enable packet forwarding for IPv6 + sysctl: name=net.ipv6.conf.all.forwarding value=1 + +- name: Do not send ICMP redirects (we are not a router) + sysctl: name=net.ipv4.conf.all.send_redirects value=0 diff --git a/roles/vpn/handlers/main.yml b/roles/vpn/handlers/main.yml new file mode 100644 index 0000000..d070b51 --- /dev/null +++ b/roles/vpn/handlers/main.yml @@ -0,0 +1,20 @@ +- name: restart strongswan + service: name=strongswan state=restarted + +- name: restart apparmor + service: name=apparmor state=restarted + +- name: save iptables + command: service netfilter-persistent save + +- name: congrats + debug: + msg: + - "#----------------------------------------------------------------------#" + - "# Congratulations! #" + - "# Your Algo server is running. #" + - "# Config files and certificates are in the ./configs/ directory. #" + - "# Go to https://www.dnsleaktest.com/ after connecting #" + - "# and ensure that all your traffic passes through the VPN. #" + - "# Local DNS resolver and Proxy IP address: 172.16.0.1 #" + - "#----------------------------------------------------------------------#" diff --git a/roles/vpn/tasks/main.yml b/roles/vpn/tasks/main.yml new file mode 100644 index 0000000..478c437 --- /dev/null +++ b/roles/vpn/tasks/main.yml @@ -0,0 +1,144 @@ +- name: Install StrongSwan + apt: name=strongswan state=latest update_cache=yes + +- name: Enforcing ipsec with apparmor + shell: aa-enforce "{{ item }}" + with_items: + - /usr/lib/ipsec/charon + - /usr/lib/ipsec/lookip + - /usr/lib/ipsec/stroke + notify: + - restart apparmor + +- name: Enable services + service: name={{ item }} enabled=yes + with_items: + - apparmor + - strongswan + - netfilter-persistent + +- name: Configure iptables so IPSec traffic can traverse the tunnel + iptables: table=nat chain=POSTROUTING source="{{ vpn_network }}" jump=MASQUERADE + notify: + - save iptables + +- name: Configure ip6tables so IPSec traffic can traverse the tunnel + iptables: ip_version=ipv6 table=nat chain=POSTROUTING source="{{ vpn_network_ipv6 }}" jump=MASQUERADE + notify: + - save iptables + +- name: Setup the ipsec.conf file from our template + template: src=ipsec.conf.j2 dest=/etc/ipsec.conf owner=root group=root mode=644 + notify: + - restart strongswan + +- name: Setup the ipsec.secrets file + template: src=ipsec.secrets.j2 dest=/etc/ipsec.secrets owner=root group=root mode=600 + notify: + - restart strongswan + +- name: Fetch easy-rsa-ipsec from git + git: repo=git://github.com/ValdikSS/easy-rsa-ipsec.git dest="{{ easyrsa_dir }}" + +- name: Setup the vars file from our template + template: src=easy-rsa.vars.j2 dest={{ easyrsa_dir }}/easyrsa3/vars + +- name: Ensure the pki directory is not exist + file: dest={{ easyrsa_dir }}/easyrsa3/pki state=absent + when: easyrsa_reinit_existent == True + +- name: Build the pki enviroments + shell: > + ./easyrsa init-pki && + touch '{{ easyrsa_dir }}/easyrsa3/pki/pki_initialized' + args: + chdir: '{{ easyrsa_dir }}/easyrsa3/' + creates: '{{ easyrsa_dir }}/easyrsa3/pki/pki_initialized' + +- name: Build the CA pair + shell: > + ./easyrsa build-ca nopass && + touch {{ easyrsa_dir }}/easyrsa3/pki/ca_initialized + args: + chdir: '{{ easyrsa_dir }}/easyrsa3/' + creates: '{{ easyrsa_dir }}/easyrsa3/pki/ca_initialized' + notify: + - restart strongswan + +- name: Build the server pair + shell: > + ./easyrsa --subject-alt-name='DNS:{{ server_name }},IP:{{ ansible_ssh_host }}' build-server-full {{ ansible_ssh_host }} nopass&& + touch '{{ easyrsa_dir }}/easyrsa3/pki/server_initialized' + args: + chdir: '{{ easyrsa_dir }}/easyrsa3/' + creates: '{{ easyrsa_dir }}/easyrsa3/pki/server_initialized' + notify: + - restart strongswan + +- name: Build the client's pair + shell: > + ./easyrsa build-client-full {{ item }} nopass && + touch '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized' + args: + chdir: '{{ easyrsa_dir }}/easyrsa3/' + creates: '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized' + with_items: "{{ users }}" + +- name: Build the client's p12 + shell: > + openssl pkcs12 -in {{ easyrsa_dir }}/easyrsa3//pki/issued/{{ item }}.crt -inkey {{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.key -export -name {{ item }} -out /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 -certfile {{ easyrsa_dir }}/easyrsa3//pki/ca.crt -passout pass:{{ easyrsa_p12_export_password }} && + touch '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_p12_initialized' + args: + chdir: '{{ easyrsa_dir }}/easyrsa3/' + creates: '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_p12_initialized' + with_items: "{{ users }}" + +- name: Copy the CA cert to the strongswan directory + copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/ca.crt' dest=/etc/ipsec.d/cacerts/ca.crt owner=root group=root mode=0600 + notify: + - restart strongswan + +- name: Copy the server cert to the strongswan directory + copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/issued/{{ ansible_ssh_host }}.crt' dest=/etc/ipsec.d/certs/{{ ansible_ssh_host }}.crt owner=root group=root mode=0600 + notify: + - restart strongswan + +- name: Copy the server key to the strongswan directory + copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/private/{{ ansible_ssh_host }}.key' dest=/etc/ipsec.d/private/{{ ansible_ssh_host }}.key owner=root group=root mode=0600 + notify: + - restart strongswan + +- name: Register p12 PayloadContent + shell: > + cat /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 | base64 + register: PayloadContent + with_items: "{{ users }}" + +- name: Register CA PayloadContent + shell: > + cat /{{ easyrsa_dir }}/easyrsa3/pki/ca.crt | base64 + register: PayloadContentCA + +- name: Build the mobileconfigs + template: src=mobileconfig.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item.0 }}.mobileconfig mode=0600 + with_together: + - "{{ users }}" + - "{{ PayloadContent.results }}" + no_log: True + +- name: Fetch users P12 + fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 dest=configs/{{ server_name }}_{{ item }}.p12 flat=yes + with_items: "{{ users }}" + +- name: Fetch users mobileconfig + fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.mobileconfig dest=configs/{{ server_name }}_{{ item }}.mobileconfig flat=yes + with_items: "{{ users }}" + +- name: Fetch server CA certificate + fetch: src=/{{ easyrsa_dir }}/easyrsa3/pki/ca.crt dest=configs/{{ server_name }}_ca.crt flat=yes + +- name: Add server to the inventory file + local_action: lineinfile dest=inventory_users line="{{ inventory_hostname }}" insertafter='\[user-management\]\n' state=present + become: false + notify: + - congrats diff --git a/security.yml b/security.yml deleted file mode 100644 index b80f3a2..0000000 --- a/security.yml +++ /dev/null @@ -1,136 +0,0 @@ ---- - -- name: Security enhancements - hosts: vpn-host - become: true - vars_files: - - config.cfg - - tasks: - # Using a two-pass approach for checking directories in order to support symlinks. - - name: Find directories for minimizing access - stat: - path: "{{ item }}" - register: minimize_access_directories - with_items: - - '/usr/local/sbin' - - '/usr/local/bin' - - '/usr/sbin' - - '/usr/bin' - - '/sbin' - - '/bin' - - - name: Minimize access - file: path='{{ item.stat.path }}' mode='go-w' recurse=yes - when: item.stat.isdir - with_items: "{{ minimize_access_directories.results }}" - no_log: True - - - name: Change shadow ownership to root and mode to 0600 - file: dest='/etc/shadow' owner=root group=root mode=0600 - - - name: change su-binary to only be accessible to user and group root - file: dest='/bin/su' owner=root group=root mode=0750 - - # auditd - - - name: Collect Use of privileged commands - shell: > - /usr/bin/find {/usr/local/sbin,/usr/local/bin,/sbin,/bin,/usr/sbin,/usr/bin} -xdev \( -perm -4000 -o -perm -2000 \) -type f | awk '{print "-a always,exit -F path=" $1 " -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged" }' - args: - executable: /bin/bash - register: privileged_programs - - - name: Auditd rules configured - template: src=audit.rules.j2 dest=/etc/audit/audit.rules - notify: - - restart auditd - - - name: Auditd configured - template: src=auditd.conf.j2 dest=/etc/audit/auditd.conf - notify: - - restart auditd - - # Rsyslog - - - name: Rsyslog configured - template: src=rsyslog.conf.j2 dest=/etc/rsyslog.conf - notify: - - restart rsyslog - - - name: Rsyslog CIS configured - template: src=CIS.conf.j2 dest=/etc/rsyslog.d/CIS.conf owner=root group=root mode=0644 - notify: - - restart rsyslog - - - name: Enable services - service: name={{ item }} enabled=yes - with_items: - - auditd - - rsyslog - - # Core dumps - - - name: Restrict core dumps (with PAM) - lineinfile: dest=/etc/security/limits.conf line="* hard core 0" state=present - - - name: Restrict core dumps (with sysctl) - sysctl: name=fs.suid_dumpable value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present - - # Kernel fixes - - - name: Disable Source Routed Packet Acceptance - sysctl: name="{{item}}" value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present - with_items: - - net.ipv4.conf.all.accept_source_route - - net.ipv4.conf.default.accept_source_route - notify: - - flush routing cache - - - name: Disable ICMP Redirect Acceptance - sysctl: name="{{item}}" value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present - with_items: - - net.ipv4.conf.all.accept_redirects - - net.ipv4.conf.default.accept_redirects - - - name: Disable Secure ICMP Redirect Acceptance - sysctl: name="{{item}}" value=0 ignoreerrors=yes sysctl_set=yes reload=yes state=present - with_items: - - net.ipv4.conf.all.secure_redirects - - net.ipv4.conf.default.secure_redirects - notify: - - flush routing cache - - - name: Enable Bad Error Message Protection - sysctl: name=net.ipv4.icmp_ignore_bogus_error_responses value=1 ignoreerrors=yes sysctl_set=yes reload=yes state=present - notify: - - flush routing cache - - - name: Enable RFC-recommended Source Route Validation - sysctl: name="{{item}}" value=1 ignoreerrors=yes sysctl_set=yes reload=yes state=present - with_items: - - net.ipv4.conf.all.rp_filter - - net.ipv4.conf.default.rp_filter - notify: - - flush routing cache - - - name: Enable packet forwarding for IPv4 - sysctl: name=net.ipv4.ip_forward value=1 - - - name: Enable packet forwarding for IPv6 - sysctl: name=net.ipv6.conf.all.forwarding value=1 - - - name: Do not send ICMP redirects (we are not a router) - sysctl: name=net.ipv4.conf.all.send_redirects value=0 - - handlers: - - name: restart auditd - service: name=auditd state=restarted - - - name: restart rsyslog - service: name=rsyslog state=restarted - - - name: flush routing cache - shell: echo 1 > /proc/sys/net/ipv4/route/flush - - diff --git a/vpn.yml b/vpn.yml deleted file mode 100644 index be6ffd4..0000000 --- a/vpn.yml +++ /dev/null @@ -1,175 +0,0 @@ ---- - -- name: VPN Configuration - hosts: vpn-host - gather_facts: false - become: true - vars_files: - - config.cfg - - tasks: - - name: Install StrongSwan - apt: name=strongswan state=latest update_cache=yes - - - name: Enforcing ipsec with apparmor - shell: aa-enforce "{{ item }}" - with_items: - - /usr/lib/ipsec/charon - - /usr/lib/ipsec/lookip - - /usr/lib/ipsec/stroke - notify: - - restart apparmor - - - name: Enable services - service: name={{ item }} enabled=yes - with_items: - - apparmor - - strongswan - - netfilter-persistent - - - name: Configure iptables so IPSec traffic can traverse the tunnel - iptables: table=nat chain=POSTROUTING source="{{ vpn_network }}" jump=MASQUERADE - notify: - - save iptables - - - name: Configure ip6tables so IPSec traffic can traverse the tunnel - iptables: ip_version=ipv6 table=nat chain=POSTROUTING source="{{ vpn_network_ipv6 }}" jump=MASQUERADE - notify: - - save iptables - - - name: Setup the ipsec.conf file from our template - template: src=ipsec.conf.j2 dest=/etc/ipsec.conf owner=root group=root mode=644 - notify: - - restart strongswan - - - name: Setup the ipsec.secrets file - template: src=ipsec.secrets.j2 dest=/etc/ipsec.secrets owner=root group=root mode=600 - notify: - - restart strongswan - - - name: Fetch easy-rsa-ipsec from git - git: repo=git://github.com/ValdikSS/easy-rsa-ipsec.git dest="{{ easyrsa_dir }}" - - - name: Setup the vars file from our template - template: src=easy-rsa.vars.j2 dest={{ easyrsa_dir }}/easyrsa3/vars - - - name: Ensure the pki directory is not exist - file: dest={{ easyrsa_dir }}/easyrsa3/pki state=absent - when: easyrsa_reinit_existent == True - - - name: Build the pki enviroments - shell: > - ./easyrsa init-pki && - touch '{{ easyrsa_dir }}/easyrsa3/pki/pki_initialized' - args: - chdir: '{{ easyrsa_dir }}/easyrsa3/' - creates: '{{ easyrsa_dir }}/easyrsa3/pki/pki_initialized' - - - name: Build the CA pair - shell: > - ./easyrsa build-ca nopass && - touch {{ easyrsa_dir }}/easyrsa3/pki/ca_initialized - args: - chdir: '{{ easyrsa_dir }}/easyrsa3/' - creates: '{{ easyrsa_dir }}/easyrsa3/pki/ca_initialized' - notify: - - restart strongswan - - - name: Build the server pair - shell: > - ./easyrsa --subject-alt-name='DNS:{{ server_name }},IP:{{ ansible_ssh_host }}' build-server-full {{ ansible_ssh_host }} nopass&& - touch '{{ easyrsa_dir }}/easyrsa3/pki/server_initialized' - args: - chdir: '{{ easyrsa_dir }}/easyrsa3/' - creates: '{{ easyrsa_dir }}/easyrsa3/pki/server_initialized' - notify: - - restart strongswan - - - name: Build the client's pair - shell: > - ./easyrsa build-client-full {{ item }} nopass && - touch '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized' - args: - chdir: '{{ easyrsa_dir }}/easyrsa3/' - creates: '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized' - with_items: "{{ users }}" - - - name: Build the client's p12 - shell: > - openssl pkcs12 -in {{ easyrsa_dir }}/easyrsa3//pki/issued/{{ item }}.crt -inkey {{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.key -export -name {{ item }} -out /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 -certfile {{ easyrsa_dir }}/easyrsa3//pki/ca.crt -passout pass:{{ easyrsa_p12_export_password }} && - touch '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_p12_initialized' - args: - chdir: '{{ easyrsa_dir }}/easyrsa3/' - creates: '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_p12_initialized' - with_items: "{{ users }}" - - - name: Copy the CA cert to the strongswan directory - copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/ca.crt' dest=/etc/ipsec.d/cacerts/ca.crt owner=root group=root mode=0600 - notify: - - restart strongswan - - - name: Copy the server cert to the strongswan directory - copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/issued/{{ ansible_ssh_host }}.crt' dest=/etc/ipsec.d/certs/{{ ansible_ssh_host }}.crt owner=root group=root mode=0600 - notify: - - restart strongswan - - - name: Copy the server key to the strongswan directory - copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/private/{{ ansible_ssh_host }}.key' dest=/etc/ipsec.d/private/{{ ansible_ssh_host }}.key owner=root group=root mode=0600 - notify: - - restart strongswan - - - name: Register p12 PayloadContent - shell: > - cat /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 | base64 - register: PayloadContent - with_items: "{{ users }}" - - - name: Register CA PayloadContent - shell: > - cat /{{ easyrsa_dir }}/easyrsa3/pki/ca.crt | base64 - register: PayloadContentCA - - - name: Build the mobileconfigs - template: src=mobileconfig.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item.0 }}.mobileconfig mode=0600 - with_together: - - "{{ users }}" - - "{{ PayloadContent.results }}" - no_log: True - - - name: Fetch users P12 - fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 dest=configs/{{ server_name }}_{{ item }}.p12 flat=yes - with_items: "{{ users }}" - - - name: Fetch users mobileconfig - fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.mobileconfig dest=configs/{{ server_name }}_{{ item }}.mobileconfig flat=yes - with_items: "{{ users }}" - - - name: Fetch server CA certificate - fetch: src=/{{ easyrsa_dir }}/easyrsa3/pki/ca.crt dest=configs/{{ server_name }}_ca.crt flat=yes - - - name: Add server to the inventory file - local_action: lineinfile dest=inventory_users line="{{ inventory_hostname }}" insertafter='\[user-management\]\n' state=present - become: false - notify: - - congrats - - handlers: - - name: restart strongswan - service: name=strongswan state=restarted - - - name: restart apparmor - service: name=apparmor state=restarted - - - name: save iptables - command: service netfilter-persistent save - - - name: congrats - debug: - msg: - - "#----------------------------------------------------------------------#" - - "# Congratulations! #" - - "# Your Algo server is running. #" - - "# Config files and certificates are in the ./configs/ directory. #" - - "# Go to https://www.dnsleaktest.com/ after connecting #" - - "# and ensure that all your traffic passes through the VPN. #" - - "#----------------------------------------------------------------------#"