{"id":13589859,"url":"https://github.com/artis3n/ansible-role-tailscale","last_synced_at":"2025-05-15T15:07:16.255Z","repository":{"id":37797830,"uuid":"256806231","full_name":"artis3n/ansible-role-tailscale","owner":"artis3n","description":"Ansible role to install and configure a Tailscale node.","archived":false,"fork":false,"pushed_at":"2025-04-02T23:34:38.000Z","size":6104,"stargazers_count":449,"open_issues_count":26,"forks_count":72,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-07T21:10:04.635Z","etag":null,"topics":["ansible","ansible-role","hacktoberfest","tailscale"],"latest_commit_sha":null,"homepage":"https://galaxy.ansible.com/ui/standalone/roles/artis3n/tailscale/","language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/artis3n.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"artis3n"}},"created_at":"2020-04-18T16:55:32.000Z","updated_at":"2025-04-06T13:59:05.000Z","dependencies_parsed_at":"2023-02-18T09:15:31.568Z","dependency_job_id":"b157f93e-7b76-4862-8cb4-5bdec2cc4756","html_url":"https://github.com/artis3n/ansible-role-tailscale","commit_stats":{"total_commits":332,"total_committers":25,"mean_commits":13.28,"dds":0.5451807228915663,"last_synced_commit":"1f7764e4b7e5354599b02384bc2220170a8c42d8"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artis3n%2Fansible-role-tailscale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artis3n%2Fansible-role-tailscale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artis3n%2Fansible-role-tailscale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artis3n%2Fansible-role-tailscale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artis3n","download_url":"https://codeload.github.com/artis3n/ansible-role-tailscale/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254364270,"owners_count":22058878,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","hacktoberfest","tailscale"],"created_at":"2024-08-01T16:00:35.484Z","updated_at":"2025-05-15T15:07:11.229Z","avatar_url":"https://github.com/artis3n.png","language":"Makefile","funding_links":["https://github.com/sponsors/artis3n","https://github.com/sponsors/artis3n?sponsor=artis3n"],"categories":["hacktoberfest","ansible"],"sub_categories":[],"readme":"# artis3n.tailscale  \u003c!-- omit in toc --\u003e\n\n[![Ansible Role](https://img.shields.io/ansible/role/d/artis3n/tailscale)](https://galaxy.ansible.com/ui/standalone/roles/artis3n/tailscale/)\n[![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/artis3n/ansible-role-tailscale?include_prereleases)](https://github.com/artis3n/ansible-role-tailscale/releases)\n[![Molecule Tests](https://github.com/artis3n/ansible-role-tailscale/actions/workflows/pull_request_target.yml/badge.svg)](https://github.com/artis3n/ansible-role-tailscale/actions/workflows/pull_request_target.yml)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6312/badge)](https://bestpractices.coreinfrastructure.org/projects/6312)\n![GitHub last commit](https://img.shields.io/github/last-commit/artis3n/ansible-role-tailscale)\n![GitHub](https://img.shields.io/github/license/artis3n/ansible-role-tailscale)\n[![GitHub Sponsors](https://img.shields.io/github/sponsors/artis3n)](https://github.com/sponsors/artis3n)\n[![GitHub followers](https://img.shields.io/github/followers/artis3n?style=social)](https://github.com/artis3n/)\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/artis3n/ansible-role-tailscale?quickstart=1)\n\nThis role installs and configures [Tailscale][] on a Linux target.\n\n\u003e [!IMPORTANT]\n\u003e **This standalone role has been migrated into a collection (\u003chttps://github.com/artis3n/ansible-collection-tailscale\u003e).**\n\u003e\n\u003e This role will continue to function but future development work will focus on the collection.\n\u003e Please try out the collection and provide feedback on the new repo.\n\u003e\n\u003e `ansible-galaxy collection install artis3n.tailscale`\n\nSupported operating systems:\n- Debian / Ubuntu\n- CentOS / RedHat\n- Rocky Linux / AlmaLinux\n- Amazon Linux 2023 / Amazon Linux 2\n- Fedora\n- Arch Linux\n- OpenSUSE\n- Oracle Linux\n- Raspbian\n\nSee the [CI worfklow](https://github.com/artis3n/ansible-role-tailscale/blob/main/.github/workflows/pull_request_target.yml) for the list of distribution versions actively tested in each pull request.\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://asciinema.org/a/g8P2DT45oedUaxXSKGBKpU2Dl\"\u003e\u003cimg src=\"docs/demo.gif\" width=650 height=450\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003e [!TIP]\n\u003e This role uses Ansible fully qualified collection names (FQCN) and therefore requires Ansible 2.11+.\n\u003e Ansible 2.12 is set as the minimum required version as this was the version tested for compatibility during the FQCN refactor.\n\nIf you or your organization gets value out of this role, I would very much appreciate one-time or recurring [sponsorship](https://github.com/sponsors/artis3n?sponsor=artis3n) of this role.\n\n- [Role Outputs](#role-outputs)\n- [Role Variables](#role-variables)\n  - [Required](#required)\n    - [tailscale\\_authkey](#tailscale_authkey)\n    - [tailscale\\_tags](#tailscale_tags)\n    - [tailscale\\_up\\_skip](#tailscale_up_skip)\n  - [Optional](#optional)\n    - [state](#state)\n    - [tailscale\\_args](#tailscale_args)\n    - [tailscale\\_oauth\\_ephemeral](#tailscale_oauth_ephemeral)\n    - [tailscale\\_oauth\\_preauthorized](#tailscale_oauth_preauthorized)\n    - [insecurely\\_log\\_authkey](#insecurely_log_authkey)\n    - [release\\_stability](#release_stability)\n    - [tailscale\\_up\\_timeout](#tailscale_up_timeout)\n    - [verbose](#verbose)\n- [Dependencies](#dependencies)\n  - [Collections](#collections)\n- [Example Playbook](#example-playbook)\n- [State Tracking](#state-tracking)\n- [License](#license)\n- [Author Information](#author-information)\n- [Development and Contributing](#development-and-contributing)\n\n\nThis role will bubble up any stderr messages from the Tailscale binary\nto resolve any end-user configuration errors with `tailscale up` arguments.\nThe `--authkey=` value will be redacted unless [`insecurely_log_authkey`](#insecurely_log_authkey) is set to `true`.\n\n![logged stderr](docs/images/printed_stderr.png)\n\n# Role Outputs\n\nThis role provides the IP v4 and v6 addresses of the Tailscale node as well as the output of `tailscale whois` against the node as facts.\nSeveral key pieces of `whois` information are provided directly, with the rest of the whois output stored as a JSON fact for your convenience.\n\nOutputted facts:\n\n```\ntailscale_node_ipv4           (string): The IPv4 address of the Tailscale node.\ntailscale_node_ipv6           (string): The IPv6 address of the Tailscale node.\ntailscale_node_hostname_full  (string): The full hostname (node.domain.ts.net) of the Tailscale node.\ntailscale_node_hostname_short (string): The short hostname (node) of the Tailscale node.\ntailscale_node_created_at     (string): The ISO-8601 timestamp the Tailscale node was created.\ntailscale_node_tags           (list):   The tags assigned to the Tailscale node.\ntailscale_node_services       (list):   The discovered services running on the Tailscale node.\ntailscale_node_whois          (dict):   The full output of `tailscale whois` against the Tailscale node.\n```\n\n# Role Variables\n\n## Required\n\nOne of `tailscale_authkey` or `tailscale_up_skip` must be present.\nIn most cases you will use `tailscale_authkey`.\n\nIf you are uninstalling Tailscale (`state: absent`),\nneither `tailscale_authkey` nor `tailscale_up_skip` is required.\n\nIf you are authenticating with an OAuth key, you must also set `tailscale_tags`.\n\n### tailscale_authkey\n\nIs **not** required if `tailscale_up_skip` is set to `true`.\n\nA Tailscale Node Authorization auth key.\n\nA Node Authorization key can be generated under your Tailscale account. The role supports two type of keys:\n\n- Auth key (`tskey-auth-XXX-YYYYY`) \u003chttps://login.tailscale.com/admin/authkeys\u003e\n- OAuth key (`tskey-client-XXX-YYYY`) \u003chttps://login.tailscale.com/admin/settings/oauth\u003e\n\n\u003e [!IMPORTANT]\n\u003e Using an OAuth key requires the following role variables:\n\u003e `tailscale_tags` (must be provided),\n\u003e `tailscale_oauth_ephemeral` (defaults to `true`),\n\u003e and `tailscale_oauth_preauthorized` (defaults to `false`).\n\nNote that auth keys expire up to a maximum of 90 days after they are generated.\nOAuth secrets do not expire unless revoked,\nand the generated OAuth access token expires after 1 hour.\n\nFor more information, see Tailscale's [OAuth clients](https://tailscale.com/kb/1215/oauth-clients) page, especially [Generating long-lived auth keys](https://tailscale.com/kb/1215/oauth-clients#generating-long-lived-auth-keys).\n\nIf an OAuth key is used, be sure to grant the `write` Auth Keys scope to the OAuth client.\n\n\u003cimg src=\"https://github.com/user-attachments/assets/f1982344-d9a1-4c55-9c93-ed0a0cc4847c\" alt=\"OAuth scopes\" width=\"40%\" height=\"40%\"\u003e\n\nThis value should be treated as a sensitive secret.\n\n### tailscale_tags\n\n**Default**: `[]`\n\nApply supplied tags to the Tailscale nodes configured by this role\n(via the `--advertise-tags` flag to `tailscale up`).\nFor more information, see [What are tags?](https://tailscale.com/kb/1068/acl-tags?q=acl%20tag#what-are-acl-tags)\n\n\u003e [!NOTE]\n\u003e Tags are required for OAuth clients (`tailscale_authkey` OAuth key).\n\nEntries should not include `tag:`.\nFor example, `tailscale_tags: ['worker']` translates to `--advertise-tags=tag:worker`.\n\n### tailscale_up_skip\n\n**If set to true, `tailscale_authkey` is not required.**\n\n**Default**: `false`\n\nWhether to install and configure Tailscale as a service but skip running `tailscale up`.\nHelpful when packaging up a Tailscale installation into a build process, such as AMI creation,\nwhen the server should not yet authenticate to your Tailscale network.\n\n## Optional\n\n### state\n\n**Default**: `latest`\n\nWhether to install or uninstall Tailscale.\nIf defined, `state` must be either `latest`, `present`, or `absent`.\n\nThis role uses `latest` by default to help ensure your software remains up-to-date\nand incorporates the latest security and product features.\nFor users who desire more control over configuration drift,\n`present` will not update Tailscale if it is already installed.\n\nChanges to [`tailscale_args`](#tailscale_args) will be applied under both `latest` and `present`;\nthis parameter only impacts the version of Tailscale installed to the target system.\n\nIf set to `absent`, this role will de-register the Tailscale node (if already authenticated)\nand clean up or disable all Tailscale artifacts added to the system.\n\nNote that neither `tailscale_authkey` nor `tailscale_up_skip` is required if `state` is set to `absent`.\n\n### tailscale_args\n\nPass command-line arguments to `tailscale up`.\n\nNote that the [command][ansible.builtin.command] module is used,\nwhich does not support subshell expressions (`$()`) or bash operations like `;` and `\u0026`.\nOnly `tailscale up` arguments can be passed in.\n\n\u003e [!CAUTION]\n\u003e **Do not use this for `--authkey`.**\n\u003e Use the `tailscale_authkey` variable instead.\n\u003e\n\u003e **Do not use this for `--advertise-tags`.**\n\u003e Use the `tailscale_tags` variable instead.\n\u003e\n\u003e **Do not use this for `--timeout`.**\n\u003e Use the `tailscale_up_timeout` variable instead.\n\nAny stdout/stderr output from the `tailscale` binary will be printed.\nSince the tasks move quickly in this section, a 5 second pause is introduced\nto grant more time for users to realize a message was printed.\n\n![printed stdout](docs/images/printed_stdout.png)\n\nStderrs will continue to fail the role's execution.\nThe sensitive `--authkey` value will be redacted by default.\nIf you need to view the unredacted value, see [`insecurely_log_authkey`](#insecurely_log_authkey).\n\n### tailscale_oauth_ephemeral\n\n\u003e [!NOTE]\n\u003e Used only when `tailscale_authkey` is an OAuth key.\n\n**Default**: `true`\n\nRegister as an [ephemeral node](https://tailscale.com/kb/1111/ephemeral-nodes), if `true`.\n\n### tailscale_oauth_preauthorized\n\n\u003e [!NOTE]\n\u003e Used only when `tailscale_authkey` is an OAuth key.\n\n**Default**: `false`\n\nSkip [manual device approval](https://tailscale.com/kb/1099/device-approval), if `true`.\n\n### insecurely_log_authkey\n\n**Default**: `false`\n\nIf set to `true`, the \"Bring Tailscale Up\" command will include the raw value of the Tailscale authkey\nwhen logging any errors encountered during `tailscale up`.\nBy default, the authkey is not logged in successful task completions\nand is redacted in the `stderr` output by this role if an error occurs.\n\n![redacted authkey](docs/images/redacted_authkey.png)\n\nIf you are encountering an error bringing Tailscale up\nand want the \"Bring Tailscale Up\" task to _not_ redact the value of the authkey,\nset this variable to `true`.\n\nRegardless, if the authkey is invalid, the role will relay Tailscale's error message on that fact:\n\n![invalid authkey](docs/images/invalid_authkey.png)\n\n### release_stability\n\n**Default**: `stable`\n\nWhether to use the Tailscale stable or unstable track.\n\n`stable`:\n\n\u003e Stable releases. If you're not sure which track to use, pick this one.\n\n`unstable`:\n\n\u003e The bleeding edge. Pushed early and often. Expect rough edges!\n\n### tailscale_up_timeout\n\n**Default**: `120`\n\nDefines the timeout duration for the `tailscale up` command in seconds.\n\n\u003e   --timeout duration\n\u003e\n\u003e    \tmaximum amount of time to wait for tailscaled to enter a Running state\n\n### verbose\n\n**Default**: `false`\n\nWhether to output additional information during role execution.\nHelpful for debugging and collecting information to submit in a GitHub issue on this repository.\n\n# Dependencies\n\n## Collections\n\n- [`community.general`](https://docs.ansible.com/ansible/latest/collections/community/general/index.html)\n\n# Example Playbook\n\n```yaml\n- name: Servers\n  hosts: all\n  roles:\n    - role: artis3n.tailscale\n      vars:\n        # Example pulling the API key from the env vars on the host running Ansible\n        tailscale_authkey: \"{{ lookup('env', 'TAILSCALE_KEY') }}\"\n```\n\nEnable Tailscale SSH:\n\n```yaml\n- name: Servers\n  hosts: all\n  roles:\n    - role: artis3n.tailscale\n      vars:\n        # Example pulling the API key from the env vars on the host running Ansible\n        tailscale_authkey: \"{{ lookup('env', 'TAILSCALE_KEY') }}\"\n        tailscale_args: \"--ssh\"\n```\n\nPass arbitrary command-line arguments:\n\n```yaml\n- name: Servers\n  hosts: all\n  tasks:\n    - name: Use Headscale\n      include_role:\n        name: artis3n.tailscale\n      vars:\n        tailscale_args: \"--login-server='http://localhost:8080'\"\n        tailscale_authkey: \"{{ lookup('env', 'HEADSCALE_KEY') }}\"\n```\n\nGet verbose output:\n\n```yaml\n- name: Servers\n  hosts: all\n  roles:\n    - role: artis3n.tailscale\n      vars:\n        verbose: true\n        tailscale_authkey: \"{{ lookup('env', 'TAILSCALE_KEY') }}\"\n```\n\nConnect using an OAuth client secret:\n\n```yaml\n- name: Servers\n  hosts: all\n  roles:\n    - role: artis3n.tailscale\n      vars:\n        verbose: true\n        tailscale_authkey: \"{{ lookup('env', 'TAILSCALE_OAUTH_CLIENT_SECRET') }}\"\n        tailscale_tags:\n          - \"oauth\"\n        # Optionally, also include:\n        tailscale_oauth_ephemeral: true\n        tailscale_oauth_preauthorized: false\n```\n\nInstall Tailscale, but don't authenticate to the network:\n\n```yaml\n- name: Servers\n  hosts: all\n  roles:\n    - role: artis3n.tailscale\n      vars:\n        tailscale_up_skip: true\n```\n\nDe-register and uninstall a Tailscale node:\n\n```yaml\n- name: Servers\n  hosts: all\n  roles:\n    - role: artis3n.tailscale\n      vars:\n        state: absent\n```\n\n# State Tracking\n\nThis role will create an `artis3n-tailscale` directory in the target's [`XDG_STATE_HOME`](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) directory,\nor `$HOME/.local/state` if the variable is not present,\nin order to maintain a concept of state from the configuration of the arguments passed to `tailscale up`.\nThis allows the role to idempotently update a Tailscale node's configuration when needed.\nDeleting this directory will lead to this role re-configuring Tailscale when it is not needed,\nbut will not otherwise break anything.\nHowever, it is recommended that you let this Ansible role manage this directory and its contents.\n\nNote that:\n\n\u003e Flags are not persisted between runs; you must specify all flags each time.\n\u003e\n\u003e ...\n\u003e\n\u003e In Tailscale v1.8 or later, if you forget to specify a flag you added before,\n\u003e the CLI will warn you and provide a copyable command that includes all existing flags.\n\n\u003csmall\u003e\n\n\\- [docs: tailscale up][tailscale up docs]\n\n\u003c/small\u003e\n\n# License\n\nMIT\n\n# Author Information\n\nAri Kalfus ([@artis3n](https://www.artis3nal.com/)) \u003cdev@artis3nal.com\u003e\n\n# Development and Contributing\n\nThis GitHub repository uses a dedicated \"test\" Tailscale account to authenticate Tailscale during CI runs.\nEach Docker container creates a new authorized machine in that test account.\nThe machines are authorized with [ephemeral auth keys][]\nand are automatically cleaned up.\n\nThis authkey is stored in a [GitHub Action secret][] with the name `TAILSCALE_CI_KEY`.\nTo test OAuth authkey compatibility, a Tailscale OAuth client secret is stored as `TAILSCALE_OAUTH_CLIENT_SECRET`.\nIf you are a Collaborator on this repository,\nyou can open a GitHub CodeSpace and these secrets will be pre-populated for you in the environment.\n\nTo test this role locally, store the Tailscale ephemeral auth key in a `TAILSCALE_CI_KEY` env var\nand, if running the `oauth` Molecule scenario,\nadd an OAuth client secret in a `TAILSCALE_OAUTH_CLIENT_SECRET` env var.\n\nAlternatively for [Molecule][] testing,\nyou can use a [Headscale][] container that is spun up as part of the create/prepare steps.\nTo do this, set a `USE_HEADSCALE` env variable.\nFor example:\n\n```bash\nUSE_HEADSCALE=true molecule test\n```\n\n[ansible.builtin.command]: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html\n[ephemeral auth keys]: https://tailscale.com/kb/1111/ephemeral-nodes/\n[github action secret]: https://docs.github.com/en/actions/reference/encrypted-secrets\n[molecule]: https://ansible.readthedocs.io/projects/molecule/\n[tailscale]: https://tailscale.com/\n[tailscale up docs]: https://tailscale.com/kb/1080/cli/#up\n[headscale]: https://github.com/juanfont/headscale/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartis3n%2Fansible-role-tailscale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartis3n%2Fansible-role-tailscale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartis3n%2Fansible-role-tailscale/lists"}