diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..ddfa4ba --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,3 @@ +skip_list: + - '204' +verbosity: 1 diff --git a/.travis.yml b/.travis.yml index 7a2c67d..e799b05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,15 +8,14 @@ services: addons: apt: - sources: + sources: &default_sources - sourceline: 'ppa:ubuntu-lxc/stable' - sourceline: 'ppa:wireguard/wireguard' - packages: + packages: &default_packages - python-pip - lxd - expect-dev - debootstrap - - shellcheck - tree - bridge-utils - dnsutils @@ -25,7 +24,12 @@ addons: - libffi-dev - python-dev - linux-headers-$(uname -r) - - wireguard-dkms + - wireguard + - libxml2-utils + - crudini + - fping + - strongswan + - libstrongswan-standard-plugins cache: directories: @@ -37,39 +41,54 @@ before_cache: - sudo tar cf $HOME/lxc/cache.tar /var/lib/lxd/images/ - sudo chown $USER. $HOME/lxc/cache.tar +custom_scripts: + provisioning: &provisioning + - ssh-keygen -f ~/.ssh/id_rsa -t rsa -N '' + - sudo ./tests/pre-deploy.sh + - 'sed -i "s/^reduce_mtu:\s0$/reduce_mtu: 20/" config.cfg' + tests: &tests + - sudo ./tests/wireguard-client.sh + - sudo env "PATH=$PATH" ./tests/ipsec-client.sh + - sudo ./tests/ssh-tunnel.sh + matrix: fast_finish: true include: - - stage: Test - name: local deployment from docker + - stage: Tests + name: code checks and linters + addons: + apt: + packages: + - shellcheck script: - - docker build -t travis/algo . - - sudo tar xf $HOME/lxc/cache.tar -C / || echo "Didn't extract cache." - - sudo cp -f tests/lxd-bridge /etc/default/lxd-bridge - - ssh-keygen -f ~/.ssh/id_rsa -t rsa -N '' - - echo -e "#cloud-config\nssh_authorized_keys:\n - $(cat ~/.ssh/id_rsa.pub)" | sudo lxc profile set default user.user-data - - - sudo service lxd restart - - sudo lxc launch ubuntu:18.04 algo - - until host algo.lxd 10.0.8.1 -t A; do sleep 3; done - - export LXC_IP="$(dig algo.lxd @10.0.8.1 +short)" - - pip install -r requirements.txt - pip install ansible-lint - - gem install awesome_bot - - ansible-playbook --version - - tree . -L 2 + - shellcheck algo install.sh - ansible-playbook main.yml --syntax-check + - ansible-lint -v roles/*/*/*.yml playbooks/*.yml *.yml + + - stage: Deploy + name: local deployment from docker + addons: + apt: + sources: *default_sources + packages: *default_packages + env: DEPLOY=docker + before_install: *provisioning + before_script: + - docker build -t travis/algo . - ./tests/local-deploy.sh - ./tests/update-users.sh + script: *tests - - stage: Test + - stage: Deploy name: cloud-init deployment - script: - - sudo tar xf $HOME/lxc/cache.tar -C / || echo "Didn't extract cache." - - sudo cp -f tests/lxd-bridge /etc/default/lxd-bridge - - sudo service lxd restart - - bash tests/cloud-init.sh | sudo lxc profile set default user.user-data - - - sudo lxc profile show default - - sudo lxc launch ubuntu:18.04 algo + addons: + apt: + sources: *default_sources + packages: *default_packages + env: DEPLOY=cloud-init + before_install: *provisioning + before_script: - until sudo lxc exec algo -- test -f /var/log/cloud-init-output.log; do echo 'Log file not found, Sleep for 3 seconds'; sleep 3; done - ( sudo lxc exec algo -- tail -f /var/log/cloud-init-output.log & ) - | @@ -78,11 +97,10 @@ matrix: sleep 30; done - sudo lxc exec algo -- test -f /opt/algo/configs/localhost/.config.yml - -# script: - # - awesome_bot --allow-dupe --skip-save-results *.md docs/*.md --white-list paypal.com,do.co,microsoft.com,https://github.com/trailofbits/algo/archive/master.zip,https://github.com/trailofbits/algo/issues/new -# - shellcheck algo -# - ansible-lint main.yml users.yml deploy_client.yml + - sudo lxc exec algo -- tar zcf /root/algo-configs.tar -C /opt/algo/configs/ . + - sudo lxc file pull algo/root/algo-configs.tar ./ + - sudo tar -C ./configs -zxf algo-configs.tar + script: *tests notifications: email: false diff --git a/algo b/algo index 07a2875..260c0e6 100755 --- a/algo +++ b/algo @@ -4,19 +4,20 @@ set -e if [ -z ${VIRTUAL_ENV+x} ] then - ACTIVATE_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/env/bin/activate" - if [ -f "$ACTIVATE_SCRIPT" ] - then - source $ACTIVATE_SCRIPT - else - echo "$ACTIVATE_SCRIPT not found. Did you follow documentation to install dependencies?" - exit 1 - fi + ACTIVATE_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/env/bin/activate" + if [ -f "$ACTIVATE_SCRIPT" ] + then + # shellcheck source=/dev/null + source "$ACTIVATE_SCRIPT" + else + echo "$ACTIVATE_SCRIPT not found. Did you follow documentation to install dependencies?" + exit 1 + fi fi case "$1" in - update-users) PLAYBOOK=users.yml; ARGS="${@:2} -t update-users";; - *) PLAYBOOK=main.yml; ARGS=${@} ;; + update-users) PLAYBOOK=users.yml; ARGS=( "${@:2}" -t update-users ) ;; + *) PLAYBOOK=main.yml; ARGS=( "${@}" ) ;; esac -ansible-playbook ${PLAYBOOK} ${ARGS} +ansible-playbook ${PLAYBOOK} "${ARGS[@]}" diff --git a/deploy_client.yml b/deploy_client.yml index 21fd770..8ee8767 100644 --- a/deploy_client.yml +++ b/deploy_client.yml @@ -1,5 +1,7 @@ +--- - name: Configure the client hosts: localhost + become: false vars_files: - config.cfg @@ -8,9 +10,10 @@ add_host: name: "{{ client_ip }}" groups: client-host - ansible_ssh_user: "{{ ssh_user }}" + ansible_ssh_user: "{{ 'root' if client_ip == 'localhost' else ssh_user }}" vpn_user: "{{ vpn_user }}" - server_ip: "{{ server_ip }}" + IP_subject_alt_name: "{{ server_ip }}" + ansible_python_interpreter: "/usr/bin/python3" - name: Configure the client and install required software hosts: client-host @@ -18,33 +21,6 @@ become: true vars_files: - config.cfg - - roles/vpn/defaults/main.yml - - pre_tasks: - - name: Get the OS - raw: uname -a - register: distribution - - - name: Modify the server name fact - set_fact: - IP_subject_alt_name: "{{ server_ip }}" - - - name: Ubuntu Xenial | Install prerequisites - raw: > - test -x /usr/bin/python2.7 || - sudo apt-get update -qq && sudo apt-get install -qq -y python2.7 && - sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 - changed_when: false - when: "'ubuntu' in distribution.stdout|lower" - - - name: Fedora 25 | Install prerequisites - raw: > - test -x /usr/bin/python2.7 || - sudo dnf install python2 -y && - sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 && - rpm -ql python2-dnf || dnf install python2-dnf -y - changed_when: false - when: "'fedora' in distribution.stdout|lower" - + - roles/strongswan/defaults/main.yml roles: - - { role: client, tags: ['client'] } + - role: client diff --git a/input.yml b/input.yml index f4b155b..d7d6aec 100644 --- a/input.yml +++ b/input.yml @@ -26,11 +26,12 @@ tasks: - block: - - pause: + - name: Region prompt + pause: prompt: | What provider would you like to use? {% for p in providers_map %} - {{ loop.index }}. {{ p['name']}} + {{ loop.index }}. {{ p['name'] }} {% endfor %} Enter the number of your desired provider @@ -41,7 +42,8 @@ set_fact: algo_provider: "{{ provider | default(providers_map[_algo_provider.user_input|default(omit)|int - 1]['alias']) }}" - - pause: + - name: VPN server name prompt + pause: prompt: | Name the vpn server [algo] @@ -50,21 +52,24 @@ - server_name is undefined - algo_provider != "local" - block: - - pause: + - name: Cellular On Demand prompt + pause: prompt: | Do you want macOS/iOS IPsec clients to enable "Connect On Demand" when connected to cellular networks? [y/N] register: _ondemand_cellular when: ondemand_cellular is undefined - - pause: + - name: Wi-Fi On Demand prompt + pause: prompt: | Do you want macOS/iOS IPsec clients to enable "Connect On Demand" when connected to Wi-Fi? [y/N] register: _ondemand_wifi when: ondemand_wifi is undefined - - pause: + - name: Trusted Wi-Fi networks prompt + pause: prompt: | List the names of any trusted Wi-Fi networks where macOS/iOS IPsec clients should not use "Connect On Demand" (e.g., your home network. Comma-separated value, e.g., HomeNet,OfficeWifi,AlgoWiFi) @@ -74,14 +79,16 @@ - (ondemand_wifi|default(false)|bool) or (booleans_map[_ondemand_wifi.user_input|default(omit)]|default(false)) - - pause: + - name: Compatible ciphers prompt + pause: prompt: | Do you want the VPN to support Windows 10 or Linux Desktop clients? (enables compatible ciphers and key exchange, less secure) [y/N] register: _windows when: windows is undefined - - pause: + - name: Retain the CA key prompt + pause: prompt: | Do you want to retain the CA key? (required to add users in the future, but less secure) [y/N] @@ -89,14 +96,16 @@ when: store_cakey is undefined when: ipsec_enabled - - pause: + - name: DNS adblocking prompt + pause: prompt: | Do you want to install an ad blocking DNS resolver on this VPN server? [y/N] register: _local_dns when: local_dns is undefined - - pause: + - name: SSH tunneling prompt + pause: prompt: | Do you want each user to have their own account for SSH tunneling? [y/N] @@ -107,36 +116,38 @@ set_fact: algo_server_name: >- {% if server_name is defined %}{% set _server = server_name %} - {%- elif _algo_server_name.user_input is defined and _algo_server_name.user_input != "" %}{% set _server = _algo_server_name.user_input %} + {%- elif _algo_server_name.user_input is defined and _algo_server_name.user_input|length > 0 -%} + {%- set _server = _algo_server_name.user_input -%} {%- else %}{% set _server = defaults['server_name'] %}{% endif -%} {{ _server | regex_replace('(?!\.)(\W|_)', '-') }} algo_ondemand_cellular: >- {% if ondemand_cellular is defined %}{{ ondemand_cellular | bool }} - {%- elif _ondemand_cellular.user_input is defined and _ondemand_cellular.user_input != "" %}{{ booleans_map[_ondemand_cellular.user_input] | default(defaults['ondemand_cellular']) }} + {%- elif _ondemand_cellular.user_input %}{{ booleans_map[_ondemand_cellular.user_input] | default(defaults['ondemand_cellular']) }} {%- else %}false{% endif %} algo_ondemand_wifi: >- {% if ondemand_wifi is defined %}{{ ondemand_wifi | bool }} - {%- elif _ondemand_wifi.user_input is defined and _ondemand_wifi.user_input != "" %}{{ booleans_map[_ondemand_wifi.user_input] | default(defaults['ondemand_wifi']) }} + {%- elif _ondemand_wifi.user_input %}{{ booleans_map[_ondemand_wifi.user_input] | default(defaults['ondemand_wifi']) }} {%- else %}false{% endif %} algo_ondemand_wifi_exclude: >- {% if ondemand_wifi_exclude is defined %}{{ ondemand_wifi_exclude | b64encode }} - {%- elif _ondemand_wifi_exclude.user_input is defined and _ondemand_wifi_exclude.user_input != "" %}{{ _ondemand_wifi_exclude.user_input | b64encode }} + {%- elif _ondemand_wifi_exclude.user_input is defined and _ondemand_wifi_exclude.user_input|length > 0 -%} + {{ _ondemand_wifi_exclude.user_input | b64encode }} {%- else %}{{ '_null' | b64encode }}{% endif %} algo_local_dns: >- {% if local_dns is defined %}{{ local_dns | bool }} - {%- elif _local_dns.user_input is defined and _local_dns.user_input != "" %}{{ booleans_map[_local_dns.user_input] | default(defaults['local_dns']) }} + {%- elif _local_dns.user_input %}{{ booleans_map[_local_dns.user_input] | default(defaults['local_dns']) }} {%- else %}false{% endif %} algo_ssh_tunneling: >- {% if ssh_tunneling is defined %}{{ ssh_tunneling | bool }} - {%- elif _ssh_tunneling.user_input is defined and _ssh_tunneling.user_input != "" %}{{ booleans_map[_ssh_tunneling.user_input] | default(defaults['ssh_tunneling']) }} + {%- elif _ssh_tunneling.user_input %}{{ booleans_map[_ssh_tunneling.user_input] | default(defaults['ssh_tunneling']) }} {%- else %}false{% endif %} algo_windows: >- {% if windows is defined %}{{ windows | bool }} - {%- elif _windows.user_input is defined and _windows.user_input != "" %}{{ booleans_map[_windows.user_input] | default(defaults['windows']) }} + {%- elif _windows.user_input %}{{ booleans_map[_windows.user_input] | default(defaults['windows']) }} {%- else %}false{% endif %} algo_store_cakey: >- {% if store_cakey is defined %}{{ store_cakey | bool }} - {%- elif _store_cakey.user_input is defined and _store_cakey.user_input != "" %}{{ booleans_map[_store_cakey.user_input] | default(defaults['store_cakey']) }} + {%- elif _store_cakey.user_input %}{{ booleans_map[_store_cakey.user_input] | default(defaults['store_cakey']) }} {%- else %}false{% endif %} rescue: - - include_tasks: playbooks/rescue.yml + - include_tasks: playbooks/rescue.yml diff --git a/install.sh b/install.sh index ed385e7..5c7cf50 100644 --- a/install.sh +++ b/install.sh @@ -36,12 +36,11 @@ installRequirements() { } getAlgo() { - [ ! -d "algo" ] && git clone https://github.com/${REPO_SLUG} algo + [ ! -d "algo" ] && git clone "https://github.com/${REPO_SLUG}" -b "${REPO_BRANCH}" algo cd algo - - git checkout ${REPO_BRANCH} - - python -m virtualenv --python=`which python2` .venv + + python -m virtualenv --python="$(command -v python2)" .venv + # shellcheck source=/dev/null . .venv/bin/activate python -m pip install -U pip virtualenv python -m pip install -r requirements.txt @@ -50,27 +49,23 @@ getAlgo() { publicIpFromInterface() { echo "Couldn't find a valid ipv4 address, using the first IP found on the interfaces as the endpoint." DEFAULT_INTERFACE="$(ip -4 route list match default | grep -Eo "dev .*" | awk '{print $2}')" - ENDPOINT=$(ip -4 addr sh dev $DEFAULT_INTERFACE | grep -w inet | head -n1 | awk '{print $2}' | grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b') + ENDPOINT=$(ip -4 addr sh dev "$DEFAULT_INTERFACE" | grep -w inet | head -n1 | awk '{print $2}' | grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b') export ENDPOINT=$ENDPOINT echo "Using ${ENDPOINT} as the endpoint" } publicIpFromMetadata() { if curl -s http://169.254.169.254/metadata/v1/vendor-data | grep DigitalOcean >/dev/null; then - PROVIDER="digitalocean" ENDPOINT="$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address)" elif test "$(curl -s http://169.254.169.254/latest/meta-data/services/domain)" = "amazonaws.com"; then - PROVIDER="amazon" ENDPOINT="$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)" elif host -t A -W 10 metadata.google.internal 127.0.0.53 >/dev/null; then - PROVIDER="gce" ENDPOINT="$(curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip")" elif test "$(curl -s -H Metadata:true 'http://169.254.169.254/metadata/instance/compute/publisher/?api-version=2017-04-02&format=text')" = "Canonical"; then - PROVIDER="azure" ENDPOINT="$(curl -H Metadata:true 'http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version=2017-04-02&format=text')" fi - if echo ${ENDPOINT} | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"; then + if echo "${ENDPOINT}" | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"; then export ENDPOINT=$ENDPOINT echo "Using ${ENDPOINT} as the endpoint" else @@ -82,23 +77,25 @@ deployAlgo() { getAlgo cd /opt/algo + # shellcheck source=/dev/null . .venv/bin/activate export HOME=/root export ANSIBLE_LOCAL_TEMP=/root/.ansible/tmp export ANSIBLE_REMOTE_TEMP=/root/.ansible/tmp + # shellcheck disable=SC2086 ansible-playbook main.yml \ -e provider=local \ - -e ondemand_cellular=${ONDEMAND_CELLULAR} \ - -e ondemand_wifi=${ONDEMAND_WIFI} \ - -e ondemand_wifi_exclude=${ONDEMAND_WIFI_EXCLUDE} \ - -e windows=${WINDOWS} \ - -e store_cakey=${STORE_CAKEY} \ - -e local_dns=${LOCAL_DNS} \ - -e ssh_tunneling=${SSH_TUNNELING} \ - -e endpoint=$ENDPOINT \ - -e users=$(echo "$USERS" | jq -Rc 'split(",")') \ + -e "ondemand_cellular=${ONDEMAND_CELLULAR}" \ + -e "ondemand_wifi=${ONDEMAND_WIFI}" \ + -e "ondemand_wifi_exclude=${ONDEMAND_WIFI_EXCLUDE}" \ + -e "windows=${WINDOWS}" \ + -e "store_cakey=${STORE_CAKEY}" \ + -e "local_dns=${LOCAL_DNS}" \ + -e "ssh_tunneling=${SSH_TUNNELING}" \ + -e "endpoint=$ENDPOINT" \ + -e "users=$(echo "$USERS" | jq -Rc 'split(",")')" \ -e server=localhost \ -e ssh_user=root \ -e "${EXTRA_VARS}" \ @@ -106,7 +103,7 @@ deployAlgo() { tee /var/log/algo.log } -if test $METHOD = "cloud"; then +if test "$METHOD" = "cloud"; then publicIpFromMetadata fi diff --git a/main.yml b/main.yml index faf4c2d..c1c14ab 100644 --- a/main.yml +++ b/main.yml @@ -1,4 +1,15 @@ --- +- hosts: localhost + become: false + tasks: + - name: Verify Ansible meets Drupal VM's version requirements. + assert: + that: "ansible_version.full is version('2.7.10', '==')" + msg: > + Ansible version is {{ ansible_version.full }}. + You must update the requirements to use this version of Algo. + Try to run python -m pip install -U -r requirements.txt + - name: Include prompts playbook import_playbook: input.yml diff --git a/playbooks/cloud-pre.yml b/playbooks/cloud-pre.yml index 53de7fa..f25dafa 100644 --- a/playbooks/cloud-pre.yml +++ b/playbooks/cloud-pre.yml @@ -1,7 +1,7 @@ --- -- name: Display the invocation environment - local_action: - module: shell +- block: + - name: Display the invocation environment + shell: > ./algo-showenv.sh \ 'algo_provider "{{ algo_provider }}"' \ 'algo_ondemand_cellular "{{ algo_ondemand_cellular }}"' \ @@ -13,17 +13,20 @@ 'wireguard_enabled "{{ wireguard_enabled }}"' \ 'dns_encryption "{{ dns_encryption }}"' \ > /dev/tty - tags: debug + tags: debug -- name: Install the requirements - local_action: - module: pip - state: latest - name: - - pyOpenSSL - - jinja2==2.8 - - segno - tags: always + - name: Install the requirements + pip: + state: latest + name: + - pyOpenSSL + - jinja2==2.8 + - segno + tags: + - always + - skip_ansible_lint + delegate_to: localhost + become: false - name: Generate the SSH private key openssl_privatekey: diff --git a/playbooks/rescue.yml b/playbooks/rescue.yml index 4c090ce..375e0e6 100644 --- a/playbooks/rescue.yml +++ b/playbooks/rescue.yml @@ -2,4 +2,5 @@ - debug: var: fail_hint -- fail: +- name: Fail the installation + fail: diff --git a/requirements.txt b/requirements.txt index 38f36da..60c89a0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -ansible==2.5.2 +ansible==2.7.10 diff --git a/roles/client/handlers/main.yml b/roles/client/handlers/main.yml index 84c893a..33b013f 100644 --- a/roles/client/handlers/main.yml +++ b/roles/client/handlers/main.yml @@ -1,4 +1,3 @@ --- - - name: restart strongswan service: name=strongswan state=restarted diff --git a/roles/client/tasks/main.yml b/roles/client/tasks/main.yml index e3b1634..a2be955 100644 --- a/roles/client/tasks/main.yml +++ b/roles/client/tasks/main.yml @@ -8,13 +8,21 @@ package: name="{{ item }}" state=present with_items: - "{{ prerequisites }}" + register: result + until: result is succeeded + retries: 10 + delay: 3 - name: Install strongSwan package: name=strongswan state=present + register: result + until: result is succeeded + retries: 10 + delay: 3 - name: Setup the ipsec config template: - src: "roles/vpn/templates/client_ipsec.conf.j2" + src: "roles/strongswan/templates/client_ipsec.conf.j2" dest: "{{ configs_prefix }}/ipsec.{{ IP_subject_alt_name }}.conf" mode: '0644' with_items: @@ -24,7 +32,7 @@ - name: Setup the ipsec secrets template: - src: "roles/vpn/templates/client_ipsec.secrets.j2" + src: "roles/strongswan/templates/client_ipsec.secrets.j2" dest: "{{ configs_prefix }}/ipsec.{{ IP_subject_alt_name }}.secrets" mode: '0600' with_items: diff --git a/roles/client/tasks/systems/CentOS.yml b/roles/client/tasks/systems/CentOS.yml index aeb495e..68929df 100644 --- a/roles/client/tasks/systems/CentOS.yml +++ b/roles/client/tasks/systems/CentOS.yml @@ -1,6 +1,6 @@ --- - -- set_fact: +- name: Set OS specific facts + set_fact: prerequisites: - epel-release configs_prefix: /etc/strongswan diff --git a/roles/client/tasks/systems/Debian.yml b/roles/client/tasks/systems/Debian.yml index 2566c07..36873c0 100644 --- a/roles/client/tasks/systems/Debian.yml +++ b/roles/client/tasks/systems/Debian.yml @@ -1,5 +1,6 @@ --- - -- set_fact: - prerequisites: [] +- name: Set OS specific facts + set_fact: + prerequisites: + - libstrongswan-standard-plugins configs_prefix: /etc diff --git a/roles/client/tasks/systems/Fedora.yml b/roles/client/tasks/systems/Fedora.yml index 6bc13ef..f480578 100644 --- a/roles/client/tasks/systems/Fedora.yml +++ b/roles/client/tasks/systems/Fedora.yml @@ -1,6 +1,6 @@ --- - -- set_fact: +- name: Set OS specific facts + set_fact: prerequisites: - libselinux-python configs_prefix: /etc/strongswan diff --git a/roles/client/tasks/systems/Ubuntu.yml b/roles/client/tasks/systems/Ubuntu.yml index 2566c07..36873c0 100644 --- a/roles/client/tasks/systems/Ubuntu.yml +++ b/roles/client/tasks/systems/Ubuntu.yml @@ -1,5 +1,6 @@ --- - -- set_fact: - prerequisites: [] +- name: Set OS specific facts + set_fact: + prerequisites: + - libstrongswan-standard-plugins configs_prefix: /etc diff --git a/roles/cloud-azure/tasks/main.yml b/roles/cloud-azure/tasks/main.yml index 2c44809..7068228 100644 --- a/roles/cloud-azure/tasks/main.yml +++ b/roles/cloud-azure/tasks/main.yml @@ -9,14 +9,14 @@ - set_fact: algo_region: >- {% if region is defined %}{{ region }} - {%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ azure_regions[_algo_region.user_input | int -1 ]['name'] }} + {%- elif _algo_region.user_input %}{{ azure_regions[_algo_region.user_input | int -1 ]['name'] }} {%- else %}{{ azure_regions[default_region | int - 1]['name'] }}{% endif %} - name: Create AlgoVPN Server azure_rm_deployment: state: present deployment_name: "{{ algo_server_name }}" - template: "{{ lookup('file', 'deployment.json') }}" + template: "{{ lookup('file', role_path + '/files/deployment.json') }}" secret: "{{ secret }}" tenant: "{{ tenant }}" client_id: "{{ client_id }}" diff --git a/roles/cloud-azure/tasks/venv.yml b/roles/cloud-azure/tasks/venv.yml index cbadf8d..bc32c6f 100644 --- a/roles/cloud-azure/tasks/venv.yml +++ b/roles/cloud-azure/tasks/venv.yml @@ -10,23 +10,32 @@ name: - packaging - requests[security] - - azure-mgmt-compute>=2.0.0,<3 - - azure-mgmt-network>=1.3.0,<2 - - azure-mgmt-storage>=1.5.0,<2 - - azure-mgmt-resource>=1.1.0,<2 - - azure-storage>=0.35.1,<0.36 - - azure-cli-core>=2.0.12,<3 + - azure-cli-core==2.0.35 + - azure-cli-nspkg==3.0.2 + - azure-common==1.1.11 + - azure-mgmt-batch==4.1.0 + - azure-mgmt-compute==2.1.0 + - azure-mgmt-containerinstance==0.4.0 + - azure-mgmt-containerregistry==2.0.0 + - azure-mgmt-containerservice==3.0.1 + - azure-mgmt-dns==1.2.0 + - azure-mgmt-keyvault==0.40.0 + - azure-mgmt-marketplaceordering==0.1.0 + - azure-mgmt-monitor==0.5.2 + - azure-mgmt-network==1.7.1 + - azure-mgmt-nspkg==2.0.0 + - azure-mgmt-rdbms==1.2.0 + - azure-mgmt-resource==1.2.2 + - azure-mgmt-sql==0.7.1 + - azure-mgmt-storage==1.5.0 + - azure-mgmt-trafficmanager==0.50.0 + - azure-mgmt-web==0.32.0 + - azure-nspkg==2.0.0 + - azure-storage==0.35.1 - msrest==0.4.29 - msrestazure==0.4.31 - - azure-mgmt-dns>=1.0.1,<2 - - azure-mgmt-keyvault>=0.40.0,<0.41 - - azure-mgmt-batch>=4.1.0,<5 - - azure-mgmt-sql>=0.7.1,<0.8 - - azure-mgmt-web>=0.32.0,<0.33 - - azure-mgmt-containerservice>=2.0.0,<3.0.0 - - azure-mgmt-containerregistry>=1.0.1 - - azure-mgmt-rdbms==1.2.0 - - azure-mgmt-containerinstance==0.4.0 + - azure-keyvault==1.0.0a1 + - azure-graphrbac==0.40.0 state: latest virtualenv: "{{ azure_venv }}" virtualenv_python: python2.7 diff --git a/roles/cloud-digitalocean/tasks/main.yml b/roles/cloud-digitalocean/tasks/main.yml index 93baefe..b601030 100644 --- a/roles/cloud-digitalocean/tasks/main.yml +++ b/roles/cloud-digitalocean/tasks/main.yml @@ -10,7 +10,7 @@ set_fact: algo_do_region: >- {% if region is defined %}{{ region }} - {%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ do_regions[_algo_region.user_input | int -1 ]['slug'] }} + {%- elif _algo_region.user_input %}{{ do_regions[_algo_region.user_input | int -1 ]['slug'] }} {%- else %}{{ do_regions[default_region | int - 1]['slug'] }}{% endif %} public_key: "{{ lookup('file', '{{ SSH_keys.public }}') }}" @@ -22,7 +22,7 @@ api_token: "{{ algo_do_token }}" name: "{{ SSH_keys.comment }}" register: ssh_keys - until: ssh_keys.changed != true + until: not ssh_keys.changed retries: 10 delay: 1 @@ -83,7 +83,7 @@ api_token: "{{ algo_do_token }}" name: "{{ SSH_keys.comment }}" register: ssh_keys - until: ssh_keys.changed != true + until: not ssh_keys.changed retries: 10 delay: 1 diff --git a/roles/cloud-ec2/files/stack.yml b/roles/cloud-ec2/files/stack.yaml similarity index 100% rename from roles/cloud-ec2/files/stack.yml rename to roles/cloud-ec2/files/stack.yaml diff --git a/roles/cloud-ec2/tasks/cloudformation.yml b/roles/cloud-ec2/tasks/cloudformation.yml index 2797720..126c531 100644 --- a/roles/cloud-ec2/tasks/cloudformation.yml +++ b/roles/cloud-ec2/tasks/cloudformation.yml @@ -6,7 +6,7 @@ stack_name: "{{ stack_name }}" state: "present" region: "{{ algo_region }}" - template: roles/cloud-ec2/files/stack.yml + template: roles/cloud-ec2/files/stack.yaml template_parameters: InstanceTypeParameter: "{{ cloud_providers.ec2.size }}" PublicSSHKeyParameter: "{{ lookup('file', SSH_keys.public) }}" diff --git a/roles/cloud-ec2/tasks/main.yml b/roles/cloud-ec2/tasks/main.yml index ce6532b..44eebc9 100644 --- a/roles/cloud-ec2/tasks/main.yml +++ b/roles/cloud-ec2/tasks/main.yml @@ -9,7 +9,7 @@ - set_fact: algo_region: >- {% if region is defined %}{{ region }} - {%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ aws_regions[_algo_region.user_input | int -1 ]['region_name'] }} + {%- elif _algo_region.user_input %}{{ aws_regions[_algo_region.user_input | int -1 ]['region_name'] }} {%- else %}{{ aws_regions[default_region | int - 1]['region_name'] }}{% endif %} stack_name: "{{ algo_server_name | replace('.', '-') }}" diff --git a/roles/cloud-gce/tasks/prompts.yml b/roles/cloud-gce/tasks/prompts.yml index b054cc9..dfedecf 100644 --- a/roles/cloud-gce/tasks/prompts.yml +++ b/roles/cloud-gce/tasks/prompts.yml @@ -63,5 +63,5 @@ - set_fact: algo_region: >- {% if region is defined %}{{ region }} - {%- elif _gce_region.user_input is defined and _gce_region.user_input != "" %}{{ gce_regions[_gce_region.user_input | int -1 ] }} + {%- elif _gce_region.user_input %}{{ gce_regions[_gce_region.user_input | int -1 ] }} {%- else %}{{ gce_regions[default_region | int - 1] }}{% endif %} diff --git a/roles/cloud-lightsail/tasks/prompts.yml b/roles/cloud-lightsail/tasks/prompts.yml index 1c98c5a..be3c3e1 100644 --- a/roles/cloud-lightsail/tasks/prompts.yml +++ b/roles/cloud-lightsail/tasks/prompts.yml @@ -57,5 +57,5 @@ - set_fact: algo_region: >- {% if region is defined %}{{ region }} - {%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ lightsail_regions[_algo_region.user_input | int -1 ]['name'] }} + {%- elif _algo_region.user_input %}{{ lightsail_regions[_algo_region.user_input | int -1 ]['name'] }} {%- else %}{{ lightsail_regions[default_region | int - 1]['name'] }}{% endif %} diff --git a/roles/cloud-openstack/tasks/main.yml b/roles/cloud-openstack/tasks/main.yml index b8c1181..bce0157 100644 --- a/roles/cloud-openstack/tasks/main.yml +++ b/roles/cloud-openstack/tasks/main.yml @@ -1,7 +1,7 @@ --- - fail: msg: "OpenStack credentials are not set. Download it from the OpenStack dashboard->Compute->API Access and source it in the shell (eg: source /tmp/dhc-openrc.sh)" - when: lookup('env', 'OS_AUTH_URL') == "" + when: lookup('env', 'OS_AUTH_URL')|length <= 0 - name: Build python virtual environment import_tasks: venv.yml diff --git a/roles/cloud-scaleway/tasks/main.yml b/roles/cloud-scaleway/tasks/main.yml index 9ff5124..3e9a39b 100644 --- a/roles/cloud-scaleway/tasks/main.yml +++ b/roles/cloud-scaleway/tasks/main.yml @@ -84,7 +84,7 @@ organization: "{{ organization_id }}" name: "{{ algo_server_name }}" image: "{{ image_id }}" - commercial_type: "{{cloud_providers.scaleway.size }}" + commercial_type: "{{ cloud_providers.scaleway.size }}" enable_ipv6: true boot_type: local tags: diff --git a/roles/cloud-scaleway/tasks/prompts.yml b/roles/cloud-scaleway/tasks/prompts.yml index 22c3f1a..b481880 100644 --- a/roles/cloud-scaleway/tasks/prompts.yml +++ b/roles/cloud-scaleway/tasks/prompts.yml @@ -30,5 +30,5 @@ algo_scaleway_org: "{{ scaleway_org | default(_scaleway_org.user_input|default(omit)) }}" algo_region: >- {% if region is defined %}{{ region }} - {%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ scaleway_regions[_algo_region.user_input | int -1 ]['alias'] }} + {%- elif _algo_region.user_input %}{{ scaleway_regions[_algo_region.user_input | int -1 ]['alias'] }} {%- else %}{{ scaleway_regions.0.alias }}{% endif %} diff --git a/roles/cloud-vultr/tasks/main.yml b/roles/cloud-vultr/tasks/main.yml index a1dfa90..03b2374 100644 --- a/roles/cloud-vultr/tasks/main.yml +++ b/roles/cloud-vultr/tasks/main.yml @@ -1,16 +1,16 @@ --- -- block: - - name: Include prompts - import_tasks: prompts.yml +- name: Include prompts + import_tasks: prompts.yml +- block: - name: Upload the SSH key - vr_ssh_key: + vultr_ssh_key: name: "{{ SSH_keys.comment }}" ssh_key: "{{ lookup('file', '{{ SSH_keys.public }}') }}" register: ssh_key - name: Creating a server - vr_server: + vultr_server: name: "{{ algo_server_name }}" hostname: "{{ algo_server_name }}" os: "{{ cloud_providers.vultr.os }}" diff --git a/roles/cloud-vultr/tasks/prompts.yml b/roles/cloud-vultr/tasks/prompts.yml index d037bf1..1245b71 100644 --- a/roles/cloud-vultr/tasks/prompts.yml +++ b/roles/cloud-vultr/tasks/prompts.yml @@ -54,5 +54,5 @@ set_fact: algo_vultr_region: >- {% if region is defined %}{{ region }} - {%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ vultr_regions[_algo_region.user_input | int -1 ]['name'] }} + {%- elif _algo_region.user_input %}{{ vultr_regions[_algo_region.user_input | int -1 ]['name'] }} {%- else %}{{ vultr_regions[default_region | int - 1]['name'] }}{% endif %} diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml index 06f5080..6b36926 100644 --- a/roles/common/handlers/main.yml +++ b/roles/common/handlers/main.yml @@ -20,8 +20,5 @@ ifconfig lo100 inet {{ local_service_ip }} netmask 255.255.255.255 && ifconfig lo100 inet6 FCAA::1/64; echo $? -- name: save iptables - shell: service netfilter-persistent save - - name: restart iptables service: name=netfilter-persistent state=restarted diff --git a/roles/common/tasks/facts.yml b/roles/common/tasks/facts.yml index 6e79bfc..c064d7b 100644 --- a/roles/common/tasks/facts.yml +++ b/roles/common/tasks/facts.yml @@ -1,26 +1,26 @@ --- - block: - name: Generate password for the CA key - local_action: - module: shell - openssl rand -hex 16 + command: openssl rand -hex 16 register: CA_password - name: Generate p12 export password - local_action: - module: shell - openssl rand 8 | python -c 'import sys,string; chars=string.ascii_letters + string.digits + "_@"; print("".join([chars[ord(c) % 64] for c in list(sys.stdin.read())]))' + shell: > + openssl rand 8 | + python -c 'import sys,string; chars=string.ascii_letters + string.digits + "_@"; print("".join([chars[ord(c) % 64] for c in list(sys.stdin.read())]))' register: p12_password_generated when: p12_password is not defined tags: update-users become: false + delegate_to: localhost - name: Define facts set_fact: p12_export_password: "{{ p12_password|default(p12_password_generated.stdout) }}" tags: update-users -- set_fact: +- name: Set facts + set_fact: CA_password: "{{ CA_password.stdout }}" IP_subject_alt_name: "{{ IP_subject_alt_name }}" @@ -31,5 +31,5 @@ - name: Check size of MTU set_fact: - reduce_mtu: "{% if reduce_mtu|int == 0 and ansible_default_ipv4['mtu']|int < 1500 %}{{ 1500 - ansible_default_ipv4['mtu']|int }}{% else %}{{ reduce_mtu|int }}{% endif %}" + reduce_mtu: "{{ 1500 - ansible_default_ipv4['mtu']|int if reduce_mtu|int == 0 and ansible_default_ipv4['mtu']|int < 1500 else reduce_mtu|int }}" tags: always diff --git a/roles/common/tasks/freebsd.yml b/roles/common/tasks/freebsd.yml index 8136263..e0d54c1 100644 --- a/roles/common/tasks/freebsd.yml +++ b/roles/common/tasks/freebsd.yml @@ -17,7 +17,8 @@ - name: Gather additional facts import_tasks: facts.yml -- set_fact: +- name: Set OS specific facts + set_fact: config_prefix: "/usr/local/" strongswan_shell: /usr/sbin/nologin strongswan_home: /var/empty @@ -73,5 +74,6 @@ 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 + changed_when: false - meta: flush_handlers diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index 4a40088..0233096 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -2,6 +2,7 @@ - name: Check the system raw: uname -a register: OS + changed_when: false tags: - update-users @@ -17,7 +18,7 @@ - name: Sysctl tuning sysctl: name="{{ item.item }}" value="{{ item.value }}" - when: item.item != "" + when: item.item with_items: - "{{ sysctl|default([]) }}" tags: diff --git a/roles/common/tasks/ubuntu.yml b/roles/common/tasks/ubuntu.yml index 08d37a3..114b418 100644 --- a/roles/common/tasks/ubuntu.yml +++ b/roles/common/tasks/ubuntu.yml @@ -25,8 +25,7 @@ ignore_errors: true - name: Wait until SSH becomes ready... - local_action: - module: wait_for + wait_for: port: 22 host: "{{ inventory_hostname }}" search_regex: OpenSSH @@ -34,6 +33,7 @@ timeout: 320 when: reboot_required is defined and reboot_required.stdout == 'required' become: false + delegate_to: localhost when: algo_provider != "local" - name: Include unatteded upgrades configuration @@ -65,18 +65,21 @@ - meta: flush_handlers - name: Check apparmor support - shell: apparmor_status + command: apparmor_status ignore_errors: yes + changed_when: false register: apparmor_status -- set_fact: +- name: Set fact if apparmor enabled + set_fact: apparmor_enabled: true when: '"profiles are in enforce mode" in apparmor_status.stdout' - name: Gather additional facts import_tasks: facts.yml -- set_fact: +- name: Set OS specific facts + set_fact: tools: - git - screen diff --git a/roles/common/tasks/unattended-upgrades.yml b/roles/common/tasks/unattended-upgrades.yml index d0beae0..582c1eb 100644 --- a/roles/common/tasks/unattended-upgrades.yml +++ b/roles/common/tasks/unattended-upgrades.yml @@ -2,7 +2,7 @@ - name: Install unattended-upgrades apt: name: unattended-upgrades - state: latest + state: present - name: Configure unattended-upgrades template: diff --git a/roles/dns_adblocking/tasks/main.yml b/roles/dns_adblocking/tasks/main.yml index cd1a54a..49cfa16 100644 --- a/roles/dns_adblocking/tasks/main.yml +++ b/roles/dns_adblocking/tasks/main.yml @@ -36,6 +36,7 @@ - name: Update adblock hosts command: /usr/local/sbin/adblock.sh + changed_when: false - meta: flush_handlers diff --git a/roles/dns_adblocking/tasks/ubuntu.yml b/roles/dns_adblocking/tasks/ubuntu.yml index ffc8887..33b62f2 100644 --- a/roles/dns_adblocking/tasks/ubuntu.yml +++ b/roles/dns_adblocking/tasks/ubuntu.yml @@ -7,13 +7,13 @@ owner: root group: root mode: 0600 - when: apparmor_enabled|default(false)|bool == true + when: apparmor_enabled|default(false)|bool notify: - restart dnsmasq - name: Ubuntu | Enforce the dnsmasq AppArmor policy - shell: aa-enforce usr.sbin.dnsmasq - when: apparmor_enabled|default(false)|bool == true + command: aa-enforce usr.sbin.dnsmasq + when: apparmor_enabled|default(false)|bool tags: ['apparmor'] - name: Ubuntu | Ensure that the dnsmasq service directory exist diff --git a/roles/dns_encryption/tasks/ubuntu.yml b/roles/dns_encryption/tasks/ubuntu.yml index f9cd7ee..76f0e15 100644 --- a/roles/dns_encryption/tasks/ubuntu.yml +++ b/roles/dns_encryption/tasks/ubuntu.yml @@ -12,7 +12,7 @@ - name: Install dnscrypt-proxy apt: name: dnscrypt-proxy - state: latest + state: present update_cache: true - name: Configure unattended-upgrades @@ -37,7 +37,7 @@ command: aa-enforce usr.bin.dnscrypt-proxy changed_when: false tags: apparmor - when: apparmor_enabled|default(false)|bool == true + when: apparmor_enabled|default(false)|bool - name: Ubuntu | Ensure that the dnscrypt-proxy service directory exist file: diff --git a/roles/local/tasks/prompts.yml b/roles/local/tasks/prompts.yml index a12b880..9df53f4 100644 --- a/roles/local/tasks/prompts.yml +++ b/roles/local/tasks/prompts.yml @@ -10,7 +10,7 @@ set_fact: cloud_instance_ip: >- {% if server is defined %}{{ server }} - {%- elif _algo_server.user_input is defined and _algo_server.user_input != "" %}{{ _algo_server.user_input }} + {%- elif _algo_server.user_input %}{{ _algo_server.user_input }} {%- else %}localhost{% endif %} - pause: @@ -26,7 +26,7 @@ set_fact: ansible_ssh_user: >- {% if ssh_user is defined %}{{ ssh_user }} - {%- elif _algo_ssh_user.user_input is defined and _algo_ssh_user.user_input != "" %}{{ _algo_ssh_user.user_input }} + {%- elif _algo_ssh_user.user_input %}{{ _algo_ssh_user.user_input }} {%- else %}root{% endif %} - pause: @@ -40,5 +40,5 @@ set_fact: IP_subject_alt_name: >- {% if endpoint is defined %}{{ endpoint }} - {%- elif _endpoint.user_input is defined and _endpoint.user_input != "" %}{{ _endpoint.user_input }} + {%- elif _endpoint.user_input %}{{ _endpoint.user_input }} {%- else %}{{ cloud_instance_ip }}{% endif %} diff --git a/roles/ssh_tunneling/tasks/main.yml b/roles/ssh_tunneling/tasks/main.yml index 4ea4680..437fa47 100644 --- a/roles/ssh_tunneling/tasks/main.yml +++ b/roles/ssh_tunneling/tasks/main.yml @@ -42,7 +42,7 @@ file: dest: "{{ ssh_tunnels_config_path }}" state: absent - when: keys_clean_all|bool == True + when: keys_clean_all|bool - name: Ensure the config directories exist file: diff --git a/roles/strongswan/handlers/main.yml b/roles/strongswan/handlers/main.yml index 6e7968f..5f35003 100644 --- a/roles/strongswan/handlers/main.yml +++ b/roles/strongswan/handlers/main.yml @@ -2,7 +2,7 @@ service: name=strongswan state=restarted - name: daemon-reload - shell: systemctl daemon-reload + systemd: daemon_reload=true - name: restart apparmor service: name=apparmor state=restarted diff --git a/roles/strongswan/tasks/client_configs.yml b/roles/strongswan/tasks/client_configs.yml index de4ff0f..145f29d 100644 --- a/roles/strongswan/tasks/client_configs.yml +++ b/roles/strongswan/tasks/client_configs.yml @@ -1,8 +1,13 @@ --- - name: Register p12 PayloadContent - shell: cat private/{{ item }}.p12 | base64 + shell: | + set -o pipefail + cat private/{{ item }}.p12 | + base64 register: PayloadContent + changed_when: false args: + executable: bash chdir: "{{ ipsec_pki_path }}" with_items: "{{ users }}" diff --git a/roles/strongswan/tasks/ipsec_configuration.yml b/roles/strongswan/tasks/ipsec_configuration.yml index af19ed4..d75a93c 100644 --- a/roles/strongswan/tasks/ipsec_configuration.yml +++ b/roles/strongswan/tasks/ipsec_configuration.yml @@ -32,8 +32,13 @@ - restart strongswan - name: Get loaded plugins - shell: > - find {{ config_prefix|default('/') }}etc/strongswan.d/charon/ -type f -name '*.conf' -exec basename {} \; | cut -f1 -d. + shell: | + set -o pipefail + find {{ config_prefix|default('/') }}etc/strongswan.d/charon/ -type f -name '*.conf' -exec basename {} \; | + cut -f1 -d. + changed_when: false + args: + executable: bash register: strongswan_plugins - name: Disable unneeded plugins diff --git a/roles/strongswan/tasks/openssl.yml b/roles/strongswan/tasks/openssl.yml index fd38611..b813e61 100644 --- a/roles/strongswan/tasks/openssl.yml +++ b/roles/strongswan/tasks/openssl.yml @@ -2,14 +2,19 @@ - block: - name: Set subjectAltName as a fact set_fact: - subjectAltName: "{{ subjectAltName_IP }}{% if ipv6_support %},IP:{{ ansible_default_ipv6['address'] }}{% endif %}{% if domain and subjectAltName_DNS %},DNS:{{ subjectAltName_DNS }}{% endif %}" + subjectAltName: >- + {{ subjectAltName_IP }} + {%- if ipv6_support -%},IP:{{ ansible_default_ipv6['address'] }}{%- endif -%} + {%- if domain and subjectAltName_DNS -%},DNS:{{ subjectAltName_DNS }}{%- endif -%} tags: always + - debug: var=subjectAltName + - name: Ensure the pki directory does not exist file: dest: "{{ ipsec_pki_path }}" state: absent - when: keys_clean_all|bool == True + when: keys_clean_all|bool - name: Ensure the pki directories exist file: @@ -182,7 +187,7 @@ awk '{print $5}' | sed 's/\/CN=//g' args: - chdir: "{{ ipsec_pki_path}}" + chdir: "{{ ipsec_pki_path }}" register: valid_certs - name: Revoke non-existing users @@ -228,11 +233,11 @@ - rereadcrls - name: Delete the CA key - local_action: - module: file + file: path: "{{ ipsec_pki_path }}/private/cakey.pem" state: absent become: false + delegate_to: localhost when: - ipsec_enabled - not algo_store_cakey diff --git a/roles/strongswan/tasks/ubuntu.yml b/roles/strongswan/tasks/ubuntu.yml index 41b5835..afaffa3 100644 --- a/roles/strongswan/tasks/ubuntu.yml +++ b/roles/strongswan/tasks/ubuntu.yml @@ -1,18 +1,19 @@ --- - -- set_fact: +- name: Set OS specific facts + set_fact: strongswan_additional_plugins: [] - name: Ubuntu | Install strongSwan apt: name: strongswan - state: latest + state: present update_cache: yes install_recommends: yes - name: Ubuntu | Enforcing ipsec with apparmor - shell: aa-enforce "{{ item }}" - when: apparmor_enabled|default(false)|bool == true + command: aa-enforce "{{ item }}" + when: apparmor_enabled|default(false)|bool + changed_when: false with_items: - /usr/lib/ipsec/charon - /usr/lib/ipsec/lookip diff --git a/roles/strongswan/templates/client_ipsec.conf.j2 b/roles/strongswan/templates/client_ipsec.conf.j2 index a45d8e3..e44f949 100644 --- a/roles/strongswan/templates/client_ipsec.conf.j2 +++ b/roles/strongswan/templates/client_ipsec.conf.j2 @@ -1,4 +1,4 @@ -conn ikev2-{{ IP_subject_alt_name }} +conn algovpn-{{ IP_subject_alt_name }} fragmentation=yes rekey=no dpdaction=clear @@ -16,7 +16,7 @@ conn ikev2-{{ IP_subject_alt_name }} right={{ IP_subject_alt_name }} rightid={{ IP_subject_alt_name }} - rightsubnet=0.0.0.0/0 + rightsubnet={{ rightsubnet | default('0.0.0.0/0') }} rightauth=pubkey leftsourceip=%config diff --git a/roles/wireguard/defaults/main.yml b/roles/wireguard/defaults/main.yml index e61c778..4c7f17f 100644 --- a/roles/wireguard/defaults/main.yml +++ b/roles/wireguard/defaults/main.yml @@ -5,7 +5,7 @@ wireguard_pki_path: "{{ wireguard_config_path }}/.pki/" wireguard_interface: wg0 keys_clean_all: false wireguard_dns_servers: >- - {% if local_dns|default(false)|bool or dns_encryption|default(false)|bool == true %} + {% if local_dns|default(false)|bool or dns_encryption|default(false)|bool %} {{ local_service_ip }} {% else %} {% for host in dns_servers.ipv4 %}{{ host }}{% if not loop.last %},{% endif %}{% endfor %}{% if ipv6_support %},{% for host in dns_servers.ipv6 %}{{ host }}{% if not loop.last %},{% endif %}{% endfor %}{% endif %} diff --git a/roles/wireguard/tasks/freebsd.yml b/roles/wireguard/tasks/freebsd.yml index 63e7b48..15bc1f5 100644 --- a/roles/wireguard/tasks/freebsd.yml +++ b/roles/wireguard/tasks/freebsd.yml @@ -4,7 +4,8 @@ name: wireguard state: present -- set_fact: +- name: Set OS specific facts + set_fact: service_name: wireguard tags: always diff --git a/roles/wireguard/tasks/keys.yml b/roles/wireguard/tasks/keys.yml index e13a015..0deaef6 100644 --- a/roles/wireguard/tasks/keys.yml +++ b/roles/wireguard/tasks/keys.yml @@ -3,7 +3,7 @@ file: dest: "{{ config_prefix|default('/') }}etc/wireguard/private_{{ item }}.lock" state: absent - when: keys_clean_all|bool == True + when: keys_clean_all|bool with_items: - "{{ users }}" - "{{ IP_subject_alt_name }}" @@ -39,7 +39,10 @@ when: wg_genkey.changed - name: Generate public keys - shell: echo "{{ lookup('file', wireguard_pki_path + '/private/' + item) }}" | wg pubkey + shell: | + set -o pipefail + echo "{{ lookup('file', wireguard_pki_path + '/private/' + item) }}" | + wg pubkey register: wg_pubkey changed_when: false args: diff --git a/roles/wireguard/tasks/ubuntu.yml b/roles/wireguard/tasks/ubuntu.yml index c75b8a7..603c065 100644 --- a/roles/wireguard/tasks/ubuntu.yml +++ b/roles/wireguard/tasks/ubuntu.yml @@ -27,6 +27,7 @@ group: root mode: 0644 -- set_fact: +- name: Set OS specific facts + set_fact: service_name: "wg-quick@{{ wireguard_interface }}" tags: always diff --git a/server.yml b/server.yml index 349150c..5c9b183 100644 --- a/server.yml +++ b/server.yml @@ -38,8 +38,7 @@ - block: - name: Dump the configuration - local_action: - module: copy + copy: dest: "configs/{{ IP_subject_alt_name }}/.config.yml" content: | server: {{ 'localhost' if inventory_hostname == 'localhost' else inventory_hostname }} @@ -59,8 +58,12 @@ IP_subject_alt_name: {{ IP_subject_alt_name }} ipsec_enabled: {{ ipsec_enabled }} wireguard_enabled: {{ wireguard_enabled }} - {% if tests|default(false)|bool %}ca_password: {{ CA_password }}{% endif %} + {% if tests|default(false)|bool %} + ca_password: {{ CA_password }} + p12_password: {{ p12_export_password }} + {% endif %} become: false + delegate_to: localhost - name: Create a symlink if deploying to localhost file: diff --git a/tests/algo.conf b/tests/algo.conf new file mode 100644 index 0000000..a93d420 --- /dev/null +++ b/tests/algo.conf @@ -0,0 +1 @@ +dhcp-host=algo,10.0.8.100 diff --git a/tests/cloud-init.sh b/tests/cloud-init.sh index 2d95c99..ca182cd 100755 --- a/tests/cloud-init.sh +++ b/tests/cloud-init.sh @@ -7,8 +7,9 @@ export ONDEMAND_WIFI_EXCLUDE=test1,test2 export WINDOWS=true export STORE_CAKEY=true export LOCAL_DNS=true -export ENDPOINT=algo.lxc -export USERS=user1,user2 +export SSH_TUNNELING=true +export ENDPOINT=10.0.8.100 +export USERS=desktop,user1,user2 export EXTRA_VARS='install_headers=false tests=true apparmor_enabled=false' export ANSIBLE_EXTRA_ARGS='--skip-tags apparmor' export REPO_SLUG=${TRAVIS_PULL_REQUEST_SLUG:-${TRAVIS_REPO_SLUG:-trailofbits/algo}} diff --git a/tests/ipsec-client.sh b/tests/ipsec-client.sh new file mode 100755 index 0000000..d2c3f54 --- /dev/null +++ b/tests/ipsec-client.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +xmllint --noout ./configs/10.0.8.100/ipsec/apple/user1.mobileconfig + +ansible-playbook deploy_client.yml \ + -e client_ip=localhost \ + -e vpn_user=desktop \ + -e server_ip=10.0.8.100 \ + -e rightsubnet='172.16.0.1/32' + +ipsec up algovpn-10.0.8.100 + +ipsec statusall + +ipsec statusall | grep -w ^algovpn-10.0.8.100 | grep -w ESTABLISHED + +fping -t 900 -c3 -r3 -Dse 10.0.8.100 172.16.0.1 + +host google.com 172.16.0.1 + +echo "IPsec tests passed" diff --git a/tests/local-deploy.sh b/tests/local-deploy.sh index fc7d038..99bf5c2 100755 --- a/tests/local-deploy.sh +++ b/tests/local-deploy.sh @@ -2,11 +2,11 @@ set -ex -DEPLOY_ARGS="provider=local server=$LXC_IP ssh_user=ubuntu endpoint=$LXC_IP apparmor_enabled=false ondemand_cellular=true ondemand_wifi=true ondemand_wifi_exclude=test local_dns=true ssh_tunneling=true windows=true store_cakey=true install_headers=false tests=true" +DEPLOY_ARGS="provider=local server=10.0.8.100 ssh_user=ubuntu endpoint=10.0.8.100 apparmor_enabled=false ondemand_cellular=true ondemand_wifi=true ondemand_wifi_exclude=test local_dns=true ssh_tunneling=true windows=true store_cakey=true install_headers=false tests=true" -if [ "${LXC_NAME}" == "docker" ] +if [ "${DEPLOY}" == "docker" ] then - docker run -it -v $(pwd)/config.cfg:/algo/config.cfg -v ~/.ssh:/root/.ssh -v $(pwd)/configs:/algo/configs -e "DEPLOY_ARGS=${DEPLOY_ARGS}" travis/algo /bin/sh -c "chown -R 0:0 /root/.ssh && source env/bin/activate && ansible-playbook main.yml -e \"${DEPLOY_ARGS}\" --skip-tags apparmor" + docker run -it -v $(pwd)/config.cfg:/algo/config.cfg -v ~/.ssh:/root/.ssh -v $(pwd)/configs:/algo/configs -e "DEPLOY_ARGS=${DEPLOY_ARGS}" travis/algo /bin/sh -c "chown -R root: /root/.ssh && chmod -R 600 /root/.ssh && source env/bin/activate && ansible-playbook main.yml -e \"${DEPLOY_ARGS}\" --skip-tags apparmor" else ansible-playbook main.yml -e "${DEPLOY_ARGS}" --skip-tags apparmor fi diff --git a/tests/lxd-bridge b/tests/lxd-bridge index 0614e87..ddc59d2 100644 --- a/tests/lxd-bridge +++ b/tests/lxd-bridge @@ -1,7 +1,7 @@ USE_LXD_BRIDGE="true" LXD_BRIDGE="lxdbr0" UPDATE_PROFILE="true" -LXD_CONFILE="" +LXD_CONFILE="/etc/default/algo.conf" LXD_DOMAIN="lxd" LXD_IPV4_ADDR="10.0.8.1" LXD_IPV4_NETMASK="255.255.255.0" @@ -13,4 +13,4 @@ LXD_IPV6_ADDR="" LXD_IPV6_MASK="" LXD_IPV6_NETWORK="" LXD_IPV6_NAT="false" -LXD_IPV6_PROXY="true" +LXD_IPV6_PROXY="false" diff --git a/tests/pre-deploy.sh b/tests/pre-deploy.sh new file mode 100755 index 0000000..764eb67 --- /dev/null +++ b/tests/pre-deploy.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +sysctl net.ipv6.conf.all.disable_ipv6=0 + +tar xf $HOME/lxc/cache.tar -C / || echo "Didn't extract cache." +cp -f tests/lxd-bridge /etc/default/lxd-bridge +cp -f tests/algo.conf /etc/default/algo.conf + +if [[ "$DEPLOY" == "cloud-init" ]]; then + bash tests/cloud-init.sh | lxc profile set default user.user-data - +else + echo -e "#cloud-config\nssh_authorized_keys:\n - $(cat ~/.ssh/id_rsa.pub)" | lxc profile set default user.user-data - +fi + +systemctl restart lxd-bridge.service lxd-containers.service lxd.service + +lxc profile set default raw.lxc lxc.aa_profile=unconfined +lxc profile set default security.privileged true +lxc profile show default +lxc launch ubuntu:18.04 algo + +ip addr + +until dig A +short algo.lxd @10.0.8.1 | grep -vE '^$' > /dev/null; do + sleep 3 +done + +lxc list diff --git a/tests/ssh-tunnel.sh b/tests/ssh-tunnel.sh new file mode 100755 index 0000000..39f6ecc --- /dev/null +++ b/tests/ssh-tunnel.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +PASS=$(grep ^p12_password: configs/10.0.8.100/.config.yml | awk '{print $2}') + +ssh-keygen -p -P ${PASS} -N '' -f configs/10.0.8.100/ssh-tunnel/desktop.pem + +ssh -o StrictHostKeyChecking=no -D 127.0.0.1:1080 -f -q -C -N desktop@10.0.8.100 -i configs/10.0.8.100/ssh-tunnel/desktop.pem + +git config --global http.proxy 'socks5://127.0.0.1:1080' + +git clone -vv https://github.com/trailofbits/algo /tmp/ssh-tunnel-check + +echo "SSH tunneling tests passed" diff --git a/tests/update-users.sh b/tests/update-users.sh index c083994..d957787 100755 --- a/tests/update-users.sh +++ b/tests/update-users.sh @@ -2,11 +2,11 @@ set -ex -USER_ARGS="{ 'server': '$LXC_IP', 'users': ['user1', 'user2'] }" +USER_ARGS="{ 'server': '10.0.8.100', 'users': ['desktop', 'user1', 'user2'] }" -if [ "${LXC_NAME}" == "docker" ] +if [ "${DEPLOY}" == "docker" ] then - docker run -it -v $(pwd)/config.cfg:/algo/config.cfg -v ~/.ssh:/root/.ssh -v $(pwd)/configs:/algo/configs -e "USER_ARGS=${USER_ARGS}" travis/algo /bin/sh -c "chown -R 0:0 /root/.ssh && source env/bin/activate && ansible-playbook users.yml -e \"${USER_ARGS}\" -t update-users" + docker run -it -v $(pwd)/config.cfg:/algo/config.cfg -v ~/.ssh:/root/.ssh -v $(pwd)/configs:/algo/configs -e "USER_ARGS=${USER_ARGS}" travis/algo /bin/sh -c "chown -R root: /root/.ssh && chmod -R 600 /root/.ssh && source env/bin/activate && ansible-playbook users.yml -e \"${USER_ARGS}\" -t update-users" else ansible-playbook users.yml -e "${USER_ARGS}" -t update-users fi @@ -15,7 +15,7 @@ fi # IPsec # -if sudo openssl crl -inform pem -noout -text -in configs/$LXC_IP/ipsec/.pki/crl/phone.crt | grep CRL +if sudo openssl crl -inform pem -noout -text -in configs/10.0.8.100/ipsec/.pki/crl/phone.crt | grep CRL then echo "The CRL check passed" else @@ -23,7 +23,7 @@ if sudo openssl crl -inform pem -noout -text -in configs/$LXC_IP/ipsec/.pki/crl/ exit 1 fi -if sudo openssl x509 -inform pem -noout -text -in configs/$LXC_IP/ipsec/.pki/certs/user1.crt | grep CN=user1 +if sudo openssl x509 -inform pem -noout -text -in configs/10.0.8.100/ipsec/.pki/certs/user1.crt | grep CN=user1 then echo "The new user exists" else @@ -35,7 +35,7 @@ fi # WireGuard # -if sudo test -f configs/$LXC_IP/wireguard/user1.conf +if sudo test -f configs/10.0.8.100/wireguard/user1.conf then echo "WireGuard: The new user exists" else @@ -47,7 +47,7 @@ fi # SSH tunneling # -if sudo test -f configs/$LXC_IP/ssh-tunnel/user1.ssh_config +if sudo test -f configs/10.0.8.100/ssh-tunnel/user1.ssh_config then echo "SSH Tunneling: The new user exists" else diff --git a/tests/wireguard-client.sh b/tests/wireguard-client.sh new file mode 100755 index 0000000..7dac2a3 --- /dev/null +++ b/tests/wireguard-client.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +crudini --set configs/10.0.8.100/wireguard/user1.conf Interface Table off + +wg-quick up configs/10.0.8.100/wireguard/user1.conf + +wg + +ifconfig user1 + +ip route add 172.16.0.1/32 dev user1 + +fping -t 900 -c3 -r3 -Dse 10.0.8.100 172.16.0.1 + +wg | grep "latest handshake" + +host google.com 172.16.0.1 + +echo "WireGuard tests passed" diff --git a/users.yml b/users.yml index 4347325..e33f04e 100644 --- a/users.yml +++ b/users.yml @@ -7,7 +7,8 @@ tasks: - block: - - pause: + - name: Server address prompt + pause: prompt: "Enter the IP address of your server: (or use localhost for local installation)" register: _server when: server is undefined @@ -16,14 +17,15 @@ set_fact: algo_server: >- {% if server is defined %}{{ server }} - {%- elif _server.user_input is defined and _server.user_input != "" %}{{ _server.user_input }} + {%- elif _server.user_input %}{{ _server.user_input }} {%- else %}omit{% endif %} - name: Import host specific variables include_vars: file: "configs/{{ algo_server }}/.config.yml" - - pause: + - name: CA password prompt + pause: prompt: Enter the password for the private CA key echo: false register: _ca_password @@ -35,7 +37,7 @@ set_fact: CA_password: >- {% if ca_password is defined %}{{ ca_password }} - {%- elif _ca_password.user_input is defined and _ca_password.user_input != "" %}{{ _ca_password.user_input }} + {%- elif _ca_password.user_input %}{{ _ca_password.user_input }} {%- else %}omit{% endif %} - name: Add the server to the vpn-host group