From db2b99f071f2461603094c65bccd2d19ff4d5fa2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 02:53:17 -0400 Subject: [PATCH 1/4] Bump actions/checkout from 4 to 5 (#14819) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/claude-code-review.yml | 2 +- .github/workflows/claude.yml | 2 +- .github/workflows/docker-image.yaml | 2 +- .github/workflows/integration-tests.yml | 4 ++-- .github/workflows/lint.yml | 10 +++++----- .github/workflows/main.yml | 10 +++++----- .github/workflows/smart-tests.yml | 12 ++++++------ .github/workflows/test-effectiveness.yml | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index d144cf2d..aec9f6c6 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -28,7 +28,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1 persist-credentials: false diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 101bfa4e..798b6248 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -27,7 +27,7 @@ jobs: actions: read # Required for Claude to read CI results on PRs steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 1 persist-credentials: false diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 3f761edf..26b61780 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index c3678004..d2f71b98 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -26,7 +26,7 @@ jobs: matrix: vpn_type: ['wireguard', 'ipsec', 'both'] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -210,7 +210,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 10 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 64066458..8dcca4e1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -11,7 +11,7 @@ jobs: name: Ansible linting runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -42,7 +42,7 @@ jobs: name: YAML linting runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -56,7 +56,7 @@ jobs: name: Python linting runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -75,7 +75,7 @@ jobs: name: Shell script linting runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -89,7 +89,7 @@ jobs: name: PowerShell script linting runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c572bed3..d2614749 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -37,7 +37,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -59,7 +59,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -87,7 +87,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -113,7 +113,7 @@ jobs: matrix: provider: [local, ec2, digitalocean, gce] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 diff --git a/.github/workflows/smart-tests.yml b/.github/workflows/smart-tests.yml index 779b01ea..e5cf3170 100644 --- a/.github/workflows/smart-tests.yml +++ b/.github/workflows/smart-tests.yml @@ -23,7 +23,7 @@ jobs: run_lint: ${{ steps.filter.outputs.lint }} run_integration: ${{ steps.filter.outputs.integration }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -77,7 +77,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -98,7 +98,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -142,7 +142,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -171,7 +171,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -223,7 +223,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 diff --git a/.github/workflows/test-effectiveness.yml b/.github/workflows/test-effectiveness.yml index b1e30585..051e713e 100644 --- a/.github/workflows/test-effectiveness.yml +++ b/.github/workflows/test-effectiveness.yml @@ -17,7 +17,7 @@ jobs: name: Analyze Test Effectiveness runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: true From 55e4cab788dfab6ae129559cbe3e0adae1ff211e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 02:53:39 -0400 Subject: [PATCH 2/4] Bump ansible from 11.8.0 to 11.9.0 (#14821) Bumps [ansible](https://github.com/ansible-community/ansible-build-data) from 11.8.0 to 11.9.0. - [Changelog](https://github.com/ansible-community/ansible-build-data/blob/main/docs/release-process.md) - [Commits](https://github.com/ansible-community/ansible-build-data/compare/11.8.0...11.9.0) --- updated-dependencies: - dependency-name: ansible dependency-version: 11.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e5ea7161..8da972d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description = "Set up a personal IPSEC VPN in the cloud" version = "2.0.0-beta" requires-python = ">=3.11" dependencies = [ - "ansible==11.8.0", + "ansible==11.9.0", "jinja2>=3.1.6", "netaddr==1.3.0", "pyyaml>=6.0.2", From b821080ebad55ed26e8e2e20f541ada7cd9d74e1 Mon Sep 17 00:00:00 2001 From: Dan Guido Date: Sat, 16 Aug 2025 03:39:00 -0400 Subject: [PATCH 3/4] Fix AWS Lightsail deployment error (boto3 parameter) (#14823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix AWS Lightsail deployment error by removing deprecated boto3 parameter Remove the deprecated boto3 parameter from get_aws_connection_info() call in the lightsail_region_facts module. This parameter has been non-functional since amazon.aws collection 4.0.0 and was removed in recent versions bundled with Ansible 11.x, causing deployment failures. The function works correctly without this parameter as the module already properly imports and validates boto3 availability. Closes #14822 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Update uv.lock to fix Docker build failure The lockfile was out of sync after the Ansible 11.8.0 to 11.9.0 upgrade. This regenerates the lockfile to include: - ansible 11.9.0 (was 11.8.0) - ansible-core 2.18.8 (was 2.18.7) This fixes the Docker build CI failure where uv sync --locked was failing due to lockfile mismatch. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix Jinja spacing linter issues correctly - Add spacing in lookup('env', 'VAR') calls - Fix spacing around pipe operators within Jinja expressions only - Preserve YAML block scalar syntax (prompt: |) - Fix array indexing spacing within Jinja expressions - All changes pass yamllint and ansible-lint tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Add algo.egg-info to .gitignore * Add unit test for AWS Lightsail boto3 parameter fix - Tests that get_aws_connection_info() is called without boto3 parameter - Verifies the module can be imported successfully - Checks source code doesn't contain boto3=True - Regression test specifically for issue #14822 - All 4 test cases pass This ensures the fix remains in place and prevents regression. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix Python linting issues in test file - Sort imports according to ruff standards - Remove trailing whitespace from blank lines - Remove unnecessary 'r' mode argument from open() - Add trailing newline at end of file All tests still pass after linting fixes. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- .gitignore | 1 + input.yml | 8 +- library/lightsail_region_facts.py | 2 +- playbooks/cloud-post.yml | 8 +- roles/cloud-azure/tasks/prompts.yml | 8 +- roles/cloud-cloudstack/tasks/prompts.yml | 8 +- roles/cloud-digitalocean/tasks/prompts.yml | 4 +- roles/cloud-ec2/tasks/prompts.yml | 6 +- roles/cloud-gce/tasks/main.yml | 4 +- roles/cloud-gce/tasks/prompts.yml | 8 +- roles/cloud-hetzner/tasks/prompts.yml | 4 +- roles/cloud-lightsail/tasks/prompts.yml | 10 +- roles/cloud-linode/tasks/prompts.yml | 4 +- roles/cloud-openstack/tasks/main.yml | 6 +- roles/cloud-scaleway/tasks/main.yml | 4 +- roles/cloud-scaleway/tasks/prompts.yml | 4 +- roles/cloud-vultr/tasks/prompts.yml | 4 +- roles/common/defaults/main.yml | 2 +- roles/common/tasks/facts.yml | 6 +- roles/common/tasks/main.yml | 2 +- roles/common/tasks/ubuntu.yml | 2 +- .../common/templates/50unattended-upgrades.j2 | 2 +- roles/common/templates/rules.v4.j2 | 22 +-- roles/common/templates/rules.v6.j2 | 20 +-- roles/dns/tasks/dns_adblocking.yml | 2 +- roles/dns/tasks/main.yml | 4 +- roles/dns/templates/adblock.sh.j2 | 2 +- roles/ssh_tunneling/handlers/main.yml | 2 +- roles/ssh_tunneling/tasks/main.yml | 6 +- roles/strongswan/defaults/main.yml | 2 +- roles/strongswan/tasks/client_configs.yml | 2 +- roles/strongswan/tasks/distribute_keys.yml | 8 +- .../strongswan/tasks/ipsec_configuration.yml | 16 +- roles/strongswan/tasks/openssl.yml | 2 +- roles/strongswan/templates/mobileconfig.j2 | 6 +- roles/wireguard/defaults/main.yml | 6 +- roles/wireguard/tasks/main.yml | 2 +- roles/wireguard/templates/client.conf.j2 | 4 +- roles/wireguard/templates/server.conf.j2 | 4 +- roles/wireguard/templates/vpn-dict.j2 | 6 +- server.yml | 4 +- tests/unit/test_lightsail_boto3_fix.py | 157 ++++++++++++++++++ users.yml | 4 +- uv.lock | 14 +- 44 files changed, 280 insertions(+), 122 deletions(-) create mode 100644 tests/unit/test_lightsail_boto3_fix.py diff --git a/.gitignore b/.gitignore index f414352a..4438ad8f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ inventory_users .ansible/ __pycache__/ *.pyc +algo.egg-info/ diff --git a/input.yml b/input.yml index 64b48056..5945f54c 100644 --- a/input.yml +++ b/input.yml @@ -42,7 +42,7 @@ - name: Set facts based on the input set_fact: - algo_provider: "{{ provider | default(providers_map[_algo_provider.user_input|default(omit)|int - 1]['alias']) }}" + algo_provider: "{{ provider | default(providers_map[_algo_provider.user_input | default(omit) | int - 1]['alias']) }}" - name: VPN server name prompt pause: @@ -110,10 +110,10 @@ 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 -%} + {%- 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|_)', '-') }} + {{ _server | regex_replace('(?!\.)(\W | _)', '-') }} algo_ondemand_cellular: >- {% if ondemand_cellular is defined %}{{ ondemand_cellular | bool }} {%- elif _ondemand_cellular.user_input is defined %}{{ booleans_map[_ondemand_cellular.user_input] | default(defaults['ondemand_cellular']) }} @@ -124,7 +124,7 @@ {%- 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|length > 0 -%} + {%- 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_dns_adblocking: >- diff --git a/library/lightsail_region_facts.py b/library/lightsail_region_facts.py index a74571c2..c61a4006 100644 --- a/library/lightsail_region_facts.py +++ b/library/lightsail_region_facts.py @@ -82,7 +82,7 @@ def main(): module.fail_json(msg='Python module "botocore" is missing, please install it') try: - region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) + region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module) client = None try: diff --git a/playbooks/cloud-post.yml b/playbooks/cloud-post.yml index 20c417b8..5a118211 100644 --- a/playbooks/cloud-post.yml +++ b/playbooks/cloud-post.yml @@ -8,8 +8,8 @@ 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 %}" - ansible_ssh_user: "{{ ansible_ssh_user|default('root') }}" - ansible_ssh_port: "{{ ansible_ssh_port|default(22) }}" + ansible_ssh_user: "{{ ansible_ssh_user | default('root') }}" + ansible_ssh_port: "{{ ansible_ssh_port | default(22) }}" ansible_python_interpreter: /usr/bin/python3 algo_provider: "{{ algo_provider }}" algo_server_name: "{{ algo_server_name }}" @@ -21,7 +21,7 @@ algo_store_pki: "{{ algo_store_pki }}" IP_subject_alt_name: "{{ IP_subject_alt_name }}" alternative_ingress_ip: "{{ alternative_ingress_ip | default(omit) }}" - cloudinit: "{{ cloudinit|default(false) }}" + cloudinit: "{{ cloudinit | default(false) }}" - name: Additional variables for the server add_host: @@ -31,7 +31,7 @@ - name: Wait until SSH becomes ready... wait_for: - port: "{{ ansible_ssh_port|default(22) }}" + port: "{{ ansible_ssh_port | default(22) }}" host: "{{ cloud_instance_ip }}" search_regex: OpenSSH delay: 10 diff --git a/roles/cloud-azure/tasks/prompts.yml b/roles/cloud-azure/tasks/prompts.yml index 99fd03b3..127a4d75 100644 --- a/roles/cloud-azure/tasks/prompts.yml +++ b/roles/cloud-azure/tasks/prompts.yml @@ -1,9 +1,9 @@ --- - 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) }}" + 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: Set the default region diff --git a/roles/cloud-cloudstack/tasks/prompts.yml b/roles/cloud-cloudstack/tasks/prompts.yml index 78d299f3..ae3de123 100644 --- a/roles/cloud-cloudstack/tasks/prompts.yml +++ b/roles/cloud-cloudstack/tasks/prompts.yml @@ -7,7 +7,7 @@ register: _cs_key when: - cs_key is undefined - - lookup('env','CLOUDSTACK_KEY')|length <= 0 + - lookup('env', 'CLOUDSTACK_KEY')|length <= 0 - pause: prompt: | @@ -16,7 +16,7 @@ register: _cs_secret when: - cs_secret is undefined - - lookup('env','CLOUDSTACK_SECRET')|length <= 0 + - lookup('env', 'CLOUDSTACK_SECRET')|length <= 0 - pause: prompt: | @@ -28,8 +28,8 @@ - lookup('env', 'CLOUDSTACK_ENDPOINT') | length <= 0 - 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_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) | diff --git a/roles/cloud-digitalocean/tasks/prompts.yml b/roles/cloud-digitalocean/tasks/prompts.yml index 7f24e3f9..1ad20409 100644 --- a/roles/cloud-digitalocean/tasks/prompts.yml +++ b/roles/cloud-digitalocean/tasks/prompts.yml @@ -6,11 +6,11 @@ register: _do_token when: - do_token is undefined - - lookup('env','DO_API_TOKEN')|length <= 0 + - lookup('env', 'DO_API_TOKEN')|length <= 0 - name: Set the token as a fact set_fact: - algo_do_token: "{{ do_token | default(_do_token.user_input|default(None)) | default(lookup('env','DO_API_TOKEN'), true) }}" + algo_do_token: "{{ do_token | default(_do_token.user_input | default(None)) | default(lookup('env', 'DO_API_TOKEN'), true) }}" - name: Get regions uri: diff --git a/roles/cloud-ec2/tasks/prompts.yml b/roles/cloud-ec2/tasks/prompts.yml index 73224727..5ca5e246 100644 --- a/roles/cloud-ec2/tasks/prompts.yml +++ b/roles/cloud-ec2/tasks/prompts.yml @@ -22,7 +22,7 @@ no_log: true when: - aws_access_key is undefined - - lookup('env','AWS_ACCESS_KEY_ID')|length <= 0 + - lookup('env', 'AWS_ACCESS_KEY_ID')|length <= 0 # Prompt for credentials if still not available - pause: @@ -33,7 +33,7 @@ register: _aws_access_key when: - aws_access_key is undefined - - lookup('env','AWS_ACCESS_KEY_ID')|length <= 0 + - lookup('env', 'AWS_ACCESS_KEY_ID')|length <= 0 - _file_access_key is undefined or _file_access_key|length <= 0 - pause: @@ -43,7 +43,7 @@ register: _aws_secret_key when: - aws_secret_key is undefined - - lookup('env','AWS_SECRET_ACCESS_KEY')|length <= 0 + - lookup('env', 'AWS_SECRET_ACCESS_KEY')|length <= 0 - _file_secret_key is undefined or _file_secret_key|length <= 0 # Set final credentials with proper precedence diff --git a/roles/cloud-gce/tasks/main.yml b/roles/cloud-gce/tasks/main.yml index 69aa56ad..9e743dcf 100644 --- a/roles/cloud-gce/tasks/main.yml +++ b/roles/cloud-gce/tasks/main.yml @@ -29,7 +29,7 @@ ports: - "500" - "4500" - - "{{ wireguard_port|string }}" + - "{{ wireguard_port | string }}" - ip_protocol: tcp ports: - "{{ ssh_port }}" @@ -70,7 +70,7 @@ - network: "{{ gcp_compute_network }}" access_configs: - name: "{{ algo_server_name }}" - nat_ip: "{{ gcp_compute_address|default(None) }}" + nat_ip: "{{ gcp_compute_address | default(None) }}" type: ONE_TO_ONE_NAT tags: items: diff --git a/roles/cloud-gce/tasks/prompts.yml b/roles/cloud-gce/tasks/prompts.yml index b770da50..cb2666dc 100644 --- a/roles/cloud-gce/tasks/prompts.yml +++ b/roles/cloud-gce/tasks/prompts.yml @@ -6,20 +6,20 @@ register: _gce_credentials_file when: - gce_credentials_file is undefined - - lookup('env','GCE_CREDENTIALS_FILE_PATH')|length <= 0 + - lookup('env', 'GCE_CREDENTIALS_FILE_PATH')|length <= 0 - set_fact: credentials_file_path: >- {{ gce_credentials_file | default(_gce_credentials_file.user_input|default(None)) | - default(lookup('env','GCE_CREDENTIALS_FILE_PATH'), true) }} + default(lookup('env', 'GCE_CREDENTIALS_FILE_PATH'), true) }} ssh_public_key_lookup: "{{ lookup('file', '{{ SSH_keys.public }}') }}" - set_fact: credentials_file_lookup: "{{ lookup('file', '{{ credentials_file_path }}') }}" - 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')) }}" + 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: Get regions diff --git a/roles/cloud-hetzner/tasks/prompts.yml b/roles/cloud-hetzner/tasks/prompts.yml index 3663b7e6..fd1afcc0 100644 --- a/roles/cloud-hetzner/tasks/prompts.yml +++ b/roles/cloud-hetzner/tasks/prompts.yml @@ -6,11 +6,11 @@ register: _hcloud_token when: - hcloud_token is undefined - - lookup('env','HCLOUD_TOKEN')|length <= 0 + - lookup('env', 'HCLOUD_TOKEN')|length <= 0 - name: Set the token as a fact set_fact: - algo_hcloud_token: "{{ hcloud_token | default(_hcloud_token.user_input|default(None)) | default(lookup('env','HCLOUD_TOKEN'), true) }}" + algo_hcloud_token: "{{ hcloud_token | default(_hcloud_token.user_input | default(None)) | default(lookup('env', 'HCLOUD_TOKEN'), true) }}" - name: Get regions hetzner.hcloud.datacenter_info: diff --git a/roles/cloud-lightsail/tasks/prompts.yml b/roles/cloud-lightsail/tasks/prompts.yml index 49e6bd01..c4848477 100644 --- a/roles/cloud-lightsail/tasks/prompts.yml +++ b/roles/cloud-lightsail/tasks/prompts.yml @@ -7,7 +7,7 @@ register: _aws_access_key when: - aws_access_key is undefined - - lookup('env','AWS_ACCESS_KEY_ID')|length <= 0 + - lookup('env', 'AWS_ACCESS_KEY_ID')|length <= 0 - pause: prompt: | @@ -16,11 +16,11 @@ register: _aws_secret_key when: - aws_secret_key is undefined - - lookup('env','AWS_SECRET_ACCESS_KEY')|length <= 0 + - lookup('env', 'AWS_SECRET_ACCESS_KEY')|length <= 0 - 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) }}" + 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: Get regions @@ -46,7 +46,7 @@ What region should the server be located in? (https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) {% for r in lightsail_regions %} - {{ (loop.index|string + '.').ljust(3) }} {{ r['name'].ljust(20) }} {{ r['displayName'] }} + {{ (loop.index | string + '.').ljust(3) }} {{ r['name'].ljust(20) }} {{ r['displayName'] }} {% endfor %} Enter the number of your desired region diff --git a/roles/cloud-linode/tasks/prompts.yml b/roles/cloud-linode/tasks/prompts.yml index 84d85b92..219fe97a 100644 --- a/roles/cloud-linode/tasks/prompts.yml +++ b/roles/cloud-linode/tasks/prompts.yml @@ -6,11 +6,11 @@ register: _linode_token when: - linode_token is undefined - - lookup('env','LINODE_API_TOKEN')|length <= 0 + - lookup('env', 'LINODE_API_TOKEN')|length <= 0 - name: Set the token as a fact set_fact: - algo_linode_token: "{{ linode_token | default(_linode_token.user_input|default(None)) | default(lookup('env','LINODE_API_TOKEN'), true) }}" + algo_linode_token: "{{ linode_token | default(_linode_token.user_input | default(None)) | default(lookup('env', 'LINODE_API_TOKEN'), true) }}" - name: Get regions uri: diff --git a/roles/cloud-openstack/tasks/main.yml b/roles/cloud-openstack/tasks/main.yml index 63af0b58..055c017c 100644 --- a/roles/cloud-openstack/tasks/main.yml +++ b/roles/cloud-openstack/tasks/main.yml @@ -10,14 +10,14 @@ - name: Security group created openstack.cloud.security_group: - state: "{{ state|default('present') }}" + state: "{{ state | default('present') }}" name: "{{ algo_server_name }}-security_group" description: AlgoVPN security group register: os_security_group - name: Security rules created openstack.cloud.security_group_rule: - state: "{{ state|default('present') }}" + state: "{{ state | default('present') }}" security_group: "{{ os_security_group.id }}" protocol: "{{ item.proto }}" port_range_min: "{{ item.port_min }}" @@ -67,7 +67,7 @@ - name: Server created openstack.cloud.server: - state: "{{ state|default('present') }}" + state: "{{ state | default('present') }}" name: "{{ algo_server_name }}" image: "{{ image_id }}" flavor: "{{ flavor_id }}" diff --git a/roles/cloud-scaleway/tasks/main.yml b/roles/cloud-scaleway/tasks/main.yml index 05c1d536..1239a949 100644 --- a/roles/cloud-scaleway/tasks/main.yml +++ b/roles/cloud-scaleway/tasks/main.yml @@ -37,7 +37,7 @@ wait: true tags: - Environment:Algo - - AUTHORIZED_KEY={{ lookup('file', SSH_keys.public)|regex_replace(' ', '_') }} + - AUTHORIZED_KEY={{ lookup('file', SSH_keys.public) | regex_replace(' ', '_') }} register: scaleway_compute - name: Patch the cloud-init @@ -64,7 +64,7 @@ wait: true tags: - Environment:Algo - - AUTHORIZED_KEY={{ lookup('file', SSH_keys.public)|regex_replace(' ', '_') }} + - AUTHORIZED_KEY={{ lookup('file', SSH_keys.public) | regex_replace(' ', '_') }} register: algo_instance until: algo_instance.msg.public_ip retries: 3 diff --git a/roles/cloud-scaleway/tasks/prompts.yml b/roles/cloud-scaleway/tasks/prompts.yml index 7e371d21..3551f646 100644 --- a/roles/cloud-scaleway/tasks/prompts.yml +++ b/roles/cloud-scaleway/tasks/prompts.yml @@ -6,7 +6,7 @@ register: _scaleway_token when: - scaleway_token is undefined - - lookup('env','SCW_TOKEN')|length <= 0 + - lookup('env', 'SCW_TOKEN')|length <= 0 - pause: prompt: | @@ -22,7 +22,7 @@ - name: Set scaleway facts set_fact: - algo_scaleway_token: "{{ scaleway_token | default(_scaleway_token.user_input) | default(lookup('env','SCW_TOKEN'), true) }}" + algo_scaleway_token: "{{ scaleway_token | default(_scaleway_token.user_input) | default(lookup('env', 'SCW_TOKEN'), true) }}" algo_region: >- {% if region is defined %}{{ region }} {%- elif _algo_region.user_input %}{{ scaleway_regions[_algo_region.user_input | int -1 ]['alias'] }} diff --git a/roles/cloud-vultr/tasks/prompts.yml b/roles/cloud-vultr/tasks/prompts.yml index 04108219..0569bb4f 100644 --- a/roles/cloud-vultr/tasks/prompts.yml +++ b/roles/cloud-vultr/tasks/prompts.yml @@ -6,11 +6,11 @@ register: _vultr_config when: - vultr_config is undefined - - lookup('env','VULTR_API_CONFIG')|length <= 0 + - lookup('env', 'VULTR_API_CONFIG')|length <= 0 - name: Set the token as a fact set_fact: - algo_vultr_config: "{{ vultr_config | default(_vultr_config.user_input) | default(lookup('env','VULTR_API_CONFIG'), true) }}" + algo_vultr_config: "{{ vultr_config | default(_vultr_config.user_input) | default(lookup('env', 'VULTR_API_CONFIG'), true) }}" - name: Set the Vultr API Key as a fact set_fact: diff --git a/roles/common/defaults/main.yml b/roles/common/defaults/main.yml index c383d37b..26156dff 100644 --- a/roles/common/defaults/main.yml +++ b/roles/common/defaults/main.yml @@ -6,4 +6,4 @@ snat_aipv4: false ipv6_default: "{{ ansible_default_ipv6.address + '/' + ansible_default_ipv6.prefix }}" ipv6_subnet_size: "{{ ipv6_default | ansible.utils.ipaddr('size') }}" ipv6_egress_ip: >- - {{ (ipv6_default | ansible.utils.next_nth_usable(15 | random(seed=algo_server_name + ansible_fqdn))) + '/124' if ipv6_subnet_size|int > 1 else ipv6_default }} + {{ (ipv6_default | ansible.utils.next_nth_usable(15 | random(seed=algo_server_name + ansible_fqdn))) + '/124' if ipv6_subnet_size | int > 1 else ipv6_default }} diff --git a/roles/common/tasks/facts.yml b/roles/common/tasks/facts.yml index 61a17ae6..98917326 100644 --- a/roles/common/tasks/facts.yml +++ b/roles/common/tasks/facts.yml @@ -1,12 +1,12 @@ --- - name: Define facts set_fact: - p12_export_password: "{{ p12_password|default(lookup('password', '/dev/null length=9 chars=ascii_letters,digits,_,@')) }}" + p12_export_password: "{{ p12_password | default(lookup('password', '/dev/null length=9 chars=ascii_letters,digits,_,@')) }}" tags: update-users - name: Set facts set_fact: - CA_password: "{{ ca_password|default(lookup('password', '/dev/null length=16 chars=ascii_letters,digits,_,@')) }}" + CA_password: "{{ ca_password | default(lookup('password', '/dev/null length=16 chars=ascii_letters,digits,_,@')) }}" IP_subject_alt_name: "{{ IP_subject_alt_name }}" - name: Set IPv6 support as a fact @@ -16,5 +16,5 @@ - name: Check size of MTU set_fact: - reduce_mtu: "{{ 1500 - ansible_default_ipv4['mtu']|int if reduce_mtu|int == 0 and ansible_default_ipv4['mtu']|int < 1500 else reduce_mtu|int }}" + 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/main.yml b/roles/common/tasks/main.yml index 573a9f1f..f1e784bf 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -19,7 +19,7 @@ sysctl: name="{{ item.item }}" value="{{ item.value }}" when: item.item with_items: - - "{{ sysctl|default([]) }}" + - "{{ sysctl | default([]) }}" tags: - always diff --git a/roles/common/tasks/ubuntu.yml b/roles/common/tasks/ubuntu.yml index 43250782..0d7e2d2d 100644 --- a/roles/common/tasks/ubuntu.yml +++ b/roles/common/tasks/ubuntu.yml @@ -140,7 +140,7 @@ - name: Install tools (legacy method) apt: - name: "{{ tools|default([]) }}" + name: "{{ tools | default([]) }}" state: present update_cache: true when: diff --git a/roles/common/templates/50unattended-upgrades.j2 b/roles/common/templates/50unattended-upgrades.j2 index 87c4b07d..4e8ab299 100644 --- a/roles/common/templates/50unattended-upgrades.j2 +++ b/roles/common/templates/50unattended-upgrades.j2 @@ -64,7 +64,7 @@ Unattended-Upgrade::Remove-Unused-Dependencies "true"; // Automatically reboot *WITHOUT CONFIRMATION* // if the file /var/run/reboot-required is found after the upgrade -Unattended-Upgrade::Automatic-Reboot "{{ unattended_reboot.enabled|lower }}"; +Unattended-Upgrade::Automatic-Reboot "{{ unattended_reboot.enabled | lower }}"; // If automatic reboot is enabled and needed, reboot at the specific // time instead of immediately diff --git a/roles/common/templates/rules.v4.j2 b/roles/common/templates/rules.v4.j2 index c127bdce..bf3cd047 100644 --- a/roles/common/templates/rules.v4.j2 +++ b/roles/common/templates/rules.v4.j2 @@ -1,5 +1,5 @@ {% set subnets = ([strongswan_network] if ipsec_enabled else []) + ([wireguard_network_ipv4] if wireguard_enabled else []) %} -{% set ports = (['500', '4500'] if ipsec_enabled else []) + ([wireguard_port] if wireguard_enabled else []) + ([wireguard_port_actual] if wireguard_enabled and wireguard_port|int == wireguard_port_avoid|int else []) %} +{% set ports = (['500', '4500'] if ipsec_enabled else []) + ([wireguard_port] if wireguard_enabled else []) + ([wireguard_port_actual] if wireguard_enabled and wireguard_port | int == wireguard_port_avoid | int else []) %} #### The mangle table # This table allows us to modify packet headers @@ -13,8 +13,8 @@ :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -{% if reduce_mtu|int > 0 and ipsec_enabled %} --A FORWARD -s {{ strongswan_network }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ 1360 - reduce_mtu|int }} +{% if reduce_mtu | int > 0 and ipsec_enabled %} +-A FORWARD -s {{ strongswan_network }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ 1360 - reduce_mtu | int }} {% endif %} COMMIT @@ -29,14 +29,14 @@ COMMIT :PREROUTING ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -{% if wireguard_enabled and wireguard_port|int == wireguard_port_avoid|int %} +{% if wireguard_enabled and wireguard_port | int == wireguard_port_avoid | int %} # Handle the special case of allowing access to WireGuard over an already used # port like 53 --A PREROUTING -s {{ subnets|join(',') }} -p udp --dport {{ wireguard_port_avoid }} -j RETURN +-A PREROUTING -s {{ subnets | join(',') }} -p udp --dport {{ wireguard_port_avoid }} -j RETURN -A PREROUTING --in-interface {{ ansible_default_ipv4['interface'] }} -p udp --dport {{ wireguard_port_avoid }} -j REDIRECT --to-port {{ wireguard_port_actual }} {% endif %} # Allow traffic from the VPN network to the outside world, and replies --A POSTROUTING -s {{ subnets|join(',') }} -m policy --pol none --dir out {{ '-j SNAT --to ' + snat_aipv4 if snat_aipv4 else '-j MASQUERADE' }} +-A POSTROUTING -s {{ subnets | join(',') }} -m policy --pol none --dir out {{ '-j SNAT --to ' + snat_aipv4 if snat_aipv4 else '-j MASQUERADE' }} COMMIT @@ -63,8 +63,8 @@ COMMIT -A INPUT -p ah -j ACCEPT # rate limit ICMP traffic per source -A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT -# Accept IPSEC/WireGuard traffic to ports {{ subnets|join(',') }} --A INPUT -p udp -m multiport --dports {{ ports|join(',') }} -j ACCEPT +# Accept IPSEC/WireGuard traffic to ports {{ subnets | join(',') }} +-A INPUT -p udp -m multiport --dports {{ ports | join(',') }} -j ACCEPT # Allow new traffic to port {{ ansible_ssh_port }} (SSH) -A INPUT -p tcp --dport {{ ansible_ssh_port }} -m conntrack --ctstate NEW -j ACCEPT @@ -82,12 +82,12 @@ COMMIT -A INPUT -d {{ local_service_ip }} -p udp --dport 53 -j ACCEPT # Drop traffic between VPN clients --A FORWARD -s {{ subnets|join(',') }} -d {{ subnets|join(',') }} -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} +-A FORWARD -s {{ subnets | join(',') }} -d {{ subnets | join(',') }} -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} # Drop traffic to VPN clients from SSH tunnels --A OUTPUT -d {{ subnets|join(',') }} -m owner --gid-owner 15000 -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} +-A OUTPUT -d {{ subnets | join(',') }} -m owner --gid-owner 15000 -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} # Drop traffic to the link-local network --A FORWARD -s {{ subnets|join(',') }} -d 169.254.0.0/16 -j DROP +-A FORWARD -s {{ subnets | join(',') }} -d 169.254.0.0/16 -j DROP # Drop traffic to the link-local network from SSH tunnels -A OUTPUT -d 169.254.0.0/16 -m owner --gid-owner 15000 -j DROP diff --git a/roles/common/templates/rules.v6.j2 b/roles/common/templates/rules.v6.j2 index b2f6f20c..9515b685 100644 --- a/roles/common/templates/rules.v6.j2 +++ b/roles/common/templates/rules.v6.j2 @@ -1,5 +1,5 @@ {% set subnets = ([strongswan_network_ipv6] if ipsec_enabled else []) + ([wireguard_network_ipv6] if wireguard_enabled else []) %} -{% set ports = (['500', '4500'] if ipsec_enabled else []) + ([wireguard_port] if wireguard_enabled else []) + ([wireguard_port_actual] if wireguard_enabled and wireguard_port|int == wireguard_port_avoid|int else []) %} +{% set ports = (['500', '4500'] if ipsec_enabled else []) + ([wireguard_port] if wireguard_enabled else []) + ([wireguard_port_actual] if wireguard_enabled and wireguard_port | int == wireguard_port_avoid | int else []) %} #### The mangle table # This table allows us to modify packet headers @@ -13,8 +13,8 @@ :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -{% if reduce_mtu|int > 0 and ipsec_enabled %} --A FORWARD -s {{ strongswan_network_ipv6 }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ 1340 - reduce_mtu|int }} +{% if reduce_mtu | int > 0 and ipsec_enabled %} +-A FORWARD -s {{ strongswan_network_ipv6 }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ 1340 - reduce_mtu | int }} {% endif %} COMMIT @@ -28,14 +28,14 @@ COMMIT :PREROUTING ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -{% if wireguard_enabled and wireguard_port|int == wireguard_port_avoid|int %} +{% if wireguard_enabled and wireguard_port | int == wireguard_port_avoid | int %} # Handle the special case of allowing access to WireGuard over an already used # port like 53 --A PREROUTING -s {{ subnets|join(',') }} -p udp --dport {{ wireguard_port_avoid }} -j RETURN +-A PREROUTING -s {{ subnets | join(',') }} -p udp --dport {{ wireguard_port_avoid }} -j RETURN -A PREROUTING --in-interface {{ ansible_default_ipv6['interface'] }} -p udp --dport {{ wireguard_port_avoid }} -j REDIRECT --to-port {{ wireguard_port_actual }} {% endif %} # Allow traffic from the VPN network to the outside world, and replies --A POSTROUTING -s {{ subnets|join(',') }} -m policy --pol none --dir out {{ '-j SNAT --to ' + ipv6_egress_ip | ansible.utils.ipaddr('address') if alternative_ingress_ip else '-j MASQUERADE' }} +-A POSTROUTING -s {{ subnets | join(',') }} -m policy --pol none --dir out {{ '-j SNAT --to ' + ipv6_egress_ip | ansible.utils.ipaddr('address') if alternative_ingress_ip else '-j MASQUERADE' }} COMMIT @@ -69,8 +69,8 @@ COMMIT -A INPUT -m ah -j ACCEPT # rate limit ICMP traffic per source -A INPUT -p icmpv6 --icmpv6-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT -# Accept IPSEC/WireGuard traffic to ports {{ subnets|join(',') }} --A INPUT -p udp -m multiport --dports {{ ports|join(',') }} -j ACCEPT +# Accept IPSEC/WireGuard traffic to ports {{ subnets | join(',') }} +-A INPUT -p udp -m multiport --dports {{ ports | join(',') }} -j ACCEPT # Allow new traffic to port {{ ansible_ssh_port }} (SSH) -A INPUT -p tcp --dport {{ ansible_ssh_port }} -m conntrack --ctstate NEW -j ACCEPT @@ -92,9 +92,9 @@ COMMIT -A INPUT -d {{ local_service_ipv6 }}/128 -p udp --dport 53 -j ACCEPT # Drop traffic between VPN clients --A FORWARD -s {{ subnets|join(',') }} -d {{ subnets|join(',') }} -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} +-A FORWARD -s {{ subnets | join(',') }} -d {{ subnets | join(',') }} -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} # Drop traffic to VPN clients from SSH tunnels --A OUTPUT -d {{ subnets|join(',') }} -m owner --gid-owner 15000 -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} +-A OUTPUT -d {{ subnets | join(',') }} -m owner --gid-owner 15000 -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }} -A FORWARD -j ICMPV6-CHECK -A FORWARD -p tcp --dport 445 -j {{ "DROP" if block_smb else "ACCEPT" }} diff --git a/roles/dns/tasks/dns_adblocking.yml b/roles/dns/tasks/dns_adblocking.yml index 5ef90249..ec2271a5 100644 --- a/roles/dns/tasks/dns_adblocking.yml +++ b/roles/dns/tasks/dns_adblocking.yml @@ -4,7 +4,7 @@ src: adblock.sh.j2 dest: /usr/local/sbin/adblock.sh owner: root - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: 0755 - name: Adblock script added to cron diff --git a/roles/dns/tasks/main.yml b/roles/dns/tasks/main.yml index 57ac5ac7..f845a382 100644 --- a/roles/dns/tasks/main.yml +++ b/roles/dns/tasks/main.yml @@ -7,14 +7,14 @@ - name: dnscrypt-proxy ip-blacklist configured template: src: ip-blacklist.txt.j2 - dest: "{{ config_prefix|default('/') }}etc/dnscrypt-proxy/ip-blacklist.txt" + dest: "{{ config_prefix | default('/') }}etc/dnscrypt-proxy/ip-blacklist.txt" notify: - restart dnscrypt-proxy - name: dnscrypt-proxy configured template: src: dnscrypt-proxy.toml.j2 - dest: "{{ config_prefix|default('/') }}etc/dnscrypt-proxy/dnscrypt-proxy.toml" + dest: "{{ config_prefix | default('/') }}etc/dnscrypt-proxy/dnscrypt-proxy.toml" notify: - restart dnscrypt-proxy diff --git a/roles/dns/templates/adblock.sh.j2 b/roles/dns/templates/adblock.sh.j2 index cd0be35c..c43efbb6 100644 --- a/roles/dns/templates/adblock.sh.j2 +++ b/roles/dns/templates/adblock.sh.j2 @@ -5,7 +5,7 @@ TEMP="$(mktemp)" TEMP_SORTED="$(mktemp)" WHITELIST="/etc/dnscrypt-proxy/white.list" BLACKLIST="/etc/dnscrypt-proxy/black.list" -BLOCKHOSTS="{{ config_prefix|default('/') }}etc/dnscrypt-proxy/blacklist.txt" +BLOCKHOSTS="{{ config_prefix | default('/') }}etc/dnscrypt-proxy/blacklist.txt" BLOCKLIST_URLS="{% for url in adblock_lists %}{{ url }} {% endfor %}" #Delete the old block.hosts to make room for the updates diff --git a/roles/ssh_tunneling/handlers/main.yml b/roles/ssh_tunneling/handlers/main.yml index eae0ef1c..84a7eef7 100644 --- a/roles/ssh_tunneling/handlers/main.yml +++ b/roles/ssh_tunneling/handlers/main.yml @@ -1,3 +1,3 @@ --- - name: restart ssh - service: name="{{ ssh_service_name|default('ssh') }}" state=restarted + service: name="{{ ssh_service_name | default('ssh') }}" state=restarted diff --git a/roles/ssh_tunneling/tasks/main.yml b/roles/ssh_tunneling/tasks/main.yml index f9680f3a..bb6bf26d 100644 --- a/roles/ssh_tunneling/tasks/main.yml +++ b/roles/ssh_tunneling/tasks/main.yml @@ -25,7 +25,7 @@ state: directory mode: 0755 owner: root - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" - block: - name: Ensure that the SSH users exist @@ -67,7 +67,7 @@ passphrase: "{{ p12_export_password }}" cipher: auto force: false - no_log: "{{ algo_no_log|bool }}" + no_log: "{{ algo_no_log | bool }}" when: not item.stat.exists with_items: "{{ privatekey.results }}" register: openssl_privatekey @@ -79,7 +79,7 @@ privatekey_passphrase: "{{ p12_export_password }}" format: OpenSSH force: true - no_log: "{{ algo_no_log|bool }}" + no_log: "{{ algo_no_log | bool }}" when: item.changed with_items: "{{ openssl_privatekey.results }}" diff --git a/roles/strongswan/defaults/main.yml b/roles/strongswan/defaults/main.yml index 0ffb344f..0816b612 100644 --- a/roles/strongswan/defaults/main.yml +++ b/roles/strongswan/defaults/main.yml @@ -17,7 +17,7 @@ openssl_constraint_random_id: "{{ IP_subject_alt_name | to_uuid }}.algo" # Subject Alternative Name (SAN) configuration - CRITICAL for client compatibility # Modern clients (especially macOS/iOS) REQUIRE SAN extension in server certificates # Without SAN, IKEv2 connections will fail with certificate validation errors -subjectAltName_type: "{{ 'DNS' if IP_subject_alt_name|regex_search('[a-z]') else 'IP' }}" +subjectAltName_type: "{{ 'DNS' if IP_subject_alt_name | regex_search('[a-z]') else 'IP' }}" subjectAltName: >- {{ subjectAltName_type }}:{{ IP_subject_alt_name }} {%- if ipv6_support -%},IP:{{ ansible_default_ipv6['address'] }}{%- endif -%} diff --git a/roles/strongswan/tasks/client_configs.yml b/roles/strongswan/tasks/client_configs.yml index 814f25e2..08e51429 100644 --- a/roles/strongswan/tasks/client_configs.yml +++ b/roles/strongswan/tasks/client_configs.yml @@ -23,7 +23,7 @@ with_together: - "{{ users }}" - "{{ PayloadContent.results }}" - no_log: "{{ algo_no_log|bool }}" + no_log: "{{ algo_no_log | bool }}" - name: Build the client ipsec config file template: diff --git a/roles/strongswan/tasks/distribute_keys.yml b/roles/strongswan/tasks/distribute_keys.yml index 55d1da12..b9a22d96 100644 --- a/roles/strongswan/tasks/distribute_keys.yml +++ b/roles/strongswan/tasks/distribute_keys.yml @@ -2,7 +2,7 @@ - name: Copy the keys to the strongswan directory copy: src: "{{ ipsec_pki_path }}/{{ item.src }}" - dest: "{{ config_prefix|default('/') }}etc/ipsec.d/{{ item.dest }}" + dest: "{{ config_prefix | default('/') }}etc/ipsec.d/{{ item.dest }}" owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" @@ -10,17 +10,17 @@ - src: cacert.pem dest: cacerts/ca.crt owner: strongswan - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0600" - src: certs/{{ IP_subject_alt_name }}.crt dest: certs/{{ IP_subject_alt_name }}.crt owner: strongswan - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0600" - src: private/{{ IP_subject_alt_name }}.key dest: private/{{ IP_subject_alt_name }}.key owner: strongswan - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0600" notify: - restart strongswan diff --git a/roles/strongswan/tasks/ipsec_configuration.yml b/roles/strongswan/tasks/ipsec_configuration.yml index 7ba44c37..18b9634d 100644 --- a/roles/strongswan/tasks/ipsec_configuration.yml +++ b/roles/strongswan/tasks/ipsec_configuration.yml @@ -2,7 +2,7 @@ - name: Setup the config files from our templates template: src: "{{ item.src }}" - dest: "{{ config_prefix|default('/') }}etc/{{ item.dest }}" + dest: "{{ config_prefix | default('/') }}etc/{{ item.dest }}" owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" @@ -10,22 +10,22 @@ - src: strongswan.conf.j2 dest: strongswan.conf owner: root - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0644" - src: ipsec.conf.j2 dest: ipsec.conf owner: root - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0644" - src: ipsec.secrets.j2 dest: ipsec.secrets owner: strongswan - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0600" - src: charon.conf.j2 dest: strongswan.d/charon.conf owner: root - group: "{{ root_group|default('root') }}" + group: "{{ root_group | default('root') }}" mode: "0644" notify: - restart strongswan @@ -33,7 +33,7 @@ - name: Get loaded plugins shell: | set -o pipefail - find {{ config_prefix|default('/') }}etc/strongswan.d/charon/ -type f -name '*.conf' -exec basename {} \; | + find {{ config_prefix | default('/') }}etc/strongswan.d/charon/ -type f -name '*.conf' -exec basename {} \; | cut -f1 -d. changed_when: false args: @@ -42,7 +42,7 @@ - name: Disable unneeded plugins lineinfile: - dest: "{{ config_prefix|default('/') }}etc/strongswan.d/charon/{{ item }}.conf" + dest: "{{ config_prefix | default('/') }}etc/strongswan.d/charon/{{ item }}.conf" regexp: .*load.* line: load = no state: present @@ -52,7 +52,7 @@ with_items: "{{ strongswan_plugins.stdout_lines }}" - name: Ensure that required plugins are enabled - lineinfile: dest="{{ config_prefix|default('/') }}etc/strongswan.d/charon/{{ item }}.conf" regexp='.*load.*' line='load = yes' state=present + lineinfile: dest="{{ config_prefix | default('/') }}etc/strongswan.d/charon/{{ item }}.conf" regexp='.*load.*' line='load = yes' state=present notify: - restart strongswan when: item in strongswan_enabled_plugins or item in strongswan_additional_plugins diff --git a/roles/strongswan/tasks/openssl.yml b/roles/strongswan/tasks/openssl.yml index e64ccdc6..3d13ad8c 100644 --- a/roles/strongswan/tasks/openssl.yml +++ b/roles/strongswan/tasks/openssl.yml @@ -269,6 +269,6 @@ - name: Copy the CRL to the vpn server copy: src: "{{ ipsec_pki_path }}/crl.pem" - dest: "{{ config_prefix|default('/') }}etc/ipsec.d/crls/algo.root.pem" + dest: "{{ config_prefix | default('/') }}etc/ipsec.d/crls/algo.root.pem" notify: - rereadcrls diff --git a/roles/strongswan/templates/mobileconfig.j2 b/roles/strongswan/templates/mobileconfig.j2 index bf6f6709..abdada99 100644 --- a/roles/strongswan/templates/mobileconfig.j2 +++ b/roles/strongswan/templates/mobileconfig.j2 @@ -13,8 +13,8 @@ OnDemandRules {% if algo_ondemand_wifi or algo_ondemand_cellular %} - {% if algo_ondemand_wifi_exclude|b64decode != '_null' %} - {% set WIFI_EXCLUDE_LIST = (algo_ondemand_wifi_exclude|b64decode|string).split(',') %} + {% if algo_ondemand_wifi_exclude | b64decode != '_null' %} + {% set WIFI_EXCLUDE_LIST = (algo_ondemand_wifi_exclude | b64decode | string).split(',') %} Action Disconnect @@ -23,7 +23,7 @@ SSIDMatch {% for network_name in WIFI_EXCLUDE_LIST %} - {{ network_name|e }} + {{ network_name | e }} {% endfor %} diff --git a/roles/wireguard/defaults/main.yml b/roles/wireguard/defaults/main.yml index a073d018..1d135a36 100644 --- a/roles/wireguard/defaults/main.yml +++ b/roles/wireguard/defaults/main.yml @@ -7,15 +7,15 @@ wireguard_port_avoid: 53 wireguard_port_actual: 51820 keys_clean_all: false wireguard_dns_servers: >- - {% if algo_dns_adblocking|default(false)|bool or dns_encryption|default(false)|bool %} + {% if algo_dns_adblocking | default(false) | bool or dns_encryption | default(false) | bool %} {{ local_service_ip }}{{ ', ' + local_service_ipv6 if ipv6_support else '' }} {% 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 %} {% endif %} wireguard_client_ip: >- - {{ wireguard_network_ipv4 | ansible.utils.ipmath(index|int+2) }} - {{ ',' + wireguard_network_ipv6 | ansible.utils.ipmath(index|int+2) if ipv6_support else '' }} + {{ wireguard_network_ipv4 | ansible.utils.ipmath(index | int+2) }} + {{ ',' + wireguard_network_ipv6 | ansible.utils.ipmath(index | int+2) if ipv6_support else '' }} wireguard_server_ip: >- {{ wireguard_network_ipv4 | ansible.utils.ipaddr('1') }} {{ ',' + wireguard_network_ipv6 | ansible.utils.ipaddr('1') if ipv6_support else '' }} diff --git a/roles/wireguard/tasks/main.yml b/roles/wireguard/tasks/main.yml index 31b35638..1cac2ae1 100644 --- a/roles/wireguard/tasks/main.yml +++ b/roles/wireguard/tasks/main.yml @@ -78,7 +78,7 @@ - name: WireGuard configured template: src: server.conf.j2 - dest: "{{ config_prefix|default('/') }}etc/wireguard/{{ wireguard_interface }}.conf" + dest: "{{ config_prefix | default('/') }}etc/wireguard/{{ wireguard_interface }}.conf" mode: "0600" notify: restart wireguard tags: update-users diff --git a/roles/wireguard/templates/client.conf.j2 b/roles/wireguard/templates/client.conf.j2 index a6e48a57..8e6c8d5b 100644 --- a/roles/wireguard/templates/client.conf.j2 +++ b/roles/wireguard/templates/client.conf.j2 @@ -2,7 +2,7 @@ PrivateKey = {{ lookup('file', wireguard_pki_path + '/private/' + item.1) }} Address = {{ wireguard_client_ip }} DNS = {{ wireguard_dns_servers }} -{% if reduce_mtu|int > 0 %}MTU = {{ 1420 - reduce_mtu|int }} +{% if reduce_mtu | int > 0 %}MTU = {{ 1420 - reduce_mtu | int }} {% endif %} [Peer] @@ -10,4 +10,4 @@ PublicKey = {{ lookup('file', wireguard_pki_path + '/public/' + IP_subject_alt_n PresharedKey = {{ lookup('file', wireguard_pki_path + '/preshared/' + item.1) }} AllowedIPs = 0.0.0.0/0,::/0 Endpoint = {% if ':' in IP_subject_alt_name %}[{{ IP_subject_alt_name }}]:{{ wireguard_port }}{% else %}{{ IP_subject_alt_name }}:{{ wireguard_port }}{% endif %} -{{ 'PersistentKeepalive = ' + wireguard_PersistentKeepalive|string if wireguard_PersistentKeepalive > 0 else '' }} +{{ 'PersistentKeepalive = ' + wireguard_PersistentKeepalive | string if wireguard_PersistentKeepalive > 0 else '' }} diff --git a/roles/wireguard/templates/server.conf.j2 b/roles/wireguard/templates/server.conf.j2 index 4f00e81d..6d0aa718 100644 --- a/roles/wireguard/templates/server.conf.j2 +++ b/roles/wireguard/templates/server.conf.j2 @@ -1,6 +1,6 @@ [Interface] Address = {{ wireguard_server_ip }} -ListenPort = {{ wireguard_port_actual if wireguard_port|int == wireguard_port_avoid|int else wireguard_port }} +ListenPort = {{ wireguard_port_actual if wireguard_port | int == wireguard_port_avoid | int else wireguard_port }} PrivateKey = {{ lookup('file', wireguard_pki_path + '/private/' + IP_subject_alt_name) }} SaveConfig = false @@ -12,6 +12,6 @@ SaveConfig = false # {{ u }} PublicKey = {{ lookup('file', wireguard_pki_path + '/public/' + u) }} PresharedKey = {{ lookup('file', wireguard_pki_path + '/preshared/' + u) }} -AllowedIPs = {{ wireguard_network_ipv4 | ansible.utils.ipmath(index|int+1) | ansible.utils.ipv4('address') }}/32{{ ',' + wireguard_network_ipv6 | ansible.utils.ipmath(index|int+1) | ansible.utils.ipv6('address') + '/128' if ipv6_support else '' }} +AllowedIPs = {{ wireguard_network_ipv4 | ansible.utils.ipmath(index | int+1) | ansible.utils.ipv4('address') }}/32{{ ',' + wireguard_network_ipv6 | ansible.utils.ipmath(index | int+1) | ansible.utils.ipv6('address') + '/128' if ipv6_support else '' }} {% endif %} {% endfor %} diff --git a/roles/wireguard/templates/vpn-dict.j2 b/roles/wireguard/templates/vpn-dict.j2 index 6444df96..4cbec89b 100644 --- a/roles/wireguard/templates/vpn-dict.j2 +++ b/roles/wireguard/templates/vpn-dict.j2 @@ -32,8 +32,8 @@ OnDemandRules {% if algo_ondemand_wifi or algo_ondemand_cellular %} - {% if algo_ondemand_wifi_exclude|b64decode != '_null' %} - {% set WIFI_EXCLUDE_LIST = (algo_ondemand_wifi_exclude|b64decode|string).split(',') %} + {% if algo_ondemand_wifi_exclude | b64decode != '_null' %} + {% set WIFI_EXCLUDE_LIST = (algo_ondemand_wifi_exclude | b64decode | string).split(',') %} Action Disconnect @@ -42,7 +42,7 @@ SSIDMatch {% for network_name in WIFI_EXCLUDE_LIST %} - {{ network_name|e }} + {{ network_name | e }} {% endfor %} diff --git a/server.yml b/server.yml index b33cad28..fd8119e2 100644 --- a/server.yml +++ b/server.yml @@ -184,7 +184,7 @@ content: | server: {{ 'localhost' if inventory_hostname == 'localhost' else inventory_hostname }} server_user: {{ ansible_ssh_user }} - ansible_ssh_port: "{{ ansible_ssh_port|default(22) }}" + ansible_ssh_port: "{{ ansible_ssh_port | default(22) }}" {% if algo_provider != "local" %} ansible_ssh_private_key_file: {{ SSH_keys.private }} {% endif %} @@ -199,7 +199,7 @@ IP_subject_alt_name: {{ IP_subject_alt_name }} ipsec_enabled: {{ ipsec_enabled }} wireguard_enabled: {{ wireguard_enabled }} - {% if tests|default(false)|bool %} + {% if tests | default(false) | bool %} ca_password: '{{ CA_password }}' p12_password: '{{ p12_export_password }}' {% endif %} diff --git a/tests/unit/test_lightsail_boto3_fix.py b/tests/unit/test_lightsail_boto3_fix.py new file mode 100644 index 00000000..d8dbbd4d --- /dev/null +++ b/tests/unit/test_lightsail_boto3_fix.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +""" +Test for AWS Lightsail boto3 parameter fix. +Verifies that get_aws_connection_info() works without the deprecated boto3 parameter. +Addresses issue #14822. +""" + +import importlib.util +import os +import sys +import unittest +from unittest.mock import MagicMock, patch + +# Add the library directory to the path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../library')) + + +class TestLightsailBoto3Fix(unittest.TestCase): + """Test that lightsail_region_facts.py works without boto3 parameter.""" + + def setUp(self): + """Set up test fixtures.""" + # Mock the ansible module_utils since we're testing outside of Ansible + self.mock_modules = { + 'ansible.module_utils.basic': MagicMock(), + 'ansible.module_utils.ec2': MagicMock(), + 'ansible.module_utils.aws.core': MagicMock(), + } + + # Apply mocks + self.patches = [] + for module_name, mock_module in self.mock_modules.items(): + patcher = patch.dict('sys.modules', {module_name: mock_module}) + patcher.start() + self.patches.append(patcher) + + def tearDown(self): + """Clean up patches.""" + for patcher in self.patches: + patcher.stop() + + def test_lightsail_region_facts_imports(self): + """Test that lightsail_region_facts can be imported.""" + try: + # Import the module + spec = importlib.util.spec_from_file_location( + "lightsail_region_facts", + os.path.join(os.path.dirname(__file__), '../../library/lightsail_region_facts.py') + ) + module = importlib.util.module_from_spec(spec) + + # This should not raise an error + spec.loader.exec_module(module) + + # Verify the module loaded + self.assertIsNotNone(module) + self.assertTrue(hasattr(module, 'main')) + + except Exception as e: + self.fail(f"Failed to import lightsail_region_facts: {e}") + + def test_get_aws_connection_info_called_without_boto3(self): + """Test that get_aws_connection_info is called without boto3 parameter.""" + # Mock get_aws_connection_info to track calls + mock_get_aws_connection_info = MagicMock( + return_value=('us-west-2', None, {}) + ) + + with patch('ansible.module_utils.ec2.get_aws_connection_info', mock_get_aws_connection_info): + # Import the module + spec = importlib.util.spec_from_file_location( + "lightsail_region_facts", + os.path.join(os.path.dirname(__file__), '../../library/lightsail_region_facts.py') + ) + module = importlib.util.module_from_spec(spec) + + # Mock AnsibleModule + mock_ansible_module = MagicMock() + mock_ansible_module.params = {} + mock_ansible_module.check_mode = False + + with patch('ansible.module_utils.basic.AnsibleModule', return_value=mock_ansible_module): + # Execute the module + try: + spec.loader.exec_module(module) + module.main() + except SystemExit: + # Module calls exit_json or fail_json which raises SystemExit + pass + except Exception: + # We expect some exceptions since we're mocking, but we want to check the call + pass + + # Verify get_aws_connection_info was called + if mock_get_aws_connection_info.called: + # Get the call arguments + call_args = mock_get_aws_connection_info.call_args + + # Ensure boto3=True is NOT in the arguments + if call_args: + # Check positional arguments + if call_args[0]: # args + self.assertTrue(len(call_args[0]) <= 1, + "get_aws_connection_info should be called with at most 1 positional arg (module)") + + # Check keyword arguments + if call_args[1]: # kwargs + self.assertNotIn('boto3', call_args[1], + "get_aws_connection_info should not be called with boto3 parameter") + + def test_no_boto3_parameter_in_source(self): + """Verify that boto3 parameter is not present in the source code.""" + lightsail_path = os.path.join(os.path.dirname(__file__), '../../library/lightsail_region_facts.py') + + with open(lightsail_path) as f: + content = f.read() + + # Check that boto3=True is not in the file + self.assertNotIn('boto3=True', content, + "boto3=True parameter should not be present in lightsail_region_facts.py") + + # Check that boto3 parameter is not used with get_aws_connection_info + self.assertNotIn('get_aws_connection_info(module, boto3', content, + "get_aws_connection_info should not be called with boto3 parameter") + + def test_regression_issue_14822(self): + """ + Regression test for issue #14822. + Ensures that the deprecated boto3 parameter is not used. + """ + # This test documents the specific issue that was fixed + # The boto3 parameter was deprecated and removed in amazon.aws collection + # that comes with Ansible 11.x + + lightsail_path = os.path.join(os.path.dirname(__file__), '../../library/lightsail_region_facts.py') + + with open(lightsail_path) as f: + lines = f.readlines() + + # Find the line that calls get_aws_connection_info + for line_num, line in enumerate(lines, 1): + if 'get_aws_connection_info' in line and 'region' in line: + # This should be around line 85 + # Verify it doesn't have boto3=True + self.assertNotIn('boto3', line, + f"Line {line_num} should not contain boto3 parameter") + + # Verify the correct format + self.assertIn('get_aws_connection_info(module)', line, + f"Line {line_num} should call get_aws_connection_info(module) without boto3") + break + else: + self.fail("Could not find get_aws_connection_info call in lightsail_region_facts.py") + + +if __name__ == '__main__': + unittest.main() diff --git a/users.yml b/users.yml index 02aa55a3..d6c1ea92 100644 --- a/users.yml +++ b/users.yml @@ -76,10 +76,10 @@ add_host: name: "{{ algo_server }}" groups: vpn-host - ansible_ssh_user: "{{ server_user|default('root') }}" + ansible_ssh_user: "{{ server_user | default('root') }}" ansible_connection: "{% if algo_server == 'localhost' %}local{% else %}ssh{% endif %}" ansible_python_interpreter: /usr/bin/python3 - CA_password: "{{ CA_password|default(omit) }}" + CA_password: "{{ CA_password | default(omit) }}" rescue: - include_tasks: playbooks/rescue.yml diff --git a/uv.lock b/uv.lock index 91091f08..60d0bf36 100644 --- a/uv.lock +++ b/uv.lock @@ -68,7 +68,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "ansible", specifier = "==11.8.0" }, + { name = "ansible", specifier = "==11.9.0" }, { name = "azure-identity", marker = "extra == 'azure'", specifier = ">=1.15.0" }, { name = "azure-mgmt-compute", marker = "extra == 'azure'", specifier = ">=30.0.0" }, { name = "azure-mgmt-network", marker = "extra == 'azure'", specifier = ">=25.0.0" }, @@ -99,19 +99,19 @@ dev = [ [[package]] name = "ansible" -version = "11.8.0" +version = "11.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ansible-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/82/74/b86d14d2c458edf27ddb56d42bf6d07335a0ccfc713f040fb0cbffd30017/ansible-11.8.0.tar.gz", hash = "sha256:28ea032c77f344bb8ea4d7d39f9a5d4e935e6c8b60836c8c8a28b9cf6c9adb1a", size = 44286995, upload-time = "2025-07-16T15:13:22.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/b3/01564da36375f35907c2ec6626d68f4d59e39e566c4b3f874f01d0d2ca19/ansible-11.9.0.tar.gz", hash = "sha256:528ca5a408f11cf1fea00daea7570e68d40e167be38b90c119a7cb45729e4921", size = 44589149, upload-time = "2025-08-12T16:03:31.912Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/47/23fe9f6d9cd533ce4d54f4925cb0b7fdcfd3500b226421aad6166d9aa11c/ansible-11.8.0-py3-none-any.whl", hash = "sha256:a2cd44c0d2c03972f5d676d1b024d09dd3d3edbd418fb0426f4dd356fca9e5b1", size = 56046023, upload-time = "2025-07-16T15:13:17.557Z" }, + { url = "https://files.pythonhosted.org/packages/84/fd/093dfe1f7f9f1058c0efa10b685f6049b676aa2c0ecd6f99c8664cafad6a/ansible-11.9.0-py3-none-any.whl", hash = "sha256:79b087ef38105b93e0e092e7013a0f840e154a6a8ce9b5fddd1b47593adc542a", size = 56340779, upload-time = "2025-08-12T16:03:26.18Z" }, ] [[package]] name = "ansible-core" -version = "2.18.7" +version = "2.18.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, @@ -120,9 +120,9 @@ dependencies = [ { name = "pyyaml" }, { name = "resolvelib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/29/33/cd25e1af669941fbb5c3d7ac4494cf4a288cb11f53225648d552f8bd8e54/ansible_core-2.18.7.tar.gz", hash = "sha256:1a129bf9fcd5dca2b17e83ce77147ee2fbc3c51a4958970152897cc5b6d0aae7", size = 3090256, upload-time = "2025-07-15T17:49:24.074Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/78/8b8680eaf7b1990a8d4c26f25cdf2b2eabaae764a3d8e5299b1d61c7c385/ansible_core-2.18.8.tar.gz", hash = "sha256:b0766215a96a47ce39933d27e1e996ca2beb54cf1b3907c742d35c913b1f78cd", size = 3088636, upload-time = "2025-08-11T19:03:12.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/a7/568e51c20f49c9e76a555a876ed641ecc59df29e93868f24cdf8c3289f6a/ansible_core-2.18.7-py3-none-any.whl", hash = "sha256:ac42ecb480fb98890d338072f7298cd462fb2117da6700d989c7ae688962ba69", size = 2209456, upload-time = "2025-07-15T17:49:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/a8/59/aa2c1918224b054c9a0d93812c0b446fa8ddba155dc96c855189fae9c82b/ansible_core-2.18.8-py3-none-any.whl", hash = "sha256:b60bc23b2f11fd0559a79d10ac152b52f58a18ca1b7be0a620dfe87f34ced689", size = 2218673, upload-time = "2025-08-11T19:03:04.75Z" }, ] [[package]] From 315898fafb327017e9630d00967ca6d7c69a563c Mon Sep 17 00:00:00 2001 From: Dan Guido Date: Sat, 16 Aug 2025 13:19:59 -0400 Subject: [PATCH 4/4] Fix Ubuntu 22.04 compatibility issues (#14824) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses two critical issues preventing Algo from working on Ubuntu 22.04: 1. Load af_key kernel module for StrongSwan - Ubuntu 22.04 minimal installs don't load af_key by default - Without this module, StrongSwan fails with namespace errors - Added modprobe task to ensure module is loaded persistently 2. Force iptables-legacy mode on Ubuntu 22.04+ - Ubuntu 22.04 uses iptables-nft backend by default - This causes firewall rules to be reordered incorrectly - VPN traffic gets blocked by misplaced DROP rules - Switching to iptables-legacy ensures correct rule ordering These changes restore full VPN functionality (both WireGuard and IPsec) on Ubuntu 22.04 installations. Closes #14820 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- roles/common/tasks/ubuntu.yml | 26 ++++++++++++++++++++++++++ roles/strongswan/tasks/ubuntu.yml | 7 +++++++ 2 files changed, 33 insertions(+) diff --git a/roles/common/tasks/ubuntu.yml b/roles/common/tasks/ubuntu.yml index 0d7e2d2d..b5a919ac 100644 --- a/roles/common/tasks/ubuntu.yml +++ b/roles/common/tasks/ubuntu.yml @@ -161,5 +161,31 @@ include_tasks: aip/main.yml when: alternative_ingress_ip +- name: Ubuntu 22.04+ | Use iptables-legacy for compatibility + block: + - name: Install iptables packages + apt: + name: + - iptables + - iptables-persistent + state: present + update_cache: true + + - name: Configure iptables-legacy as default + alternatives: + name: "{{ item }}" + path: "/usr/sbin/{{ item }}-legacy" + with_items: + - iptables + - ip6tables + - iptables-save + - iptables-restore + - ip6tables-save + - ip6tables-restore + when: + - ansible_distribution == "Ubuntu" + - ansible_distribution_version is version('22.04', '>=') + tags: iptables + - include_tasks: iptables.yml tags: iptables diff --git a/roles/strongswan/tasks/ubuntu.yml b/roles/strongswan/tasks/ubuntu.yml index f98fcf4c..b17b3a0b 100644 --- a/roles/strongswan/tasks/ubuntu.yml +++ b/roles/strongswan/tasks/ubuntu.yml @@ -2,6 +2,13 @@ - name: Set OS specific facts set_fact: strongswan_additional_plugins: [] + +- name: Ubuntu | Ensure af_key kernel module is loaded + modprobe: + name: af_key + state: present + persistent: present + - name: Ubuntu | Install strongSwan (individual) apt: name: strongswan