diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..607e7e1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +# Set update schedule for GitHub Actions +--- +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d3536a5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,67 @@ +--- +name: CI +"on": + pull_request: + push: + branches: + - main + tags: + - "v*" + +defaults: + run: + working-directory: ngine_io.tailscale + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Check out the codebase. + uses: actions/checkout@v4 + with: + path: ngine_io.tailscale + + - name: Set up Python 3. + uses: actions/setup-python@v5 + with: + python-version: 3.x + + - name: Install test dependencies. + run: pip3 install ansible ansible-lint + + - name: Lint code. + run: | + ansible-lint . + + molecule: + name: Molecule + runs-on: ubuntu-latest + strategy: + matrix: + include: + - distro: debian12 + playbook: converge.yml + steps: + - name: Check out the codebase. + uses: actions/checkout@v4 + with: + path: ngine_io.tailscale + + - name: Set up Python 3. + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Install test dependencies. + run: | + python3 -m pip install ansible molecule molecule-docker docker + python3 -m pip install -r requirements.txt + + - name: Run Molecule tests. + run: molecule test + env: + PY_COLORS: "1" + ANSIBLE_FORCE_COLOR: "1" + MOLECULE_DISTRO: ${{ matrix.distro }} + MOLECULE_PLAYBOOK: ${{ matrix.playbook }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..904476e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,40 @@ +--- +# This workflow requires a GALAXY_API_KEY secret present in the GitHub +# repository or organization. + +name: Release +"on": + release: + types: [created] + +defaults: + run: + working-directory: ngine_io.tailscale + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Check out the codebase. + uses: actions/checkout@v4 + with: + path: ngine_io.tailscale + + - name: Set up Python 3. + uses: actions/setup-python@v5 + with: + python-version: 3.x + + - name: Install Ansible. + run: pip3 install ansible-core + + - name: Trigger a new import on Galaxy. + env: + ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} + run: >- + ansible-galaxy role import + --token "$ANSIBLE_GALAXY_API_KEY" + --role-name tailscale + $(echo ${{ github.repository }} | cut -d/ -f1) + $(echo ${{ github.repository }} | cut -d/ -f2) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38f8e88 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dev diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c98c96 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +[![CI](https://github.com/ngine-io/ansible-role-tailscale/actions/workflows/ci.yml/badge.svg)](https://github.com/ngine-io/ansible-role-tailscale/actions/workflows/ci.yml) + +# Ansible Role: Tailscale + +Installs [Tailscale](https://tailscale.com/) server on Debian Linux. + +## Requirements + +See `requirements.txt`. + +## Installation + +Via `requirements.yml`: + +```yaml +--- +# file: requirements.yml +roles: + - name: ngine_io.tailscale + version: v0.1.0 +``` + +To install: + +``` +ansible-galaxy install -r requirements.yml +``` +## License + +MIT / Apache2 + +## Author Information + +This role was created in 2024 by [René Moser](https://renemoser.net). diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..4aaf9b2 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,9 @@ +--- +tailscale__apt_key_url: https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg +tailscale__apt_repository_host: pkgs.tailscale.com +tailscale__apt_repository_url: https://{{ tailscale__apt_repository_host }}/stable/debian + +tailscale__version: "" +tailscale__package: tailscale +tailscale__auth_token: +tailscale__subnets: [] diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..23e36fc --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart tailscaled + ansible.builtin.systemd: + name: tailscaled + state: restarted diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..a5b55a9 --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + role_name: tailscale + namespace: ngine_io + author: René Moser + company: renemoser.net / ngine.io + description: Tailscale + license: "license (Apache2, MIT)" + min_ansible_version: "2.17" + platforms: + - name: Debian + versions: + # 12 + - bookworm + galaxy_tags: + - vpn + - tailscale diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..eb93411 --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,13 @@ +--- +- name: Converge + hosts: all + become: true + pre_tasks: + - name: Update apt cache + ansible.builtin.apt: + update_cache: true + cache_valid_time: 600 + when: ansible_os_family == "Debian" + changed_when: false + roles: + - role: ngine_io.tailscale diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..14d97d1 --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,18 @@ +--- +dependency: + name: galaxy +driver: + name: docker +platforms: + - name: instance + image: "geerlingguy/docker-${MOLECULE_DISTRO:-debian12}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + playbooks: + converge: ${MOLECULE_PLAYBOOK:-converge.yml} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..45c1e03 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +jmespath diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..16a78f4 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,65 @@ +--- +- name: Install HTTPS transport for apt + ansible.builtin.apt: + name: + - apt-transport-https + - ca-certificates + when: tailscale__apt_repository_url.startswith('https') + register: result + until: result is succeeded + retries: 5 + delay: 2 + +- name: Import GPG key to apt + ansible.builtin.get_url: + url: "{{ tailscale__apt_key_url }}" + dest: /etc/apt/trusted.gpg.d/tailscale.gpg + mode: "0644" + owner: "root" + register: result + until: result is succeeded + retries: 5 + delay: 2 + +- name: Add repository + ansible.builtin.apt_repository: + repo: deb {{ tailscale__apt_repository_url }} {{ ansible_distribution_release }} main + +- name: Install from repository + ansible.builtin.apt: + name: "{{ tailscale__package + '=' + tailscale__version if tailscale__version else tailscale__package }}" + register: result + until: result is succeeded + retries: 5 + delay: 2 + +- name: Configure IP forward + ansible.posix.sysctl: + name: "{{ item }}" + value: '1' + with_items: + - net.ipv4.ip_forward + - net.ipv6.conf.all.forwarding + notify: Restart tailscaled + +- name: Start and enable service + ansible.builtin.systemd: + name: tailscaled.service + state: started + enabled: true + +- name: Tailscale status + ansible.builtin.command: tailscale status --self --peers=false --json + register: _tailscale__status + changed_when: false + check_mode: false + +- name: Print Tailscale Backend State + ansible.builtin.debug: + msg: "BackendState is {{ _tailscale__status.stdout | ansible.builtin.from_json | community.general.json_query('BackendState') }}" + +- name: Tailscale up + ansible.builtin.command: # noqa: no-changed-when + args: tailscale up --auth-key={{ tailscale__auth_token }} --advertise-routes={{ tailscale__subnets | join(',') }} + when: tailscale__auth_token and _tailscale__status.stdout | ansible.builtin.from_json | community.general.json_query('BackendState') == 'NeedsLogin' + register: result