From e97349372ed366903fc38cd373445ef7d3d0a1a6 Mon Sep 17 00:00:00 2001 From: Jack Ivanov Date: Sun, 19 Feb 2017 23:40:45 +0300 Subject: [PATCH] FreeBSD draft #35 --- playbooks/common.yml | 13 ++ roles/common/handlers/main.yml | 7 + roles/common/tasks/freebsd.yml | 39 ++++ roles/common/tasks/main.yml | 95 +-------- roles/common/tasks/ubuntu.yml | 91 +++++++++ roles/vpn/tasks/client_configs.yml | 79 +++++++ roles/vpn/tasks/freebsd.yml | 19 ++ roles/vpn/tasks/main.yml | 273 +++---------------------- roles/vpn/tasks/openssl.yml | 117 +++++++++++ roles/vpn/tasks/ubuntu.yml | 49 +++++ roles/vpn/templates/strongswan.conf.j2 | 10 + 11 files changed, 456 insertions(+), 336 deletions(-) create mode 100644 roles/common/tasks/freebsd.yml create mode 100644 roles/common/tasks/ubuntu.yml create mode 100644 roles/vpn/tasks/client_configs.yml create mode 100644 roles/vpn/tasks/freebsd.yml create mode 100644 roles/vpn/tasks/openssl.yml create mode 100644 roles/vpn/tasks/ubuntu.yml diff --git a/playbooks/common.yml b/playbooks/common.yml index c195b13d3..39b463607 100644 --- a/playbooks/common.yml +++ b/playbooks/common.yml @@ -1,10 +1,23 @@ - name: Install prerequisites raw: sleep 10 && sudo apt-get update -qq && sudo apt-get install -qq -y python2.7 + tags: + - ubuntu - name: Configure defaults raw: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 tags: - update-alternatives + - ubuntu + +- name: Install prerequisites + raw: sleep 10 && sudo pkg install -y python27 + tags: + - freebsd + +- name: Configure defaults + raw: sudo ln -sf /usr/local/bin/python2.7 /usr/bin/python2.7 + tags: + - freebsd - name: Ensure the algo ssh key exist on the server authorized_key: diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml index c22968503..4e07ade1d 100644 --- a/roles/common/handlers/main.yml +++ b/roles/common/handlers/main.yml @@ -6,3 +6,10 @@ - name: restart loopback shell: ifdown lo:100 && ifup lo:100 + +- name: restart loopback bsd + shell: > + ifconfig lo100 destroy || true && + ifconfig lo100 create && + ifconfig lo100 inet 172.16.0.1 netmask 255.255.255.255 && + ifconfig lo100 inet6 FCAA::1/64; echo $? diff --git a/roles/common/tasks/freebsd.yml b/roles/common/tasks/freebsd.yml new file mode 100644 index 000000000..a1174d731 --- /dev/null +++ b/roles/common/tasks/freebsd.yml @@ -0,0 +1,39 @@ +--- + +- set_fact: + tools: + - git + - screen + - coreutils + - openssl + sysctl: + forwarding: + - net.inet.ip.forwarding + - net.inet6.ip6.forwarding + tags: + - always + +- name: Loopback included into the rc config + blockinfile: + dest: /etc/rc.conf + create: yes + block: | + cloned_interfaces="lo100" + ifconfig_lo100="inet {{ local_service_ip }}/255.255.255.255" + ifconfig_lo100="inet6 FCAA::1/64" + notify: + - restart loopback bsd + tags: + - always + +- name: Enable the gateway features + lineinfile: dest=/etc/rc.conf regexp='^{{ item.param }}.*' line='{{ item.param }}={{ item.value }}' + with_items: + - { param: firewall_enable, value: '"YES"' } + - { param: firewall_type, value: '"open"' } + - { param: gateway_enable, value: '"YES"' } + - { param: natd_enable, value: '"YES"' } + - { param: natd_interface, value: '""' } + - { param: natd_flags, value: '"-dynamic -m"' } + tags: + - always diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index 1262d3fcd..d49c18a5e 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -5,101 +5,22 @@ tags: - always -- name: Install software updates - apt: update_cache=yes upgrade=dist - tags: - - cloud - -- name: Check if reboot is required - shell: > - if [[ -e /var/run/reboot-required ]]; then echo "required"; else echo "no"; fi - args: - executable: /bin/bash - register: reboot_required - tags: - - cloud - -- 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 - tags: - - cloud - -- name: Wait until SSH becomes ready... - local_action: - module: wait_for - port: 22 - host: "{{ inventory_hostname }}" - search_regex: OpenSSH - delay: 10 - timeout: 320 - when: reboot_required is defined and reboot_required.stdout == 'required' - become: false - tags: - - cloud - -- 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' } - tags: - - cloud +- include: ubuntu.yml + when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' + +- include: freebsd.yml + when: ansible_distribution == 'FreeBSD' - name: Install tools - apt: name="{{ item }}" state=latest + package: name="{{ item }}" state=present with_items: - - git - - screen - - apparmor-utils - - uuid-runtime - - coreutils - - sendmail - - iptables-persistent - - cgroup-tools - - openssl - tags: - - always - -- name: Loopback for services configured - template: src=10-loopback-services.cfg.j2 dest=/etc/network/interfaces.d/10-loopback-services.cfg - notify: - - restart loopback - tags: - - always - -- 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 - tags: - - always - -- meta: flush_handlers + - "{{ tools }}" tags: - always - name: Enable packet forwarding for IPv4 sysctl: name="{{ item }}" value=1 with_items: - - net.ipv4.ip_forward - - net.ipv4.conf.all.forwarding - tags: - - always - -- name: Enable packet forwarding for IPv6 - sysctl: name=net.ipv6.conf.all.forwarding value=1 + - "{{ sysctl.forwarding }}" tags: - always - -- name: Check apparmor support - shell: apparmor_status - ignore_errors: yes - register: apparmor_status - -- set_fact: - apparmor_enabled: true - when: '"profiles are in enforce mode" in apparmor_status.stdout' diff --git a/roles/common/tasks/ubuntu.yml b/roles/common/tasks/ubuntu.yml new file mode 100644 index 000000000..e83099390 --- /dev/null +++ b/roles/common/tasks/ubuntu.yml @@ -0,0 +1,91 @@ +--- + +- name: Install software updates + apt: update_cache=yes upgrade=dist + tags: + - cloud + +- name: Check if reboot is required + shell: > + if [[ -e /var/run/reboot-required ]]; then echo "required"; else echo "no"; fi + args: + executable: /bin/bash + register: reboot_required + tags: + - cloud + +- 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 + tags: + - cloud + +- name: Wait until SSH becomes ready... + local_action: + module: wait_for + port: 22 + host: "{{ inventory_hostname }}" + search_regex: OpenSSH + delay: 10 + timeout: 320 + when: reboot_required is defined and reboot_required.stdout == 'required' + become: false + tags: + - cloud + +- 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' } + tags: + - cloud + +- name: Loopback for services configured + template: src=10-loopback-services.cfg.j2 dest=/etc/network/interfaces.d/10-loopback-services.cfg + notify: + - restart loopback + tags: + - always + +- 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 + tags: + - always + +- meta: flush_handlers + tags: + - always + +- name: Check apparmor support + shell: apparmor_status + ignore_errors: yes + register: apparmor_status + +- set_fact: + apparmor_enabled: true + when: '"profiles are in enforce mode" in apparmor_status.stdout' + +- set_fact: + tools: + - git + - screen + - apparmor-utils + - uuid-runtime + - coreutils + - sendmail + - iptables-persistent + - cgroup-tools + - openssl + sysctl: + forwarding: + - net.ipv4.ip_forward + - net.ipv4.conf.all.forwarding + - net.ipv6.conf.all.forwarding + tags: + - always diff --git a/roles/vpn/tasks/client_configs.yml b/roles/vpn/tasks/client_configs.yml new file mode 100644 index 000000000..76f5a05ae --- /dev/null +++ b/roles/vpn/tasks/client_configs.yml @@ -0,0 +1,79 @@ +--- + +- name: Register p12 PayloadContent + local_action: > + shell cat private/{{ item }}.p12 | base64 + register: PayloadContent + become: no + args: + chdir: "configs/{{ IP_subject_alt_name }}/pki/" + with_items: "{{ users }}" + +- name: Set facts for mobileconfigs + set_fact: + proxy_enabled: false + PayloadContentCA: "{{ lookup('file' , 'configs/{{ IP_subject_alt_name }}/pki/cacert.pem')|b64encode }}" + +- name: Build the mobileconfigs + local_action: + module: template + src: mobileconfig.j2 + dest: configs/{{ IP_subject_alt_name }}/{{ item.0 }}.mobileconfig + mode: 0600 + become: no + with_together: + - "{{ users }}" + - "{{ PayloadContent.results }}" + no_log: True + +- name: Build the strongswan app android config + local_action: + module: template + src: sswan.j2 + dest: configs/{{ IP_subject_alt_name }}/{{ item.0 }}.sswan + mode: 0600 + become: no + with_together: + - "{{ users }}" + - "{{ PayloadContent.results }}" + no_log: True + +- name: Build the client ipsec config file + local_action: + module: template + src: client_ipsec.conf.j2 + dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.conf + mode: 0600 + become: no + with_items: + - "{{ users }}" + +- name: Build the client ipsec secret file + local_action: + module: template + src: client_ipsec.secrets.j2 + dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.secrets + mode: 0600 + become: no + with_items: + - "{{ users }}" + +- name: Build the windows client powershell script + local_action: + module: template + src: client_windows.ps1.j2 + dest: configs/{{ IP_subject_alt_name }}/windows_{{ item }}.ps1 + mode: 0600 + become: no + when: Win10_Enabled is defined and Win10_Enabled == "Y" + with_items: "{{ users }}" + +- name: Restrict permissions for the local private directories + local_action: + module: file + path: "{{ item }}" + state: directory + mode: 0700 + become: no + with_items: + - configs/{{ IP_subject_alt_name }} diff --git a/roles/vpn/tasks/freebsd.yml b/roles/vpn/tasks/freebsd.yml new file mode 100644 index 000000000..969002479 --- /dev/null +++ b/roles/vpn/tasks/freebsd.yml @@ -0,0 +1,19 @@ +--- + +- set_fact: + config_prefix: "/usr/local/" + root_group: wheel + +- name: Activate IPFW + shell: > + kldstat -n ipfw.ko || kldload ipfw ; sysctl net.inet.ip.fw.enable=0 && + bash /etc/rc.firewall && sysctl net.inet.ip.fw.enable=1 + +- name: Enable strongswan + lineinfile: dest=/etc/rc.conf regexp=^strongswan_enable= line='strongswan_enable="YES"' + +- set_fact: + strongswan_enabled_plugins: + - "{{ strongswan_enabled_plugins }}" + - kernel-pfroute + - kernel-pfkey diff --git a/roles/vpn/tasks/main.yml b/roles/vpn/tasks/main.yml index dfd31eb4e..0b2b72558 100644 --- a/roles/vpn/tasks/main.yml +++ b/roles/vpn/tasks/main.yml @@ -3,7 +3,7 @@ - name: Generate password for the CA key shell: > - < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-12};echo; + openssl rand -hex 6 register: CA_password - set_fact: @@ -16,41 +16,14 @@ algo_params: "rsa:2048" when: Win10_Enabled is defined and Win10_Enabled == "Y" -- name: Install StrongSwan - apt: name=strongswan state=latest update_cache=yes - -- name: Enforcing ipsec with apparmor - shell: aa-enforce "{{ item }}" - when: apparmor_enabled is defined and apparmor_enabled == true - with_items: - - /usr/lib/ipsec/charon - - /usr/lib/ipsec/lookip - - /usr/lib/ipsec/stroke - notify: - - restart apparmor - tags: ['apparmor'] +- include: ubuntu.yml + when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' -- name: Enable services - service: name={{ item }} enabled=yes - with_items: - - apparmor - - strongswan - - netfilter-persistent +- include: freebsd.yml + when: ansible_distribution == 'FreeBSD' -- name: Configure iptables so IPSec traffic can traverse the tunnel - iptables: table=nat chain=POSTROUTING source="{{ vpn_network }}" jump=MASQUERADE - when: (security_enabled is not defined) or - (security_enabled is defined and security_enabled != "y") - 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 - when: ((security_enabled is not defined) or - (security_enabled is defined and security_enabled != "y")) and - ipv6_support is defined and ipv6_support == "yes" - notify: - - save iptables +- name: Install StrongSwan + package: name=strongswan state=present - name: Ensure that the strongswan group exist group: name=strongswan state=present @@ -58,263 +31,65 @@ - name: Ensure that the strongswan user exist user: name=strongswan group=strongswan state=present -- name: Ensure that the strongswan service directory exist - file: path=/etc/systemd/system/strongswan.service.d/ state=directory mode=0755 owner=root group=root - -- name: Setup the cgroup limitations for the ipsec daemon - template: src=100-CustomLimitations.conf.j2 dest=/etc/systemd/system/strongswan.service.d/100-CustomLimitations.conf - notify: - - daemon-reload - - restart strongswan - -- meta: flush_handlers - - name: Setup the strongswan.conf file from our template - template: src=strongswan.conf.j2 dest=/etc/strongswan.conf owner=root group=root mode=0644 + template: src=strongswan.conf.j2 dest={{ config_prefix|default('/') }}etc/strongswan.conf owner=root group="{{ root_group|default('root') }}" mode=0644 notify: - restart strongswan - name: Setup the ipsec.conf file from our template - template: src=ipsec.conf.j2 dest=/etc/ipsec.conf owner=root group=root mode=0644 + template: src=ipsec.conf.j2 dest={{ config_prefix|default('/') }}etc/ipsec.conf owner=root group="{{ root_group|default('root') }}" mode=0644 notify: - restart strongswan - name: Setup the ipsec.secrets file - template: src=ipsec.secrets.j2 dest=/etc/ipsec.secrets owner=strongswan group=root mode=0600 + template: src=ipsec.secrets.j2 dest={{ config_prefix|default('/') }}etc/ipsec.secrets owner=strongswan group="{{ root_group|default('root') }}" mode=0600 notify: - restart strongswan - name: Get loaded plugins shell: > - find /etc/strongswan.d/charon/ -type f -name '*.conf' -printf '%f\n' | cut -f1 -d. + find {{ config_prefix|default('/') }}etc/strongswan.d/charon/ -type f -name '*.conf' -exec basename {} \; | cut -f1 -d. register: strongswan_plugins - name: Disable unneeded plugins - lineinfile: dest="/etc/strongswan.d/charon/{{ item }}.conf" regexp='.*load.*' line='load = no' state=present + lineinfile: dest="{{ config_prefix|default('/') }}etc/strongswan.d/charon/{{ item }}.conf" regexp='.*load.*' line='load = no' state=present notify: - restart strongswan when: item not in strongswan_enabled_plugins with_items: "{{ strongswan_plugins.stdout_lines }}" - name: Ensure that required plugins are enabled - lineinfile: dest="/etc/strongswan.d/charon/{{ item }}.conf" regexp='.*load.*' line='load = yes' state=present + lineinfile: dest="{{ config_prefix|default('/') }}etc/strongswan.d/charon/{{ item }}.conf" regexp='.*load.*' line='load = yes' state=present notify: - restart strongswan when: item in strongswan_enabled_plugins with_items: "{{ strongswan_plugins.stdout_lines }}" -- name: Ensure the pki directory is not exist - local_action: - module: file - dest: configs/{{ IP_subject_alt_name }}/pki - state: absent - become: no - when: easyrsa_reinit_existent == True - -- name: Ensure the pki directories are exist - local_action: - module: file - dest: "configs/{{ IP_subject_alt_name }}/pki/{{ item }}" - state: directory - recurse: yes - become: no - with_items: - - ecparams - - certs - - crl - - newcerts - - private - - reqs - -- name: Ensure the files are exist - local_action: - module: file - dest: "configs/{{ IP_subject_alt_name }}/pki/{{ item }}" - state: touch - become: no - with_items: - - ".rnd" - - "private/.rnd" - - "index.txt" - - "index.txt.attr" - - "serial" - -- name: Generate the openssl server configs - local_action: - module: template - src: openssl.cnf.j2 - dest: "configs/{{ IP_subject_alt_name }}/pki/openssl.cnf" - become: no - -- name: Build the CA pair - local_action: > - shell openssl ecparam -name prime256v1 -out ecparams/prime256v1.pem && - openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/cakey.pem -out cacert.pem -x509 -days 3650 -batch -passout pass:"{{ easyrsa_CA_password }}" && - touch {{ IP_subject_alt_name }}_ca_generated - become: no - args: - chdir: "configs/{{ IP_subject_alt_name }}/pki/" - creates: "{{ IP_subject_alt_name }}_ca_generated" - environment: - subjectAltName: "DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}" - -- name: Copy the CA certificate - local_action: - module: copy - src: "configs/{{ IP_subject_alt_name }}/pki/cacert.pem" - dest: "configs/{{ IP_subject_alt_name }}/cacert.pem" - mode: 0600 - become: no - -- name: Generate the serial number - local_action: > - shell echo 01 > serial && - touch serial_generated - become: no - args: - chdir: "configs/{{ IP_subject_alt_name }}/pki/" - creates: serial_generated - -- name: Build the server pair - local_action: > - shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ IP_subject_alt_name }}.key -out reqs/{{ IP_subject_alt_name }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ IP_subject_alt_name }}" -batch && - openssl ca -utf8 -in reqs/{{ IP_subject_alt_name }}.req -out certs/{{ IP_subject_alt_name }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ IP_subject_alt_name }}" && - touch certs/{{ IP_subject_alt_name }}_crt_generated - become: no - args: - chdir: "configs/{{ IP_subject_alt_name }}/pki/" - creates: certs/{{ IP_subject_alt_name }}_crt_generated - environment: - subjectAltName: "DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}" - -- name: Build the client's pair - local_action: > - shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ item }}.key -out reqs/{{ item }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" -batch && - openssl ca -utf8 -in reqs/{{ item }}.req -out certs/{{ item }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" && - touch certs/{{ item }}_crt_generated - become: no - args: - chdir: "configs/{{ IP_subject_alt_name }}/pki/" - creates: certs/{{ item }}_crt_generated - environment: - subjectAltName: "DNS:{{ item }}" - with_items: "{{ users }}" - -- name: Build the client's p12 - local_action: > - shell openssl pkcs12 -in certs/{{ item }}.crt -inkey private/{{ item }}.key -export -name {{ item }} -out private/{{ item }}.p12 -certfile cacert.pem -passout pass:"{{ easyrsa_p12_export_password }}" - become: no - args: - chdir: "configs/{{ IP_subject_alt_name }}/pki/" - with_items: "{{ users }}" - -- name: Copy the p12 certificates - local_action: - module: copy - src: "configs/{{ IP_subject_alt_name }}/pki/private/{{ item }}.p12" - dest: "configs/{{ IP_subject_alt_name }}/{{ item }}.p12" - mode: 0600 - become: no - with_items: - - "{{ users }}" +- include: openssl.yml - name: Copy the CA cert to the strongswan directory - copy: src='configs/{{ IP_subject_alt_name }}/pki/cacert.pem' dest=/etc/ipsec.d/cacerts/ca.crt owner=strongswan group=root mode=0600 + copy: src='configs/{{ IP_subject_alt_name }}/pki/cacert.pem' dest={{ config_prefix|default('/') }}etc/ipsec.d/cacerts/ca.crt owner=strongswan group="{{ root_group|default('root') }}" mode=0600 notify: - restart strongswan - name: Copy the server cert to the strongswan directory - copy: src='configs/{{ IP_subject_alt_name }}/pki/certs/{{ IP_subject_alt_name }}.crt' dest=/etc/ipsec.d/certs/{{ IP_subject_alt_name }}.crt owner=strongswan group=root mode=0600 + copy: src='configs/{{ IP_subject_alt_name }}/pki/certs/{{ IP_subject_alt_name }}.crt' dest={{ config_prefix|default('/') }}etc/ipsec.d/certs/{{ IP_subject_alt_name }}.crt owner=strongswan group="{{ root_group|default('root') }}" mode=0600 notify: - restart strongswan - name: Copy the server key to the strongswan directory - copy: src='configs/{{ IP_subject_alt_name }}/pki/private/{{ IP_subject_alt_name }}.key' dest=/etc/ipsec.d/private/{{ IP_subject_alt_name }}.key owner=strongswan group=root mode=0600 + copy: src='configs/{{ IP_subject_alt_name }}/pki/private/{{ IP_subject_alt_name }}.key' dest={{ config_prefix|default('/') }}etc/ipsec.d/private/{{ IP_subject_alt_name }}.key owner=strongswan group="{{ root_group|default('root') }}" mode=0600 notify: - restart strongswan -- name: Register p12 PayloadContent - local_action: > - shell cat private/{{ item }}.p12 | base64 - register: PayloadContent - become: no - args: - chdir: "configs/{{ IP_subject_alt_name }}/pki/" - with_items: "{{ users }}" - -- name: Set facts for mobileconfigs - set_fact: - proxy_enabled: false - PayloadContentCA: "{{ lookup('file' , 'configs/{{ IP_subject_alt_name }}/pki/cacert.pem')|b64encode }}" - -- name: Build the mobileconfigs - local_action: - module: template - src: mobileconfig.j2 - dest: configs/{{ IP_subject_alt_name }}/{{ item.0 }}.mobileconfig - mode: 0600 - become: no - with_together: - - "{{ users }}" - - "{{ PayloadContent.results }}" - no_log: True - -- name: Build the strongswan app android config - local_action: - module: template - src: sswan.j2 - dest: configs/{{ IP_subject_alt_name }}/{{ item.0 }}.sswan - mode: 0600 - become: no - with_together: - - "{{ users }}" - - "{{ PayloadContent.results }}" - no_log: True - -- name: Build the client ipsec config file - local_action: - module: template - src: client_ipsec.conf.j2 - dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.conf - mode: 0600 - become: no - with_items: - - "{{ users }}" - -- name: Build the client ipsec secret file - local_action: - module: template - src: client_ipsec.secrets.j2 - dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.secrets - mode: 0600 - become: no - with_items: - - "{{ users }}" - -- name: Build the windows client powershell script - local_action: - module: template - src: client_windows.ps1.j2 - dest: configs/{{ IP_subject_alt_name }}/windows_{{ item }}.ps1 - mode: 0600 - become: no - when: Win10_Enabled is defined and Win10_Enabled == "Y" - with_items: "{{ users }}" - - name: Restrict permissions for the remote private directories - file: path="{{ item }}" state=directory mode=0700 owner=strongswan group=root + file: path="{{ item }}" state=directory mode=0700 owner=strongswan group="{{ root_group|default('root') }}" with_items: - - /etc/ipsec.d/private + - "{{ config_prefix|default('/') }}etc/ipsec.d/private" -- name: Restrict permissions for the local private directories - local_action: - module: file - path: "{{ item }}" - state: directory - mode: 0700 - become: no - with_items: - - configs/{{ IP_subject_alt_name }} +- include: client_configs.yml + +- meta: flush_handlers -- include: iptables.yml - tags: iptables +- name: StrongSwan started + service: name=strongswan state=started diff --git a/roles/vpn/tasks/openssl.yml b/roles/vpn/tasks/openssl.yml new file mode 100644 index 000000000..8f9d52aba --- /dev/null +++ b/roles/vpn/tasks/openssl.yml @@ -0,0 +1,117 @@ +--- + +- name: Ensure the pki directory is not exist + local_action: + module: file + dest: configs/{{ IP_subject_alt_name }}/pki + state: absent + become: no + when: easyrsa_reinit_existent == True + +- name: Ensure the pki directories are exist + local_action: + module: file + dest: "configs/{{ IP_subject_alt_name }}/pki/{{ item }}" + state: directory + recurse: yes + become: no + with_items: + - ecparams + - certs + - crl + - newcerts + - private + - reqs + +- name: Ensure the files are exist + local_action: + module: file + dest: "configs/{{ IP_subject_alt_name }}/pki/{{ item }}" + state: touch + become: no + with_items: + - ".rnd" + - "private/.rnd" + - "index.txt" + - "index.txt.attr" + - "serial" + +- name: Generate the openssl server configs + local_action: + module: template + src: openssl.cnf.j2 + dest: "configs/{{ IP_subject_alt_name }}/pki/openssl.cnf" + become: no + + +- name: Build the CA pair + local_action: > + shell openssl ecparam -name prime256v1 -out ecparams/prime256v1.pem && + openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/cakey.pem -out cacert.pem -x509 -days 3650 -batch -passout pass:"{{ easyrsa_CA_password }}" && + touch {{ IP_subject_alt_name }}_ca_generated + become: no + args: + chdir: "configs/{{ IP_subject_alt_name }}/pki/" + creates: "{{ IP_subject_alt_name }}_ca_generated" + environment: + subjectAltName: "DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}" + +- name: Copy the CA certificate + local_action: + module: copy + src: "configs/{{ IP_subject_alt_name }}/pki/cacert.pem" + dest: "configs/{{ IP_subject_alt_name }}/cacert.pem" + mode: 0600 + become: no + +- name: Generate the serial number + local_action: > + shell echo 01 > serial && + touch serial_generated + become: no + args: + chdir: "configs/{{ IP_subject_alt_name }}/pki/" + creates: serial_generated + +- name: Build the server pair + local_action: > + shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ IP_subject_alt_name }}.key -out reqs/{{ IP_subject_alt_name }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ IP_subject_alt_name }}" -batch && + openssl ca -utf8 -in reqs/{{ IP_subject_alt_name }}.req -out certs/{{ IP_subject_alt_name }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ IP_subject_alt_name }}" && + touch certs/{{ IP_subject_alt_name }}_crt_generated + become: no + args: + chdir: "configs/{{ IP_subject_alt_name }}/pki/" + creates: certs/{{ IP_subject_alt_name }}_crt_generated + environment: + subjectAltName: "DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}" + +- name: Build the client's pair + local_action: > + shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ item }}.key -out reqs/{{ item }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" -batch && + openssl ca -utf8 -in reqs/{{ item }}.req -out certs/{{ item }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" && + touch certs/{{ item }}_crt_generated + become: no + args: + chdir: "configs/{{ IP_subject_alt_name }}/pki/" + creates: certs/{{ item }}_crt_generated + environment: + subjectAltName: "DNS:{{ item }}" + with_items: "{{ users }}" + +- name: Build the client's p12 + local_action: > + shell openssl pkcs12 -in certs/{{ item }}.crt -inkey private/{{ item }}.key -export -name {{ item }} -out private/{{ item }}.p12 -certfile cacert.pem -passout pass:"{{ easyrsa_p12_export_password }}" + become: no + args: + chdir: "configs/{{ IP_subject_alt_name }}/pki/" + with_items: "{{ users }}" + +- name: Copy the p12 certificates + local_action: + module: copy + src: "configs/{{ IP_subject_alt_name }}/pki/private/{{ item }}.p12" + dest: "configs/{{ IP_subject_alt_name }}/{{ item }}.p12" + mode: 0600 + become: no + with_items: + - "{{ users }}" diff --git a/roles/vpn/tasks/ubuntu.yml b/roles/vpn/tasks/ubuntu.yml new file mode 100644 index 000000000..151d4c4a6 --- /dev/null +++ b/roles/vpn/tasks/ubuntu.yml @@ -0,0 +1,49 @@ +--- + +- name: Update apt cache + apt: update_cache=yes + +- name: Enforcing ipsec with apparmor + shell: aa-enforce "{{ item }}" + when: apparmor_enabled is defined and apparmor_enabled == true + with_items: + - /usr/lib/ipsec/charon + - /usr/lib/ipsec/lookip + - /usr/lib/ipsec/stroke + notify: + - restart apparmor + tags: ['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 + when: (security_enabled is not defined) or + (security_enabled is defined and security_enabled != "y") + 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 + when: ((security_enabled is not defined) or + (security_enabled is defined and security_enabled != "y")) and + ipv6_support is defined and ipv6_support == "yes" + notify: + - save iptables + +- name: Ensure that the strongswan service directory exist + file: path=/etc/systemd/system/strongswan.service.d/ state=directory mode=0755 owner=root group=root + +- name: Setup the cgroup limitations for the ipsec daemon + template: src=100-CustomLimitations.conf.j2 dest=/etc/systemd/system/strongswan.service.d/100-CustomLimitations.conf + notify: + - daemon-reload + - restart strongswan + +- include: iptables.yml + tags: iptables diff --git a/roles/vpn/templates/strongswan.conf.j2 b/roles/vpn/templates/strongswan.conf.j2 index 4eab82fdf..5e66cb2e5 100644 --- a/roles/vpn/templates/strongswan.conf.j2 +++ b/roles/vpn/templates/strongswan.conf.j2 @@ -11,6 +11,16 @@ charon { } user = strongswan group = strongswan + + filelog { + /var/log/charon.log { + time_format = %b %e %T + ike_name = yes + append = no + default = 1 + flush_line = yes + } + } } include strongswan.d/*.conf