From 0fa40513cd19bfd2d01fbe99037ecc4592e7118d Mon Sep 17 00:00:00 2001 From: juju4 Date: Sat, 26 Aug 2023 15:12:49 +0000 Subject: [PATCH] chore: fix ansible-lint 6.17.2 --- .ansible-lint | 17 ++++--- .github/workflows/main.yml | 3 +- ansible.cfg | 1 + cloud.yml | 11 ++-- input.yml | 25 ++++----- main.yml | 13 ++--- playbooks/rescue.yml | 6 --- requirements.txt | 2 +- requirements.yml | 12 +++++ roles/cloud-azure/tasks/main.yml | 12 +++-- roles/cloud-azure/tasks/prompts.yml | 13 +++-- roles/cloud-azure/tasks/venv.yml | 2 +- roles/cloud-cloudstack/tasks/main.yml | 29 ++++++----- roles/cloud-cloudstack/tasks/prompts.yml | 24 +++++---- roles/cloud-cloudstack/tasks/venv.yml | 2 +- roles/cloud-digitalocean/tasks/main.yml | 21 ++++---- roles/cloud-digitalocean/tasks/prompts.yml | 16 +++--- roles/cloud-ec2/tasks/cloudformation.yml | 2 +- roles/cloud-ec2/tasks/main.yml | 13 ++--- roles/cloud-ec2/tasks/prompts.yml | 41 +++++++++------ roles/cloud-ec2/tasks/venv.yml | 2 +- roles/cloud-gce/tasks/main.yml | 22 ++++---- roles/cloud-gce/tasks/prompts.yml | 32 +++++++----- roles/cloud-gce/tasks/venv.yml | 2 +- roles/cloud-hetzner/tasks/main.yml | 11 ++-- roles/cloud-hetzner/tasks/prompts.yml | 16 +++--- roles/cloud-hetzner/tasks/venv.yml | 2 +- .../cloud-lightsail/tasks/cloudformation.yml | 2 +- roles/cloud-lightsail/tasks/main.yml | 9 ++-- roles/cloud-lightsail/tasks/prompts.yml | 26 ++++++---- roles/cloud-lightsail/tasks/venv.yml | 2 +- roles/cloud-linode/tasks/main.yml | 39 +++----------- roles/cloud-linode/tasks/prompts.yml | 16 +++--- roles/cloud-linode/tasks/venv.yml | 2 +- roles/cloud-openstack/tasks/main.yml | 14 ++--- roles/cloud-openstack/tasks/venv.yml | 2 +- roles/cloud-scaleway/tasks/main.yml | 28 ++++++---- roles/cloud-scaleway/tasks/prompts.yml | 8 +-- roles/cloud-vultr/tasks/main.yml | 21 ++++---- roles/cloud-vultr/tasks/prompts.yml | 18 ++++--- roles/common/defaults/main.yml | 3 ++ roles/local/tasks/main.yml | 2 +- roles/local/tasks/prompts.yml | 36 +++++++------ server.yml | 41 ++++++++------- {playbooks => tasks}/cloud-post.yml | 15 +++--- {playbooks => tasks}/cloud-pre.yml | 18 ++++--- tasks/rescue.yml | 7 +++ {playbooks => tasks}/tmpfs/linux.yml | 0 {playbooks => tasks}/tmpfs/macos.yml | 0 {playbooks => tasks}/tmpfs/main.yml | 0 {playbooks => tasks}/tmpfs/umount.yml | 0 users.yml | 51 ++++++++++--------- 52 files changed, 396 insertions(+), 316 deletions(-) delete mode 100644 playbooks/rescue.yml create mode 100644 requirements.yml rename {playbooks => tasks}/cloud-post.yml (88%) rename {playbooks => tasks}/cloud-pre.yml (86%) create mode 100644 tasks/rescue.yml rename {playbooks => tasks}/tmpfs/linux.yml (100%) rename {playbooks => tasks}/tmpfs/macos.yml (100%) rename {playbooks => tasks}/tmpfs/main.yml (100%) rename {playbooks => tasks}/tmpfs/umount.yml (100%) diff --git a/.ansible-lint b/.ansible-lint index 21d582b..c4744a8 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -1,10 +1,15 @@ +--- skip_list: - - yaml - - '204' + - package-latest + - jinja[spacing] verbosity: 1 warn_list: - - no-changed-when - - no-handler - - fqcn-builtins - - var-spacing + - experimental + - var-naming[pattern] + - yaml[line-length] + # - no-changed-when + # - var-spacing +exclude_paths: + - .github/workflows/ + - roles/cloud-*/files/stack.yaml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 75d405f..22d5b9f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,8 +25,9 @@ jobs: - name: Checks and linters run: | /snap/bin/shellcheck algo install.sh + [ -f requirements.yml ] && ansible-galaxy install -r requirements.yml ansible-playbook main.yml --syntax-check - ansible-lint -x experimental,package-latest,unnamed-task -v *.yml roles/{local,cloud-*}/*/*.yml || true + ansible-lint *.yml roles/{local,cloud-*}/*/*.yml || true scripted-deploy: runs-on: ubuntu-20.04 diff --git a/ansible.cfg b/ansible.cfg index 2216133..587d6fc 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -7,6 +7,7 @@ timeout = 60 stdout_callback = default display_skipped_hosts = no force_valid_group_names = ignore +callbacks_enabled = profile_tasks, timer [paramiko_connection] record_host_keys = False diff --git a/cloud.yml b/cloud.yml index 91d65fa..ce449db 100644 --- a/cloud.yml +++ b/cloud.yml @@ -7,15 +7,16 @@ - config.cfg tasks: - - block: + - name: Play cloud + block: - name: Local pre-tasks - import_tasks: playbooks/cloud-pre.yml + ansible.builtin.import_tasks: tasks/cloud-pre.yml - name: Include a provisioning role - include_role: + ansible.builtin.include_role: name: "{{ 'local' if algo_provider == 'local' else 'cloud-' + algo_provider }}" - name: Local post-tasks - import_tasks: playbooks/cloud-post.yml + ansible.builtin.import_tasks: tasks/cloud-post.yml rescue: - - include_tasks: playbooks/rescue.yml + - ansible.builtin.include_tasks: tasks/rescue.yml diff --git a/input.yml b/input.yml index 64b4805..3003f1e 100644 --- a/input.yml +++ b/input.yml @@ -27,9 +27,10 @@ - config.cfg tasks: - - block: + - name: Inputs + block: - name: Cloud prompt - pause: + ansible.builtin.pause: prompt: | What provider would you like to use? {% for p in providers_map %} @@ -41,11 +42,11 @@ when: provider is undefined - name: Set facts based on the input - set_fact: + ansible.builtin.set_fact: algo_provider: "{{ provider | default(providers_map[_algo_provider.user_input|default(omit)|int - 1]['alias']) }}" - name: VPN server name prompt - pause: + ansible.builtin.pause: prompt: | Name the vpn server [algo] @@ -55,7 +56,7 @@ - algo_provider != "local" - name: Cellular On Demand prompt - pause: + ansible.builtin.pause: prompt: | Do you want macOS/iOS clients to enable "Connect On Demand" when connected to cellular networks? [y/N] @@ -63,7 +64,7 @@ when: ondemand_cellular is undefined - name: Wi-Fi On Demand prompt - pause: + ansible.builtin.pause: prompt: | Do you want macOS/iOS clients to enable "Connect On Demand" when connected to Wi-Fi? [y/N] @@ -71,7 +72,7 @@ when: ondemand_wifi is undefined - name: Trusted Wi-Fi networks prompt - pause: + ansible.builtin.pause: prompt: | List the names of any trusted Wi-Fi networks where macOS/iOS clients should not use "Connect On Demand" (e.g., your home network. Comma-separated value, e.g., HomeNet,OfficeWifi,AlgoWiFi) @@ -81,7 +82,7 @@ - (ondemand_wifi|default(false)|bool) or (booleans_map[_ondemand_wifi.user_input|default(omit)]|default(false)) - name: Retain the PKI prompt - pause: + ansible.builtin.pause: prompt: | Do you want to retain the keys (PKI)? (required to add users in the future, but less secure) [y/N] @@ -91,7 +92,7 @@ - ipsec_enabled - name: DNS adblocking prompt - pause: + ansible.builtin.pause: prompt: | Do you want to enable DNS ad blocking on this VPN server? [y/N] @@ -99,7 +100,7 @@ when: dns_adblocking is undefined - name: SSH tunneling prompt - pause: + ansible.builtin.pause: prompt: | Do you want each user to have their own account for SSH tunneling? [y/N] @@ -107,7 +108,7 @@ when: ssh_tunneling is undefined - name: Set facts based on the input - set_fact: + ansible.builtin.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|length > 0 -%} @@ -140,4 +141,4 @@ {%- elif _store_pki.user_input is defined %}{{ booleans_map[_store_pki.user_input] | default(defaults['store_pki']) }} {%- else %}false{% endif %}{% endif %} rescue: - - include_tasks: playbooks/rescue.yml + - ansible.builtin.include_tasks: playbooks/rescue.yml diff --git a/main.yml b/main.yml index 1b68d4c..a52c9a0 100644 --- a/main.yml +++ b/main.yml @@ -3,26 +3,27 @@ become: false tasks: - name: Playbook dir stat - stat: + ansible.builtin.stat: path: "{{ playbook_dir }}" register: _playbook_dir - name: Ensure Ansible is not being run in a world writable directory - assert: + ansible.builtin.assert: that: _playbook_dir.stat.mode|int <= 775 msg: > Ansible is being run in a world writable directory ({{ playbook_dir }}), ignoring it as an ansible.cfg source. For more information see https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir - name: Ensure the requirements installed - debug: + ansible.builtin.debug: msg: "{{ '' | ipaddr }}" ignore_errors: true no_log: true register: ipaddr + # FIXME! failing if another matching pattern in requirements.txt aka ansible-lint - name: Set required ansible version as a fact - set_fact: + ansible.builtin.set_fact: required_ansible_version: "{{ item | regex_replace('^ansible[\\s+]?(?P[=,>,<]+)[\\s+]?(?P\\d.\\d+(.\\d+)?)$', '{\"op\": \"\\g\",\"ver\"\ : \"\\g\" }') }}" when: '"ansible" in item' @@ -33,7 +34,7 @@ register: pip_package_info - name: Verify Python meets Algo VPN requirements - assert: + ansible.builtin.assert: that: (ansible_python.version.major|string + '.' + ansible_python.version.minor|string) is version('3.8', '>=') msg: > Python version is not supported. @@ -41,7 +42,7 @@ See for more details - https://trailofbits.github.io/algo/troubleshooting.html#python-version-is-not-supported - name: Verify Ansible meets Algo VPN requirements - assert: + ansible.builtin.assert: that: - pip_package_info.packages.pip.ansible.0.version is version(required_ansible_version.ver, required_ansible_version.op) - not ipaddr.failed diff --git a/playbooks/rescue.yml b/playbooks/rescue.yml deleted file mode 100644 index 375e0e6..0000000 --- a/playbooks/rescue.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- debug: - var: fail_hint - -- name: Fail the installation - fail: diff --git a/requirements.txt b/requirements.txt index 886f8b4..aa1af45 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -ansible==6.1.0 +ansible==8.3.0 jinja2~=3.0.3 netaddr diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..b221216 --- /dev/null +++ b/requirements.yml @@ -0,0 +1,12 @@ +--- + +collections: + - community.general + - community.aws + - community.digitalocean + - amazon.aws + - azure.azcollection + - google.cloud + - hetzner.hcloud + - ngine_io.cloudstack + - vultr.cloud diff --git a/roles/cloud-azure/tasks/main.yml b/roles/cloud-azure/tasks/main.yml index dafbe0d..6af6e16 100644 --- a/roles/cloud-azure/tasks/main.yml +++ b/roles/cloud-azure/tasks/main.yml @@ -1,18 +1,19 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml -- set_fact: +- name: Set fact + ansible.builtin.set_fact: algo_region: >- {% if region is defined %}{{ region }} {%- 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: + azure.azcollection.azure_rm_deployment: state: present deployment_name: "{{ algo_server_name }}" template: "{{ lookup('file', role_path + '/files/deployment.json') }}" @@ -45,7 +46,8 @@ value: "{{ lookup('template', 'files/cloud-init/base.yml') | b64encode }}" register: azure_rm_deployment -- set_fact: +- name: Set fact + ansible.builtin.set_fact: cloud_instance_ip: "{{ azure_rm_deployment.deployment.outputs.publicIPAddresses.value }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-azure/tasks/prompts.yml b/roles/cloud-azure/tasks/prompts.yml index 99fd03b..f7dc400 100644 --- a/roles/cloud-azure/tasks/prompts.yml +++ b/roles/cloud-azure/tasks/prompts.yml @@ -1,19 +1,23 @@ --- -- set_fact: +- name: Set facts + ansible.builtin.set_fact: secret: "{{ azure_secret | default(lookup('env','AZURE_SECRET'), true) }}" tenant: "{{ azure_tenant | default(lookup('env','AZURE_TENANT'), true) }}" client_id: "{{ azure_client_id | default(lookup('env','AZURE_CLIENT_ID'), true) }}" subscription_id: "{{ azure_subscription_id | default(lookup('env','AZURE_SUBSCRIPTION_ID'), true) }}" -- block: +- name: Prompts + when: region is undefined + block: - name: Set the default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in azure_regions %} {%- if r['name'] == "eastus" %}{{ loop.index }}{% endif %} {%- endfor %} - - pause: + - name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? {% for r in azure_regions %} @@ -23,4 +27,3 @@ Enter the number of your desired region [{{ default_region }}] register: _algo_region - when: region is undefined diff --git a/roles/cloud-azure/tasks/venv.yml b/roles/cloud-azure/tasks/venv.yml index 5b8d52b..1d302ff 100644 --- a/roles/cloud-azure/tasks/venv.yml +++ b/roles/cloud-azure/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: requirements: https://raw.githubusercontent.com/ansible-collections/azure/v1.13.0/requirements-azure.txt state: latest virtualenv_python: python3 diff --git a/roles/cloud-cloudstack/tasks/main.yml b/roles/cloud-cloudstack/tasks/main.yml index ea05938..ff340c8 100644 --- a/roles/cloud-cloudstack/tasks/main.yml +++ b/roles/cloud-cloudstack/tasks/main.yml @@ -1,25 +1,31 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml -- block: - - set_fact: +- name: Cloudstack + environment: + CLOUDSTACK_KEY: "{{ algo_cs_key }}" + CLOUDSTACK_SECRET: "{{ algo_cs_token }}" + CLOUDSTACK_ENDPOINT: "{{ algo_cs_url }}" + block: + - name: Set facts + ansible.builtin.set_fact: algo_region: >- {% if region is defined %}{{ region }} {%- elif _algo_region.user_input is defined and _algo_region.user_input | length > 0 %}{{ cs_zones[_algo_region.user_input | int -1 ]['name'] }} {%- else %}{{ cs_zones[default_zone | int - 1]['name'] }}{% endif %} - name: Security group created - cs_securitygroup: + ngine_io.cloudstack.cs_securitygroup: name: "{{ algo_server_name }}-security_group" description: AlgoVPN security group register: cs_security_group - name: Security rules created - cs_securitygroup_rule: + ngine_io.cloudstack.cs_securitygroup_rule: security_group: "{{ cs_security_group.name }}" protocol: "{{ item.proto }}" start_port: "{{ item.start_port }}" @@ -32,13 +38,13 @@ - { proto: udp, start_port: "{{ wireguard_port }}", end_port: "{{ wireguard_port }}", range: 0.0.0.0/0 } - name: Set facts - set_fact: + ansible.builtin.set_fact: image_id: "{{ cloud_providers.cloudstack.image }}" size: "{{ cloud_providers.cloudstack.size }}" disk: "{{ cloud_providers.cloudstack.disk }}" - name: Server created - cs_instance: + ngine_io.cloudstack.cs_instance: name: "{{ algo_server_name }}" root_disk_size: "{{ disk }}" template: "{{ image_id }}" @@ -48,12 +54,9 @@ user_data: "{{ lookup('template', 'files/cloud-init/base.yml') }}" register: cs_server - - set_fact: + - name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ cs_server.default_ip }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" cloudinit: true - environment: - CLOUDSTACK_KEY: "{{ algo_cs_key }}" - CLOUDSTACK_SECRET: "{{ algo_cs_token }}" - CLOUDSTACK_ENDPOINT: "{{ algo_cs_url }}" diff --git a/roles/cloud-cloudstack/tasks/prompts.yml b/roles/cloud-cloudstack/tasks/prompts.yml index df39a35..8040f64 100644 --- a/roles/cloud-cloudstack/tasks/prompts.yml +++ b/roles/cloud-cloudstack/tasks/prompts.yml @@ -1,6 +1,8 @@ --- -- block: - - pause: +- name: Prompts + block: + - name: Read API key + ansible.builtin.pause: prompt: | Enter the API key (https://trailofbits.github.io/algo/cloud-cloudstack.html): echo: false @@ -9,7 +11,8 @@ - cs_key is undefined - lookup('env','CLOUDSTACK_KEY')|length <= 0 - - pause: + - name: Read API secret + ansible.builtin.pause: prompt: | Enter the API ssecret (https://trailofbits.github.io/algo/cloud-cloudstack.html): echo: false @@ -18,7 +21,8 @@ - cs_secret is undefined - lookup('env','CLOUDSTACK_SECRET')|length <= 0 - - pause: + - name: Read API endpoint + ansible.builtin.pause: prompt: | Enter the API endpoint (https://trailofbits.github.io/algo/cloud-cloudstack.html) [https://api.exoscale.com/compute] @@ -27,14 +31,15 @@ - cs_url is undefined - lookup('env', 'CLOUDSTACK_ENDPOINT') | length <= 0 - - set_fact: + - name: Set facts + ansible.builtin.set_fact: algo_cs_key: "{{ cs_key | default(_cs_key.user_input|default(None)) | default(lookup('env', 'CLOUDSTACK_KEY'), true) }}" algo_cs_token: "{{ cs_secret | default(_cs_secret.user_input|default(None)) | default(lookup('env', 'CLOUDSTACK_SECRET'), true) }}" algo_cs_url: "{{ cs_url | default(_cs_url.user_input|default(None)) | default(lookup('env', 'CLOUDSTACK_ENDPOINT'), true) | default('https://api.exoscale.com/compute',\ \ true) }}" - name: Get zones on cloud - cs_zone_info: + ngine_io.cloudstack.cs_zone_info: register: _cs_zones environment: CLOUDSTACK_KEY: "{{ algo_cs_key }}" @@ -42,17 +47,18 @@ CLOUDSTACK_ENDPOINT: "{{ algo_cs_url }}" - name: Extract zones from output - set_fact: + ansible.builtin.set_fact: cs_zones: "{{ _cs_zones['zones'] | sort(attribute='name') }}" - name: Set the default zone - set_fact: + ansible.builtin.set_fact: default_zone: >- {% for z in cs_zones %} {%- if z['name'] == "ch-gva-2" %}{{ loop.index }}{% endif %} {%- endfor %} - - pause: + - name: Read zone + ansible.builtin.pause: prompt: | What zone should the server be located in? {% for z in cs_zones %} diff --git a/roles/cloud-cloudstack/tasks/venv.yml b/roles/cloud-cloudstack/tasks/venv.yml index 2883342..a7f4b72 100644 --- a/roles/cloud-cloudstack/tasks/venv.yml +++ b/roles/cloud-cloudstack/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: - cs - sshpubkeys diff --git a/roles/cloud-digitalocean/tasks/main.yml b/roles/cloud-digitalocean/tasks/main.yml index 952b4fc..5af7309 100644 --- a/roles/cloud-digitalocean/tasks/main.yml +++ b/roles/cloud-digitalocean/tasks/main.yml @@ -1,16 +1,16 @@ --- - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml - name: Upload the SSH key - digital_ocean_sshkey: + community.digitalocean.digital_ocean_sshkey: oauth_token: "{{ algo_do_token }}" name: "{{ SSH_keys.comment }}" ssh_pub_key: "{{ lookup('file', '{{ SSH_keys.public }}') }}" register: do_ssh_key - name: Creating a droplet... - digital_ocean_droplet: + community.digitalocean.digital_ocean_droplet: state: present name: "{{ algo_server_name }}" oauth_token: "{{ algo_do_token }}" @@ -27,23 +27,26 @@ register: digital_ocean_droplet # Return data is not idempotent -- set_fact: +- name: Set fact + ansible.builtin.set_fact: droplet: "{{ digital_ocean_droplet.data.droplet | default(digital_ocean_droplet.data) }}" -- block: +- name: Alternative ingress IP + when: alternative_ingress_ip + block: - name: Create a Floating IP - digital_ocean_floating_ip: + community.digitalocean.digital_ocean_floating_ip: state: present oauth_token: "{{ algo_do_token }}" droplet_id: "{{ droplet.id }}" register: digital_ocean_floating_ip - name: Set the static ip as a fact - set_fact: + ansible.builtin.set_fact: cloud_alternative_ingress_ip: "{{ digital_ocean_floating_ip.data.floating_ip.ip }}" - when: alternative_ingress_ip -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ (droplet.networks.v4 | selectattr('type', '==', 'public')).0.ip_address }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-digitalocean/tasks/prompts.yml b/roles/cloud-digitalocean/tasks/prompts.yml index 7f24e3f..46107d9 100644 --- a/roles/cloud-digitalocean/tasks/prompts.yml +++ b/roles/cloud-digitalocean/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read API token + ansible.builtin.pause: prompt: | Enter your API token. The token must have read and write permissions (https://cloud.digitalocean.com/settings/api/tokens): echo: false @@ -9,11 +10,11 @@ - lookup('env','DO_API_TOKEN')|length <= 0 - name: Set the token as a fact - set_fact: + ansible.builtin.set_fact: algo_do_token: "{{ do_token | default(_do_token.user_input|default(None)) | default(lookup('env','DO_API_TOKEN'), true) }}" - name: Get regions - uri: + ansible.builtin.uri: url: https://api.digitalocean.com/v2/regions method: GET status_code: 200 @@ -23,17 +24,18 @@ register: _do_regions - name: Set facts about the regions - set_fact: + ansible.builtin.set_fact: do_regions: "{{ _do_regions.json.regions | selectattr('available', 'true') | sort(attribute='slug') }}" - name: Set default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in do_regions %} {%- if r['slug'] == "nyc3" %}{{ loop.index }}{% endif %} {%- endfor %} -- pause: +- name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? {% for r in do_regions %} @@ -46,7 +48,7 @@ when: region is undefined - name: Set additional facts - set_fact: + ansible.builtin.set_fact: algo_do_region: >- {% if region is defined %}{{ region }} {%- elif _algo_region.user_input %}{{ do_regions[_algo_region.user_input | int -1 ]['slug'] }} diff --git a/roles/cloud-ec2/tasks/cloudformation.yml b/roles/cloud-ec2/tasks/cloudformation.yml index f05ab37..dc6a10c 100644 --- a/roles/cloud-ec2/tasks/cloudformation.yml +++ b/roles/cloud-ec2/tasks/cloudformation.yml @@ -1,6 +1,6 @@ --- - name: Deploy the template - cloudformation: + amazon.aws.cloudformation: aws_access_key: "{{ access_key }}" aws_secret_key: "{{ secret_key }}" stack_name: "{{ stack_name }}" diff --git a/roles/cloud-ec2/tasks/main.yml b/roles/cloud-ec2/tasks/main.yml index 5f68c92..2b6319e 100644 --- a/roles/cloud-ec2/tasks/main.yml +++ b/roles/cloud-ec2/tasks/main.yml @@ -1,12 +1,12 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml - name: Locate official AMI for region - ec2_ami_info: + amazon.aws.ec2_ami_info: aws_access_key: "{{ access_key }}" aws_secret_key: "{{ secret_key }}" owners: "{{ cloud_providers.ec2.image.owner }}" @@ -17,13 +17,14 @@ register: ami_search - name: Set the ami id as a fact - set_fact: + ansible.builtin.set_fact: ami_image: "{{ (ami_search.images | sort(attribute='creation_date') | last)['image_id'] }}" - name: Deploy the stack - import_tasks: cloudformation.yml + ansible.builtin.import_tasks: cloudformation.yml -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ stack.stack_outputs.ElasticIP }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-ec2/tasks/prompts.yml b/roles/cloud-ec2/tasks/prompts.yml index 368922f..2bae2f5 100644 --- a/roles/cloud-ec2/tasks/prompts.yml +++ b/roles/cloud-ec2/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read access key ID + ansible.builtin.pause: prompt: | Enter your AWS Access Key ID (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) Note: Make sure to use an IAM user with an acceptable policy attached (see https://github.com/trailofbits/algo/blob/master/docs/deploy-from-ansible.md) @@ -9,7 +10,8 @@ - aws_access_key is undefined - lookup('env','AWS_ACCESS_KEY_ID')|length <= 0 -- pause: +- name: Read secret access key + ansible.builtin.pause: prompt: | Enter your AWS Secret Access Key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) echo: false @@ -18,30 +20,34 @@ - aws_secret_key is undefined - lookup('env','AWS_SECRET_ACCESS_KEY')|length <= 0 -- set_fact: +- name: Set facts + ansible.builtin.set_fact: access_key: "{{ aws_access_key | default(_aws_access_key.user_input|default(None)) | default(lookup('env','AWS_ACCESS_KEY_ID'), true) }}" secret_key: "{{ aws_secret_key | default(_aws_secret_key.user_input|default(None)) | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true) }}" -- block: +- name: Prompt region + when: region is undefined + block: - name: Get regions - aws_region_info: + community.aws.aws_region_info: aws_access_key: "{{ access_key }}" aws_secret_key: "{{ secret_key }}" region: us-east-1 register: _aws_regions - name: Set facts about the regions - set_fact: + ansible.builtin.set_fact: aws_regions: "{{ _aws_regions.regions | sort(attribute='region_name') }}" - name: Set the default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in aws_regions %} {%- if r['region_name'] == "us-east-1" %}{{ loop.index }}{% endif %} {%- endfor %} - - pause: + - name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? (https://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region) @@ -52,28 +58,31 @@ Enter the number of your desired region [{{ default_region }}] register: _algo_region - when: region is undefined - name: Set algo_region and stack_name facts - set_fact: + ansible.builtin.set_fact: algo_region: >- {% if region is defined %}{{ region }} {%- 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('.', '-') }}" -- block: +- name: Use existing eip + when: cloud_providers.ec2.use_existing_eip + block: - name: Get existing available Elastic IPs - ec2_eip_info: + amazon.aws.ec2_eip_info: aws_access_key: "{{ access_key }}" aws_secret_key: "{{ secret_key }}" region: "{{ algo_region }}" register: raw_eip_addresses - - set_fact: + - name: Set fact + ansible.builtin.set_fact: available_eip_addresses: "{{ raw_eip_addresses.addresses | selectattr('association_id', 'undefined') | list }}" - - pause: + - name: Read Elastic IP + ansible.builtin.pause: prompt: >- What Elastic IP would you like to use? {% for eip in available_eip_addresses %} @@ -83,6 +92,6 @@ Enter the number of your desired Elastic IP register: _use_existing_eip - - set_fact: + - name: Set fact + ansible.builtin.set_fact: existing_eip: "{{ available_eip_addresses[_use_existing_eip.user_input | int -1 ]['allocation_id'] }}" - when: cloud_providers.ec2.use_existing_eip diff --git a/roles/cloud-ec2/tasks/venv.yml b/roles/cloud-ec2/tasks/venv.yml index 1ab85bd..e28d18f 100644 --- a/roles/cloud-ec2/tasks/venv.yml +++ b/roles/cloud-ec2/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: - boto>=2.5 - boto3 diff --git a/roles/cloud-gce/tasks/main.yml b/roles/cloud-gce/tasks/main.yml index 69aa56a..c926172 100644 --- a/roles/cloud-gce/tasks/main.yml +++ b/roles/cloud-gce/tasks/main.yml @@ -1,12 +1,12 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml - name: Network configured - gcp_compute_network: + google.cloud.gcp_compute_network: auth_kind: serviceaccount service_account_file: "{{ credentials_file_path }}" project: "{{ project_id }}" @@ -17,7 +17,7 @@ register: gcp_compute_network - name: Firewall configured - gcp_compute_firewall: + google.cloud.gcp_compute_firewall: auth_kind: serviceaccount service_account_file: "{{ credentials_file_path }}" project: "{{ project_id }}" @@ -35,9 +35,11 @@ - "{{ ssh_port }}" - ip_protocol: icmp -- block: +- name: External IP + when: cloud_providers.gce.external_static_ip + block: - name: External IP allocated - gcp_compute_address: + google.cloud.gcp_compute_address: auth_kind: serviceaccount service_account_file: "{{ credentials_file_path }}" project: "{{ project_id }}" @@ -46,12 +48,11 @@ register: gcp_compute_address - name: Set External IP as a fact - set_fact: + ansible.builtin.set_fact: external_ip: "{{ gcp_compute_address.address }}" - when: cloud_providers.gce.external_static_ip - name: Instance created - gcp_compute_instance: + google.cloud.gcp_compute_instance: auth_kind: serviceaccount service_account_file: "{{ credentials_file_path }}" project: "{{ project_id }}" @@ -77,7 +78,8 @@ - environment-algo register: gcp_compute_instance -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ gcp_compute_instance.networkInterfaces[0].accessConfigs[0].natIP }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-gce/tasks/prompts.yml b/roles/cloud-gce/tasks/prompts.yml index bc7eedd..c5c8ee4 100644 --- a/roles/cloud-gce/tasks/prompts.yml +++ b/roles/cloud-gce/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read credentials filepath + ansible.builtin.pause: prompt: | Enter the local path to your credentials JSON file (https://support.google.com/cloud/answer/6158849?hl=en&ref_topic=6262490#serviceaccounts) @@ -8,21 +9,26 @@ - gce_credentials_file is undefined - lookup('env','GCE_CREDENTIALS_FILE_PATH')|length <= 0 -- set_fact: +- name: Set facts + ansible.builtin.set_fact: credentials_file_path: "{{ gce_credentials_file | default(_gce_credentials_file.user_input|default(None)) | default(lookup('env','GCE_CREDENTIALS_FILE_PATH'),\ \ true) }}" ssh_public_key_lookup: "{{ lookup('file', '{{ SSH_keys.public }}') }}" -- set_fact: +- name: Set fact + ansible.builtin.set_fact: credentials_file_lookup: "{{ lookup('file', '{{ credentials_file_path }}') }}" -- set_fact: +- name: Set facts + ansible.builtin.set_fact: service_account_email: "{{ credentials_file_lookup.client_email | default(lookup('env','GCE_EMAIL')) }}" project_id: "{{ credentials_file_lookup.project_id | default(lookup('env','GCE_PROJECT')) }}" -- block: +- name: Region undefined + when: region is undefined + block: - name: Get regions - gcp_compute_location_info: + google.cloud.gcp_compute_location_info: auth_kind: serviceaccount service_account_file: "{{ credentials_file_path }}" project: "{{ project_id }}" @@ -31,20 +37,21 @@ register: gcp_compute_regions_info - name: Set facts about the regions - set_fact: + ansible.builtin.set_fact: gce_regions: >- [{%- for region in gcp_compute_regions_info.resources | sort(attribute='name') -%} '{{ region.name }}'{% if not loop.last %},{% endif %} {%- endfor -%}] - name: Set facts about the default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for region in gce_regions %} {%- if region == "us-east1" %}{{ loop.index }}{% endif %} {%- endfor %} - - pause: + - name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? (https://cloud.google.com/compute/docs/regions-zones/#locations) @@ -55,17 +62,16 @@ Enter the number of your desired region [{{ default_region }}] register: _gce_region - when: region is undefined - name: Set region as a fact - set_fact: + ansible.builtin.set_fact: algo_region: >- {% if region is defined %}{{ region }} {%- elif _gce_region.user_input %}{{ gce_regions[_gce_region.user_input | int -1 ] }} {%- else %}{{ gce_regions[default_region | int - 1] }}{% endif %} - name: Get zones - gcp_compute_location_info: + google.cloud.gcp_compute_location_info: auth_kind: serviceaccount service_account_file: "{{ credentials_file_path }}" project: "{{ project_id }}" @@ -76,5 +82,5 @@ register: gcp_compute_zone_info - name: Set random available zone as a fact - set_fact: + ansible.builtin.set_fact: algo_zone: "{{ (gcp_compute_zone_info.resources | random(seed=algo_server_name + algo_region + project_id) ).name }}" diff --git a/roles/cloud-gce/tasks/venv.yml b/roles/cloud-gce/tasks/venv.yml index e200624..f0c5506 100644 --- a/roles/cloud-gce/tasks/venv.yml +++ b/roles/cloud-gce/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: - requests>=2.18.4 - google-auth>=1.3.0 diff --git a/roles/cloud-hetzner/tasks/main.yml b/roles/cloud-hetzner/tasks/main.yml index c533164..07a5ba6 100644 --- a/roles/cloud-hetzner/tasks/main.yml +++ b/roles/cloud-hetzner/tasks/main.yml @@ -1,12 +1,12 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml - name: Create an ssh key - hcloud_ssh_key: + hetzner.hcloud.hcloud_ssh_key: name: algo-{{ 999999 | random(seed=lookup('file', SSH_keys.public)) }} public_key: "{{ lookup('file', SSH_keys.public) }}" state: present @@ -14,7 +14,7 @@ register: hcloud_ssh_key - name: Create a server... - hcloud_server: + hetzner.hcloud.hcloud_server: name: "{{ algo_server_name }}" location: "{{ algo_hcloud_region }}" server_type: "{{ cloud_providers.hetzner.server_type }}" @@ -27,7 +27,8 @@ Environment: algo register: hcloud_server -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ hcloud_server.hcloud_server.ipv4_address }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-hetzner/tasks/prompts.yml b/roles/cloud-hetzner/tasks/prompts.yml index 5f240df..a9bfb3e 100644 --- a/roles/cloud-hetzner/tasks/prompts.yml +++ b/roles/cloud-hetzner/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read API token + ansible.builtin.pause: prompt: | Enter your API token (https://trailofbits.github.io/algo/cloud-hetzner.html#api-token): echo: false @@ -9,26 +10,27 @@ - lookup('env','HCLOUD_TOKEN')|length <= 0 - name: Set the token as a fact - set_fact: + ansible.builtin.set_fact: algo_hcloud_token: "{{ hcloud_token | default(_hcloud_token.user_input|default(None)) | default(lookup('env','HCLOUD_TOKEN'), true) }}" - name: Get regions - hcloud_datacenter_facts: + hetzner.hcloud.hcloud_datacenter_info: api_token: "{{ algo_hcloud_token }}" register: _hcloud_regions - name: Set facts about the regions - set_fact: + ansible.builtin.set_fact: hcloud_regions: "{{ hcloud_datacenter_facts | sort(attribute='location') }}" - name: Set default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in hcloud_regions %} {%- if r['location'] == "nbg1" %}{{ loop.index }}{% endif %} {%- endfor %} -- pause: +- name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? {% for r in hcloud_regions %} @@ -41,7 +43,7 @@ when: region is undefined - name: Set additional facts - set_fact: + ansible.builtin.set_fact: algo_hcloud_region: >- {% if region is defined %}{{ region }} {%- elif _algo_region.user_input %}{{ hcloud_regions[_algo_region.user_input | int -1 ]['location'] }} diff --git a/roles/cloud-hetzner/tasks/venv.yml b/roles/cloud-hetzner/tasks/venv.yml index 52f588a..29f1774 100644 --- a/roles/cloud-hetzner/tasks/venv.yml +++ b/roles/cloud-hetzner/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: - hcloud state: latest diff --git a/roles/cloud-lightsail/tasks/cloudformation.yml b/roles/cloud-lightsail/tasks/cloudformation.yml index d3798a9..c04b61b 100644 --- a/roles/cloud-lightsail/tasks/cloudformation.yml +++ b/roles/cloud-lightsail/tasks/cloudformation.yml @@ -1,6 +1,6 @@ --- - name: Deploy the template - cloudformation: + amazon.aws.cloudformation: aws_access_key: "{{ access_key }}" aws_secret_key: "{{ secret_key }}" stack_name: "{{ stack_name }}" diff --git a/roles/cloud-lightsail/tasks/main.yml b/roles/cloud-lightsail/tasks/main.yml index 2d8d702..6197364 100644 --- a/roles/cloud-lightsail/tasks/main.yml +++ b/roles/cloud-lightsail/tasks/main.yml @@ -1,14 +1,15 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml - name: Deploy the stack - import_tasks: cloudformation.yml + ansible.builtin.import_tasks: cloudformation.yml -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ stack.stack_outputs.IpAddress }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-lightsail/tasks/prompts.yml b/roles/cloud-lightsail/tasks/prompts.yml index 49e6bd0..3cbe9a5 100644 --- a/roles/cloud-lightsail/tasks/prompts.yml +++ b/roles/cloud-lightsail/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read access key + ansible.builtin.pause: prompt: | Enter your aws_access_key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) Note: Make sure to use an IAM user with an acceptable policy attached (see https://github.com/trailofbits/algo/blob/master/docs/deploy-from-ansible.md) @@ -9,7 +10,8 @@ - aws_access_key is undefined - lookup('env','AWS_ACCESS_KEY_ID')|length <= 0 -- pause: +- name: Read secret key + ansible.builtin.pause: prompt: | Enter your aws_secret_key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) echo: false @@ -18,30 +20,34 @@ - aws_secret_key is undefined - lookup('env','AWS_SECRET_ACCESS_KEY')|length <= 0 -- set_fact: +- name: Set facts + ansible.builtin.set_fact: access_key: "{{ aws_access_key | default(_aws_access_key.user_input|default(None)) | default(lookup('env','AWS_ACCESS_KEY_ID'), true) }}" secret_key: "{{ aws_secret_key | default(_aws_secret_key.user_input|default(None)) | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true) }}" -- block: +- name: region undefined + when: region is undefined + block: - name: Get regions - lightsail_region_facts: + community.aws.aws_region_info: aws_access_key: "{{ access_key }}" aws_secret_key: "{{ secret_key }}" region: us-east-1 register: _lightsail_regions - name: Set facts about the regions - set_fact: + ansible.builtin.set_fact: lightsail_regions: "{{ _lightsail_regions.data.regions | sort(attribute='name') }}" - name: Set the default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in lightsail_regions %} {%- if r['name'] == "us-east-1" %}{{ loop.index }}{% endif %} {%- endfor %} - - pause: + - name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? (https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) @@ -52,9 +58,9 @@ Enter the number of your desired region [{{ default_region }}] register: _algo_region - when: region is undefined -- set_fact: +- name: Set facts + ansible.builtin.set_fact: stack_name: "{{ algo_server_name | replace('.', '-') }}" algo_region: >- {% if region is defined %}{{ region }} diff --git a/roles/cloud-lightsail/tasks/venv.yml b/roles/cloud-lightsail/tasks/venv.yml index 1ab85bd..e28d18f 100644 --- a/roles/cloud-lightsail/tasks/venv.yml +++ b/roles/cloud-lightsail/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: - boto>=2.5 - boto3 diff --git a/roles/cloud-linode/tasks/main.yml b/roles/cloud-linode/tasks/main.yml index 8cdd47f..7deac6d 100644 --- a/roles/cloud-linode/tasks/main.yml +++ b/roles/cloud-linode/tasks/main.yml @@ -1,44 +1,19 @@ --- - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml - name: Set facts - set_fact: + ansible.builtin.set_fact: stackscript: | {{ lookup('template', 'files/cloud-init/base.sh') }} mkdir -p /var/lib/cloud/data/ || true touch /var/lib/cloud/data/result.json -- name: Create a stackscript - linode_stackscript_v4: - access_token: "{{ algo_linode_token }}" - label: "{{ algo_server_name }}" - state: present - description: Environment:Algo - images: - - "{{ cloud_providers.linode.image }}" - script: | - {{ stackscript }} - register: _linode_stackscript - -- name: Update the stackscript - uri: - url: https://api.linode.com/v4/linode/stackscripts/{{ _linode_stackscript.stackscript.id }} - method: PUT - body_format: json - body: - script: | - {{ stackscript }} - headers: - Content-Type: application/json - Authorization: Bearer {{ algo_linode_token }} - when: (_linode_stackscript.stackscript.script | hash('md5')) != (stackscript | hash('md5')) - - name: Creating an instance... - linode_v4: + community.general.linode_v4: access_token: "{{ algo_linode_token }}" label: "{{ algo_server_name }}" state: present @@ -46,10 +21,12 @@ image: "{{ cloud_providers.linode.image }}" type: "{{ cloud_providers.linode.type }}" authorized_keys: "{{ public_key }}" - stackscript_id: "{{ _linode_stackscript.stackscript.id }}" + stackscript_data: | + {{ stackscript }} register: _linode -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ _linode.instance.ipv4[0] }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-linode/tasks/prompts.yml b/roles/cloud-linode/tasks/prompts.yml index 84d85b9..73cc840 100644 --- a/roles/cloud-linode/tasks/prompts.yml +++ b/roles/cloud-linode/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read + ansible.builtin.pause: prompt: | Enter your ACCESS token. (https://developers.linode.com/api/v4/#access-and-authentication): echo: false @@ -9,28 +10,29 @@ - lookup('env','LINODE_API_TOKEN')|length <= 0 - name: Set the token as a fact - set_fact: + ansible.builtin.set_fact: algo_linode_token: "{{ linode_token | default(_linode_token.user_input|default(None)) | default(lookup('env','LINODE_API_TOKEN'), true) }}" - name: Get regions - uri: + ansible.builtin.uri: url: https://api.linode.com/v4/regions method: GET status_code: 200 register: _linode_regions - name: Set facts about the regions - set_fact: + ansible.builtin.set_fact: linode_regions: "{{ _linode_regions.json.data | sort(attribute='id') }}" - name: Set default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in linode_regions %} {%- if r['id'] == "us-east" %}{{ loop.index }}{% endif %} {%- endfor %} -- pause: +- name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? {% for r in linode_regions %} @@ -43,7 +45,7 @@ when: region is undefined - name: Set additional facts - set_fact: + ansible.builtin.set_fact: algo_linode_region: >- {% if region is defined %}{{ region }} {%- elif _algo_region.user_input %}{{ linode_regions[_algo_region.user_input | int -1 ]['id'] }} diff --git a/roles/cloud-linode/tasks/venv.yml b/roles/cloud-linode/tasks/venv.yml index ece831e..1daa198 100644 --- a/roles/cloud-linode/tasks/venv.yml +++ b/roles/cloud-linode/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: - linode_api4 state: latest diff --git a/roles/cloud-openstack/tasks/main.yml b/roles/cloud-openstack/tasks/main.yml index ac6cbd3..9863a2c 100644 --- a/roles/cloud-openstack/tasks/main.yml +++ b/roles/cloud-openstack/tasks/main.yml @@ -1,10 +1,11 @@ --- -- fail: +- name: Fail on credentials + ansible.builtin.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')|length <= 0 - name: Build python virtual environment - import_tasks: venv.yml + ansible.builtin.import_tasks: venv.yml - name: Security group created openstack.cloud.security_group: @@ -38,7 +39,7 @@ register: os_image - name: Set image as a fact - set_fact: + ansible.builtin.set_fact: image_id: "{{ item.id }}" loop: "{{ os_image.openstack_image }}" when: @@ -50,7 +51,7 @@ register: os_network - name: Set the network as a fact - set_fact: + ansible.builtin.set_fact: public_network_id: "{{ item.id }}" when: - item['router:external']|default(omit) @@ -59,7 +60,7 @@ with_items: "{{ os_network.openstack_networks }}" - name: Set facts - set_fact: + ansible.builtin.set_fact: flavor_id: "{{ (os_flavor.openstack_flavors | sort(attribute='ram'))[0]['id'] }}" security_group_name: "{{ os_security_group['secgroup']['name'] }}" @@ -75,7 +76,8 @@ - net-id: "{{ public_network_id }}" register: os_server -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ os_server['openstack']['public_v4'] }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-openstack/tasks/venv.yml b/roles/cloud-openstack/tasks/venv.yml index 7f386a0..12a38e3 100644 --- a/roles/cloud-openstack/tasks/venv.yml +++ b/roles/cloud-openstack/tasks/venv.yml @@ -1,6 +1,6 @@ --- - name: Install requirements - pip: + ansible.builtin.pip: name: shade state: latest virtualenv_python: python3 diff --git a/roles/cloud-scaleway/tasks/main.yml b/roles/cloud-scaleway/tasks/main.yml index 05c1d53..ac5400a 100644 --- a/roles/cloud-scaleway/tasks/main.yml +++ b/roles/cloud-scaleway/tasks/main.yml @@ -1,19 +1,24 @@ --- - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml -- block: +- name: Scaleway + environment: + SCW_TOKEN: "{{ algo_scaleway_token }}" + block: - name: Gather Scaleway organizations facts - scaleway_organization_info: + community.general.scaleway_organization_info: + api_token: "{{ algo_scaleway_token }}" register: scaleway_org - name: Get images - scaleway_image_info: + community.general.scaleway_image_info: region: "{{ algo_region }}" + api_token: "{{ algo_scaleway_token }}" register: scaleway_image - name: Set cloud specific facts - set_fact: + ansible.builtin.set_fact: organization_id: "{{ scaleway_org.scaleway_organization_info[0]['id'] }}" images: >- [{% for i in scaleway_image.scaleway_image_info -%} @@ -24,7 +29,8 @@ {%- endfor -%}] - name: Create a server - scaleway_compute: + community.general.scaleway_compute: + api_token: "{{ algo_scaleway_token }}" name: "{{ algo_server_name }}" enable_ipv6: true public_ip: dynamic @@ -41,7 +47,7 @@ register: scaleway_compute - name: Patch the cloud-init - uri: + ansible.builtin.uri: url: https://cp-{{ algo_region }}.scaleway.com/servers/{{ scaleway_compute.msg.id }}/user_data/cloud-init method: PATCH body: "{{ lookup('template', 'files/cloud-init/base.yml') }}" @@ -51,7 +57,8 @@ X-Auth-Token: "{{ algo_scaleway_token }}" - name: Start the server - scaleway_compute: + community.general.scaleway_compute: + api_token: "{{ algo_scaleway_token }}" name: "{{ algo_server_name }}" enable_ipv6: true public_ip: dynamic @@ -69,10 +76,9 @@ until: algo_instance.msg.public_ip retries: 3 delay: 3 - environment: - SCW_TOKEN: "{{ algo_scaleway_token }}" -- set_fact: +- name: Set facts + ansible.builtin.set_fact: cloud_instance_ip: "{{ algo_instance.msg.public_ip.address }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" diff --git a/roles/cloud-scaleway/tasks/prompts.yml b/roles/cloud-scaleway/tasks/prompts.yml index 7e371d2..0335a42 100644 --- a/roles/cloud-scaleway/tasks/prompts.yml +++ b/roles/cloud-scaleway/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read auth token + ansible.builtin.pause: prompt: | Enter your auth token (https://trailofbits.github.io/algo/cloud-scaleway.html) echo: false @@ -8,7 +9,8 @@ - scaleway_token is undefined - lookup('env','SCW_TOKEN')|length <= 0 -- pause: +- name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? {% for r in scaleway_regions %} @@ -21,7 +23,7 @@ when: region is undefined - name: Set scaleway facts - set_fact: + ansible.builtin.set_fact: algo_scaleway_token: "{{ scaleway_token | default(_scaleway_token.user_input) | default(lookup('env','SCW_TOKEN'), true) }}" algo_region: >- {% if region is defined %}{{ region }} diff --git a/roles/cloud-vultr/tasks/main.yml b/roles/cloud-vultr/tasks/main.yml index 2aa1b8d..7628a7b 100644 --- a/roles/cloud-vultr/tasks/main.yml +++ b/roles/cloud-vultr/tasks/main.yml @@ -1,14 +1,17 @@ --- - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml -- block: +- name: Vultr setup + environment: + VULTR_API_CONFIG: "{{ algo_vultr_config }}" + block: - name: Creating a firewall group - vultr_firewall_group: + vultr.cloud.firewall_group: name: "{{ algo_server_name }}" - name: Creating firewall rules - vultr_firewall_rule: + vultr.cloud.firewall_rule: group: "{{ algo_server_name }}" protocol: "{{ item.protocol }}" port: "{{ item.port }}" @@ -25,13 +28,13 @@ - { protocol: udp, port: "{{ wireguard_port }}", ip: v6, cidr: "::/0" } - name: Upload the startup script - vultr_startup_script: + vultr.cloud.startup_script: name: algo-startup script: | {{ lookup('template', 'files/cloud-init/base.yml') }} - name: Creating a server - vultr_server: + vultr.cloud.vpc: name: "{{ algo_server_name }}" startup_script: algo-startup hostname: "{{ algo_server_name }}" @@ -46,11 +49,9 @@ notify_activate: false register: vultr_server - - set_fact: + - name: Set fact vultr + ansible.builtin.set_fact: cloud_instance_ip: "{{ vultr_server.vultr_server.v4_main_ip }}" ansible_ssh_user: algo ansible_ssh_port: "{{ ssh_port }}" cloudinit: true - - environment: - VULTR_API_CONFIG: "{{ algo_vultr_config }}" diff --git a/roles/cloud-vultr/tasks/prompts.yml b/roles/cloud-vultr/tasks/prompts.yml index 1245b71..c73eb70 100644 --- a/roles/cloud-vultr/tasks/prompts.yml +++ b/roles/cloud-vultr/tasks/prompts.yml @@ -1,5 +1,6 @@ --- -- pause: +- name: Read configuration ini + ansible.builtin.pause: prompt: | Enter the local path to your configuration INI file (https://trailofbits.github.io/algo/cloud-vultr.html): @@ -9,35 +10,36 @@ - lookup('env','VULTR_API_CONFIG')|length <= 0 - name: Set the token as a fact - set_fact: + ansible.builtin.set_fact: algo_vultr_config: "{{ vultr_config | default(_vultr_config.user_input) | default(lookup('env','VULTR_API_CONFIG'), true) }}" - name: Get regions - uri: + ansible.builtin.uri: url: https://api.vultr.com/v1/regions/list method: GET status_code: 200 register: _vultr_regions - name: Format regions - set_fact: + ansible.builtin.set_fact: regions: >- [ {% for k, v in _vultr_regions.json.items() %} {{ v }}{% if not loop.last %},{% endif %} {% endfor %} ] - name: Set regions as a fact - set_fact: + ansible.builtin.set_fact: vultr_regions: "{{ regions | sort(attribute='country') }}" - name: Set default region - set_fact: + ansible.builtin.set_fact: default_region: >- {% for r in vultr_regions %} {%- if r['DCID'] == "1" %}{{ loop.index }}{% endif %} {%- endfor %} -- pause: +- name: Read region + ansible.builtin.pause: prompt: | What region should the server be located in? (https://www.vultr.com/locations/): @@ -51,7 +53,7 @@ when: region is undefined - name: Set the desired region as a fact - set_fact: + ansible.builtin.set_fact: algo_vultr_region: >- {% if region is defined %}{{ region }} {%- elif _algo_region.user_input %}{{ vultr_regions[_algo_region.user_input | int -1 ]['name'] }} diff --git a/roles/common/defaults/main.yml b/roles/common/defaults/main.yml index bf29472..eb71669 100644 --- a/roles/common/defaults/main.yml +++ b/roles/common/defaults/main.yml @@ -7,3 +7,6 @@ ipv6_default: "{{ ansible_default_ipv6.address + '/' + ansible_default_ipv6.pref ipv6_subnet_size: "{{ ipv6_default | ipaddr('size') }}" ipv6_egress_ip: >- {{ (ipv6_default | next_nth_usable(15 | random(seed=algo_server_name + ansible_fqdn))) + '/124' if ipv6_subnet_size|int > 1 else ipv6_default }} + +# as used in common role +wireguard_port_avoid: 53 diff --git a/roles/local/tasks/main.yml b/roles/local/tasks/main.yml index b690b6b..f78cd50 100644 --- a/roles/local/tasks/main.yml +++ b/roles/local/tasks/main.yml @@ -1,3 +1,3 @@ --- - name: Include prompts - import_tasks: prompts.yml + ansible.builtin.import_tasks: prompts.yml diff --git a/roles/local/tasks/prompts.yml b/roles/local/tasks/prompts.yml index 76d2a4e..c4963f7 100644 --- a/roles/local/tasks/prompts.yml +++ b/roles/local/tasks/prompts.yml @@ -1,17 +1,18 @@ --- -- pause: - prompt: "{{ item }}" +- name: Starting warning + ansible.builtin.pause: + prompt: | + https://trailofbits.github.io/algo/deploy-to-ubuntu.html + + Local installation might break your server. Use at your own risk. + + Proceed? Press ENTER to continue or CTRL+C and A to abort... when: not tests|default(false)|bool tags: - skip_ansible_lint - with_items: | - https://trailofbits.github.io/algo/deploy-to-ubuntu.html - Local installation might break your server. Use at your own risk. - - Proceed? Press ENTER to continue or CTRL+C and A to abort... - -- pause: +- name: Read IP address + ansible.builtin.pause: prompt: | Enter the IP address of your server: (or use localhost for local installation): [localhost] @@ -19,14 +20,17 @@ when: server is undefined - name: Set the facts - set_fact: + ansible.builtin.set_fact: cloud_instance_ip: >- {% if server is defined %}{{ server }} {%- elif _algo_server.user_input %}{{ _algo_server.user_input }} {%- else %}localhost{% endif %} -- block: - - pause: +- name: Var cloud_instance_ip not localhost + when: cloud_instance_ip != "localhost" + block: + - name: Read user + ansible.builtin.pause: prompt: | What user should we use to login on the server? (note: passwordless login required, or ignore if you're deploying to localhost) [root] @@ -34,14 +38,14 @@ when: ssh_user is undefined - name: Set the facts - set_fact: + ansible.builtin.set_fact: ansible_ssh_user: >- {% if ssh_user is defined %}{{ ssh_user }} {%- elif _algo_ssh_user.user_input %}{{ _algo_ssh_user.user_input }} {%- else %}root{% endif %} - when: cloud_instance_ip != "localhost" -- pause: +- name: Read public IP address + ansible.builtin.pause: prompt: | Enter the public IP address or domain name of your server: (IMPORTANT! This is used to verify the certificate) [{{ cloud_instance_ip }}] @@ -49,7 +53,7 @@ when: endpoint is undefined - name: Set the facts - set_fact: + ansible.builtin.set_fact: IP_subject_alt_name: >- {% if endpoint is defined %}{{ endpoint }} {%- elif _endpoint.user_input %}{{ _endpoint.user_input }} diff --git a/server.yml b/server.yml index 18af459..8c5fb4c 100644 --- a/server.yml +++ b/server.yml @@ -6,9 +6,10 @@ vars_files: - config.cfg tasks: - - block: + - name: Play server + block: - name: Wait until the cloud-init completed - wait_for: + ansible.builtin.wait_for: path: /var/lib/cloud/data/result.json delay: 10 timeout: 600 @@ -16,15 +17,19 @@ become: false when: cloudinit - - block: + - name: Not localhost + when: inventory_hostname != 'localhost' + become: false + delegate_to: localhost + block: - name: Ensure the config directory exists - file: + ansible.builtin.file: dest: configs/{{ IP_subject_alt_name }} state: directory mode: "0700" - name: Dump the ssh config - copy: + ansible.builtin.copy: dest: configs/{{ IP_subject_alt_name }}/ssh_config mode: "0600" content: | @@ -35,38 +40,36 @@ IdentityFile {{ SSH_keys.private | realpath }} KeepAlive yes ServerAliveInterval 30 - when: inventory_hostname != 'localhost' - become: false - delegate_to: localhost - - import_role: + - ansible.builtin.import_role: name: common tags: common - - import_role: + - ansible.builtin.import_role: name: dns when: - algo_dns_adblocking or dns_encryption tags: dns - - import_role: + - ansible.builtin.import_role: name: wireguard when: wireguard_enabled tags: wireguard - - import_role: + - ansible.builtin.import_role: name: strongswan when: ipsec_enabled tags: ipsec - - import_role: + - ansible.builtin.import_role: name: ssh_tunneling when: algo_ssh_tunneling tags: ssh_tunneling - - block: + - name: Set configuration + block: - name: Dump the configuration - copy: + ansible.builtin.copy: dest: configs/{{ IP_subject_alt_name }}/.config.yml content: | server: {{ 'localhost' if inventory_hostname == 'localhost' else inventory_hostname }} @@ -94,7 +97,7 @@ delegate_to: localhost - name: Create a symlink if deploying to localhost - file: + ansible.builtin.file: src: "{{ IP_subject_alt_name }}" dest: configs/localhost state: link @@ -102,7 +105,7 @@ when: inventory_hostname == 'localhost' - name: Import tmpfs tasks - import_tasks: playbooks/tmpfs/umount.yml + ansible.builtin.import_tasks: tasks/tmpfs/umount.yml become: false delegate_to: localhost vars: @@ -111,7 +114,7 @@ - pki_in_tmpfs - not algo_store_pki - - debug: + - ansible.builtin.debug: msg: - "{{ congrats.common.split('\n') }}" - " {{ congrats.p12_pass if algo_ssh_tunneling or ipsec_enabled else '' }}" @@ -119,4 +122,4 @@ - " {{ congrats.ssh_access if algo_provider != 'local' else ''}}" tags: always rescue: - - include_tasks: playbooks/rescue.yml + - ansible.builtin.include_tasks: tasks/rescue.yml diff --git a/playbooks/cloud-post.yml b/tasks/cloud-post.yml similarity index 88% rename from playbooks/cloud-post.yml rename to tasks/cloud-post.yml index 36b7d94..2b0fbff 100644 --- a/playbooks/cloud-post.yml +++ b/tasks/cloud-post.yml @@ -1,10 +1,10 @@ --- - name: Set subjectAltName as a fact - set_fact: + ansible.builtin.set_fact: IP_subject_alt_name: "{{ (IP_subject_alt_name if algo_provider == 'local' else cloud_instance_ip) | lower }}" - name: Add the server to an inventory group - add_host: + ansible.builtin.add_host: name: "{% if cloud_instance_ip == 'localhost' %}localhost{% else %}{{ cloud_instance_ip }}{% endif %}" groups: vpn-host ansible_connection: "{% if cloud_instance_ip == 'localhost' %}local{% else %}ssh{% endif %}" @@ -24,13 +24,13 @@ cloudinit: "{{ cloudinit|default(false) }}" - name: Additional variables for the server - add_host: + ansible.builtin.add_host: name: "{% if cloud_instance_ip == 'localhost' %}localhost{% else %}{{ cloud_instance_ip }}{% endif %}" ansible_ssh_private_key_file: "{{ SSH_keys.private_tmp }}" when: algo_provider != 'local' - name: Wait until SSH becomes ready... - wait_for: + ansible.builtin.wait_for: port: "{{ ansible_ssh_port|default(22) }}" host: "{{ cloud_instance_ip }}" search_regex: OpenSSH @@ -40,16 +40,17 @@ when: cloud_instance_ip != "localhost" - name: Mount tmpfs - import_tasks: tmpfs/main.yml + ansible.builtin.import_tasks: tmpfs/main.yml when: - pki_in_tmpfs - not algo_store_pki - ansible_system == "Darwin" or ansible_system == "Linux" -- debug: +- name: Debug | var IP_subject_alt_name + ansible.builtin.debug: var: IP_subject_alt_name - name: Wait 600 seconds for target connection to become reachable/usable - wait_for_connection: + ansible.builtin.wait_for_connection: delegate_to: "{{ item }}" loop: "{{ groups['vpn-host'] }}" diff --git a/playbooks/cloud-pre.yml b/tasks/cloud-pre.yml similarity index 86% rename from playbooks/cloud-pre.yml rename to tasks/cloud-pre.yml index da0019d..aa8051d 100644 --- a/playbooks/cloud-pre.yml +++ b/tasks/cloud-pre.yml @@ -1,7 +1,8 @@ --- -- block: +- name: cloud-pre + block: - name: Display the invocation environment - shell: > + ansible.builtin.shell: > ./algo-showenv.sh \ 'algo_provider "{{ algo_provider }}"' \ {% if ipsec_enabled %} @@ -17,7 +18,7 @@ tags: debug - name: Install the requirements - pip: + ansible.builtin.pip: state: present name: - pyOpenSSL>=0.15 @@ -28,26 +29,27 @@ delegate_to: localhost become: false -- block: +- name: Provider not local + when: algo_provider != "local" + block: - name: Generate the SSH private key - openssl_privatekey: + ansible.builtin.openssl_privatekey: path: "{{ SSH_keys.private }}" size: 2048 mode: "0600" type: RSA - name: Generate the SSH public key - openssl_publickey: + ansible.builtin.openssl_publickey: path: "{{ SSH_keys.public }}" privatekey_path: "{{ SSH_keys.private }}" format: OpenSSH - name: Copy the private SSH key to /tmp - copy: + ansible.builtin.copy: src: "{{ SSH_keys.private }}" dest: "{{ SSH_keys.private_tmp }}" force: true mode: "0600" delegate_to: localhost become: false - when: algo_provider != "local" diff --git a/tasks/rescue.yml b/tasks/rescue.yml new file mode 100644 index 0000000..e82a922 --- /dev/null +++ b/tasks/rescue.yml @@ -0,0 +1,7 @@ +--- +- name: Debug | var fail_hint + ansible.builtin.debug: + var: fail_hint + +- name: Fail the installation + ansible.builtin.fail: diff --git a/playbooks/tmpfs/linux.yml b/tasks/tmpfs/linux.yml similarity index 100% rename from playbooks/tmpfs/linux.yml rename to tasks/tmpfs/linux.yml diff --git a/playbooks/tmpfs/macos.yml b/tasks/tmpfs/macos.yml similarity index 100% rename from playbooks/tmpfs/macos.yml rename to tasks/tmpfs/macos.yml diff --git a/playbooks/tmpfs/main.yml b/tasks/tmpfs/main.yml similarity index 100% rename from playbooks/tmpfs/main.yml rename to tasks/tmpfs/main.yml diff --git a/playbooks/tmpfs/umount.yml b/tasks/tmpfs/umount.yml similarity index 100% rename from playbooks/tmpfs/umount.yml rename to tasks/tmpfs/umount.yml diff --git a/users.yml b/users.yml index e9e8c08..365d671 100644 --- a/users.yml +++ b/users.yml @@ -1,14 +1,17 @@ --- -- hosts: localhost +- name: Playbook users + hosts: localhost gather_facts: false tags: always vars_files: - config.cfg tasks: - - block: + - name: Var server undefined + when: server is undefined + block: - name: Get list of installed config files - find: + ansible.builtin.find: paths: configs/ depth: 2 recurse: true @@ -17,12 +20,12 @@ register: _configs_list - name: Verify servers - assert: + ansible.builtin.assert: that: _configs_list.matched > 0 msg: No servers found, nothing to update. - name: Build list of installed servers - set_fact: + ansible.builtin.set_fact: server_list: >- [{% for i in _configs_list.files %} {% set config = lookup('file', i.path)|from_yaml %} @@ -31,49 +34,50 @@ {% endfor %}] - name: Server address prompt - pause: + ansible.builtin.pause: prompt: | Select the server to update user list below: {% for r in server_list %} {{ loop.index }}. {{ r }} {% endfor %} register: _server - when: server is undefined - - block: + - name: Set variables + block: - name: Set facts based on the input - set_fact: + ansible.builtin.set_fact: algo_server: >- {% if server is defined %}{{ server }} {%- elif _server.user_input %}{{ server_list[_server.user_input | int -1 ] }} {%- else %}omit{% endif %} - name: Import host specific variables - include_vars: + ansible.builtin.include_vars: file: configs/{{ algo_server }}/.config.yml - - when: ipsec_enabled + - name: ipsec enabled + when: ipsec_enabled block: - name: CA password prompt - pause: + ansible.builtin.pause: prompt: Enter the password for the private CA key echo: false register: _ca_password when: ca_password is undefined - name: Set facts based on the input - set_fact: + ansible.builtin.set_fact: CA_password: >- {% if ca_password is defined %}{{ ca_password }} {%- elif _ca_password.user_input %}{{ _ca_password.user_input }} {%- else %}omit{% endif %} - name: Local pre-tasks - import_tasks: playbooks/cloud-pre.yml + ansible.builtin.import_tasks: tasks/cloud-pre.yml become: false - name: Add the server to the vpn-host group - add_host: + ansible.builtin.add_host: name: "{{ algo_server }}" groups: vpn-host ansible_ssh_user: "{{ server_user|default('root') }}" @@ -81,7 +85,7 @@ ansible_python_interpreter: /usr/bin/python3 CA_password: "{{ CA_password|default(omit) }}" rescue: - - include_tasks: playbooks/rescue.yml + - ansible.builtin.include_tasks: tasks/rescue.yml - name: User management hosts: vpn-host @@ -92,24 +96,25 @@ - configs/{{ inventory_hostname }}/.config.yml tasks: - - block: - - import_role: + - name: Play roles + block: + - ansible.builtin.import_role: name: common - - import_role: + - ansible.builtin.import_role: name: wireguard when: wireguard_enabled - - import_role: + - ansible.builtin.import_role: name: strongswan when: ipsec_enabled tags: ipsec - - import_role: + - ansible.builtin.import_role: name: ssh_tunneling when: algo_ssh_tunneling - - debug: + - ansible.builtin.debug: msg: - "{{ congrats.common.split('\n') }}" - " {{ congrats.p12_pass if algo_ssh_tunneling or ipsec_enabled else '' }}" @@ -117,4 +122,4 @@ - " {{ congrats.ssh_access if algo_provider != 'local' else ''}}" tags: always rescue: - - include_tasks: playbooks/rescue.yml + - ansible.builtin.include_tasks: playbooks/rescue.yml